]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
Cosmetics: fix prototypes in oggdec
[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 ogg_save(AVFormatContext *s)
59 {
60     struct ogg *ogg = s->priv_data;
61     struct ogg_state *ost =
62         av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
63     int i;
64     ost->pos = avio_tell (s->pb);
65     ost->curidx = ogg->curidx;
66     ost->next = ogg->state;
67     ost->nstreams = ogg->nstreams;
68     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
69
70     for (i = 0; i < ogg->nstreams; i++){
71         struct ogg_stream *os = ogg->streams + i;
72         os->buf = av_malloc (os->bufsize);
73         memset (os->buf, 0, os->bufsize);
74         memcpy (os->buf, ost->streams[i].buf, os->bufpos);
75     }
76
77     ogg->state = ost;
78
79     return 0;
80 }
81
82 static int ogg_restore(AVFormatContext *s, int discard)
83 {
84     struct ogg *ogg = s->priv_data;
85     AVIOContext *bc = s->pb;
86     struct ogg_state *ost = ogg->state;
87     int i;
88
89     if (!ost)
90         return 0;
91
92     ogg->state = ost->next;
93
94     if (!discard){
95         for (i = 0; i < ogg->nstreams; i++)
96             av_free (ogg->streams[i].buf);
97
98         avio_seek (bc, ost->pos, SEEK_SET);
99         ogg->curidx = ost->curidx;
100         ogg->nstreams = ost->nstreams;
101         memcpy(ogg->streams, ost->streams,
102                ost->nstreams * sizeof(*ogg->streams));
103     }
104
105     av_free (ost);
106
107     return 0;
108 }
109
110 static int ogg_reset(struct ogg *ogg)
111 {
112     int i;
113
114     for (i = 0; i < ogg->nstreams; i++){
115         struct ogg_stream *os = ogg->streams + i;
116         os->bufpos = 0;
117         os->pstart = 0;
118         os->psize = 0;
119         os->granule = -1;
120         os->lastpts = AV_NOPTS_VALUE;
121         os->lastdts = AV_NOPTS_VALUE;
122         os->sync_pos = -1;
123         os->page_pos = 0;
124         os->nsegs = 0;
125         os->segp = 0;
126         os->incomplete = 0;
127     }
128
129     ogg->curidx = -1;
130
131     return 0;
132 }
133
134 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
135 {
136     int i;
137
138     for (i = 0; ogg_codecs[i]; i++)
139         if (size >= ogg_codecs[i]->magicsize &&
140             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
141             return ogg_codecs[i];
142
143     return NULL;
144 }
145
146 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
147 {
148
149     struct ogg *ogg = s->priv_data;
150     int idx = ogg->nstreams++;
151     AVStream *st;
152     struct ogg_stream *os;
153
154     ogg->streams = av_realloc (ogg->streams,
155                                ogg->nstreams * sizeof (*ogg->streams));
156     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
157     os = ogg->streams + idx;
158     os->serial = serial;
159     os->bufsize = DECODER_BUFFER_SIZE;
160     os->buf = av_malloc(os->bufsize);
161     os->header = -1;
162
163     if (new_avstream) {
164         st = av_new_stream(s, idx);
165         if (!st)
166             return AVERROR(ENOMEM);
167
168         av_set_pts_info(st, 64, 1, 1000000);
169     }
170
171     return idx;
172 }
173
174 static int ogg_new_buf(struct ogg *ogg, int idx)
175 {
176     struct ogg_stream *os = ogg->streams + idx;
177     uint8_t *nb = av_malloc(os->bufsize);
178     int size = os->bufpos - os->pstart;
179     if(os->buf){
180         memcpy(nb, os->buf + os->pstart, size);
181         av_free(os->buf);
182     }
183     os->buf = nb;
184     os->bufpos = size;
185     os->pstart = 0;
186
187     return 0;
188 }
189
190 static int ogg_read_page(AVFormatContext *s, int *str)
191 {
192     AVIOContext *bc = s->pb;
193     struct ogg *ogg = s->priv_data;
194     struct ogg_stream *os;
195     int i = 0;
196     int flags, nsegs;
197     uint64_t gp;
198     uint32_t serial;
199     uint32_t seq;
200     uint32_t crc;
201     int size, idx;
202     uint8_t sync[4];
203     int sp = 0;
204
205     if (avio_read (bc, sync, 4) < 4)
206         return -1;
207
208     do{
209         int c;
210
211         if (sync[sp & 3] == 'O' &&
212             sync[(sp + 1) & 3] == 'g' &&
213             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
214             break;
215
216         c = avio_r8(bc);
217         if (bc->eof_reached)
218             return -1;
219         sync[sp++ & 3] = c;
220     }while (i++ < MAX_PAGE_SIZE);
221
222     if (i >= MAX_PAGE_SIZE){
223         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
224         return -1;
225     }
226
227     if (avio_r8(bc) != 0)      /* version */
228         return -1;
229
230     flags = avio_r8(bc);
231     gp = avio_rl64 (bc);
232     serial = avio_rl32 (bc);
233     seq = avio_rl32 (bc);
234     crc = avio_rl32 (bc);
235     nsegs = avio_r8(bc);
236
237     idx = ogg_find_stream (ogg, serial);
238     if (idx < 0){
239         if (ogg->headers) {
240             int n;
241
242             for (n = 0; n < ogg->nstreams; n++) {
243                 av_freep(&ogg->streams[n].buf);
244                 av_freep(&ogg->streams[n].private);
245             }
246             ogg->curidx   = -1;
247             ogg->nstreams = 0;
248             idx = ogg_new_stream(s, serial, 0);
249         } else {
250             idx = ogg_new_stream(s, serial, 1);
251         }
252         if (idx < 0)
253             return -1;
254     }
255
256     os = ogg->streams + idx;
257     os->page_pos = avio_tell(bc) - 27;
258
259     if(os->psize > 0)
260         ogg_new_buf(ogg, idx);
261
262     if (avio_read (bc, os->segments, nsegs) < nsegs)
263         return -1;
264
265     os->nsegs = nsegs;
266     os->segp = 0;
267
268     size = 0;
269     for (i = 0; i < nsegs; i++)
270         size += os->segments[i];
271
272     if (flags & OGG_FLAG_CONT || os->incomplete){
273         if (!os->psize){
274             while (os->segp < os->nsegs){
275                 int seg = os->segments[os->segp++];
276                 os->pstart += seg;
277                 if (seg < 255)
278                     break;
279             }
280             os->sync_pos = os->page_pos;
281         }
282     }else{
283         os->psize = 0;
284         os->sync_pos = os->page_pos;
285     }
286
287     if (os->bufsize - os->bufpos < size){
288         uint8_t *nb = av_malloc (os->bufsize *= 2);
289         memcpy (nb, os->buf, os->bufpos);
290         av_free (os->buf);
291         os->buf = nb;
292     }
293
294     if (avio_read (bc, os->buf + os->bufpos, size) < size)
295         return -1;
296
297     os->bufpos += size;
298     os->granule = gp;
299     os->flags = flags;
300
301     if (str)
302         *str = idx;
303
304     return 0;
305 }
306
307 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
308                       int64_t *fpos)
309 {
310     struct ogg *ogg = s->priv_data;
311     int idx, i;
312     struct ogg_stream *os;
313     int complete = 0;
314     int segp = 0, psize = 0;
315
316     av_dlog(s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
317
318     do{
319         idx = ogg->curidx;
320
321         while (idx < 0){
322             if (ogg_read_page (s, &idx) < 0)
323                 return -1;
324         }
325
326         os = ogg->streams + idx;
327
328         av_dlog(s, AV_LOG_DEBUG,
329                 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
330                 idx, os->pstart, os->psize, os->segp, os->nsegs);
331
332         if (!os->codec){
333             if (os->header < 0){
334                 os->codec = ogg_find_codec (os->buf, os->bufpos);
335                 if (!os->codec){
336                     os->header = 0;
337                     return 0;
338                 }
339             }else{
340                 return 0;
341             }
342         }
343
344         segp = os->segp;
345         psize = os->psize;
346
347         while (os->segp < os->nsegs){
348             int ss = os->segments[os->segp++];
349             os->psize += ss;
350             if (ss < 255){
351                 complete = 1;
352                 break;
353             }
354         }
355
356         if (!complete && os->segp == os->nsegs){
357             ogg->curidx = -1;
358             os->incomplete = 1;
359         }
360     }while (!complete);
361
362     av_dlog(s, AV_LOG_DEBUG,
363             "ogg_packet: idx %i, frame size %i, start %i\n",
364             idx, os->psize, os->pstart);
365
366     if (os->granule == -1)
367         av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
368
369     ogg->curidx = idx;
370     os->incomplete = 0;
371
372     if (os->header) {
373         os->header = os->codec->header (s, idx);
374         if (!os->header){
375             os->segp = segp;
376             os->psize = psize;
377
378             // We have reached the first non-header packet in this stream.
379             // Unfortunately more header packets may still follow for others,
380             // so we reset this later unless we are done with the headers
381             // for all streams.
382             ogg->headers = 1;
383
384             // Update the header state for all streams and
385             // compute the data_offset.
386             if (!s->data_offset)
387                 s->data_offset = os->sync_pos;
388             for (i = 0; i < ogg->nstreams; i++) {
389                 struct ogg_stream *cur_os = ogg->streams + i;
390                 if (cur_os->header > 0)
391                     ogg->headers = 0;
392
393                 // if we have a partial non-header packet, its start is
394                 // obviously at or after the data start
395                 if (cur_os->incomplete)
396                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
397             }
398         }else{
399             os->pstart += os->psize;
400             os->psize = 0;
401         }
402     } else {
403         os->pflags = 0;
404         os->pduration = 0;
405         if (os->codec && os->codec->packet)
406             os->codec->packet (s, idx);
407         if (str)
408             *str = idx;
409         if (dstart)
410             *dstart = os->pstart;
411         if (dsize)
412             *dsize = os->psize;
413         if (fpos)
414             *fpos = os->sync_pos;
415         os->pstart += os->psize;
416         os->psize = 0;
417         os->sync_pos = os->page_pos;
418     }
419
420     // determine whether there are more complete packets in this page
421     // if not, the page's granule will apply to this packet
422     os->page_end = 1;
423     for (i = os->segp; i < os->nsegs; i++)
424         if (os->segments[i] < 255) {
425             os->page_end = 0;
426             break;
427         }
428
429     if (os->segp == os->nsegs)
430         ogg->curidx = -1;
431
432     return 0;
433 }
434
435 static int 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     av_dlog(s, AV_LOG_DEBUG, "found headers\n");
445
446     return 0;
447 }
448
449 static int ogg_get_length(AVFormatContext *s)
450 {
451     struct ogg *ogg = s->priv_data;
452     int i;
453     int64_t size, end;
454
455     if(!s->pb->seekable)
456         return 0;
457
458 // already set
459     if (s->duration != AV_NOPTS_VALUE)
460         return 0;
461
462     size = avio_size(s->pb);
463     if(size < 0)
464         return 0;
465     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
466
467     ogg_save (s);
468     avio_seek (s->pb, end, SEEK_SET);
469
470     while (!ogg_read_page (s, &i)){
471         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
472             ogg->streams[i].codec) {
473             s->streams[i]->duration =
474                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
475             if (s->streams[i]->start_time != AV_NOPTS_VALUE)
476                 s->streams[i]->duration -= s->streams[i]->start_time;
477         }
478     }
479
480     ogg_restore (s, 0);
481
482     return 0;
483 }
484
485 static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap)
486 {
487     struct ogg *ogg = s->priv_data;
488     int i;
489     ogg->curidx = -1;
490     //linear headers seek from start
491     if (ogg_get_headers (s) < 0){
492         return -1;
493     }
494
495     for (i = 0; i < ogg->nstreams; i++)
496         if (ogg->streams[i].header < 0)
497             ogg->streams[i].codec = NULL;
498
499     //linear granulepos seek from end
500     ogg_get_length (s);
501
502     //fill the extradata in the per codec callbacks
503     return 0;
504 }
505
506 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
507 {
508     struct ogg *ogg = s->priv_data;
509     struct ogg_stream *os = ogg->streams + idx;
510     int64_t pts = AV_NOPTS_VALUE;
511
512     if (dts)
513         *dts = AV_NOPTS_VALUE;
514
515     if (os->lastpts != AV_NOPTS_VALUE) {
516         pts = os->lastpts;
517         os->lastpts = AV_NOPTS_VALUE;
518     }
519     if (os->lastdts != AV_NOPTS_VALUE) {
520         if (dts)
521             *dts = os->lastdts;
522         os->lastdts = AV_NOPTS_VALUE;
523     }
524     if (os->page_end) {
525         if (os->granule != -1LL) {
526             if (os->codec && os->codec->granule_is_start)
527                 pts = ogg_gptopts(s, idx, os->granule, dts);
528             else
529                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
530             os->granule = -1LL;
531         }
532     }
533     return pts;
534 }
535
536 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
537 {
538     struct ogg *ogg;
539     struct ogg_stream *os;
540     int idx = -1;
541     int pstart, psize;
542     int64_t fpos, pts, dts;
543
544     //Get an ogg packet
545 retry:
546     do{
547         if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
548             return AVERROR(EIO);
549     }while (idx < 0 || !s->streams[idx]);
550
551     ogg = s->priv_data;
552     os = ogg->streams + idx;
553
554     // pflags might not be set until after this
555     pts = ogg_calc_pts(s, idx, &dts);
556
557     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
558         goto retry;
559     os->keyframe_seek = 0;
560
561     //Alloc a pkt
562     if (av_new_packet (pkt, psize) < 0)
563         return AVERROR(EIO);
564     pkt->stream_index = idx;
565     memcpy (pkt->data, os->buf + pstart, psize);
566
567     pkt->pts = pts;
568     pkt->dts = dts;
569     pkt->flags = os->pflags;
570     pkt->duration = os->pduration;
571     pkt->pos = fpos;
572
573     return psize;
574 }
575
576 static int ogg_read_close(AVFormatContext *s)
577 {
578     struct ogg *ogg = s->priv_data;
579     int i;
580
581     for (i = 0; i < ogg->nstreams; i++){
582         av_free (ogg->streams[i].buf);
583         av_free (ogg->streams[i].private);
584     }
585     av_free (ogg->streams);
586     return 0;
587 }
588
589 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
590                                   int64_t *pos_arg, int64_t pos_limit)
591 {
592     struct ogg *ogg = s->priv_data;
593     struct ogg_stream *os = ogg->streams + stream_index;
594     AVIOContext *bc = s->pb;
595     int64_t pts = AV_NOPTS_VALUE;
596     int i;
597     avio_seek(bc, *pos_arg, SEEK_SET);
598     ogg_reset(ogg);
599
600     while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
601         if (i == stream_index) {
602             pts = ogg_calc_pts(s, i, NULL);
603             if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
604                 pts = AV_NOPTS_VALUE;
605         }
606         if (pts != AV_NOPTS_VALUE)
607             break;
608     }
609     ogg_reset(ogg);
610     return pts;
611 }
612
613 static int ogg_read_seek(AVFormatContext *s, int stream_index,
614                          int64_t timestamp, int flags)
615 {
616     struct ogg *ogg = s->priv_data;
617     struct ogg_stream *os = ogg->streams + stream_index;
618     int ret;
619
620     // Try seeking to a keyframe first. If this fails (very possible),
621     // av_seek_frame will fall back to ignoring keyframes
622     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
623         && !(flags & AVSEEK_FLAG_ANY))
624         os->keyframe_seek = 1;
625
626     ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
627     if (ret < 0)
628         os->keyframe_seek = 0;
629     return ret;
630 }
631
632 static int ogg_probe(AVProbeData *p)
633 {
634     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
635         return AVPROBE_SCORE_MAX;
636     return 0;
637 }
638
639 AVInputFormat ff_ogg_demuxer = {
640     .name           = "ogg",
641     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
642     .priv_data_size = sizeof(struct ogg),
643     .read_probe     = ogg_probe,
644     .read_header    = ogg_read_header,
645     .read_packet    = ogg_read_packet,
646     .read_close     = ogg_read_close,
647     .read_seek      = ogg_read_seek,
648     .read_timestamp = ogg_read_timestamp,
649     .extensions     = "ogg",
650     .flags          = AVFMT_GENERIC_INDEX,
651 };