oggdec.c
Go to the documentation of this file.
1 /*
2  * Ogg bitstream support
3  * Luca Barbato <lu_zero@gentoo.org>
4  * Based on tcvp implementation
5  */
6 
7 /*
8  Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
9 
10  Permission is hereby granted, free of charge, to any person
11  obtaining a copy of this software and associated documentation
12  files (the "Software"), to deal in the Software without
13  restriction, including without limitation the rights to use, copy,
14  modify, merge, publish, distribute, sublicense, and/or sell copies
15  of the Software, and to permit persons to whom the Software is
16  furnished to do so, subject to the following conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  DEALINGS IN THE SOFTWARE.
29  */
30 
31 
32 #include <stdio.h>
33 #include "oggdec.h"
34 #include "avformat.h"
35 #include "internal.h"
36 #include "vorbiscomment.h"
37 
38 #define MAX_PAGE_SIZE 65307
39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40 
41 static const struct ogg_codec * const ogg_codecs[] = {
55  NULL
56 };
57 
58 //FIXME We could avoid some structure duplication
59 static int ogg_save(AVFormatContext *s)
60 {
61  struct ogg *ogg = s->priv_data;
62  struct ogg_state *ost =
63  av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
64  int i;
65  ost->pos = avio_tell(s->pb);
66  ost->curidx = ogg->curidx;
67  ost->next = ogg->state;
68  ost->nstreams = ogg->nstreams;
69  memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70 
71  for (i = 0; i < ogg->nstreams; i++) {
72  struct ogg_stream *os = ogg->streams + i;
74  memcpy(os->buf, ost->streams[i].buf, os->bufpos);
75  }
76 
77  ogg->state = ost;
78 
79  return 0;
80 }
81 
82 static int ogg_restore(AVFormatContext *s, int discard)
83 {
84  struct ogg *ogg = s->priv_data;
85  AVIOContext *bc = s->pb;
86  struct ogg_state *ost = ogg->state;
87  int i;
88 
89  if (!ost)
90  return 0;
91 
92  ogg->state = ost->next;
93 
94  if (!discard) {
95  struct ogg_stream *old_streams = ogg->streams;
96 
97  for (i = 0; i < ogg->nstreams; i++)
98  av_free(ogg->streams[i].buf);
99 
100  avio_seek(bc, ost->pos, SEEK_SET);
101  ogg->curidx = ost->curidx;
102  ogg->nstreams = ost->nstreams;
103  ogg->streams = av_realloc(ogg->streams,
104  ogg->nstreams * sizeof(*ogg->streams));
105 
106  if (ogg->streams) {
107  memcpy(ogg->streams, ost->streams,
108  ost->nstreams * sizeof(*ogg->streams));
109  } else {
110  av_free(old_streams);
111  ogg->nstreams = 0;
112  }
113  }
114 
115  av_free(ost);
116 
117  return 0;
118 }
119 
120 static int ogg_reset(struct ogg *ogg)
121 {
122  int i;
123 
124  for (i = 0; i < ogg->nstreams; i++) {
125  struct ogg_stream *os = ogg->streams + i;
126  os->bufpos = 0;
127  os->pstart = 0;
128  os->psize = 0;
129  os->granule = -1;
130  os->lastpts = AV_NOPTS_VALUE;
131  os->lastdts = AV_NOPTS_VALUE;
132  os->sync_pos = -1;
133  os->page_pos = 0;
134  os->nsegs = 0;
135  os->segp = 0;
136  os->incomplete = 0;
137  }
138 
139  ogg->curidx = -1;
140 
141  return 0;
142 }
143 
144 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
145 {
146  int i;
147 
148  for (i = 0; ogg_codecs[i]; i++)
149  if (size >= ogg_codecs[i]->magicsize &&
150  !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
151  return ogg_codecs[i];
152 
153  return NULL;
154 }
155 
156 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
157 {
158  struct ogg *ogg = s->priv_data;
159  int idx = ogg->nstreams++;
160  AVStream *st;
161  struct ogg_stream *os;
162 
163  os = av_realloc(ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
164 
165  if (!os)
166  return AVERROR(ENOMEM);
167 
168  ogg->streams = os;
169 
170  memset(ogg->streams + idx, 0, sizeof(*ogg->streams));
171 
172  os = ogg->streams + idx;
173  os->serial = serial;
176  os->header = -1;
178 
179  if (new_avstream) {
180  st = avformat_new_stream(s, NULL);
181  if (!st)
182  return AVERROR(ENOMEM);
183 
184  st->id = idx;
185  avpriv_set_pts_info(st, 64, 1, 1000000);
186  }
187 
188  return idx;
189 }
190 
191 static int ogg_new_buf(struct ogg *ogg, int idx)
192 {
193  struct ogg_stream *os = ogg->streams + idx;
195  int size = os->bufpos - os->pstart;
196 
197  if (os->buf) {
198  memcpy(nb, os->buf + os->pstart, size);
199  av_free(os->buf);
200  }
201 
202  os->buf = nb;
203  os->bufpos = size;
204  os->pstart = 0;
205 
206  return 0;
207 }
208 
209 static int ogg_read_page(AVFormatContext *s, int *str)
210 {
211  AVIOContext *bc = s->pb;
212  struct ogg *ogg = s->priv_data;
213  struct ogg_stream *os;
214  int ret, i = 0;
215  int flags, nsegs;
216  uint64_t gp;
217  uint32_t serial;
218  int size, idx;
219  uint8_t sync[4];
220  int sp = 0;
221 
222  ret = avio_read(bc, sync, 4);
223  if (ret < 4)
224  return ret < 0 ? ret : AVERROR_EOF;
225 
226  do {
227  int c;
228 
229  if (sync[sp & 3] == 'O' &&
230  sync[(sp + 1) & 3] == 'g' &&
231  sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
232  break;
233 
234  c = avio_r8(bc);
235 
236  if (bc->eof_reached)
237  return AVERROR_EOF;
238 
239  sync[sp++ & 3] = c;
240  } while (i++ < MAX_PAGE_SIZE);
241 
242  if (i >= MAX_PAGE_SIZE) {
243  av_log(s, AV_LOG_INFO, "cannot find sync word\n");
244  return AVERROR_INVALIDDATA;
245  }
246 
247  if (avio_r8(bc) != 0) /* version */
248  return AVERROR_INVALIDDATA;
249 
250  flags = avio_r8(bc);
251  gp = avio_rl64(bc);
252  serial = avio_rl32(bc);
253  avio_skip(bc, 8); /* seq, crc */
254  nsegs = avio_r8(bc);
255 
256  idx = ogg_find_stream(ogg, serial);
257  if (idx < 0) {
258  if (ogg->headers) {
259  int n;
260 
261  for (n = 0; n < ogg->nstreams; n++) {
262  av_freep(&ogg->streams[n].buf);
263  if (!ogg->state ||
264  ogg->state->streams[n].private != ogg->streams[n].private)
265  av_freep(&ogg->streams[n].private);
266  }
267 
268  ogg->curidx = -1;
269  ogg->nstreams = 0;
270 
271  idx = ogg_new_stream(s, serial, 0);
272  } else {
273  idx = ogg_new_stream(s, serial, 1);
274  }
275  if (idx < 0)
276  return idx;
277  }
278 
279  os = ogg->streams + idx;
280  os->page_pos = avio_tell(bc) - 27;
281 
282  if (os->psize > 0)
283  ogg_new_buf(ogg, idx);
284 
285  ret = avio_read(bc, os->segments, nsegs);
286  if (ret < nsegs)
287  return ret < 0 ? ret : AVERROR_EOF;
288 
289  os->nsegs = nsegs;
290  os->segp = 0;
291 
292  size = 0;
293  for (i = 0; i < nsegs; i++)
294  size += os->segments[i];
295 
296  if (flags & OGG_FLAG_CONT || os->incomplete) {
297  if (!os->psize) {
298  while (os->segp < os->nsegs) {
299  int seg = os->segments[os->segp++];
300  os->pstart += seg;
301  if (seg < 255)
302  break;
303  }
304  os->sync_pos = os->page_pos;
305  }
306  } else {
307  os->psize = 0;
308  os->sync_pos = os->page_pos;
309  }
310 
311  if (os->bufsize - os->bufpos < size) {
313  if (!nb)
314  return AVERROR(ENOMEM);
315  memcpy(nb, os->buf, os->bufpos);
316  av_free(os->buf);
317  os->buf = nb;
318  }
319 
320  ret = avio_read(bc, os->buf + os->bufpos, size);
321  if (ret < size)
322  return ret < 0 ? ret : AVERROR_EOF;
323 
324  os->bufpos += size;
325  os->granule = gp;
326  os->flags = flags;
327 
328  memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
329  if (str)
330  *str = idx;
331 
332  return 0;
333 }
334 
335 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
336  int64_t *fpos)
337 {
338  struct ogg *ogg = s->priv_data;
339  int idx, i, ret;
340  struct ogg_stream *os;
341  int complete = 0;
342  int segp = 0, psize = 0;
343 
344  av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
345 
346  do {
347  idx = ogg->curidx;
348 
349  while (idx < 0) {
350  ret = ogg_read_page(s, &idx);
351  if (ret < 0)
352  return ret;
353  }
354 
355  os = ogg->streams + idx;
356 
357  av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
358  idx, os->pstart, os->psize, os->segp, os->nsegs);
359 
360  if (!os->codec) {
361  if (os->header < 0) {
362  os->codec = ogg_find_codec(os->buf, os->bufpos);
363  if (!os->codec) {
364  av_log(s, AV_LOG_WARNING, "Codec not found\n");
365  os->header = 0;
366  return 0;
367  }
368  } else {
369  return 0;
370  }
371  }
372 
373  segp = os->segp;
374  psize = os->psize;
375 
376  while (os->segp < os->nsegs) {
377  int ss = os->segments[os->segp++];
378  os->psize += ss;
379  if (ss < 255) {
380  complete = 1;
381  break;
382  }
383  }
384 
385  if (!complete && os->segp == os->nsegs) {
386  ogg->curidx = -1;
387  // Do not set incomplete for empty packets.
388  // Together with the code in ogg_read_page
389  // that discards all continuation of empty packets
390  // we would get an infinite loop.
391  os->incomplete = !!os->psize;
392  }
393  } while (!complete);
394 
395  av_dlog(s, "ogg_packet: idx %i, frame size %i, start %i\n",
396  idx, os->psize, os->pstart);
397 
398  if (os->granule == -1)
400  "Page at %"PRId64" is missing granule\n",
401  os->page_pos);
402 
403  ogg->curidx = idx;
404  os->incomplete = 0;
405 
406  if (os->header) {
407  os->header = os->codec->header(s, idx);
408  if (!os->header) {
409  os->segp = segp;
410  os->psize = psize;
411 
412  // We have reached the first non-header packet in this stream.
413  // Unfortunately more header packets may still follow for others,
414  // but if we continue with header parsing we may lose data packets.
415  ogg->headers = 1;
416 
417  // Update the header state for all streams and
418  // compute the data_offset.
419  if (!s->data_offset)
420  s->data_offset = os->sync_pos;
421 
422  for (i = 0; i < ogg->nstreams; i++) {
423  struct ogg_stream *cur_os = ogg->streams + i;
424 
425  // if we have a partial non-header packet, its start is
426  // obviously at or after the data start
427  if (cur_os->incomplete)
428  s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
429  }
430  } else {
431  os->nb_header++;
432  os->pstart += os->psize;
433  os->psize = 0;
434  }
435  } else {
436  os->pflags = 0;
437  os->pduration = 0;
438  if (os->codec && os->codec->packet)
439  os->codec->packet(s, idx);
440  if (str)
441  *str = idx;
442  if (dstart)
443  *dstart = os->pstart;
444  if (dsize)
445  *dsize = os->psize;
446  if (fpos)
447  *fpos = os->sync_pos;
448  os->pstart += os->psize;
449  os->psize = 0;
450  os->sync_pos = os->page_pos;
451  }
452 
453  // determine whether there are more complete packets in this page
454  // if not, the page's granule will apply to this packet
455  os->page_end = 1;
456  for (i = os->segp; i < os->nsegs; i++)
457  if (os->segments[i] < 255) {
458  os->page_end = 0;
459  break;
460  }
461 
462  if (os->segp == os->nsegs)
463  ogg->curidx = -1;
464 
465  return 0;
466 }
467 
469 {
470  struct ogg *ogg = s->priv_data;
471  int ret, i;
472 
473  do {
474  ret = ogg_packet(s, NULL, NULL, NULL, NULL);
475  if (ret < 0)
476  return ret;
477  } while (!ogg->headers);
478 
479  for (i = 0; i < ogg->nstreams; i++) {
480  struct ogg_stream *os = ogg->streams + i;
481 
482  if (os->codec && os->codec->nb_header &&
483  os->nb_header < os->codec->nb_header) {
484  av_log(s, AV_LOG_ERROR,
485  "Headers mismatch for stream %d\n", i);
486  return AVERROR_INVALIDDATA;
487  }
489  os->lastpts = s->streams[i]->start_time =
490  ogg_gptopts(s, i, os->start_granule, NULL);
491  }
492  av_dlog(s, "found headers\n");
493 
494  return 0;
495 }
496 
498 {
499  struct ogg *ogg = s->priv_data;
500  int i;
501  int64_t size, end;
502 
503  if (!s->pb->seekable)
504  return 0;
505 
506 // already set
507  if (s->duration != AV_NOPTS_VALUE)
508  return 0;
509 
510  size = avio_size(s->pb);
511  if (size < 0)
512  return 0;
513  end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
514 
515  ogg_save(s);
516  avio_seek(s->pb, end, SEEK_SET);
517 
518  while (!ogg_read_page(s, &i)) {
519  if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
520  ogg->streams[i].codec) {
521  s->streams[i]->duration =
522  ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
523  if (s->streams[i]->start_time != AV_NOPTS_VALUE)
524  s->streams[i]->duration -= s->streams[i]->start_time;
525  }
526  }
527 
528  ogg_restore(s, 0);
529 
530  return 0;
531 }
532 
534 {
535  struct ogg *ogg = s->priv_data;
536  int i;
537 
538  for (i = 0; i < ogg->nstreams; i++) {
539  av_free(ogg->streams[i].buf);
540  if (ogg->streams[i].codec &&
541  ogg->streams[i].codec->cleanup) {
542  ogg->streams[i].codec->cleanup(s, i);
543  }
544  av_free(ogg->streams[i].private);
545  }
546  av_free(ogg->streams);
547  return 0;
548 }
549 
551 {
552  struct ogg *ogg = s->priv_data;
553  int ret, i;
554  ogg->curidx = -1;
555  //linear headers seek from start
556  ret = ogg_get_headers(s);
557  if (ret < 0) {
558  ogg_read_close(s);
559  return ret;
560  }
561 
562  for (i = 0; i < ogg->nstreams; i++)
563  if (ogg->streams[i].header < 0)
564  ogg->streams[i].codec = NULL;
565 
566  //linear granulepos seek from end
567  ogg_get_length(s);
568 
569  //fill the extradata in the per codec callbacks
570  return 0;
571 }
572 
573 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
574 {
575  struct ogg *ogg = s->priv_data;
576  struct ogg_stream *os = ogg->streams + idx;
577  int64_t pts = AV_NOPTS_VALUE;
578 
579  if (dts)
580  *dts = AV_NOPTS_VALUE;
581 
582  if (os->lastpts != AV_NOPTS_VALUE) {
583  pts = os->lastpts;
584  os->lastpts = AV_NOPTS_VALUE;
585  }
586  if (os->lastdts != AV_NOPTS_VALUE) {
587  if (dts)
588  *dts = os->lastdts;
589  os->lastdts = AV_NOPTS_VALUE;
590  }
591  if (os->page_end) {
592  if (os->granule != -1LL) {
593  if (os->codec && os->codec->granule_is_start)
594  pts = ogg_gptopts(s, idx, os->granule, dts);
595  else
596  os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
597  os->granule = -1LL;
598  }
599  }
600  return pts;
601 }
602 
604 {
605  struct ogg *ogg;
606  struct ogg_stream *os;
607  int idx = -1, ret;
608  int pstart, psize;
609  int64_t fpos, pts, dts;
610 
611  //Get an ogg packet
612 retry:
613  do {
614  ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
615  if (ret < 0)
616  return ret;
617  } while (idx < 0 || !s->streams[idx]);
618 
619  ogg = s->priv_data;
620  os = ogg->streams + idx;
621 
622  // pflags might not be set until after this
623  pts = ogg_calc_pts(s, idx, &dts);
624 
625  if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
626  goto retry;
627  os->keyframe_seek = 0;
628 
629  //Alloc a pkt
630  ret = av_new_packet(pkt, psize);
631  if (ret < 0)
632  return ret;
633  pkt->stream_index = idx;
634  memcpy(pkt->data, os->buf + pstart, psize);
635 
636  pkt->pts = pts;
637  pkt->dts = dts;
638  pkt->flags = os->pflags;
639  pkt->duration = os->pduration;
640  pkt->pos = fpos;
641 
642  return psize;
643 }
644 
645 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
646  int64_t *pos_arg, int64_t pos_limit)
647 {
648  struct ogg *ogg = s->priv_data;
649  AVIOContext *bc = s->pb;
650  int64_t pts = AV_NOPTS_VALUE;
651  int i = -1;
652  avio_seek(bc, *pos_arg, SEEK_SET);
653  ogg_reset(ogg);
654 
655  while (avio_tell(bc) < pos_limit &&
656  !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
657  if (i == stream_index) {
658  struct ogg_stream *os = ogg->streams + stream_index;
659  pts = ogg_calc_pts(s, i, NULL);
660  if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
661  pts = AV_NOPTS_VALUE;
662  }
663  if (pts != AV_NOPTS_VALUE)
664  break;
665  }
666  ogg_reset(ogg);
667  return pts;
668 }
669 
670 static int ogg_read_seek(AVFormatContext *s, int stream_index,
671  int64_t timestamp, int flags)
672 {
673  struct ogg *ogg = s->priv_data;
674  struct ogg_stream *os = ogg->streams + stream_index;
675  int ret;
676 
677  // Try seeking to a keyframe first. If this fails (very possible),
678  // av_seek_frame will fall back to ignoring keyframes
679  if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
680  && !(flags & AVSEEK_FLAG_ANY))
681  os->keyframe_seek = 1;
682 
683  ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
684  os = ogg->streams + stream_index;
685  if (ret < 0)
686  os->keyframe_seek = 0;
687  return ret;
688 }
689 
690 static int ogg_probe(AVProbeData *p)
691 {
692  if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
693  return AVPROBE_SCORE_MAX;
694  return 0;
695 }
696 
698  .name = "ogg",
699  .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
700  .priv_data_size = sizeof(struct ogg),
701  .read_probe = ogg_probe,
702  .read_header = ogg_read_header,
703  .read_packet = ogg_read_packet,
704  .read_close = ogg_read_close,
705  .read_seek = ogg_read_seek,
706  .read_timestamp = ogg_read_timestamp,
707  .extensions = "ogg",
708  .flags = AVFMT_GENERIC_INDEX,
709 };