Mercurial > libavformat.hg
changeset 726:17178af951b4 libavformat
Ogg demuxer ported from tcvp by Luca Barbato <lu_zero at gentoo dot org>,
fixups by me.
author | mru |
---|---|
date | Sat, 09 Apr 2005 15:32:58 +0000 |
parents | dc20bf86353f |
children | a827309802b5 |
files | Makefile allformats.c avformat.h ogg.c ogg2.c ogg2.h oggparsevorbis.c |
diffstat | 7 files changed, 909 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Sun Apr 03 05:02:08 2005 +0000 +++ b/Makefile Sat Apr 09 15:32:58 2005 +0000 @@ -16,8 +16,8 @@ avienc.o avidec.o wav.o swf.o au.o gif.o mov.o mpjpeg.o dv.o \ yuv4mpeg.o 4xm.o flvenc.o flvdec.o movenc.o psxstr.o idroq.o ipmovie.o \ nut.o wc3movie.o mp3.o westwood.o segafilm.o idcin.o flic.o \ - sierravmd.o matroska.o sol.o electronicarts.o nsvdec.o asf.o asf-enc.o - + sierravmd.o matroska.o sol.o electronicarts.o nsvdec.o asf.o asf-enc.o \ + ogg2.o oggparsevorbis.o AMROBJS= ifeq ($(AMR_NB),yes) AMROBJS= amr.o
--- a/allformats.c Sun Apr 03 05:02:08 2005 +0000 +++ b/allformats.c Sat Apr 09 15:32:58 2005 +0000 @@ -81,9 +81,10 @@ amr_init(); #endif yuv4mpeg_init(); - + + ogg_init(); #ifdef CONFIG_LIBOGG - ogg_init(); + libogg_init(); #endif ffm_init();
--- a/avformat.h Sun Apr 03 05:02:08 2005 +0000 +++ b/avformat.h Sat Apr 09 15:32:58 2005 +0000 @@ -467,8 +467,11 @@ /* yuv4mpeg.c */ int yuv4mpeg_init(void); +/* ogg2.c */ +int ogg_init(void); + /* ogg.c */ -int ogg_init(void); +int libogg_init(void); /* dv.c */ int ff_dv_init(void);
--- a/ogg.c Sun Apr 03 05:02:08 2005 +0000 +++ b/ogg.c Sat Apr 09 15:32:58 2005 +0000 @@ -134,7 +134,7 @@ } ; #endif //CONFIG_ENCODERS - +#if 0 static int next_packet(AVFormatContext *avfcontext, ogg_packet *op) { OggContext *context = avfcontext->priv_data ; ogg_page og ; @@ -247,12 +247,12 @@ ogg_read_close, .extensions = "ogg", } ; - +#endif -int ogg_init(void) { +int libogg_init(void) { #ifdef CONFIG_ENCODERS av_register_output_format(&ogg_oformat) ; #endif - av_register_input_format(&ogg_iformat); +/* av_register_input_format(&ogg_iformat); */ return 0 ; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ogg2.c Sat Apr 09 15:32:58 2005 +0000 @@ -0,0 +1,643 @@ +/* + * Ogg bitstream support + * Luca Barbato <lu_zero@gentoo.org> + * Based on tcvp implementation + * + */ + +/** + Copyright (C) 2005 Michael Ahlberg, Måns Rullgård + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +**/ + + +#include <stdio.h> +#include "ogg2.h" +#include "avformat.h" + +#define MAX_PAGE_SIZE 65307 +#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE + +static ogg_codec_t *ogg_codecs[] = { + &vorbis_codec, + NULL +}; + +#if 0 // CONFIG_ENCODERS +static int +ogg_write_header (AVFormatContext * avfcontext) +{ +} + +static int +ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt) +{ +} + + +static int +ogg_write_trailer (AVFormatContext * avfcontext) +{ +} + + +static AVOutputFormat ogg_oformat = { + "ogg", + "Ogg Vorbis", + "audio/x-vorbis", + "ogg", + sizeof (OggContext), + CODEC_ID_VORBIS, + 0, + ogg_write_header, + ogg_write_packet, + ogg_write_trailer, +}; +#endif //CONFIG_ENCODERS + +//FIXME We could avoid some structure duplication +static int +ogg_save (AVFormatContext * s) +{ + ogg_t *ogg = s->priv_data; + ogg_state_t *ost = + av_malloc(sizeof (*ost) + ogg->nstreams * sizeof (*ogg->streams)); + int i; + ost->pos = url_ftell (&s->pb);; + ost->curidx = ogg->curidx; + ost->next = ogg->state; + memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams)); + + for (i = 0; i < ogg->nstreams; i++){ + ogg_stream_t *os = ogg->streams + i; + os->buf = av_malloc (os->bufsize); + memset (os->buf, 0, os->bufsize); + memcpy (os->buf, ost->streams[i].buf, os->bufpos); + } + + ogg->state = ost; + + return 0; +} + +static int +ogg_restore (AVFormatContext * s, int discard) +{ + ogg_t *ogg = s->priv_data; + ByteIOContext *bc = &s->pb; + ogg_state_t *ost = ogg->state; + int i; + + if (!ost) + return 0; + + ogg->state = ost->next; + + if (!discard){ + for (i = 0; i < ogg->nstreams; i++) + av_free (ogg->streams[i].buf); + + url_fseek (bc, ost->pos, SEEK_SET); + ogg->curidx = ost->curidx; + memcpy (ogg->streams, ost->streams, + ogg->nstreams * sizeof (*ogg->streams)); + } + + av_free (ost); + + return 0; +} + +static int +ogg_reset (ogg_t * ogg) +{ + int i; + + for (i = 0; i < ogg->nstreams; i++){ + ogg_stream_t *os = ogg->streams + i; + os->bufpos = 0; + os->pstart = 0; + os->psize = 0; + os->granule = -1; + os->lastgp = -1; + os->nsegs = 0; + os->segp = 0; + } + + ogg->curidx = -1; + + return 0; +} + +static ogg_codec_t * +ogg_find_codec (u_char * buf, int size) +{ + int i; + + for (i = 0; ogg_codecs[i]; i++) + if (size >= ogg_codecs[i]->magicsize && + !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize)) + return ogg_codecs[i]; + + return NULL; +} + +static int +ogg_find_stream (ogg_t * ogg, int serial) +{ + int i; + + for (i = 0; i < ogg->nstreams; i++) + if (ogg->streams[i].serial == serial) + return i; + + return -1; +} + +static int +ogg_new_stream (AVFormatContext * s, uint32_t serial) +{ + + ogg_t *ogg = s->priv_data; + int idx = ogg->nstreams++; + AVStream *st; + ogg_stream_t *os; + + ogg->streams = av_realloc (ogg->streams, + ogg->nstreams * sizeof (*ogg->streams)); + memset (ogg->streams + idx, 0, sizeof (*ogg->streams)); + os = ogg->streams + idx; + os->serial = serial; + os->bufsize = DECODER_BUFFER_SIZE; + os->buf = av_malloc (os->bufsize); + memset (os->buf, 0, os->bufsize); + os->header = -1; + + st = av_new_stream (s, idx); + if (!st) + return AVERROR_NOMEM; + + av_set_pts_info(st, 64, 1, 1000000); + st->start_time = 0; + + return idx; +} + +static int +ogg_read_page (AVFormatContext * s, int *str) +{ + ByteIOContext *bc = &s->pb; + ogg_t *ogg = s->priv_data; + ogg_stream_t *os; + int i = 0; + int flags, nsegs; + uint64_t gp; + uint32_t serial; + uint32_t seq; + uint32_t crc; + int size, idx; + char sync[4]; + int sp = 0; + + if (get_buffer (bc, sync, 4) < 4) + return -1; + + do{ + int c; + + if (sync[sp & 3] == 'O' && + sync[(sp + 1) & 3] == 'g' && + sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S') + break; + + c = url_fgetc (bc); + if (c < 0) + return -1; + sync[sp++ & 3] = c; + }while (i++ < MAX_PAGE_SIZE); + + if (i >= MAX_PAGE_SIZE){ + av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n"); + return -1; + } + + if (url_fgetc (bc) != 0) /* version */ + return -1; + + flags = url_fgetc (bc); + gp = get_le64 (bc); + serial = get_le32 (bc); + seq = get_le32 (bc); + crc = get_le32 (bc); + nsegs = url_fgetc (bc); + + idx = ogg_find_stream (ogg, serial); + if (idx < 0){ + idx = ogg_new_stream (s, serial); + if (idx < 0) + return -1; + } + + os = ogg->streams + idx; + + if (get_buffer (bc, os->segments, nsegs) < nsegs) + return -1; + + os->nsegs = nsegs; + os->segp = 0; + + size = 0; + for (i = 0; i < nsegs; i++) + size += os->segments[i]; + + if (flags & OGG_FLAG_CONT){ + if (!os->psize){ + while (os->segp < os->nsegs){ + int seg = os->segments[os->segp++]; + os->pstart += seg; + if (seg < 255) + break; + } + } + }else{ + os->psize = 0; + } + + if (os->bufsize - os->bufpos < size){ + u_char *nb = av_malloc (os->bufsize *= 2); + memset (nb, 0, os->bufsize); + memcpy (nb, os->buf, os->bufpos); + av_free (os->buf); + os->buf = nb; + } + + if (get_buffer (bc, os->buf + os->bufpos, size) < size) + return -1; + + os->lastgp = os->granule; + os->bufpos += size; + os->granule = gp; + os->flags = flags; + + if (str) + *str = idx; + + return 0; +} + +static int +ogg_packet (AVFormatContext * s, int *str) +{ + ogg_t *ogg = s->priv_data; + int idx; + ogg_stream_t *os; + int complete = 0; + int segp = 0, psize = 0; + +#if 0 + av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx); +#endif + + do{ + idx = ogg->curidx; + + while (idx < 0){ + if (ogg_read_page (s, &idx) < 0) + return -1; + } + + os = ogg->streams + idx; + +#if 0 + av_log (s, AV_LOG_DEBUG, + "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n", + idx, os->pstart, os->psize, os->segp, os->nsegs); +#endif + + if (!os->codec){ + if (os->header < 0){ + os->codec = ogg_find_codec (os->buf, os->bufpos); + if (!os->codec){ + os->header = 0; + return 0; + } + }else{ + return 0; + } + } + + segp = os->segp; + psize = os->psize; + + while (os->segp < os->nsegs){ + int ss = os->segments[os->segp++]; + os->psize += ss; + if (ss < 255){ + complete = 1; + break; + } + } + + if (!complete && os->segp == os->nsegs){ + u_char *nb = av_malloc (os->bufsize); + int size = os->bufpos - os->pstart; + memset (nb, 0, os->bufsize); + memcpy (nb, os->buf + os->pstart, size); + av_free (os->buf); + os->buf = nb; + os->bufpos = size; + os->pstart = 0; + ogg->curidx = -1; + } + }while (!complete); + +#if 0 + av_log (s, AV_LOG_DEBUG, + "ogg_packet: idx %i, frame size %i, start %i\n", + idx, os->psize, os->pstart); +#endif + + ogg->curidx = idx; + + if (os->header < 0){ + int hdr = os->codec->header (s, idx); + if (!hdr){ + os->header = os->seq; + os->segp = segp; + os->psize = psize; + ogg->headers = 1; + }else{ + os->pstart += os->psize; + os->psize = 0; + } + } + + if (os->header > -1 && os->seq > os->header){ + if (os->codec && os->codec->packet) + os->codec->packet (s, idx); + if (str) + *str = idx; + } + + os->seq++; + if (os->segp == os->nsegs) + ogg->curidx = -1; + + return 0; +} + +static int +ogg_get_headers (AVFormatContext * s) +{ + ogg_t *ogg = s->priv_data; + + do{ + if (ogg_packet (s, NULL) < 0) + return -1; + }while (!ogg->headers); + +#if 0 + av_log (s, AV_LOG_DEBUG, "found headers\n"); +#endif + + return 0; +} + +static uint64_t +ogg_gptopts (AVFormatContext * s, int i, uint64_t gp) +{ + AVStream *st = s->streams[i]; + AVCodecContext *codec = &st->codec; + uint64_t pts = AV_NOPTS_VALUE; + + if (codec->codec_type == CODEC_TYPE_AUDIO){ + pts = gp * 1000000LL / codec->sample_rate; + }else if (codec->codec_type == CODEC_TYPE_VIDEO){ +//FIXME + pts = gp * 1000000LL / codec->sample_rate; +// pts = gp * st->video.frame_rate.den * 27000000LL / +// st->video.frame_rate.num; + } + + return pts; +} + + +static int +ogg_get_length (AVFormatContext * s) +{ + ogg_t *ogg = s->priv_data; + URLContext *h = url_fileno (&s->pb); + int idx = -1, i; +//FIXME: get the right ctx flag to know if is seekable or not +// if(ogg->f->flags & URL_FLAG_STREAMED) +// return 0; + +// already set + if (s->duration != AV_NOPTS_VALUE) + return 0; + + ogg_save (s); + url_seek (h, -MAX_PAGE_SIZE, SEEK_END); + + while (!ogg_read_page (s, &i)){ + if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0) + idx = i; + } + + if (idx != -1){ + s->streams[idx]->duration = + ogg_gptopts (s, idx, ogg->streams[idx].granule); + } + + ogg->size = url_filesize(h); + ogg_restore (s, 0); + + return 0; +} + + +static int +ogg_read_header (AVFormatContext * s, AVFormatParameters * ap) +{ + ogg_t *ogg = s->priv_data; + ogg->curidx = -1; + //linear headers seek from start + if (ogg_get_headers (s) < 0){ + return -1; + } + + //linear granulepos seek from end + ogg_get_length (s); + + //fill the extradata in the per codec callbacks + return 0; +} + + +static int +ogg_read_packet (AVFormatContext * s, AVPacket * pkt) +{ + ogg_t *ogg; + ogg_stream_t *os; + int idx = -1; + + //Get an ogg packet + do{ + if (ogg_packet (s, &idx) < 0) + return AVERROR_IO; + }while (idx < 0 || !s->streams[idx]); + + ogg = s->priv_data; + os = ogg->streams + idx; + + //Alloc a pkt + if (av_new_packet (pkt, os->psize) < 0) + return AVERROR_IO; + pkt->stream_index = idx; + memcpy (pkt->data, os->buf + os->pstart, os->psize); + if (os->lastgp != -1LL){ + pkt->pts = ogg_gptopts (s, idx, os->lastgp); + os->lastgp = -1; + } + //next + os->pstart += os->psize; + os->psize = 0; + return os->psize; +} + + +static int +ogg_read_close (AVFormatContext * s) +{ + ogg_t *ogg = s->priv_data; + int i; + + for (i = 0; i < ogg->nstreams; i++){ + av_free (ogg->streams[i].buf); + av_freep (&s->streams[i]->codec.extradata); + } + av_free (ogg->streams); + return 0; +} + + +static int +ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts, + int flags) +{ + ogg_t *ogg = s->priv_data; + ByteIOContext *bc = &s->pb; + uint64_t min = 0, max = ogg->size; + uint64_t tmin = 0, tmax = s->duration; + int64_t pts = AV_NOPTS_VALUE; + + ogg_save (s); + + while (min <= max){ + uint64_t p = min + (max - min) * target_ts / (tmax - tmin); + int i = -1; + + url_fseek (bc, p, SEEK_SET); + + while (!ogg_read_page (s, &i)){ + if (ogg->streams[i].granule != 0 && ogg->streams[i].granule != -1) + break; + } + + if (i == -1) + break; + + pts = ogg_gptopts (s, i, ogg->streams[i].granule); + p = url_ftell (bc); + + if (ABS (pts - target_ts) < 1000000LL) + break; + + if (pts > target_ts){ + max = p; + tmax = pts; + }else{ + min = p; + tmin = pts; + } + } + + if (ABS (pts - target_ts) < 1000000LL){ + ogg_restore (s, 1); + ogg_reset (ogg); + }else{ + ogg_restore (s, 0); + pts = AV_NOPTS_VALUE; + } + + return pts; + +#if 0 + //later... + int64_t pos; + if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0) + return -1; + pos = url_ftell (&s->pb); + ogg_read_timestamp (s, stream_index, &pos, pos - 1); +#endif + +} + +#if 0 +static int64_t +ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg, + int64_t pos_limit) +{ + ogg_t *ogg = s->priv_data; + ByteIOContext *bc = &s->pb; + int64_t pos, pts; + + if (*pos_arg < 0) + return AV_NOPTS_VALUE; + + pos = *pos_arg; +} +#endif + +static AVInputFormat ogg_iformat = { + "ogg", + "Ogg", + sizeof (ogg_t), + NULL, + ogg_read_header, + ogg_read_packet, + ogg_read_close, + ogg_read_seek, +// ogg_read_timestamp, + .extensions = "ogg", +}; + +int +ogg_init (void) +{ +#if 0 // CONFIG_ENCODERS + av_register_output_format (&ogg_oformat); +#endif + av_register_input_format (&ogg_iformat); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ogg2.h Sat Apr 09 15:32:58 2005 +0000 @@ -0,0 +1,84 @@ +/** + Copyright (C) 2005 Michael Ahlberg, Måns Rullgård + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +**/ + +#ifndef OGG_H +#define OGG_H + +#include "avformat.h" + +typedef struct ogg_codec { + uint8_t *magic; + uint8_t magicsize; + int8_t *name; + int (*header)(AVFormatContext *, int); + int (*packet)(AVFormatContext *, int); +} ogg_codec_t; + +typedef struct ogg_stream { + uint8_t *buf; + unsigned int bufsize; + unsigned int bufpos; + unsigned int pstart; + unsigned int psize; + uint32_t serial; + uint32_t seq; + uint64_t granule, lastgp; + int flags; + ogg_codec_t *codec; + int header; + int nsegs, segp; + uint8_t segments[255]; +} ogg_stream_t; + +typedef struct ogg_state { + uint64_t pos; + int curidx; + struct ogg_state *next; + ogg_stream_t streams[]; +} ogg_state_t; + +typedef struct ogg { + ogg_stream_t *streams; + int nstreams; + int headers; + int curidx; + uint64_t size; + ogg_state_t *state; +} ogg_t; + +#define OGG_FLAG_CONT 1 +#define OGG_FLAG_BOS 2 +#define OGG_FLAG_EOS 4 + +extern ogg_codec_t vorbis_codec; +#if 0 +extern ogg_codec_t ogm_video_codec; +extern ogg_codec_t ogm_audio_codec; +extern ogg_codec_t ogm_old_codec; +extern ogg_codec_t flac_codec; +#endif + +extern int vorbis_comment(AVFormatContext *ms, char *buf, int size); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oggparsevorbis.c Sat Apr 09 15:32:58 2005 +0000 @@ -0,0 +1,169 @@ +/** + Copyright (C) 2005 Michael Ahlberg, Måns Rullgård + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +**/ + +#include <stdlib.h> +#include "avformat.h" +#include "bitstream.h" +#include "bswap.h" +#include "ogg2.h" + +extern int +vorbis_comment (AVFormatContext * as, char *buf, int size) +{ + char *p = buf; + int s, n, j; + + if (size < 4) + return -1; + + s = le2me_32 (unaligned32 (p)); + p += 4; + size -= 4; + + if (size < s + 4) + return -1; + + p += s; + size -= s; + + n = le2me_32 (unaligned32 (p)); + p += 4; + size -= 4; + + while (size >= 4){ + char *t, *v; + int tl, vl; + + s = le2me_32 (unaligned32 (p)); + p += 4; + size -= 4; + + if (size < s) + break; + + t = p; + p += s; + size -= s; + n--; + + v = memchr (t, '=', s); + if (!v) + continue; + + tl = v - t; + vl = s - tl - 1; + v++; + + if (tl && vl){ + char tt[tl + 1]; + char ct[vl + 1]; + + for (j = 0; j < tl; j++) + tt[j] = toupper (t[j]); + tt[tl] = 0; + + memcpy (ct, v, vl); + ct[vl] = 0; + + // took from Vorbis_I_spec + if (!strcmp (tt, "AUTHOR")) + strncpy (as->author, ct, FFMIN(sizeof (as->author), vl)); + else if (!strcmp (tt, "TITLE")) + strncpy (as->title, ct, FFMIN(sizeof (as->title), vl)); + else if (!strcmp (tt, "COPYRIGHT")) + strncpy (as->copyright, ct, FFMIN(sizeof (as->copyright), vl)); + else if (!strcmp (tt, "DESCRIPTION")) + strncpy (as->comment, ct, FFMIN(sizeof (as->comment), vl)); + else if (!strcmp (tt, "GENRE")) + strncpy (as->genre, ct, FFMIN(sizeof (as->genre), vl)); + else if (!strcmp (tt, "TRACKNUMBER")) + as->track = atoi (ct); + //Too bored to add others for today + } + } + + if (size > 0) + av_log (as, AV_LOG_INFO, "%i bytes of comment header remain\n", size); + if (n > 0) + av_log (as, AV_LOG_INFO, + "truncated comment header, %i comments not found\n", n); + + return 0; +} + + +/** Parse the vorbis header + * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec + * [vorbis_version] = read 32 bits as unsigned integer | Not used + * [audio_channels] = read 8 bit integer as unsigned | Used + * [audio_sample_rate] = read 32 bits as unsigned integer | Used + * [bitrate_maximum] = read 32 bits as signed integer | Not used yet + * [bitrate_nominal] = read 32 bits as signed integer | Not used yet + * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate + * [blocksize_0] = read 4 bits as unsigned integer | Not Used + * [blocksize_1] = read 4 bits as unsigned integer | Not Used + * [framing_flag] = read one bit | Not Used + * */ + +static int +vorbis_header (AVFormatContext * s, int idx) +{ + ogg_t *ogg = s->priv_data; + ogg_stream_t *os = ogg->streams + idx; + AVStream *st = s->streams[idx]; + int cds = st->codec.extradata_size + os->psize + 2; + u_char *cdp; + + if (os->seq > 2) + return 0; + + st->codec.extradata = av_realloc (st->codec.extradata, cds); + cdp = st->codec.extradata + st->codec.extradata_size; + *cdp++ = os->psize >> 8; + *cdp++ = os->psize & 0xff; + memcpy (cdp, os->buf + os->pstart, os->psize); + st->codec.extradata_size = cds; + + if (os->buf[os->pstart] == 1) { + u_char *p = os->buf + os->pstart + 11; //skip up to the audio channels + st->codec.channels = *p++; + st->codec.sample_rate = le2me_32 (unaligned32 (p)); + p += 8; //skip maximum and and nominal bitrate + st->codec.bit_rate = le2me_32 (unaligned32 (p)); //Minimum bitrate + + st->codec.codec_type = CODEC_TYPE_AUDIO; + st->codec.codec_id = CODEC_ID_VORBIS; + + } else if (os->buf[os->pstart] == 3) { + vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8); + } + + return os->seq < 3; +} + +ogg_codec_t vorbis_codec = { + .magic = "\001vorbis", + .magicsize = 7, + .header = vorbis_header +};