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