]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
Export metadata in the generic format. Deprecate old conversion API.
[ffmpeg] / libavformat / oggdec.c
1 /*
2  * Ogg bitstream support
3  * Luca Barbato <lu_zero@gentoo.org>
4  * Based on tcvp implementation
5  *
6  */
7
8 /**
9     Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
10
11     Permission is hereby granted, free of charge, to any person
12     obtaining a copy of this software and associated documentation
13     files (the "Software"), to deal in the Software without
14     restriction, including without limitation the rights to use, copy,
15     modify, merge, publish, distribute, sublicense, and/or sell copies
16     of the Software, and to permit persons to whom the Software is
17     furnished to do so, subject to the following conditions:
18
19     The above copyright notice and this permission notice shall be
20     included in all copies or substantial portions of the Software.
21
22     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29     DEALINGS IN THE SOFTWARE.
30 **/
31
32
33 #include <stdio.h>
34 #include "oggdec.h"
35 #include "avformat.h"
36 #include "vorbiscomment.h"
37
38 #define MAX_PAGE_SIZE 65307
39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
41 static const struct ogg_codec * const ogg_codecs[] = {
42     &ff_skeleton_codec,
43     &ff_dirac_codec,
44     &ff_speex_codec,
45     &ff_vorbis_codec,
46     &ff_theora_codec,
47     &ff_flac_codec,
48     &ff_old_dirac_codec,
49     &ff_old_flac_codec,
50     &ff_ogm_video_codec,
51     &ff_ogm_audio_codec,
52     &ff_ogm_text_codec,
53     &ff_ogm_old_codec,
54     NULL
55 };
56
57 //FIXME We could avoid some structure duplication
58 static int
59 ogg_save (AVFormatContext * s)
60 {
61     struct ogg *ogg = s->priv_data;
62     struct ogg_state *ost =
63         av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
64     int i;
65     ost->pos = url_ftell (s->pb);
66     ost->curidx = ogg->curidx;
67     ost->next = ogg->state;
68     ost->nstreams = ogg->nstreams;
69     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70
71     for (i = 0; i < ogg->nstreams; i++){
72         struct ogg_stream *os = ogg->streams + i;
73         os->buf = av_malloc (os->bufsize);
74         memset (os->buf, 0, os->bufsize);
75         memcpy (os->buf, ost->streams[i].buf, os->bufpos);
76     }
77
78     ogg->state = ost;
79
80     return 0;
81 }
82
83 static int
84 ogg_restore (AVFormatContext * s, int discard)
85 {
86     struct ogg *ogg = s->priv_data;
87     ByteIOContext *bc = s->pb;
88     struct ogg_state *ost = ogg->state;
89     int i;
90
91     if (!ost)
92         return 0;
93
94     ogg->state = ost->next;
95
96     if (!discard){
97         for (i = 0; i < ogg->nstreams; i++)
98             av_free (ogg->streams[i].buf);
99
100         url_fseek (bc, ost->pos, SEEK_SET);
101         ogg->curidx = ost->curidx;
102         ogg->nstreams = ost->nstreams;
103         memcpy(ogg->streams, ost->streams,
104                ost->nstreams * sizeof(*ogg->streams));
105     }
106
107     av_free (ost);
108
109     return 0;
110 }
111
112 static int
113 ogg_reset (struct ogg * ogg)
114 {
115     int i;
116
117     for (i = 0; i < ogg->nstreams; i++){
118         struct ogg_stream *os = ogg->streams + i;
119         os->bufpos = 0;
120         os->pstart = 0;
121         os->psize = 0;
122         os->granule = -1;
123         os->lastpts = AV_NOPTS_VALUE;
124         os->lastdts = AV_NOPTS_VALUE;
125         os->sync_pos = -1;
126         os->page_pos = 0;
127         os->nsegs = 0;
128         os->segp = 0;
129         os->incomplete = 0;
130     }
131
132     ogg->curidx = -1;
133
134     return 0;
135 }
136
137 static const struct ogg_codec *
138 ogg_find_codec (uint8_t * buf, int size)
139 {
140     int i;
141
142     for (i = 0; ogg_codecs[i]; i++)
143         if (size >= ogg_codecs[i]->magicsize &&
144             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
145             return ogg_codecs[i];
146
147     return NULL;
148 }
149
150 static int
151 ogg_new_stream (AVFormatContext * s, uint32_t serial)
152 {
153
154     struct ogg *ogg = s->priv_data;
155     int idx = ogg->nstreams++;
156     AVStream *st;
157     struct ogg_stream *os;
158
159     ogg->streams = av_realloc (ogg->streams,
160                                ogg->nstreams * sizeof (*ogg->streams));
161     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
162     os = ogg->streams + idx;
163     os->serial = serial;
164     os->bufsize = DECODER_BUFFER_SIZE;
165     os->buf = av_malloc(os->bufsize);
166     os->header = -1;
167
168     st = av_new_stream (s, idx);
169     if (!st)
170         return AVERROR(ENOMEM);
171
172     av_set_pts_info(st, 64, 1, 1000000);
173
174     return idx;
175 }
176
177 static int
178 ogg_new_buf(struct ogg *ogg, int idx)
179 {
180     struct ogg_stream *os = ogg->streams + idx;
181     uint8_t *nb = av_malloc(os->bufsize);
182     int size = os->bufpos - os->pstart;
183     if(os->buf){
184         memcpy(nb, os->buf + os->pstart, size);
185         av_free(os->buf);
186     }
187     os->buf = nb;
188     os->bufpos = size;
189     os->pstart = 0;
190
191     return 0;
192 }
193
194 static int
195 ogg_read_page (AVFormatContext * s, int *str)
196 {
197     ByteIOContext *bc = s->pb;
198     struct ogg *ogg = s->priv_data;
199     struct ogg_stream *os;
200     int i = 0;
201     int flags, nsegs;
202     uint64_t gp;
203     uint32_t serial;
204     uint32_t seq;
205     uint32_t crc;
206     int size, idx;
207     uint8_t sync[4];
208     int sp = 0;
209
210     if (get_buffer (bc, sync, 4) < 4)
211         return -1;
212
213     do{
214         int c;
215
216         if (sync[sp & 3] == 'O' &&
217             sync[(sp + 1) & 3] == 'g' &&
218             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
219             break;
220
221         c = url_fgetc (bc);
222         if (c < 0)
223             return -1;
224         sync[sp++ & 3] = c;
225     }while (i++ < MAX_PAGE_SIZE);
226
227     if (i >= MAX_PAGE_SIZE){
228         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
229         return -1;
230     }
231
232     if (url_fgetc (bc) != 0)      /* version */
233         return -1;
234
235     flags = url_fgetc (bc);
236     gp = get_le64 (bc);
237     serial = get_le32 (bc);
238     seq = get_le32 (bc);
239     crc = get_le32 (bc);
240     nsegs = url_fgetc (bc);
241
242     idx = ogg_find_stream (ogg, serial);
243     if (idx < 0){
244         idx = ogg_new_stream (s, serial);
245         if (idx < 0)
246             return -1;
247     }
248
249     os = ogg->streams + idx;
250     os->page_pos = url_ftell(bc) - 27;
251
252     if(os->psize > 0)
253         ogg_new_buf(ogg, idx);
254
255     if (get_buffer (bc, os->segments, nsegs) < nsegs)
256         return -1;
257
258     os->nsegs = nsegs;
259     os->segp = 0;
260
261     size = 0;
262     for (i = 0; i < nsegs; i++)
263         size += os->segments[i];
264
265     if (flags & OGG_FLAG_CONT || os->incomplete){
266         if (!os->psize){
267             while (os->segp < os->nsegs){
268                 int seg = os->segments[os->segp++];
269                 os->pstart += seg;
270                 if (seg < 255)
271                     break;
272             }
273             os->sync_pos = os->page_pos;
274         }
275     }else{
276         os->psize = 0;
277         os->sync_pos = os->page_pos;
278     }
279
280     if (os->bufsize - os->bufpos < size){
281         uint8_t *nb = av_malloc (os->bufsize *= 2);
282         memcpy (nb, os->buf, os->bufpos);
283         av_free (os->buf);
284         os->buf = nb;
285     }
286
287     if (get_buffer (bc, os->buf + os->bufpos, size) < size)
288         return -1;
289
290     os->bufpos += size;
291     os->granule = gp;
292     os->flags = flags;
293
294     if (str)
295         *str = idx;
296
297     return 0;
298 }
299
300 static int
301 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
302 {
303     struct ogg *ogg = s->priv_data;
304     int idx, i;
305     struct ogg_stream *os;
306     int complete = 0;
307     int segp = 0, psize = 0;
308
309 #if 0
310     av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
311 #endif
312
313     do{
314         idx = ogg->curidx;
315
316         while (idx < 0){
317             if (ogg_read_page (s, &idx) < 0)
318                 return -1;
319         }
320
321         os = ogg->streams + idx;
322
323 #if 0
324         av_log (s, AV_LOG_DEBUG,
325                 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
326                 idx, os->pstart, os->psize, os->segp, os->nsegs);
327 #endif
328
329         if (!os->codec){
330             if (os->header < 0){
331                 os->codec = ogg_find_codec (os->buf, os->bufpos);
332                 if (!os->codec){
333                     os->header = 0;
334                     return 0;
335                 }
336             }else{
337                 return 0;
338             }
339         }
340
341         segp = os->segp;
342         psize = os->psize;
343
344         while (os->segp < os->nsegs){
345             int ss = os->segments[os->segp++];
346             os->psize += ss;
347             if (ss < 255){
348                 complete = 1;
349                 break;
350             }
351         }
352
353         if (!complete && os->segp == os->nsegs){
354             ogg->curidx = -1;
355             os->incomplete = 1;
356         }
357     }while (!complete);
358
359 #if 0
360     av_log (s, AV_LOG_DEBUG,
361             "ogg_packet: idx %i, frame size %i, start %i\n",
362             idx, os->psize, os->pstart);
363 #endif
364
365     if (os->granule == -1)
366         av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
367
368     ogg->curidx = idx;
369     os->incomplete = 0;
370
371     if (os->header) {
372         os->header = os->codec->header (s, idx);
373         if (!os->header){
374             os->segp = segp;
375             os->psize = psize;
376             if (!ogg->headers)
377                 s->data_offset = os->sync_pos;
378             ogg->headers = 1;
379         }else{
380             os->pstart += os->psize;
381             os->psize = 0;
382         }
383     } else {
384         os->pflags = 0;
385         os->pduration = 0;
386         if (os->codec && os->codec->packet)
387             os->codec->packet (s, idx);
388         if (str)
389             *str = idx;
390         if (dstart)
391             *dstart = os->pstart;
392         if (dsize)
393             *dsize = os->psize;
394         if (fpos)
395             *fpos = os->sync_pos;
396         os->pstart += os->psize;
397         os->psize = 0;
398         os->sync_pos = os->page_pos;
399     }
400
401     // determine whether there are more complete packets in this page
402     // if not, the page's granule will apply to this packet
403     os->page_end = 1;
404     for (i = os->segp; i < os->nsegs; i++)
405         if (os->segments[i] < 255) {
406             os->page_end = 0;
407             break;
408         }
409
410     if (os->segp == os->nsegs)
411         ogg->curidx = -1;
412
413     return 0;
414 }
415
416 static int
417 ogg_get_headers (AVFormatContext * s)
418 {
419     struct ogg *ogg = s->priv_data;
420
421     do{
422         if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
423             return -1;
424     }while (!ogg->headers);
425
426 #if 0
427     av_log (s, AV_LOG_DEBUG, "found headers\n");
428 #endif
429
430     return 0;
431 }
432
433 static int
434 ogg_get_length (AVFormatContext * s)
435 {
436     struct ogg *ogg = s->priv_data;
437     int i;
438     int64_t size, end;
439
440     if(url_is_streamed(s->pb))
441         return 0;
442
443 // already set
444     if (s->duration != AV_NOPTS_VALUE)
445         return 0;
446
447     size = url_fsize(s->pb);
448     if(size < 0)
449         return 0;
450     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
451
452     ogg_save (s);
453     url_fseek (s->pb, end, SEEK_SET);
454
455     while (!ogg_read_page (s, &i)){
456         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
457             ogg->streams[i].codec) {
458             s->streams[i]->duration =
459                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
460             if (s->streams[i]->start_time != AV_NOPTS_VALUE)
461                 s->streams[i]->duration -= s->streams[i]->start_time;
462         }
463     }
464
465     ogg_restore (s, 0);
466
467     return 0;
468 }
469
470
471 static int
472 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
473 {
474     struct ogg *ogg = s->priv_data;
475     int i;
476     ogg->curidx = -1;
477     //linear headers seek from start
478     if (ogg_get_headers (s) < 0){
479         return -1;
480     }
481
482     for (i = 0; i < ogg->nstreams; i++)
483         if (ogg->streams[i].header < 0)
484             ogg->streams[i].codec = NULL;
485
486     //linear granulepos seek from end
487     ogg_get_length (s);
488
489     //fill the extradata in the per codec callbacks
490     return 0;
491 }
492
493 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
494 {
495     struct ogg *ogg = s->priv_data;
496     struct ogg_stream *os = ogg->streams + idx;
497     int64_t pts = AV_NOPTS_VALUE;
498
499     if (dts)
500         *dts = AV_NOPTS_VALUE;
501
502     if (os->lastpts != AV_NOPTS_VALUE) {
503         pts = os->lastpts;
504         os->lastpts = AV_NOPTS_VALUE;
505     }
506     if (os->lastdts != AV_NOPTS_VALUE) {
507         if (dts)
508             *dts = os->lastdts;
509         os->lastdts = AV_NOPTS_VALUE;
510     }
511     if (os->page_end) {
512         if (os->granule != -1LL) {
513             if (os->codec && os->codec->granule_is_start)
514                 pts = ogg_gptopts(s, idx, os->granule, dts);
515             else
516                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
517             os->granule = -1LL;
518         }
519     }
520     return pts;
521 }
522
523 static int
524 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
525 {
526     struct ogg *ogg;
527     struct ogg_stream *os;
528     int idx = -1;
529     int pstart, psize;
530     int64_t fpos, pts, dts;
531
532     //Get an ogg packet
533 retry:
534     do{
535         if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
536             return AVERROR(EIO);
537     }while (idx < 0 || !s->streams[idx]);
538
539     ogg = s->priv_data;
540     os = ogg->streams + idx;
541
542     // pflags might not be set until after this
543     pts = ogg_calc_pts(s, idx, &dts);
544
545     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
546         goto retry;
547     os->keyframe_seek = 0;
548
549     //Alloc a pkt
550     if (av_new_packet (pkt, psize) < 0)
551         return AVERROR(EIO);
552     pkt->stream_index = idx;
553     memcpy (pkt->data, os->buf + pstart, psize);
554
555     pkt->pts = pts;
556     pkt->dts = dts;
557     pkt->flags = os->pflags;
558     pkt->duration = os->pduration;
559     pkt->pos = fpos;
560
561     return psize;
562 }
563
564
565 static int
566 ogg_read_close (AVFormatContext * s)
567 {
568     struct ogg *ogg = s->priv_data;
569     int i;
570
571     for (i = 0; i < ogg->nstreams; i++){
572         av_free (ogg->streams[i].buf);
573         av_free (ogg->streams[i].private);
574     }
575     av_free (ogg->streams);
576     return 0;
577 }
578
579
580 static int64_t
581 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
582                     int64_t pos_limit)
583 {
584     struct ogg *ogg = s->priv_data;
585     struct ogg_stream *os = ogg->streams + stream_index;
586     ByteIOContext *bc = s->pb;
587     int64_t pts = AV_NOPTS_VALUE;
588     int i;
589     url_fseek(bc, *pos_arg, SEEK_SET);
590     ogg_reset(ogg);
591
592     while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
593         if (i == stream_index) {
594             pts = ogg_calc_pts(s, i, NULL);
595             if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
596                 pts = AV_NOPTS_VALUE;
597         }
598         if (pts != AV_NOPTS_VALUE)
599             break;
600     }
601     ogg_reset(ogg);
602     return pts;
603 }
604
605 static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
606 {
607     struct ogg *ogg = s->priv_data;
608     struct ogg_stream *os = ogg->streams + stream_index;
609     int ret;
610
611     // Try seeking to a keyframe first. If this fails (very possible),
612     // av_seek_frame will fall back to ignoring keyframes
613     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
614         && !(flags & AVSEEK_FLAG_ANY))
615         os->keyframe_seek = 1;
616
617     ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
618     if (ret < 0)
619         os->keyframe_seek = 0;
620     return ret;
621 }
622
623 static int ogg_probe(AVProbeData *p)
624 {
625     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
626         p->buf[2] == 'g' && p->buf[3] == 'S' &&
627         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
628         return AVPROBE_SCORE_MAX;
629     else
630         return 0;
631 }
632
633 AVInputFormat ogg_demuxer = {
634     "ogg",
635     NULL_IF_CONFIG_SMALL("Ogg"),
636     sizeof (struct ogg),
637     ogg_probe,
638     ogg_read_header,
639     ogg_read_packet,
640     ogg_read_close,
641     ogg_read_seek,
642     ogg_read_timestamp,
643     .extensions = "ogg",
644     .flags = AVFMT_GENERIC_INDEX,
645 };