]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
avio: avio_ prefix for url_fsize
[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 = avio_tell (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     AVIOContext *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         avio_seek (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     AVIOContext *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 (avio_read (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 = avio_r8(bc);
222         if (url_feof(bc))
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 (avio_r8(bc) != 0)      /* version */
233         return -1;
234
235     flags = avio_r8(bc);
236     gp = avio_rl64 (bc);
237     serial = avio_rl32 (bc);
238     seq = avio_rl32 (bc);
239     crc = avio_rl32 (bc);
240     nsegs = avio_r8(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 = avio_tell(bc) - 27;
251
252     if(os->psize > 0)
253         ogg_new_buf(ogg, idx);
254
255     if (avio_read (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 (avio_read (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
377             // We have reached the first non-header packet in this stream.
378             // Unfortunately more header packets may still follow for others,
379             // so we reset this later unless we are done with the headers
380             // for all streams.
381             ogg->headers = 1;
382
383             // Update the header state for all streams and
384             // compute the data_offset.
385             if (!s->data_offset)
386                 s->data_offset = os->sync_pos;
387             for (i = 0; i < ogg->nstreams; i++) {
388                 struct ogg_stream *cur_os = ogg->streams + i;
389                 if (cur_os->header > 0)
390                     ogg->headers = 0;
391
392                 // if we have a partial non-header packet, its start is
393                 // obviously at or after the data start
394                 if (cur_os->incomplete)
395                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
396             }
397         }else{
398             os->pstart += os->psize;
399             os->psize = 0;
400         }
401     } else {
402         os->pflags = 0;
403         os->pduration = 0;
404         if (os->codec && os->codec->packet)
405             os->codec->packet (s, idx);
406         if (str)
407             *str = idx;
408         if (dstart)
409             *dstart = os->pstart;
410         if (dsize)
411             *dsize = os->psize;
412         if (fpos)
413             *fpos = os->sync_pos;
414         os->pstart += os->psize;
415         os->psize = 0;
416         os->sync_pos = os->page_pos;
417     }
418
419     // determine whether there are more complete packets in this page
420     // if not, the page's granule will apply to this packet
421     os->page_end = 1;
422     for (i = os->segp; i < os->nsegs; i++)
423         if (os->segments[i] < 255) {
424             os->page_end = 0;
425             break;
426         }
427
428     if (os->segp == os->nsegs)
429         ogg->curidx = -1;
430
431     return 0;
432 }
433
434 static int
435 ogg_get_headers (AVFormatContext * s)
436 {
437     struct ogg *ogg = s->priv_data;
438
439     do{
440         if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
441             return -1;
442     }while (!ogg->headers);
443
444 #if 0
445     av_log (s, AV_LOG_DEBUG, "found headers\n");
446 #endif
447
448     return 0;
449 }
450
451 static int
452 ogg_get_length (AVFormatContext * s)
453 {
454     struct ogg *ogg = s->priv_data;
455     int i;
456     int64_t size, end;
457
458     if(url_is_streamed(s->pb))
459         return 0;
460
461 // already set
462     if (s->duration != AV_NOPTS_VALUE)
463         return 0;
464
465     size = avio_size(s->pb);
466     if(size < 0)
467         return 0;
468     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
469
470     ogg_save (s);
471     avio_seek (s->pb, end, SEEK_SET);
472
473     while (!ogg_read_page (s, &i)){
474         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
475             ogg->streams[i].codec) {
476             s->streams[i]->duration =
477                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
478             if (s->streams[i]->start_time != AV_NOPTS_VALUE)
479                 s->streams[i]->duration -= s->streams[i]->start_time;
480         }
481     }
482
483     ogg_restore (s, 0);
484
485     return 0;
486 }
487
488
489 static int
490 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
491 {
492     struct ogg *ogg = s->priv_data;
493     int i;
494     ogg->curidx = -1;
495     //linear headers seek from start
496     if (ogg_get_headers (s) < 0){
497         return -1;
498     }
499
500     for (i = 0; i < ogg->nstreams; i++)
501         if (ogg->streams[i].header < 0)
502             ogg->streams[i].codec = NULL;
503
504     //linear granulepos seek from end
505     ogg_get_length (s);
506
507     //fill the extradata in the per codec callbacks
508     return 0;
509 }
510
511 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
512 {
513     struct ogg *ogg = s->priv_data;
514     struct ogg_stream *os = ogg->streams + idx;
515     int64_t pts = AV_NOPTS_VALUE;
516
517     if (dts)
518         *dts = AV_NOPTS_VALUE;
519
520     if (os->lastpts != AV_NOPTS_VALUE) {
521         pts = os->lastpts;
522         os->lastpts = AV_NOPTS_VALUE;
523     }
524     if (os->lastdts != AV_NOPTS_VALUE) {
525         if (dts)
526             *dts = os->lastdts;
527         os->lastdts = AV_NOPTS_VALUE;
528     }
529     if (os->page_end) {
530         if (os->granule != -1LL) {
531             if (os->codec && os->codec->granule_is_start)
532                 pts = ogg_gptopts(s, idx, os->granule, dts);
533             else
534                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
535             os->granule = -1LL;
536         }
537     }
538     return pts;
539 }
540
541 static int
542 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
543 {
544     struct ogg *ogg;
545     struct ogg_stream *os;
546     int idx = -1;
547     int pstart, psize;
548     int64_t fpos, pts, dts;
549
550     //Get an ogg packet
551 retry:
552     do{
553         if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
554             return AVERROR(EIO);
555     }while (idx < 0 || !s->streams[idx]);
556
557     ogg = s->priv_data;
558     os = ogg->streams + idx;
559
560     // pflags might not be set until after this
561     pts = ogg_calc_pts(s, idx, &dts);
562
563     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
564         goto retry;
565     os->keyframe_seek = 0;
566
567     //Alloc a pkt
568     if (av_new_packet (pkt, psize) < 0)
569         return AVERROR(EIO);
570     pkt->stream_index = idx;
571     memcpy (pkt->data, os->buf + pstart, psize);
572
573     pkt->pts = pts;
574     pkt->dts = dts;
575     pkt->flags = os->pflags;
576     pkt->duration = os->pduration;
577     pkt->pos = fpos;
578
579     return psize;
580 }
581
582
583 static int
584 ogg_read_close (AVFormatContext * s)
585 {
586     struct ogg *ogg = s->priv_data;
587     int i;
588
589     for (i = 0; i < ogg->nstreams; i++){
590         av_free (ogg->streams[i].buf);
591         av_free (ogg->streams[i].private);
592     }
593     av_free (ogg->streams);
594     return 0;
595 }
596
597
598 static int64_t
599 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
600                     int64_t pos_limit)
601 {
602     struct ogg *ogg = s->priv_data;
603     struct ogg_stream *os = ogg->streams + stream_index;
604     AVIOContext *bc = s->pb;
605     int64_t pts = AV_NOPTS_VALUE;
606     int i;
607     avio_seek(bc, *pos_arg, SEEK_SET);
608     ogg_reset(ogg);
609
610     while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
611         if (i == stream_index) {
612             pts = ogg_calc_pts(s, i, NULL);
613             if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
614                 pts = AV_NOPTS_VALUE;
615         }
616         if (pts != AV_NOPTS_VALUE)
617             break;
618     }
619     ogg_reset(ogg);
620     return pts;
621 }
622
623 static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
624 {
625     struct ogg *ogg = s->priv_data;
626     struct ogg_stream *os = ogg->streams + stream_index;
627     int ret;
628
629     // Try seeking to a keyframe first. If this fails (very possible),
630     // av_seek_frame will fall back to ignoring keyframes
631     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
632         && !(flags & AVSEEK_FLAG_ANY))
633         os->keyframe_seek = 1;
634
635     ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
636     if (ret < 0)
637         os->keyframe_seek = 0;
638     return ret;
639 }
640
641 static int ogg_probe(AVProbeData *p)
642 {
643     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
644         p->buf[2] == 'g' && p->buf[3] == 'S' &&
645         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
646         return AVPROBE_SCORE_MAX;
647     else
648         return 0;
649 }
650
651 AVInputFormat ff_ogg_demuxer = {
652     "ogg",
653     NULL_IF_CONFIG_SMALL("Ogg"),
654     sizeof (struct ogg),
655     ogg_probe,
656     ogg_read_header,
657     ogg_read_packet,
658     ogg_read_close,
659     ogg_read_seek,
660     ogg_read_timestamp,
661     .extensions = "ogg",
662     .flags = AVFMT_GENERIC_INDEX,
663 };