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 (url_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  av_freep(&ogg->streams);
651  return 0;
652 }
653 
655 {
656  struct ogg *ogg = s->priv_data;
657  int ret, i;
658 
659  ogg->curidx = -1;
660 
661  //linear headers seek from start
662  do {
663  ret = ogg_packet(s, NULL, NULL, NULL, NULL);
664  if (ret < 0) {
665  ogg_read_close(s);
666  return ret;
667  }
668  } while (!ogg->headers);
669  av_dlog(s, "found headers\n");
670 
671  for (i = 0; i < ogg->nstreams; i++) {
672  struct ogg_stream *os = ogg->streams + i;
673 
674  if (ogg->streams[i].header < 0) {
675  av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
676  ogg->streams[i].codec = NULL;
677  } else if (os->codec && os->nb_header < os->codec->nb_header) {
679  "Headers mismatch for stream %d: "
680  "expected %d received %d.\n",
681  i, os->codec->nb_header, os->nb_header);
683  return AVERROR_INVALIDDATA;
684  }
686  os->lastpts = s->streams[i]->start_time =
687  ogg_gptopts(s, i, os->start_granule, NULL);
688  }
689 
690  //linear granulepos seek from end
691  ogg_get_length(s);
692 
693  return 0;
694 }
695 
696 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
697 {
698  struct ogg *ogg = s->priv_data;
699  struct ogg_stream *os = ogg->streams + idx;
700  int64_t pts = AV_NOPTS_VALUE;
701 
702  if (dts)
703  *dts = AV_NOPTS_VALUE;
704 
705  if (os->lastpts != AV_NOPTS_VALUE) {
706  pts = os->lastpts;
707  os->lastpts = AV_NOPTS_VALUE;
708  }
709  if (os->lastdts != AV_NOPTS_VALUE) {
710  if (dts)
711  *dts = os->lastdts;
712  os->lastdts = AV_NOPTS_VALUE;
713  }
714  if (os->page_end) {
715  if (os->granule != -1LL) {
716  if (os->codec && os->codec->granule_is_start)
717  pts = ogg_gptopts(s, idx, os->granule, dts);
718  else
719  os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
720  os->granule = -1LL;
721  }
722  }
723  return pts;
724 }
725 
726 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
727 {
728  struct ogg *ogg = s->priv_data;
729  struct ogg_stream *os = ogg->streams + idx;
730  int invalid = 0;
731  if (psize) {
732  switch (s->streams[idx]->codec->codec_id) {
733  case AV_CODEC_ID_THEORA:
734  invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
735  break;
736  case AV_CODEC_ID_VP8:
737  invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
738  }
739  if (invalid) {
740  os->pflags ^= AV_PKT_FLAG_KEY;
741  av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
742  (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
743  }
744  }
745 }
746 
748 {
749  struct ogg *ogg;
750  struct ogg_stream *os;
751  int idx, ret;
752  int pstart, psize;
753  int64_t fpos, pts, dts;
754 
755  if (s->io_repositioned) {
756  ogg_reset(s);
757  s->io_repositioned = 0;
758  }
759 
760  //Get an ogg packet
761 retry:
762  do {
763  ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
764  if (ret < 0)
765  return ret;
766  } while (idx < 0 || !s->streams[idx]);
767 
768  ogg = s->priv_data;
769  os = ogg->streams + idx;
770 
771  // pflags might not be set until after this
772  pts = ogg_calc_pts(s, idx, &dts);
773  ogg_validate_keyframe(s, idx, pstart, psize);
774 
775  if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
776  goto retry;
777  os->keyframe_seek = 0;
778 
779  //Alloc a pkt
780  ret = av_new_packet(pkt, psize);
781  if (ret < 0)
782  return ret;
783  pkt->stream_index = idx;
784  memcpy(pkt->data, os->buf + pstart, psize);
785 
786  pkt->pts = pts;
787  pkt->dts = dts;
788  pkt->flags = os->pflags;
789  pkt->duration = os->pduration;
790  pkt->pos = fpos;
791 
792  if (os->end_trimming) {
793  uint8_t *side_data = av_packet_new_side_data(pkt,
795  10);
796  if(side_data == NULL) {
797  av_free_packet(pkt);
798  av_free(pkt);
799  return AVERROR(ENOMEM);
800  }
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  memcpy(side_data, os->new_metadata, os->new_metadata_size);
810  av_freep(&os->new_metadata);
811  os->new_metadata_size = 0;
812  }
813 
814  return psize;
815 }
816 
817 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
818  int64_t *pos_arg, int64_t pos_limit)
819 {
820  struct ogg *ogg = s->priv_data;
821  AVIOContext *bc = s->pb;
822  int64_t pts = AV_NOPTS_VALUE;
823  int64_t keypos = -1;
824  int i;
825  int pstart, psize;
826  avio_seek(bc, *pos_arg, SEEK_SET);
827  ogg_reset(s);
828 
829  while ( avio_tell(bc) <= pos_limit
830  && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
831  if (i == stream_index) {
832  struct ogg_stream *os = ogg->streams + stream_index;
833  // Dont trust the last timestamps of a ogm video
834  if ( (os->flags & OGG_FLAG_EOS)
835  && !(os->flags & OGG_FLAG_BOS)
836  && os->codec == &ff_ogm_video_codec)
837  continue;
838  pts = ogg_calc_pts(s, i, NULL);
839  ogg_validate_keyframe(s, i, pstart, psize);
840  if (os->pflags & AV_PKT_FLAG_KEY) {
841  keypos = *pos_arg;
842  } else if (os->keyframe_seek) {
843  // if we had a previous keyframe but no pts for it,
844  // return that keyframe with this pts value.
845  if (keypos >= 0)
846  *pos_arg = keypos;
847  else
848  pts = AV_NOPTS_VALUE;
849  }
850  }
851  if (pts != AV_NOPTS_VALUE)
852  break;
853  }
854  ogg_reset(s);
855  return pts;
856 }
857 
858 static int ogg_read_seek(AVFormatContext *s, int stream_index,
859  int64_t timestamp, int flags)
860 {
861  struct ogg *ogg = s->priv_data;
862  struct ogg_stream *os = ogg->streams + stream_index;
863  int ret;
864 
865  av_assert0(stream_index < ogg->nstreams);
866  // Ensure everything is reset even when seeking via
867  // the generated index.
868  ogg_reset(s);
869 
870  // Try seeking to a keyframe first. If this fails (very possible),
871  // av_seek_frame will fall back to ignoring keyframes
872  if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
873  && !(flags & AVSEEK_FLAG_ANY))
874  os->keyframe_seek = 1;
875 
876  ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
877  os = ogg->streams + stream_index;
878  if (ret < 0)
879  os->keyframe_seek = 0;
880  return ret;
881 }
882 
883 static int ogg_probe(AVProbeData *p)
884 {
885  if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
886  return AVPROBE_SCORE_MAX;
887  return 0;
888 }
889 
891  .name = "ogg",
892  .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
893  .priv_data_size = sizeof(struct ogg),
894  .read_probe = ogg_probe,
895  .read_header = ogg_read_header,
896  .read_packet = ogg_read_packet,
897  .read_close = ogg_read_close,
898  .read_seek = ogg_read_seek,
899  .read_timestamp = ogg_read_timestamp,
900  .extensions = "ogg",
902 };