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