aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure18
-rw-r--r--libavformat/Makefile4
-rw-r--r--libavformat/allformats.c5
-rw-r--r--libavformat/avformat.h5
-rw-r--r--libavformat/ogg.c8
-rw-r--r--libavformat/ogg2.c643
-rw-r--r--libavformat/ogg2.h84
-rw-r--r--libavformat/oggparsevorbis.c169
8 files changed, 918 insertions, 18 deletions
diff --git a/configure b/configure
index 3c4c406099..044fa24d92 100755
--- a/configure
+++ b/configure
@@ -16,7 +16,7 @@ echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --libdir=DIR install libs in DIR [PREFIX/lib]"
echo " --mandir=DIR man documentation in DIR [PREFIX/man]"
echo " --enable-mp3lame enable mp3 encoding via libmp3lame [default=no]"
-echo " --enable-ogg enable ogg support via libogg [default=no]"
+echo " --enable-libogg enable ogg support via libogg [default=no]"
echo " --enable-vorbis enable vorbis support via libvorbis [default=no]"
echo " --enable-theora enable theora support via libtheora [default=no]"
echo " --enable-faad enable faad support via libfaad [default=no]"
@@ -154,7 +154,7 @@ dc1394="no"
network="yes"
zlib="yes"
mp3lame="no"
-ogg="no"
+libogg="no"
vorbis="no"
theora="no"
faad="no"
@@ -432,7 +432,7 @@ for opt do
;;
--enable-mp3lame) mp3lame="yes"
;;
- --enable-ogg) ogg="yes"
+ --enable-libogg) libogg="yes"
;;
--enable-vorbis) vorbis="yes"
;;
@@ -492,16 +492,16 @@ for opt do
done
if test "$theora" = "yes" ; then
- if test "$ogg" = "no" ; then
- echo "Ogg must be enabled to enable Theora"
+ if test "$libogg" = "no"; then
+ echo "libogg must be enabled to enable Theora"
fail="yes"
theora="no"
fi
fi
if test "$vorbis" = "yes" ; then
- if test "$ogg" = "no" ; then
- echo "Ogg must be enabled to enable Vorbis"
+ if test "$libogg" = "no"; then
+ echo "libogg must be enabled to enable Vorbis"
fail="yes"
vorbis="no"
fi
@@ -1095,7 +1095,7 @@ fi
echo "gprof enabled $gprof"
echo "zlib enabled $zlib"
echo "mp3lame enabled $mp3lame"
-echo "ogg enabled $ogg"
+echo "libogg enabled $libogg"
echo "vorbis enabled $vorbis"
echo "theora enabled $theora"
echo "faad enabled $faad"
@@ -1395,7 +1395,7 @@ if test "$mp3lame" = "yes" ; then
echo "CONFIG_MP3LAME=yes" >> config.mak
fi
-if test "$ogg" = "yes" ; then
+if test "$libogg" = "yes" ; then
echo "#define CONFIG_LIBOGG 1" >> $TMPH
echo "CONFIG_LIBOGG=yes" >> config.mak
fi
diff --git a/libavformat/Makefile b/libavformat/Makefile
index bdc0d67ff1..3b804d2c05 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -16,8 +16,8 @@ OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o img2.o raw.o rm.o \
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
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index bc7eff5066..d13c90ea58 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -81,9 +81,10 @@ void av_register_all(void)
amr_init();
#endif
yuv4mpeg_init();
-
-#ifdef CONFIG_LIBOGG
+
ogg_init();
+#ifdef CONFIG_LIBOGG
+ libogg_init();
#endif
ffm_init();
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 7beef99999..892b0f8c23 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -467,9 +467,12 @@ int mp3_init(void);
/* yuv4mpeg.c */
int yuv4mpeg_init(void);
-/* ogg.c */
+/* ogg2.c */
int ogg_init(void);
+/* ogg.c */
+int libogg_init(void);
+
/* dv.c */
int ff_dv_init(void);
diff --git a/libavformat/ogg.c b/libavformat/ogg.c
index c30ccd2f24..ab47d029a5 100644
--- a/libavformat/ogg.c
+++ b/libavformat/ogg.c
@@ -134,7 +134,7 @@ static AVOutputFormat ogg_oformat = {
} ;
#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 @@ static AVInputFormat ogg_iformat = {
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 ;
}
diff --git a/libavformat/ogg2.c b/libavformat/ogg2.c
new file mode 100644
index 0000000000..c54b2a04c5
--- /dev/null
+++ b/libavformat/ogg2.c
@@ -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;
+}
diff --git a/libavformat/ogg2.h b/libavformat/ogg2.h
new file mode 100644
index 0000000000..b1146e314c
--- /dev/null
+++ b/libavformat/ogg2.h
@@ -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
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
new file mode 100644
index 0000000000..0c765e2b83
--- /dev/null
+++ b/libavformat/oggparsevorbis.c
@@ -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
+};