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