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