]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
Set duration in Smacker demuxer
[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
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40 static const struct ogg_codec * const ogg_codecs[] = {
41     &ff_dirac_codec,
42     &ff_speex_codec,
43     &ff_vorbis_codec,
44     &ff_theora_codec,
45     &ff_flac_codec,
46     &ff_old_dirac_codec,
47     &ff_old_flac_codec,
48     &ff_ogm_video_codec,
49     &ff_ogm_audio_codec,
50     &ff_ogm_text_codec,
51     &ff_ogm_old_codec,
52     NULL
53 };
54
55 //FIXME We could avoid some structure duplication
56 static int
57 ogg_save (AVFormatContext * s)
58 {
59     struct ogg *ogg = s->priv_data;
60     struct ogg_state *ost =
61         av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
62     int i;
63     ost->pos = url_ftell (s->pb);
64     ost->curidx = ogg->curidx;
65     ost->next = ogg->state;
66     ost->nstreams = ogg->nstreams;
67     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
68
69     for (i = 0; i < ogg->nstreams; i++){
70         struct ogg_stream *os = ogg->streams + i;
71         os->buf = av_malloc (os->bufsize);
72         memset (os->buf, 0, os->bufsize);
73         memcpy (os->buf, ost->streams[i].buf, os->bufpos);
74     }
75
76     ogg->state = ost;
77
78     return 0;
79 }
80
81 static int
82 ogg_restore (AVFormatContext * s, int discard)
83 {
84     struct ogg *ogg = s->priv_data;
85     ByteIOContext *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         url_fseek (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
111 ogg_reset (struct ogg * ogg)
112 {
113     int i;
114
115     for (i = 0; i < ogg->nstreams; i++){
116         struct ogg_stream *os = ogg->streams + i;
117         os->bufpos = 0;
118         os->pstart = 0;
119         os->psize = 0;
120         os->granule = -1;
121         os->lastpts = AV_NOPTS_VALUE;
122         os->lastdts = AV_NOPTS_VALUE;
123         os->nsegs = 0;
124         os->segp = 0;
125     }
126
127     ogg->curidx = -1;
128
129     return 0;
130 }
131
132 static const struct ogg_codec *
133 ogg_find_codec (uint8_t * buf, int size)
134 {
135     int i;
136
137     for (i = 0; ogg_codecs[i]; i++)
138         if (size >= ogg_codecs[i]->magicsize &&
139             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
140             return ogg_codecs[i];
141
142     return NULL;
143 }
144
145 static int
146 ogg_find_stream (struct ogg * ogg, int serial)
147 {
148     int i;
149
150     for (i = 0; i < ogg->nstreams; i++)
151         if (ogg->streams[i].serial == serial)
152             return i;
153
154     return -1;
155 }
156
157 static int
158 ogg_new_stream (AVFormatContext * s, uint32_t serial)
159 {
160
161     struct ogg *ogg = s->priv_data;
162     int idx = ogg->nstreams++;
163     AVStream *st;
164     struct ogg_stream *os;
165
166     ogg->streams = av_realloc (ogg->streams,
167                                ogg->nstreams * sizeof (*ogg->streams));
168     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
169     os = ogg->streams + idx;
170     os->serial = serial;
171     os->bufsize = DECODER_BUFFER_SIZE;
172     os->buf = av_malloc(os->bufsize);
173     os->header = -1;
174
175     st = av_new_stream (s, idx);
176     if (!st)
177         return AVERROR(ENOMEM);
178
179     av_set_pts_info(st, 64, 1, 1000000);
180
181     return idx;
182 }
183
184 static int
185 ogg_new_buf(struct ogg *ogg, int idx)
186 {
187     struct ogg_stream *os = ogg->streams + idx;
188     uint8_t *nb = av_malloc(os->bufsize);
189     int size = os->bufpos - os->pstart;
190     if(os->buf){
191         memcpy(nb, os->buf + os->pstart, size);
192         av_free(os->buf);
193     }
194     os->buf = nb;
195     os->bufpos = size;
196     os->pstart = 0;
197
198     return 0;
199 }
200
201 static int
202 ogg_read_page (AVFormatContext * s, int *str)
203 {
204     ByteIOContext *bc = s->pb;
205     struct ogg *ogg = s->priv_data;
206     struct ogg_stream *os;
207     int i = 0;
208     int flags, nsegs;
209     uint64_t gp;
210     uint32_t serial;
211     uint32_t seq;
212     uint32_t crc;
213     int size, idx;
214     uint8_t sync[4];
215     int sp = 0;
216
217     if (get_buffer (bc, sync, 4) < 4)
218         return -1;
219
220     do{
221         int c;
222
223         if (sync[sp & 3] == 'O' &&
224             sync[(sp + 1) & 3] == 'g' &&
225             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
226             break;
227
228         c = url_fgetc (bc);
229         if (c < 0)
230             return -1;
231         sync[sp++ & 3] = c;
232     }while (i++ < MAX_PAGE_SIZE);
233
234     if (i >= MAX_PAGE_SIZE){
235         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
236         return -1;
237     }
238
239     if (url_fgetc (bc) != 0)      /* version */
240         return -1;
241
242     flags = url_fgetc (bc);
243     gp = get_le64 (bc);
244     serial = get_le32 (bc);
245     seq = get_le32 (bc);
246     crc = get_le32 (bc);
247     nsegs = url_fgetc (bc);
248
249     idx = ogg_find_stream (ogg, serial);
250     if (idx < 0){
251         idx = ogg_new_stream (s, serial);
252         if (idx < 0)
253             return -1;
254     }
255
256     os = ogg->streams + idx;
257
258     if(os->psize > 0)
259         ogg_new_buf(ogg, idx);
260
261     if (get_buffer (bc, os->segments, nsegs) < nsegs)
262         return -1;
263
264     os->nsegs = nsegs;
265     os->segp = 0;
266
267     size = 0;
268     for (i = 0; i < nsegs; i++)
269         size += os->segments[i];
270
271     if (flags & OGG_FLAG_CONT){
272         if (!os->psize){
273             while (os->segp < os->nsegs){
274                 int seg = os->segments[os->segp++];
275                 os->pstart += seg;
276                 if (seg < 255)
277                     break;
278             }
279         }
280     }else{
281         os->psize = 0;
282     }
283
284     if (os->bufsize - os->bufpos < size){
285         uint8_t *nb = av_malloc (os->bufsize *= 2);
286         memcpy (nb, os->buf, os->bufpos);
287         av_free (os->buf);
288         os->buf = nb;
289     }
290
291     if (get_buffer (bc, os->buf + os->bufpos, size) < size)
292         return -1;
293
294     os->bufpos += size;
295     os->granule = gp;
296     os->flags = flags;
297
298     if (str)
299         *str = idx;
300
301     return 0;
302 }
303
304 static int
305 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
306 {
307     struct ogg *ogg = s->priv_data;
308     int idx, i;
309     struct ogg_stream *os;
310     int complete = 0;
311     int segp = 0, psize = 0;
312
313 #if 0
314     av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
315 #endif
316
317     do{
318         idx = ogg->curidx;
319
320         while (idx < 0){
321             if (ogg_read_page (s, &idx) < 0)
322                 return -1;
323         }
324
325         os = ogg->streams + idx;
326
327 #if 0
328         av_log (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 #endif
332
333         if (!os->codec){
334             if (os->header < 0){
335                 os->codec = ogg_find_codec (os->buf, os->bufpos);
336                 if (!os->codec){
337                     os->header = 0;
338                     return 0;
339                 }
340             }else{
341                 return 0;
342             }
343         }
344
345         segp = os->segp;
346         psize = os->psize;
347
348         while (os->segp < os->nsegs){
349             int ss = os->segments[os->segp++];
350             os->psize += ss;
351             if (ss < 255){
352                 complete = 1;
353                 break;
354             }
355         }
356
357         if (!complete && os->segp == os->nsegs){
358             ogg->curidx = -1;
359         }
360     }while (!complete);
361
362 #if 0
363     av_log (s, AV_LOG_DEBUG,
364             "ogg_packet: idx %i, frame size %i, start %i\n",
365             idx, os->psize, os->pstart);
366 #endif
367
368     ogg->curidx = idx;
369
370     if (os->header < 0){
371         int hdr = os->codec->header (s, idx);
372         if (!hdr){
373             os->header = os->seq;
374             os->segp = segp;
375             os->psize = psize;
376             ogg->headers = 1;
377         }else{
378             os->pstart += os->psize;
379             os->psize = 0;
380         }
381     }
382
383     if (os->header > -1 && os->seq > os->header){
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         os->pstart += os->psize;
395         os->psize = 0;
396     }
397
398     // determine whether there are more complete packets in this page
399     // if not, the page's granule will apply to this packet
400     os->page_end = 1;
401     for (i = os->segp; i < os->nsegs; i++)
402         if (os->segments[i] < 255) {
403             os->page_end = 0;
404             break;
405         }
406
407     os->seq++;
408     if (os->segp == os->nsegs)
409         ogg->curidx = -1;
410
411     return 0;
412 }
413
414 static int
415 ogg_get_headers (AVFormatContext * s)
416 {
417     struct ogg *ogg = s->priv_data;
418
419     do{
420         if (ogg_packet (s, NULL, NULL, NULL) < 0)
421             return -1;
422     }while (!ogg->headers);
423
424 #if 0
425     av_log (s, AV_LOG_DEBUG, "found headers\n");
426 #endif
427
428     return 0;
429 }
430
431 static uint64_t
432 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp, int64_t *dts)
433 {
434     struct ogg *ogg = s->priv_data;
435     struct ogg_stream *os = ogg->streams + i;
436     uint64_t pts = AV_NOPTS_VALUE;
437
438     if(os->codec->gptopts){
439         pts = os->codec->gptopts(s, i, gp, dts);
440     } else {
441         pts = gp;
442         if (dts)
443             *dts = pts;
444     }
445
446     return pts;
447 }
448
449
450 static int
451 ogg_get_length (AVFormatContext * s)
452 {
453     struct ogg *ogg = s->priv_data;
454     int idx = -1, i;
455     int64_t size, end;
456
457     if(url_is_streamed(s->pb))
458         return 0;
459
460 // already set
461     if (s->duration != AV_NOPTS_VALUE)
462         return 0;
463
464     size = url_fsize(s->pb);
465     if(size < 0)
466         return 0;
467     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
468
469     ogg_save (s);
470     url_fseek (s->pb, end, SEEK_SET);
471
472     while (!ogg_read_page (s, &i)){
473         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
474             ogg->streams[i].codec)
475             idx = i;
476     }
477
478     if (idx != -1){
479         s->streams[idx]->duration =
480             ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
481     }
482
483     ogg->size = size;
484     ogg_restore (s, 0);
485
486     return 0;
487 }
488
489
490 static int
491 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
492 {
493     struct ogg *ogg = s->priv_data;
494     int i;
495     ogg->curidx = -1;
496     //linear headers seek from start
497     if (ogg_get_headers (s) < 0){
498         return -1;
499     }
500
501     for (i = 0; i < ogg->nstreams; i++)
502         if (ogg->streams[i].header < 0)
503             ogg->streams[i].codec = NULL;
504
505     //linear granulepos seek from end
506     ogg_get_length (s);
507
508     //fill the extradata in the per codec callbacks
509     return 0;
510 }
511
512
513 static int
514 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
515 {
516     struct ogg *ogg;
517     struct ogg_stream *os;
518     int idx = -1;
519     int pstart, psize;
520
521     //Get an ogg packet
522     do{
523         if (ogg_packet (s, &idx, &pstart, &psize) < 0)
524             return AVERROR(EIO);
525     }while (idx < 0 || !s->streams[idx]);
526
527     ogg = s->priv_data;
528     os = ogg->streams + idx;
529
530     //Alloc a pkt
531     if (av_new_packet (pkt, psize) < 0)
532         return AVERROR(EIO);
533     pkt->stream_index = idx;
534     memcpy (pkt->data, os->buf + pstart, psize);
535
536     if (os->lastpts != AV_NOPTS_VALUE) {
537         pkt->pts = os->lastpts;
538         os->lastpts = AV_NOPTS_VALUE;
539     }
540     if (os->lastdts != AV_NOPTS_VALUE) {
541         pkt->dts = os->lastdts;
542         os->lastdts = AV_NOPTS_VALUE;
543     }
544     if (os->page_end) {
545         if (os->granule != -1LL) {
546             if (os->codec && os->codec->granule_is_start)
547                 pkt->pts    = ogg_gptopts(s, idx, os->granule, &pkt->dts);
548             else
549                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
550             os->granule = -1LL;
551         } else
552             av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
553     }
554
555     pkt->flags = os->pflags;
556     pkt->duration = os->pduration;
557
558     return psize;
559 }
560
561
562 static int
563 ogg_read_close (AVFormatContext * s)
564 {
565     struct ogg *ogg = s->priv_data;
566     int i;
567
568     for (i = 0; i < ogg->nstreams; i++){
569         av_free (ogg->streams[i].buf);
570         av_free (ogg->streams[i].private);
571     }
572     av_free (ogg->streams);
573     return 0;
574 }
575
576
577 static int64_t
578 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
579                     int64_t pos_limit)
580 {
581     struct ogg *ogg = s->priv_data;
582     ByteIOContext *bc = s->pb;
583     int64_t pts = AV_NOPTS_VALUE;
584     int i;
585     url_fseek(bc, *pos_arg, SEEK_SET);
586     while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
587         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
588             ogg->streams[i].codec && i == stream_index) {
589             pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
590             // FIXME: this is the position of the packet after the one with above
591             // pts.
592             *pos_arg = url_ftell(bc);
593             break;
594         }
595     }
596     ogg_reset(ogg);
597     return pts;
598 }
599
600 static int ogg_probe(AVProbeData *p)
601 {
602     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
603         p->buf[2] == 'g' && p->buf[3] == 'S' &&
604         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
605         return AVPROBE_SCORE_MAX;
606     else
607         return 0;
608 }
609
610 AVInputFormat ogg_demuxer = {
611     "ogg",
612     NULL_IF_CONFIG_SMALL("Ogg"),
613     sizeof (struct ogg),
614     ogg_probe,
615     ogg_read_header,
616     ogg_read_packet,
617     ogg_read_close,
618     NULL,
619     ogg_read_timestamp,
620     .extensions = "ogg",
621     .metadata_conv = ff_vorbiscomment_metadata_conv,
622 };