]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
Move put_le16_nolen() to asf.c and give it a ff_ prefix. This way, it is easier
[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     ogg->curidx = idx;
366     os->incomplete = 0;
367
368     if (os->header) {
369         os->header = os->codec->header (s, idx);
370         if (!os->header){
371             os->segp = segp;
372             os->psize = psize;
373             if (!ogg->headers)
374                 s->data_offset = os->sync_pos;
375             ogg->headers = 1;
376         }else{
377             os->pstart += os->psize;
378             os->psize = 0;
379         }
380     } else {
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         if (fpos)
392             *fpos = os->sync_pos;
393         os->pstart += os->psize;
394         os->psize = 0;
395         os->sync_pos = os->page_pos;
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     if (os->segp == os->nsegs)
408         ogg->curidx = -1;
409
410     return 0;
411 }
412
413 static int
414 ogg_get_headers (AVFormatContext * s)
415 {
416     struct ogg *ogg = s->priv_data;
417
418     do{
419         if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
420             return -1;
421     }while (!ogg->headers);
422
423 #if 0
424     av_log (s, AV_LOG_DEBUG, "found headers\n");
425 #endif
426
427     return 0;
428 }
429
430 static int
431 ogg_get_length (AVFormatContext * s)
432 {
433     struct ogg *ogg = s->priv_data;
434     int idx = -1, i;
435     int64_t size, end;
436
437     if(url_is_streamed(s->pb))
438         return 0;
439
440 // already set
441     if (s->duration != AV_NOPTS_VALUE)
442         return 0;
443
444     size = url_fsize(s->pb);
445     if(size < 0)
446         return 0;
447     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
448
449     ogg_save (s);
450     url_fseek (s->pb, end, SEEK_SET);
451
452     while (!ogg_read_page (s, &i)){
453         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
454             ogg->streams[i].codec)
455             idx = i;
456     }
457
458     if (idx != -1){
459         s->streams[idx]->duration =
460             ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
461         if (s->streams[idx]->start_time != AV_NOPTS_VALUE)
462             s->streams[idx]->duration -= s->streams[idx]->start_time;
463     }
464
465     ogg->size = size;
466     ogg_restore (s, 0);
467
468     return 0;
469 }
470
471
472 static int
473 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
474 {
475     struct ogg *ogg = s->priv_data;
476     int i;
477     ogg->curidx = -1;
478     //linear headers seek from start
479     if (ogg_get_headers (s) < 0){
480         return -1;
481     }
482
483     for (i = 0; i < ogg->nstreams; i++)
484         if (ogg->streams[i].header < 0)
485             ogg->streams[i].codec = NULL;
486
487     //linear granulepos seek from end
488     ogg_get_length (s);
489
490     //fill the extradata in the per codec callbacks
491     return 0;
492 }
493
494 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
495 {
496     struct ogg *ogg = s->priv_data;
497     struct ogg_stream *os = ogg->streams + idx;
498     int64_t pts = AV_NOPTS_VALUE;
499
500     if (dts)
501         *dts = AV_NOPTS_VALUE;
502
503     if (os->lastpts != AV_NOPTS_VALUE) {
504         pts = os->lastpts;
505         os->lastpts = AV_NOPTS_VALUE;
506     }
507     if (os->lastdts != AV_NOPTS_VALUE) {
508         if (dts)
509             *dts = os->lastdts;
510         os->lastdts = AV_NOPTS_VALUE;
511     }
512     if (os->page_end) {
513         if (os->granule != -1LL) {
514             if (os->codec && os->codec->granule_is_start)
515                 pts = ogg_gptopts(s, idx, os->granule, dts);
516             else
517                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
518             os->granule = -1LL;
519         } else
520             av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
521     }
522     return pts;
523 }
524
525 static int
526 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
527 {
528     struct ogg *ogg;
529     struct ogg_stream *os;
530     int idx = -1;
531     int pstart, psize;
532     int64_t fpos, pts, dts;
533
534     //Get an ogg packet
535 retry:
536     do{
537         if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
538             return AVERROR(EIO);
539     }while (idx < 0 || !s->streams[idx]);
540
541     ogg = s->priv_data;
542     os = ogg->streams + idx;
543
544     // pflags might not be set until after this
545     pts = ogg_calc_pts(s, idx, &dts);
546
547     if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
548         goto retry;
549     os->keyframe_seek = 0;
550
551     //Alloc a pkt
552     if (av_new_packet (pkt, psize) < 0)
553         return AVERROR(EIO);
554     pkt->stream_index = idx;
555     memcpy (pkt->data, os->buf + pstart, psize);
556
557     pkt->pts = pts;
558     pkt->dts = dts;
559     pkt->flags = os->pflags;
560     pkt->duration = os->pduration;
561     pkt->pos = fpos;
562
563     return psize;
564 }
565
566
567 static int
568 ogg_read_close (AVFormatContext * s)
569 {
570     struct ogg *ogg = s->priv_data;
571     int i;
572
573     for (i = 0; i < ogg->nstreams; i++){
574         av_free (ogg->streams[i].buf);
575         av_free (ogg->streams[i].private);
576     }
577     av_free (ogg->streams);
578     return 0;
579 }
580
581
582 static int64_t
583 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
584                     int64_t pos_limit)
585 {
586     struct ogg *ogg = s->priv_data;
587     struct ogg_stream *os = ogg->streams + stream_index;
588     ByteIOContext *bc = s->pb;
589     int64_t pts = AV_NOPTS_VALUE;
590     int i;
591     url_fseek(bc, *pos_arg, SEEK_SET);
592     ogg_reset(ogg);
593
594     while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
595         if (i == stream_index) {
596             pts = ogg_calc_pts(s, i, NULL);
597             if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
598                 pts = AV_NOPTS_VALUE;
599         }
600         if (pts != AV_NOPTS_VALUE)
601             break;
602     }
603     ogg_reset(ogg);
604     return pts;
605 }
606
607 static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
608 {
609     struct ogg *ogg = s->priv_data;
610     struct ogg_stream *os = ogg->streams + stream_index;
611     int ret;
612
613     // Try seeking to a keyframe first. If this fails (very possible),
614     // av_seek_frame will fall back to ignoring keyframes
615     if (s->streams[stream_index]->codec->codec_type == CODEC_TYPE_VIDEO
616         && !(flags & AVSEEK_FLAG_ANY))
617         os->keyframe_seek = 1;
618
619     ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
620     if (ret < 0)
621         os->keyframe_seek = 0;
622     return ret;
623 }
624
625 static int ogg_probe(AVProbeData *p)
626 {
627     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
628         p->buf[2] == 'g' && p->buf[3] == 'S' &&
629         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
630         return AVPROBE_SCORE_MAX;
631     else
632         return 0;
633 }
634
635 AVInputFormat ogg_demuxer = {
636     "ogg",
637     NULL_IF_CONFIG_SMALL("Ogg"),
638     sizeof (struct ogg),
639     ogg_probe,
640     ogg_read_header,
641     ogg_read_packet,
642     ogg_read_close,
643     ogg_read_seek,
644     ogg_read_timestamp,
645     .extensions = "ogg",
646     .metadata_conv = ff_vorbiscomment_metadata_conv,
647 };