]> git.sesse.net Git - ffmpeg/blob - libavformat/ogg2.c
fix some signedness warnings
[ffmpeg] / libavformat / ogg2.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 "ogg2.h"
35 #include "avformat.h"
36
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40 static ogg_codec_t *ogg_codecs[] = {
41     &vorbis_codec,
42     &theora_codec,
43     &flac_codec,
44     &ogm_video_codec,
45     &ogm_audio_codec,
46     &ogm_old_codec,
47     NULL
48 };
49
50 #if 0                           // CONFIG_MUXERS
51 static int
52 ogg_write_header (AVFormatContext * avfcontext)
53 {
54 }
55
56 static int
57 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
58 {
59 }
60
61
62 static int
63 ogg_write_trailer (AVFormatContext * avfcontext)
64 {
65 }
66
67
68 AVOutputFormat ogg_muxer = {
69     "ogg",
70     "Ogg Vorbis",
71     "audio/x-vorbis",
72     "ogg",
73     sizeof (OggContext),
74     CODEC_ID_VORBIS,
75     0,
76     ogg_write_header,
77     ogg_write_packet,
78     ogg_write_trailer,
79 };
80 #endif //CONFIG_MUXERS
81
82 //FIXME We could avoid some structure duplication
83 static int
84 ogg_save (AVFormatContext * s)
85 {
86     ogg_t *ogg = s->priv_data;
87     ogg_state_t *ost =
88         av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
89     int i;
90     ost->pos = url_ftell (&s->pb);;
91     ost->curidx = ogg->curidx;
92     ost->next = ogg->state;
93     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
94
95     for (i = 0; i < ogg->nstreams; i++){
96         ogg_stream_t *os = ogg->streams + i;
97         os->buf = av_malloc (os->bufsize);
98         memset (os->buf, 0, os->bufsize);
99         memcpy (os->buf, ost->streams[i].buf, os->bufpos);
100     }
101
102     ogg->state = ost;
103
104     return 0;
105 }
106
107 static int
108 ogg_restore (AVFormatContext * s, int discard)
109 {
110     ogg_t *ogg = s->priv_data;
111     ByteIOContext *bc = &s->pb;
112     ogg_state_t *ost = ogg->state;
113     int i;
114
115     if (!ost)
116         return 0;
117
118     ogg->state = ost->next;
119
120     if (!discard){
121         for (i = 0; i < ogg->nstreams; i++)
122             av_free (ogg->streams[i].buf);
123
124         url_fseek (bc, ost->pos, SEEK_SET);
125         ogg->curidx = ost->curidx;
126         memcpy (ogg->streams, ost->streams,
127         ogg->nstreams * sizeof (*ogg->streams));
128     }
129
130     av_free (ost);
131
132     return 0;
133 }
134
135 static int
136 ogg_reset (ogg_t * ogg)
137 {
138     int i;
139
140     for (i = 0; i < ogg->nstreams; i++){
141         ogg_stream_t *os = ogg->streams + i;
142         os->bufpos = 0;
143         os->pstart = 0;
144         os->psize = 0;
145         os->granule = -1;
146         os->lastgp = -1;
147         os->nsegs = 0;
148         os->segp = 0;
149     }
150
151     ogg->curidx = -1;
152
153     return 0;
154 }
155
156 static ogg_codec_t *
157 ogg_find_codec (uint8_t * buf, int size)
158 {
159     int i;
160
161     for (i = 0; ogg_codecs[i]; i++)
162         if (size >= ogg_codecs[i]->magicsize &&
163             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
164             return ogg_codecs[i];
165
166     return NULL;
167 }
168
169 static int
170 ogg_find_stream (ogg_t * ogg, int serial)
171 {
172     int i;
173
174     for (i = 0; i < ogg->nstreams; i++)
175         if (ogg->streams[i].serial == serial)
176             return i;
177
178     return -1;
179 }
180
181 static int
182 ogg_new_stream (AVFormatContext * s, uint32_t serial)
183 {
184
185     ogg_t *ogg = s->priv_data;
186     int idx = ogg->nstreams++;
187     AVStream *st;
188     ogg_stream_t *os;
189
190     ogg->streams = av_realloc (ogg->streams,
191                                ogg->nstreams * sizeof (*ogg->streams));
192     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
193     os = ogg->streams + idx;
194     os->serial = serial;
195     os->bufsize = DECODER_BUFFER_SIZE;
196     os->buf = av_malloc(os->bufsize);
197     os->header = -1;
198
199     st = av_new_stream (s, idx);
200     if (!st)
201         return AVERROR_NOMEM;
202
203     av_set_pts_info(st, 64, 1, 1000000);
204
205     return idx;
206 }
207
208 static int
209 ogg_new_buf(ogg_t *ogg, int idx)
210 {
211     ogg_stream_t *os = ogg->streams + idx;
212     uint8_t *nb = av_malloc(os->bufsize);
213     int size = os->bufpos - os->pstart;
214     if(os->buf){
215         memcpy(nb, os->buf + os->pstart, size);
216         av_free(os->buf);
217     }
218     os->buf = nb;
219     os->bufpos = size;
220     os->pstart = 0;
221
222     return 0;
223 }
224
225 static int
226 ogg_read_page (AVFormatContext * s, int *str)
227 {
228     ByteIOContext *bc = &s->pb;
229     ogg_t *ogg = s->priv_data;
230     ogg_stream_t *os;
231     int i = 0;
232     int flags, nsegs;
233     uint64_t gp;
234     uint32_t serial;
235     uint32_t seq;
236     uint32_t crc;
237     int size, idx;
238     uint8_t sync[4];
239     int sp = 0;
240
241     if (get_buffer (bc, sync, 4) < 4)
242         return -1;
243
244     do{
245         int c;
246
247         if (sync[sp & 3] == 'O' &&
248             sync[(sp + 1) & 3] == 'g' &&
249             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
250             break;
251
252         c = url_fgetc (bc);
253         if (c < 0)
254             return -1;
255         sync[sp++ & 3] = c;
256     }while (i++ < MAX_PAGE_SIZE);
257
258     if (i >= MAX_PAGE_SIZE){
259         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
260         return -1;
261     }
262
263     if (url_fgetc (bc) != 0)      /* version */
264         return -1;
265
266     flags = url_fgetc (bc);
267     gp = get_le64 (bc);
268     serial = get_le32 (bc);
269     seq = get_le32 (bc);
270     crc = get_le32 (bc);
271     nsegs = url_fgetc (bc);
272
273     idx = ogg_find_stream (ogg, serial);
274     if (idx < 0){
275         idx = ogg_new_stream (s, serial);
276         if (idx < 0)
277             return -1;
278     }
279
280     os = ogg->streams + idx;
281
282     if(os->psize > 0)
283         ogg_new_buf(ogg, idx);
284
285     if (get_buffer (bc, os->segments, nsegs) < nsegs)
286         return -1;
287
288     os->nsegs = nsegs;
289     os->segp = 0;
290
291     size = 0;
292     for (i = 0; i < nsegs; i++)
293         size += os->segments[i];
294
295     if (flags & OGG_FLAG_CONT){
296         if (!os->psize){
297             while (os->segp < os->nsegs){
298                 int seg = os->segments[os->segp++];
299                 os->pstart += seg;
300                 if (seg < 255)
301                   break;
302             }
303         }
304     }else{
305       os->psize = 0;
306     }
307
308     if (os->bufsize - os->bufpos < size){
309         uint8_t *nb = av_malloc (os->bufsize *= 2);
310         memcpy (nb, os->buf, os->bufpos);
311         av_free (os->buf);
312         os->buf = nb;
313     }
314
315     if (get_buffer (bc, os->buf + os->bufpos, size) < size)
316         return -1;
317
318     os->lastgp = os->granule;
319     os->bufpos += size;
320     os->granule = gp;
321     os->flags = flags;
322
323     if (str)
324         *str = idx;
325
326     return 0;
327 }
328
329 static int
330 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
331 {
332     ogg_t *ogg = s->priv_data;
333     int idx;
334     ogg_stream_t *os;
335     int complete = 0;
336     int segp = 0, psize = 0;
337
338 #if 0
339     av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
340 #endif
341
342     do{
343         idx = ogg->curidx;
344
345         while (idx < 0){
346             if (ogg_read_page (s, &idx) < 0)
347                 return -1;
348         }
349
350         os = ogg->streams + idx;
351
352 #if 0
353         av_log (s, AV_LOG_DEBUG,
354                 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
355                 idx, os->pstart, os->psize, os->segp, os->nsegs);
356 #endif
357
358         if (!os->codec){
359             if (os->header < 0){
360                 os->codec = ogg_find_codec (os->buf, os->bufpos);
361                 if (!os->codec){
362                     os->header = 0;
363                     return 0;
364                 }
365             }else{
366                 return 0;
367             }
368         }
369
370         segp = os->segp;
371         psize = os->psize;
372
373         while (os->segp < os->nsegs){
374             int ss = os->segments[os->segp++];
375             os->psize += ss;
376             if (ss < 255){
377                 complete = 1;
378                 break;
379             }
380         }
381
382         if (!complete && os->segp == os->nsegs){
383             ogg->curidx = -1;
384         }
385     }while (!complete);
386
387 #if 0
388     av_log (s, AV_LOG_DEBUG,
389             "ogg_packet: idx %i, frame size %i, start %i\n",
390             idx, os->psize, os->pstart);
391 #endif
392
393     ogg->curidx = idx;
394
395     if (os->header < 0){
396         int hdr = os->codec->header (s, idx);
397         if (!hdr){
398           os->header = os->seq;
399           os->segp = segp;
400           os->psize = psize;
401           ogg->headers = 1;
402         }else{
403           os->pstart += os->psize;
404           os->psize = 0;
405         }
406     }
407
408     if (os->header > -1 && os->seq > os->header){
409         if (os->codec && os->codec->packet)
410             os->codec->packet (s, idx);
411         if (str)
412             *str = idx;
413         if (dstart)
414             *dstart = os->pstart;
415         if (dsize)
416             *dsize = os->psize;
417         os->pstart += os->psize;
418         os->psize = 0;
419     }
420
421     os->seq++;
422     if (os->segp == os->nsegs)
423         ogg->curidx = -1;
424
425     return 0;
426 }
427
428 static int
429 ogg_get_headers (AVFormatContext * s)
430 {
431     ogg_t *ogg = s->priv_data;
432
433     do{
434         if (ogg_packet (s, NULL, NULL, NULL) < 0)
435             return -1;
436     }while (!ogg->headers);
437
438 #if 0
439     av_log (s, AV_LOG_DEBUG, "found headers\n");
440 #endif
441
442     return 0;
443 }
444
445 static uint64_t
446 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
447 {
448     ogg_t *ogg = s->priv_data;
449     ogg_stream_t *os = ogg->streams + i;
450     uint64_t pts = AV_NOPTS_VALUE;
451
452     if(os->codec->gptopts){
453         pts = os->codec->gptopts(s, i, gp);
454     } else {
455         pts = gp;
456     }
457
458     return pts;
459 }
460
461
462 static int
463 ogg_get_length (AVFormatContext * s)
464 {
465     ogg_t *ogg = s->priv_data;
466     int idx = -1, i;
467     offset_t size, end;
468
469     if(s->pb.is_streamed)
470         return 0;
471
472 // already set
473     if (s->duration != AV_NOPTS_VALUE)
474         return 0;
475
476     size = url_fsize(&s->pb);
477     if(size < 0)
478         return 0;
479     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
480
481     ogg_save (s);
482     url_fseek (&s->pb, end, SEEK_SET);
483
484     while (!ogg_read_page (s, &i)){
485         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
486             idx = i;
487     }
488
489     if (idx != -1){
490         s->streams[idx]->duration =
491             ogg_gptopts (s, idx, ogg->streams[idx].granule);
492     }
493
494     ogg->size = size;
495     ogg_restore (s, 0);
496     ogg_save (s);
497     while (ogg_read_page (s, &i)) {
498         if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
499             break;
500     }
501     if (i == idx) {
502         s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
503         s->streams[idx]->duration -= s->streams[idx]->start_time;
504     }
505     ogg_restore (s, 0);
506
507     return 0;
508 }
509
510
511 static int
512 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
513 {
514     ogg_t *ogg = s->priv_data;
515     ogg->curidx = -1;
516     //linear headers seek from start
517     if (ogg_get_headers (s) < 0){
518       return -1;
519     }
520
521     //linear granulepos seek from end
522     ogg_get_length (s);
523
524     //fill the extradata in the per codec callbacks
525     return 0;
526 }
527
528
529 static int
530 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
531 {
532     ogg_t *ogg;
533     ogg_stream_t *os;
534     int idx = -1;
535     int pstart, psize;
536
537     //Get an ogg packet
538     do{
539         if (ogg_packet (s, &idx, &pstart, &psize) < 0)
540             return AVERROR_IO;
541     }while (idx < 0 || !s->streams[idx]);
542
543     ogg = s->priv_data;
544     os = ogg->streams + idx;
545
546     //Alloc a pkt
547     if (av_new_packet (pkt, psize) < 0)
548         return AVERROR_IO;
549     pkt->stream_index = idx;
550     memcpy (pkt->data, os->buf + pstart, psize);
551     if (os->lastgp != -1LL){
552         pkt->pts = ogg_gptopts (s, idx, os->lastgp);
553         os->lastgp = -1;
554     }
555
556     return psize;
557 }
558
559
560 static int
561 ogg_read_close (AVFormatContext * s)
562 {
563     ogg_t *ogg = s->priv_data;
564     int i;
565
566     for (i = 0; i < ogg->nstreams; i++){
567         av_free (ogg->streams[i].buf);
568         av_free (ogg->streams[i].private);
569     }
570     av_free (ogg->streams);
571     return 0;
572 }
573
574
575 static int
576 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
577                int flags)
578 {
579     AVStream *st = s->streams[stream_index];
580     ogg_t *ogg = s->priv_data;
581     ByteIOContext *bc = &s->pb;
582     uint64_t min = 0, max = ogg->size;
583     uint64_t tmin = st->start_time, tmax = st->start_time + st->duration;
584     int64_t pts = AV_NOPTS_VALUE;
585
586     ogg_save (s);
587
588     if ((uint64_t)target_ts < tmin || target_ts < 0)
589         target_ts = tmin;
590     while (min <= max && tmin < tmax){
591         uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
592         int i = -1;
593
594         url_fseek (bc, p, SEEK_SET);
595
596         while (!ogg_read_page (s, &i)){
597             if (i == stream_index && ogg->streams[i].granule != 0 &&
598                 ogg->streams[i].granule != -1)
599                 break;
600         }
601
602         if (i == -1)
603             break;
604
605         pts = ogg_gptopts (s, i, ogg->streams[i].granule);
606         p = url_ftell (bc);
607
608         if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
609             break;
610
611         if (pts > target_ts){
612             if (max == p && tmax == pts) {
613                 // probably our tmin is wrong, causing us to always end up too late in the file
614                 tmin = (target_ts + tmin + 1) / 2;
615                 if (tmin == target_ts) {
616                     url_fseek(bc, min, SEEK_SET);
617                     break;
618                 }
619             }
620             max = p;
621             tmax = pts;
622         }else{
623             if (min == p && tmin == pts) {
624                 // probably our tmax is wrong, causing us to always end up too early in the file
625                 tmax = (target_ts + tmax) / 2;
626                 if (tmax == target_ts) {
627                     url_fseek(bc, max, SEEK_SET);
628                     break;
629                 }
630             }
631             min = p;
632             tmin = pts;
633         }
634     }
635
636     if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
637         ogg_restore (s, 1);
638         ogg_reset (ogg);
639     }else{
640         ogg_restore (s, 0);
641         pts = AV_NOPTS_VALUE;
642     }
643
644     av_update_cur_dts(s, st, pts);
645     return 0;
646
647 #if 0
648     //later...
649     int64_t pos;
650     if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
651         return -1;
652     pos = url_ftell (&s->pb);
653     ogg_read_timestamp (s, stream_index, &pos, pos - 1);
654 #endif
655
656 }
657
658 #if 0
659 static int64_t
660 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
661                     int64_t pos_limit)
662 {
663     ogg_t *ogg = s->priv_data;
664     ByteIOContext *bc = &s->pb;
665     int64_t pos, pts;
666
667     if (*pos_arg < 0)
668         return AV_NOPTS_VALUE;
669
670     pos = *pos_arg;
671 }
672 #endif
673
674 static int ogg_probe(AVProbeData *p)
675 {
676     if (p->buf_size < 6)
677         return 0;
678     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
679         p->buf[2] == 'g' && p->buf[3] == 'S' &&
680         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
681         return AVPROBE_SCORE_MAX;
682     else
683         return 0;
684 }
685
686 AVInputFormat ogg_demuxer = {
687     "ogg",
688     "Ogg",
689     sizeof (ogg_t),
690     ogg_probe,
691     ogg_read_header,
692     ogg_read_packet,
693     ogg_read_close,
694     ogg_read_seek,
695 // ogg_read_timestamp,
696     .extensions = "ogg",
697 };