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 
159  struct ogg *ogg = s->priv_data;
160  int idx = ogg->nstreams++;
161  AVStream *st;
162  struct ogg_stream *os;
163 
164  os = av_realloc (ogg->streams, ogg->nstreams * sizeof (*ogg->streams));
165 
166  if (!os)
167  return AVERROR(ENOMEM);
168 
169  ogg->streams = os;
170 
171  memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
172  os = ogg->streams + idx;
173  os->serial = serial;
176  os->header = -1;
177 
178  if (new_avstream) {
179  st = avformat_new_stream(s, NULL);
180  if (!st)
181  return AVERROR(ENOMEM);
182 
183  st->id = idx;
184  avpriv_set_pts_info(st, 64, 1, 1000000);
185  }
186 
187  return idx;
188 }
189 
190 static int ogg_new_buf(struct ogg *ogg, int idx)
191 {
192  struct ogg_stream *os = ogg->streams + idx;
193  uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
194  int size = os->bufpos - os->pstart;
195  if(os->buf){
196  memcpy(nb, os->buf + os->pstart, size);
197  av_free(os->buf);
198  }
199  os->buf = nb;
200  os->bufpos = size;
201  os->pstart = 0;
202 
203  return 0;
204 }
205 
206 static int ogg_read_page(AVFormatContext *s, int *str)
207 {
208  AVIOContext *bc = s->pb;
209  struct ogg *ogg = s->priv_data;
210  struct ogg_stream *os;
211  int ret, i = 0;
212  int flags, nsegs;
213  uint64_t gp;
214  uint32_t serial;
215  int size, idx;
216  uint8_t sync[4];
217  int sp = 0;
218 
219  ret = avio_read(bc, sync, 4);
220  if (ret < 4)
221  return ret < 0 ? ret : AVERROR_EOF;
222 
223  do{
224  int c;
225 
226  if (sync[sp & 3] == 'O' &&
227  sync[(sp + 1) & 3] == 'g' &&
228  sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
229  break;
230 
231  c = avio_r8(bc);
232  if (bc->eof_reached)
233  return AVERROR_EOF;
234  sync[sp++ & 3] = c;
235  }while (i++ < MAX_PAGE_SIZE);
236 
237  if (i >= MAX_PAGE_SIZE){
238  av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
239  return AVERROR_INVALIDDATA;
240  }
241 
242  if (avio_r8(bc) != 0) /* version */
243  return AVERROR_INVALIDDATA;
244 
245  flags = avio_r8(bc);
246  gp = avio_rl64 (bc);
247  serial = avio_rl32 (bc);
248  avio_skip(bc, 8); /* seq, crc */
249  nsegs = avio_r8(bc);
250 
251  idx = ogg_find_stream (ogg, serial);
252  if (idx < 0){
253  if (ogg->headers) {
254  int n;
255 
256  for (n = 0; n < ogg->nstreams; n++) {
257  av_freep(&ogg->streams[n].buf);
258  if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
259  av_freep(&ogg->streams[n].private);
260  }
261  ogg->curidx = -1;
262  ogg->nstreams = 0;
263  idx = ogg_new_stream(s, serial, 0);
264  } else {
265  idx = ogg_new_stream(s, serial, 1);
266  }
267  if (idx < 0)
268  return idx;
269  }
270 
271  os = ogg->streams + idx;
272  os->page_pos = avio_tell(bc) - 27;
273 
274  if(os->psize > 0)
275  ogg_new_buf(ogg, idx);
276 
277  ret = avio_read(bc, os->segments, nsegs);
278  if (ret < nsegs)
279  return ret < 0 ? ret : AVERROR_EOF;
280 
281  os->nsegs = nsegs;
282  os->segp = 0;
283 
284  size = 0;
285  for (i = 0; i < nsegs; i++)
286  size += os->segments[i];
287 
288  if (flags & OGG_FLAG_CONT || os->incomplete){
289  if (!os->psize){
290  while (os->segp < os->nsegs){
291  int seg = os->segments[os->segp++];
292  os->pstart += seg;
293  if (seg < 255)
294  break;
295  }
296  os->sync_pos = os->page_pos;
297  }
298  }else{
299  os->psize = 0;
300  os->sync_pos = os->page_pos;
301  }
302 
303  if (os->bufsize - os->bufpos < size){
304  uint8_t *nb = av_malloc ((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
305  if (!nb)
306  return AVERROR(ENOMEM);
307  memcpy (nb, os->buf, os->bufpos);
308  av_free (os->buf);
309  os->buf = nb;
310  }
311 
312  ret = avio_read(bc, os->buf + os->bufpos, size);
313  if (ret < size)
314  return ret < 0 ? ret : AVERROR_EOF;
315 
316  os->bufpos += size;
317  os->granule = gp;
318  os->flags = flags;
319 
320  memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
321  if (str)
322  *str = idx;
323 
324  return 0;
325 }
326 
327 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
328  int64_t *fpos)
329 {
330  struct ogg *ogg = s->priv_data;
331  int idx, i, ret;
332  struct ogg_stream *os;
333  int complete = 0;
334  int segp = 0, psize = 0;
335 
336  av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
337 
338  do{
339  idx = ogg->curidx;
340 
341  while (idx < 0){
342  ret = ogg_read_page(s, &idx);
343  if (ret < 0)
344  return ret;
345  }
346 
347  os = ogg->streams + idx;
348 
349  av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
350  idx, os->pstart, os->psize, os->segp, os->nsegs);
351 
352  if (!os->codec){
353  if (os->header < 0){
354  os->codec = ogg_find_codec (os->buf, os->bufpos);
355  if (!os->codec){
356  av_log(s, AV_LOG_WARNING, "Codec not found\n");
357  os->header = 0;
358  return 0;
359  }
360  }else{
361  return 0;
362  }
363  }
364 
365  segp = os->segp;
366  psize = os->psize;
367 
368  while (os->segp < os->nsegs){
369  int ss = os->segments[os->segp++];
370  os->psize += ss;
371  if (ss < 255){
372  complete = 1;
373  break;
374  }
375  }
376 
377  if (!complete && os->segp == os->nsegs){
378  ogg->curidx = -1;
379  os->incomplete = 1;
380  }
381  }while (!complete);
382 
383  av_dlog(s, "ogg_packet: idx %i, frame size %i, start %i\n",
384  idx, os->psize, os->pstart);
385 
386  if (os->granule == -1)
387  av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
388 
389  ogg->curidx = idx;
390  os->incomplete = 0;
391 
392  if (os->header) {
393  os->header = os->codec->header (s, idx);
394  if (!os->header){
395  os->segp = segp;
396  os->psize = psize;
397 
398  // We have reached the first non-header packet in this stream.
399  // Unfortunately more header packets may still follow for others,
400  // but if we continue with header parsing we may lose data packets.
401  ogg->headers = 1;
402 
403  // Update the header state for all streams and
404  // compute the data_offset.
405  if (!s->data_offset)
406  s->data_offset = os->sync_pos;
407  for (i = 0; i < ogg->nstreams; i++) {
408  struct ogg_stream *cur_os = ogg->streams + i;
409 
410  // if we have a partial non-header packet, its start is
411  // obviously at or after the data start
412  if (cur_os->incomplete)
413  s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
414  }
415  }else{
416  os->pstart += os->psize;
417  os->psize = 0;
418  }
419  } else {
420  os->pflags = 0;
421  os->pduration = 0;
422  if (os->codec && os->codec->packet)
423  os->codec->packet (s, idx);
424  if (str)
425  *str = idx;
426  if (dstart)
427  *dstart = os->pstart;
428  if (dsize)
429  *dsize = os->psize;
430  if (fpos)
431  *fpos = os->sync_pos;
432  os->pstart += os->psize;
433  os->psize = 0;
434  os->sync_pos = os->page_pos;
435  }
436 
437  // determine whether there are more complete packets in this page
438  // if not, the page's granule will apply to this packet
439  os->page_end = 1;
440  for (i = os->segp; i < os->nsegs; i++)
441  if (os->segments[i] < 255) {
442  os->page_end = 0;
443  break;
444  }
445 
446  if (os->segp == os->nsegs)
447  ogg->curidx = -1;
448 
449  return 0;
450 }
451 
453 {
454  struct ogg *ogg = s->priv_data;
455  int ret;
456 
457  do{
458  ret = ogg_packet(s, NULL, NULL, NULL, NULL);
459  if (ret < 0)
460  return ret;
461  }while (!ogg->headers);
462 
463  av_dlog(s, "found headers\n");
464 
465  return 0;
466 }
467 
469 {
470  struct ogg *ogg = s->priv_data;
471  int i;
472  int64_t size, end;
473 
474  if(!s->pb->seekable)
475  return 0;
476 
477 // already set
478  if (s->duration != AV_NOPTS_VALUE)
479  return 0;
480 
481  size = avio_size(s->pb);
482  if(size < 0)
483  return 0;
484  end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
485 
486  ogg_save (s);
487  avio_seek (s->pb, end, SEEK_SET);
488 
489  while (!ogg_read_page (s, &i)){
490  if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
491  ogg->streams[i].codec) {
492  s->streams[i]->duration =
493  ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
494  if (s->streams[i]->start_time != AV_NOPTS_VALUE)
495  s->streams[i]->duration -= s->streams[i]->start_time;
496  }
497  }
498 
499  ogg_restore (s, 0);
500 
501  return 0;
502 }
503 
505 {
506  struct ogg *ogg = s->priv_data;
507  int i;
508 
509  for (i = 0; i < ogg->nstreams; i++) {
510  av_free(ogg->streams[i].buf);
511  if (ogg->streams[i].codec &&
512  ogg->streams[i].codec->cleanup) {
513  ogg->streams[i].codec->cleanup(s, i);
514  }
515  av_free(ogg->streams[i].private);
516  }
517  av_free(ogg->streams);
518  return 0;
519 }
520 
522 {
523  struct ogg *ogg = s->priv_data;
524  int ret, i;
525  ogg->curidx = -1;
526  //linear headers seek from start
527  ret = ogg_get_headers(s);
528  if (ret < 0) {
529  ogg_read_close(s);
530  return ret;
531  }
532 
533  for (i = 0; i < ogg->nstreams; i++)
534  if (ogg->streams[i].header < 0)
535  ogg->streams[i].codec = NULL;
536 
537  //linear granulepos seek from end
538  ogg_get_length (s);
539 
540  //fill the extradata in the per codec callbacks
541  return 0;
542 }
543 
544 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
545 {
546  struct ogg *ogg = s->priv_data;
547  struct ogg_stream *os = ogg->streams + idx;
548  int64_t pts = AV_NOPTS_VALUE;
549 
550  if (dts)
551  *dts = AV_NOPTS_VALUE;
552 
553  if (os->lastpts != AV_NOPTS_VALUE) {
554  pts = os->lastpts;
555  os->lastpts = AV_NOPTS_VALUE;
556  }
557  if (os->lastdts != AV_NOPTS_VALUE) {
558  if (dts)
559  *dts = os->lastdts;
560  os->lastdts = AV_NOPTS_VALUE;
561  }
562  if (os->page_end) {
563  if (os->granule != -1LL) {
564  if (os->codec && os->codec->granule_is_start)
565  pts = ogg_gptopts(s, idx, os->granule, dts);
566  else
567  os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
568  os->granule = -1LL;
569  }
570  }
571  return pts;
572 }
573 
575 {
576  struct ogg *ogg;
577  struct ogg_stream *os;
578  int idx = -1, ret;
579  int pstart, psize;
580  int64_t fpos, pts, dts;
581 
582  //Get an ogg packet
583 retry:
584  do{
585  ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
586  if (ret < 0)
587  return ret;
588  }while (idx < 0 || !s->streams[idx]);
589 
590  ogg = s->priv_data;
591  os = ogg->streams + idx;
592 
593  // pflags might not be set until after this
594  pts = ogg_calc_pts(s, idx, &dts);
595 
596  if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
597  goto retry;
598  os->keyframe_seek = 0;
599 
600  //Alloc a pkt
601  ret = av_new_packet(pkt, psize);
602  if (ret < 0)
603  return ret;
604  pkt->stream_index = idx;
605  memcpy (pkt->data, os->buf + pstart, psize);
606 
607  pkt->pts = pts;
608  pkt->dts = dts;
609  pkt->flags = os->pflags;
610  pkt->duration = os->pduration;
611  pkt->pos = fpos;
612 
613  return psize;
614 }
615 
616 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
617  int64_t *pos_arg, int64_t pos_limit)
618 {
619  struct ogg *ogg = s->priv_data;
620  AVIOContext *bc = s->pb;
621  int64_t pts = AV_NOPTS_VALUE;
622  int i = -1;
623  avio_seek(bc, *pos_arg, SEEK_SET);
624  ogg_reset(ogg);
625 
626  while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
627  if (i == stream_index) {
628  struct ogg_stream *os = ogg->streams + stream_index;
629  pts = ogg_calc_pts(s, i, NULL);
630  if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
631  pts = AV_NOPTS_VALUE;
632  }
633  if (pts != AV_NOPTS_VALUE)
634  break;
635  }
636  ogg_reset(ogg);
637  return pts;
638 }
639 
640 static int ogg_read_seek(AVFormatContext *s, int stream_index,
641  int64_t timestamp, int flags)
642 {
643  struct ogg *ogg = s->priv_data;
644  struct ogg_stream *os = ogg->streams + stream_index;
645  int ret;
646 
647  // Try seeking to a keyframe first. If this fails (very possible),
648  // av_seek_frame will fall back to ignoring keyframes
649  if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
650  && !(flags & AVSEEK_FLAG_ANY))
651  os->keyframe_seek = 1;
652 
653  ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
654  os = ogg->streams + stream_index;
655  if (ret < 0)
656  os->keyframe_seek = 0;
657  return ret;
658 }
659 
660 static int ogg_probe(AVProbeData *p)
661 {
662  if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
663  return AVPROBE_SCORE_MAX;
664  return 0;
665 }
666 
668  .name = "ogg",
669  .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
670  .priv_data_size = sizeof(struct ogg),
671  .read_probe = ogg_probe,
672  .read_header = ogg_read_header,
673  .read_packet = ogg_read_packet,
674  .read_close = ogg_read_close,
675  .read_seek = ogg_read_seek,
676  .read_timestamp = ogg_read_timestamp,
677  .extensions = "ogg",
678  .flags = AVFMT_GENERIC_INDEX,
679 };