mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
Ogg demuxer ported from tcvp by Luca Barbato <lu_zero at gentoo dot org>,
fixups by me. Originally committed as revision 4113 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
a18ba90880
commit
9146ca3700
18
configure
vendored
18
configure
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 ;
|
||||
}
|
||||
|
643
libavformat/ogg2.c
Normal file
643
libavformat/ogg2.c
Normal file
@ -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;
|
||||
}
|
84
libavformat/ogg2.h
Normal file
84
libavformat/ogg2.h
Normal file
@ -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
|
169
libavformat/oggparsevorbis.c
Normal file
169
libavformat/oggparsevorbis.c
Normal file
@ -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
|
||||
};
|
Loading…
Reference in New Issue
Block a user