FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 #include <stdio.h>
32 #include "libavutil/avassert.h"
33 #include "libavutil/intreadwrite.h"
34 #include "oggdec.h"
35 #include "avformat.h"
36 #include "internal.h"
37 #include "vorbiscomment.h"
38 
39 #define MAX_PAGE_SIZE 65307
40 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
41 
42 static const struct ogg_codec * const ogg_codecs[] = {
51  &ff_vp8_codec,
58  NULL
59 };
60 
61 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
62 static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
63 
64 //FIXME We could avoid some structure duplication
66 {
67  struct ogg *ogg = s->priv_data;
68  struct ogg_state *ost =
69  av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
70  int i;
71 
72  if (!ost)
73  return AVERROR(ENOMEM);
74 
75  ost->pos = avio_tell(s->pb);
76  ost->curidx = ogg->curidx;
77  ost->next = ogg->state;
78  ost->nstreams = ogg->nstreams;
79  memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
80 
81  for (i = 0; i < ogg->nstreams; i++) {
82  struct ogg_stream *os = ogg->streams + i;
84  memcpy(os->buf, ost->streams[i].buf, os->bufpos);
85  os->new_metadata = NULL;
86  os->new_metadata_size = 0;
87  }
88 
89  ogg->state = ost;
90 
91  return 0;
92 }
93 
94 static int ogg_restore(AVFormatContext *s, int discard)
95 {
96  struct ogg *ogg = s->priv_data;
97  AVIOContext *bc = s->pb;
98  struct ogg_state *ost = ogg->state;
99  int i, err;
100 
101  if (!ost)
102  return 0;
103 
104  ogg->state = ost->next;
105 
106  if (!discard) {
107 
108  for (i = 0; i < ogg->nstreams; i++)
109  av_freep(&ogg->streams[i].buf);
110 
111  avio_seek(bc, ost->pos, SEEK_SET);
112  ogg->page_pos = -1;
113  ogg->curidx = ost->curidx;
114  ogg->nstreams = ost->nstreams;
115  if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
116  sizeof(*ogg->streams))) < 0) {
117  ogg->nstreams = 0;
118  return err;
119  } else
120  memcpy(ogg->streams, ost->streams,
121  ost->nstreams * sizeof(*ogg->streams));
122  }
123 
124  av_free(ost);
125 
126  return 0;
127 }
128 
130 {
131  struct ogg *ogg = s->priv_data;
132  int i;
133  int64_t start_pos = avio_tell(s->pb);
134 
135  for (i = 0; i < ogg->nstreams; i++) {
136  struct ogg_stream *os = ogg->streams + i;
137  os->bufpos = 0;
138  os->pstart = 0;
139  os->psize = 0;
140  os->granule = -1;
141  os->lastpts = AV_NOPTS_VALUE;
142  os->lastdts = AV_NOPTS_VALUE;
143  os->sync_pos = -1;
144  os->page_pos = 0;
145  os->nsegs = 0;
146  os->segp = 0;
147  os->incomplete = 0;
148  os->got_data = 0;
149  if (start_pos <= s->internal->data_offset) {
150  os->lastpts = 0;
151  }
152  os->end_trimming = 0;
153  av_freep(&os->new_metadata);
154  os->new_metadata_size = 0;
155  }
156 
157  ogg->page_pos = -1;
158  ogg->curidx = -1;
159 
160  return 0;
161 }
162 
163 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
164 {
165  int i;
166 
167  for (i = 0; ogg_codecs[i]; i++)
168  if (size >= ogg_codecs[i]->magicsize &&
169  !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
170  return ogg_codecs[i];
171 
172  return NULL;
173 }
174 
175 /**
176  * Replace the current stream with a new one. This is a typical webradio
177  * situation where a new audio stream spawn (identified with a new serial) and
178  * must replace the previous one (track switch).
179  */
180 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
181 {
182  struct ogg *ogg = s->priv_data;
183  struct ogg_stream *os;
184  const struct ogg_codec *codec;
185  int i = 0;
186 
187  if (s->pb->seekable) {
188  uint8_t magic[8];
189  int64_t pos = avio_tell(s->pb);
190  avio_skip(s->pb, nsegs);
191  avio_read(s->pb, magic, sizeof(magic));
192  avio_seek(s->pb, pos, SEEK_SET);
193  codec = ogg_find_codec(magic, sizeof(magic));
194  if (!codec) {
195  av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
196  return AVERROR_INVALIDDATA;
197  }
198  for (i = 0; i < ogg->nstreams; i++) {
199  if (ogg->streams[i].codec == codec)
200  break;
201  }
202  if (i >= ogg->nstreams)
203  return ogg_new_stream(s, serial);
204  } else if (ogg->nstreams != 1) {
205  avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
206  return AVERROR_PATCHWELCOME;
207  }
208 
209  os = &ogg->streams[i];
210 
211  os->serial = serial;
212  return i;
213 
214 #if 0
215  buf = os->buf;
216  bufsize = os->bufsize;
217  codec = os->codec;
218 
219  if (!ogg->state || ogg->state->streams[i].private != os->private)
220  av_freep(&ogg->streams[i].private);
221 
222  /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
223  * also re-use the ogg_stream allocated buffer */
224  memset(os, 0, sizeof(*os));
225  os->serial = serial;
226  os->bufsize = bufsize;
227  os->buf = buf;
228  os->header = -1;
229  os->codec = codec;
230 
231  return i;
232 #endif
233 }
234 
235 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
236 {
237  struct ogg *ogg = s->priv_data;
238  int idx = ogg->nstreams;
239  AVStream *st;
240  struct ogg_stream *os;
241  size_t size;
242 
243  if (ogg->state) {
244  av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
245  "in between Ogg context save/restore operations.\n");
246  return AVERROR_BUG;
247  }
248 
249  /* Allocate and init a new Ogg Stream */
250  if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
251  !(os = av_realloc(ogg->streams, size)))
252  return AVERROR(ENOMEM);
253  ogg->streams = os;
254  os = ogg->streams + idx;
255  memset(os, 0, sizeof(*os));
256  os->serial = serial;
259  os->header = -1;
261  if (!os->buf)
262  return AVERROR(ENOMEM);
263 
264  /* Create the associated AVStream */
265  st = avformat_new_stream(s, NULL);
266  if (!st) {
267  av_freep(&os->buf);
268  return AVERROR(ENOMEM);
269  }
270  st->id = idx;
271  avpriv_set_pts_info(st, 64, 1, 1000000);
272 
273  ogg->nstreams++;
274  return idx;
275 }
276 
277 static int ogg_new_buf(struct ogg *ogg, int idx)
278 {
279  struct ogg_stream *os = ogg->streams + idx;
281  int size = os->bufpos - os->pstart;
282 
283  if (!nb)
284  return AVERROR(ENOMEM);
285 
286  if (os->buf) {
287  memcpy(nb, os->buf + os->pstart, size);
288  av_free(os->buf);
289  }
290 
291  os->buf = nb;
292  os->bufpos = size;
293  os->pstart = 0;
294 
295  return 0;
296 }
297 
298 static int data_packets_seen(const struct ogg *ogg)
299 {
300  int i;
301 
302  for (i = 0; i < ogg->nstreams; i++)
303  if (ogg->streams[i].got_data)
304  return 1;
305  return 0;
306 }
307 
308 static int ogg_read_page(AVFormatContext *s, int *sid)
309 {
310  AVIOContext *bc = s->pb;
311  struct ogg *ogg = s->priv_data;
312  struct ogg_stream *os;
313  int ret, i = 0;
314  int flags, nsegs;
315  uint64_t gp;
316  uint32_t serial;
317  int size, idx;
318  uint8_t sync[4];
319  int sp = 0;
320 
321  ret = avio_read(bc, sync, 4);
322  if (ret < 4)
323  return ret < 0 ? ret : AVERROR_EOF;
324 
325  do {
326  int c;
327 
328  if (sync[sp & 3] == 'O' &&
329  sync[(sp + 1) & 3] == 'g' &&
330  sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
331  break;
332 
333  if(!i && bc->seekable && ogg->page_pos > 0) {
334  memset(sync, 0, 4);
335  avio_seek(bc, ogg->page_pos+4, SEEK_SET);
336  ogg->page_pos = -1;
337  }
338 
339  c = avio_r8(bc);
340 
341  if (avio_feof(bc))
342  return AVERROR_EOF;
343 
344  sync[sp++ & 3] = c;
345  } while (i++ < MAX_PAGE_SIZE);
346 
347  if (i >= MAX_PAGE_SIZE) {
348  av_log(s, AV_LOG_INFO, "cannot find sync word\n");
349  return AVERROR_INVALIDDATA;
350  }
351 
352  if (avio_r8(bc) != 0) { /* version */
353  av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
354  return AVERROR_INVALIDDATA;
355  }
356 
357  flags = avio_r8(bc);
358  gp = avio_rl64(bc);
359  serial = avio_rl32(bc);
360  avio_skip(bc, 8); /* seq, crc */
361  nsegs = avio_r8(bc);
362 
363  idx = ogg_find_stream(ogg, serial);
364  if (idx < 0) {
365  if (data_packets_seen(ogg))
366  idx = ogg_replace_stream(s, serial, nsegs);
367  else
368  idx = ogg_new_stream(s, serial);
369 
370  if (idx < 0) {
371  av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
372  return idx;
373  }
374  }
375 
376  os = ogg->streams + idx;
377  ogg->page_pos =
378  os->page_pos = avio_tell(bc) - 27;
379 
380  if (os->psize > 0) {
381  ret = ogg_new_buf(ogg, idx);
382  if (ret < 0)
383  return ret;
384  }
385 
386  ret = avio_read(bc, os->segments, nsegs);
387  if (ret < nsegs)
388  return ret < 0 ? ret : AVERROR_EOF;
389 
390  os->nsegs = nsegs;
391  os->segp = 0;
392 
393  size = 0;
394  for (i = 0; i < nsegs; i++)
395  size += os->segments[i];
396 
397  if (!(flags & OGG_FLAG_BOS))
398  os->got_data = 1;
399 
400  if (flags & OGG_FLAG_CONT || os->incomplete) {
401  if (!os->psize) {
402  // If this is the very first segment we started
403  // playback in the middle of a continuation packet.
404  // Discard it since we missed the start of it.
405  while (os->segp < os->nsegs) {
406  int seg = os->segments[os->segp++];
407  os->pstart += seg;
408  if (seg < 255)
409  break;
410  }
411  os->sync_pos = os->page_pos;
412  }
413  } else {
414  os->psize = 0;
415  os->sync_pos = os->page_pos;
416  }
417 
418  if (os->bufsize - os->bufpos < size) {
420  if (!nb)
421  return AVERROR(ENOMEM);
422  memcpy(nb, os->buf, os->bufpos);
423  av_free(os->buf);
424  os->buf = nb;
425  }
426 
427  ret = avio_read(bc, os->buf + os->bufpos, size);
428  if (ret < size)
429  return ret < 0 ? ret : AVERROR_EOF;
430 
431  os->bufpos += size;
432  os->granule = gp;
433  os->flags = flags;
434 
435  memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
436  if (sid)
437  *sid = idx;
438 
439  return 0;
440 }
441 
442 /**
443  * @brief find the next Ogg packet
444  * @param *sid is set to the stream for the packet or -1 if there is
445  * no matching stream, in that case assume all other return
446  * values to be uninitialized.
447  * @return negative value on error or EOF.
448  */
449 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
450  int64_t *fpos)
451 {
452  struct ogg *ogg = s->priv_data;
453  int idx, i, ret;
454  struct ogg_stream *os;
455  int complete = 0;
456  int segp = 0, psize = 0;
457 
458  av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
459  if (sid)
460  *sid = -1;
461 
462  do {
463  idx = ogg->curidx;
464 
465  while (idx < 0) {
466  ret = ogg_read_page(s, &idx);
467  if (ret < 0)
468  return ret;
469  }
470 
471  os = ogg->streams + idx;
472 
473  av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
474  idx, os->pstart, os->psize, os->segp, os->nsegs);
475 
476  if (!os->codec) {
477  if (os->header < 0) {
478  os->codec = ogg_find_codec(os->buf, os->bufpos);
479  if (!os->codec) {
480  av_log(s, AV_LOG_WARNING, "Codec not found\n");
481  os->header = 0;
482  return 0;
483  }
484  } else {
485  return 0;
486  }
487  }
488 
489  segp = os->segp;
490  psize = os->psize;
491 
492  while (os->segp < os->nsegs) {
493  int ss = os->segments[os->segp++];
494  os->psize += ss;
495  if (ss < 255) {
496  complete = 1;
497  break;
498  }
499  }
500 
501  if (!complete && os->segp == os->nsegs) {
502  ogg->curidx = -1;
503  // Do not set incomplete for empty packets.
504  // Together with the code in ogg_read_page
505  // that discards all continuation of empty packets
506  // we would get an infinite loop.
507  os->incomplete = !!os->psize;
508  }
509  } while (!complete);
510 
511 
512  if (os->granule == -1)
514  "Page at %"PRId64" is missing granule\n",
515  os->page_pos);
516 
517  ogg->curidx = idx;
518  os->incomplete = 0;
519 
520  if (os->header) {
521  os->header = os->codec->header(s, idx);
522  if (!os->header) {
523  os->segp = segp;
524  os->psize = psize;
525 
526  // We have reached the first non-header packet in this stream.
527  // Unfortunately more header packets may still follow for others,
528  // but if we continue with header parsing we may lose data packets.
529  ogg->headers = 1;
530 
531  // Update the header state for all streams and
532  // compute the data_offset.
533  if (!s->internal->data_offset)
534  s->internal->data_offset = os->sync_pos;
535 
536  for (i = 0; i < ogg->nstreams; i++) {
537  struct ogg_stream *cur_os = ogg->streams + i;
538 
539  // if we have a partial non-header packet, its start is
540  // obviously at or after the data start
541  if (cur_os->incomplete)
543  }
544  } else {
545  os->nb_header++;
546  os->pstart += os->psize;
547  os->psize = 0;
548  }
549  } else {
550  os->pflags = 0;
551  os->pduration = 0;
552  if (os->codec && os->codec->packet)
553  os->codec->packet(s, idx);
554  if (sid)
555  *sid = idx;
556  if (dstart)
557  *dstart = os->pstart;
558  if (dsize)
559  *dsize = os->psize;
560  if (fpos)
561  *fpos = os->sync_pos;
562  os->pstart += os->psize;
563  os->psize = 0;
564  if(os->pstart == os->bufpos)
565  os->bufpos = os->pstart = 0;
566  os->sync_pos = os->page_pos;
567  }
568 
569  // determine whether there are more complete packets in this page
570  // if not, the page's granule will apply to this packet
571  os->page_end = 1;
572  for (i = os->segp; i < os->nsegs; i++)
573  if (os->segments[i] < 255) {
574  os->page_end = 0;
575  break;
576  }
577 
578  if (os->segp == os->nsegs)
579  ogg->curidx = -1;
580 
581  return 0;
582 }
583 
585 {
586  struct ogg *ogg = s->priv_data;
587  int i;
588  int64_t size, end;
589  int streams_left=0;
590  int ret;
591 
592  if (!s->pb->seekable)
593  return 0;
594 
595 // already set
596  if (s->duration != AV_NOPTS_VALUE)
597  return 0;
598 
599  size = avio_size(s->pb);
600  if (size < 0)
601  return 0;
602  end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
603 
604  ret = ogg_save(s);
605  if (ret < 0)
606  return ret;
607  avio_seek(s->pb, end, SEEK_SET);
608  ogg->page_pos = -1;
609 
610  while (!ogg_read_page(s, &i)) {
611  if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
612  ogg->streams[i].codec) {
613  s->streams[i]->duration =
614  ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
615  if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
616  s->streams[i]->duration -= s->streams[i]->start_time;
617  streams_left-= (ogg->streams[i].got_start==-1);
618  ogg->streams[i].got_start= 1;
619  } else if(!ogg->streams[i].got_start) {
620  ogg->streams[i].got_start= -1;
621  streams_left++;
622  }
623  }
624  }
625 
626  ogg_restore(s, 0);
627 
628  ret = ogg_save(s);
629  if (ret < 0)
630  return ret;
631 
632  avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
633  ogg_reset(s);
634  while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
635  int64_t pts;
636  if (i < 0) continue;
637  pts = ogg_calc_pts(s, i, NULL);
638  if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
639  s->streams[i]->duration -= pts;
640  ogg->streams[i].got_start= 1;
641  streams_left--;
642  }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
643  ogg->streams[i].got_start= 1;
644  streams_left--;
645  }
646  }
647  ogg_restore (s, 0);
648 
649  return 0;
650 }
651 
653 {
654  struct ogg *ogg = s->priv_data;
655  int i;
656 
657  for (i = 0; i < ogg->nstreams; i++) {
658  av_freep(&ogg->streams[i].buf);
659  if (ogg->streams[i].codec &&
660  ogg->streams[i].codec->cleanup) {
661  ogg->streams[i].codec->cleanup(s, i);
662  }
663  av_freep(&ogg->streams[i].private);
664  av_freep(&ogg->streams[i].new_metadata);
665  }
666 
667  ogg->nstreams = 0;
668 
669  av_freep(&ogg->streams);
670  return 0;
671 }
672 
674 {
675  struct ogg *ogg = s->priv_data;
676  int ret, i;
677 
678  ogg->curidx = -1;
679 
680  //linear headers seek from start
681  do {
682  ret = ogg_packet(s, NULL, NULL, NULL, NULL);
683  if (ret < 0) {
684  ogg_read_close(s);
685  return ret;
686  }
687  } while (!ogg->headers);
688  av_dlog(s, "found headers\n");
689 
690  for (i = 0; i < ogg->nstreams; i++) {
691  struct ogg_stream *os = ogg->streams + i;
692 
693  if (ogg->streams[i].header < 0) {
694  av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
695  ogg->streams[i].codec = NULL;
696  } else if (os->codec && os->nb_header < os->codec->nb_header) {
698  "Headers mismatch for stream %d: "
699  "expected %d received %d.\n",
700  i, os->codec->nb_header, os->nb_header);
702  return AVERROR_INVALIDDATA;
703  }
705  os->lastpts = s->streams[i]->start_time =
706  ogg_gptopts(s, i, os->start_granule, NULL);
707  }
708 
709  //linear granulepos seek from end
710  ogg_get_length(s);
711 
712  return 0;
713 }
714 
715 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
716 {
717  struct ogg *ogg = s->priv_data;
718  struct ogg_stream *os = ogg->streams + idx;
719  int64_t pts = AV_NOPTS_VALUE;
720 
721  if (dts)
722  *dts = AV_NOPTS_VALUE;
723 
724  if (os->lastpts != AV_NOPTS_VALUE) {
725  pts = os->lastpts;
726  os->lastpts = AV_NOPTS_VALUE;
727  }
728  if (os->lastdts != AV_NOPTS_VALUE) {
729  if (dts)
730  *dts = os->lastdts;
731  os->lastdts = AV_NOPTS_VALUE;
732  }
733  if (os->page_end) {
734  if (os->granule != -1LL) {
735  if (os->codec && os->codec->granule_is_start)
736  pts = ogg_gptopts(s, idx, os->granule, dts);
737  else
738  os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
739  os->granule = -1LL;
740  }
741  }
742  return pts;
743 }
744 
745 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
746 {
747  struct ogg *ogg = s->priv_data;
748  struct ogg_stream *os = ogg->streams + idx;
749  int invalid = 0;
750  if (psize) {
751  switch (s->streams[idx]->codec->codec_id) {
752  case AV_CODEC_ID_THEORA:
753  invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
754  break;
755  case AV_CODEC_ID_VP8:
756  invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
757  }
758  if (invalid) {
759  os->pflags ^= AV_PKT_FLAG_KEY;
760  av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
761  (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
762  }
763  }
764 }
765 
767 {
768  struct ogg *ogg;
769  struct ogg_stream *os;
770  int idx, ret;
771  int pstart, psize;
772  int64_t fpos, pts, dts;
773 
774  if (s->io_repositioned) {
775  ogg_reset(s);
776  s->io_repositioned = 0;
777  }
778 
779  //Get an ogg packet
780 retry:
781  do {
782  ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
783  if (ret < 0)
784  return ret;
785  } while (idx < 0 || !s->streams[idx]);
786 
787  ogg = s->priv_data;
788  os = ogg->streams + idx;
789 
790  // pflags might not be set until after this
791  pts = ogg_calc_pts(s, idx, &dts);
792  ogg_validate_keyframe(s, idx, pstart, psize);
793 
794  if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
795  goto retry;
796  os->keyframe_seek = 0;
797 
798  //Alloc a pkt
799  ret = av_new_packet(pkt, psize);
800  if (ret < 0)
801  return ret;
802  pkt->stream_index = idx;
803  memcpy(pkt->data, os->buf + pstart, psize);
804 
805  pkt->pts = pts;
806  pkt->dts = dts;
807  pkt->flags = os->pflags;
808  pkt->duration = os->pduration;
809  pkt->pos = fpos;
810 
811  if (os->end_trimming) {
812  uint8_t *side_data = av_packet_new_side_data(pkt,
814  10);
815  if(!side_data)
816  goto fail;
817  AV_WL32(side_data + 4, os->end_trimming);
818  os->end_trimming = 0;
819  }
820 
821  if (os->new_metadata) {
822  uint8_t *side_data = av_packet_new_side_data(pkt,
824  os->new_metadata_size);
825  if(!side_data)
826  goto fail;
827 
828  memcpy(side_data, os->new_metadata, os->new_metadata_size);
829  av_freep(&os->new_metadata);
830  os->new_metadata_size = 0;
831  }
832 
833  return psize;
834 fail:
835  av_free_packet(pkt);
836  return AVERROR(ENOMEM);
837 }
838 
839 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
840  int64_t *pos_arg, int64_t pos_limit)
841 {
842  struct ogg *ogg = s->priv_data;
843  AVIOContext *bc = s->pb;
844  int64_t pts = AV_NOPTS_VALUE;
845  int64_t keypos = -1;
846  int i;
847  int pstart, psize;
848  avio_seek(bc, *pos_arg, SEEK_SET);
849  ogg_reset(s);
850 
851  while ( avio_tell(bc) <= pos_limit
852  && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
853  if (i == stream_index) {
854  struct ogg_stream *os = ogg->streams + stream_index;
855  // Do not trust the last timestamps of a ogm video
856  if ( (os->flags & OGG_FLAG_EOS)
857  && !(os->flags & OGG_FLAG_BOS)
858  && os->codec == &ff_ogm_video_codec)
859  continue;
860  pts = ogg_calc_pts(s, i, NULL);
861  ogg_validate_keyframe(s, i, pstart, psize);
862  if (os->pflags & AV_PKT_FLAG_KEY) {
863  keypos = *pos_arg;
864  } else if (os->keyframe_seek) {
865  // if we had a previous keyframe but no pts for it,
866  // return that keyframe with this pts value.
867  if (keypos >= 0)
868  *pos_arg = keypos;
869  else
870  pts = AV_NOPTS_VALUE;
871  }
872  }
873  if (pts != AV_NOPTS_VALUE)
874  break;
875  }
876  ogg_reset(s);
877  return pts;
878 }
879 
880 static int ogg_read_seek(AVFormatContext *s, int stream_index,
881  int64_t timestamp, int flags)
882 {
883  struct ogg *ogg = s->priv_data;
884  struct ogg_stream *os = ogg->streams + stream_index;
885  int ret;
886 
887  av_assert0(stream_index < ogg->nstreams);
888  // Ensure everything is reset even when seeking via
889  // the generated index.
890  ogg_reset(s);
891 
892  // Try seeking to a keyframe first. If this fails (very possible),
893  // av_seek_frame will fall back to ignoring keyframes
894  if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
895  && !(flags & AVSEEK_FLAG_ANY))
896  os->keyframe_seek = 1;
897 
898  ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
899  os = ogg->streams + stream_index;
900  if (ret < 0)
901  os->keyframe_seek = 0;
902  return ret;
903 }
904 
905 static int ogg_probe(AVProbeData *p)
906 {
907  if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
908  return AVPROBE_SCORE_MAX;
909  return 0;
910 }
911 
913  .name = "ogg",
914  .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
915  .priv_data_size = sizeof(struct ogg),
916  .read_probe = ogg_probe,
917  .read_header = ogg_read_header,
918  .read_packet = ogg_read_packet,
919  .read_close = ogg_read_close,
920  .read_seek = ogg_read_seek,
921  .read_timestamp = ogg_read_timestamp,
922  .extensions = "ogg",
924 };