summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rwxr-xr-xconfigure10
-rw-r--r--ffserver.c5
-rw-r--r--libav/Makefile4
-rw-r--r--libav/allformats.c4
-rw-r--r--libav/avformat.h3
-rw-r--r--libav/ffm.c2
-rw-r--r--libav/ogg.c168
-rw-r--r--libavcodec/Makefile5
-rw-r--r--libavcodec/allcodecs.c3
-rw-r--r--libavcodec/avcodec.h2
-rw-r--r--libavcodec/oggvorbis.c140
-rw-r--r--libavcodec/oggvorbis.h10
13 files changed, 359 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 19d81d9e6c..9e2d203ddf 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,9 @@ DEP_LIBS=libavcodec/libavcodec.a libav/libavformat.a
ifeq ($(CONFIG_MP3LAME),yes)
EXTRALIBS+=-lmp3lame
endif
+ifeq ($(CONFIG_VORBIS),yes)
+EXTRALIBS+=-logg -lvorbis -lvorbisenc
+endif
endif
OBJS = ffmpeg.o ffserver.o
diff --git a/configure b/configure
index a9bd98b155..1f94134263 100755
--- a/configure
+++ b/configure
@@ -48,6 +48,7 @@ audio_oss="yes"
network="yes"
zlib="yes"
mp3lame="no"
+vorbis="no"
a52="yes"
a52bin="no"
win32="no"
@@ -176,6 +177,8 @@ for opt do
;;
--enable-mp3lame) mp3lame="yes"
;;
+ --enable-vorbis) vorbis="yes"
+ ;;
--disable-vhook) vhook="no"
;;
--disable-simple_idct) simpleidct="no"
@@ -305,6 +308,7 @@ echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --enable-mp3lame enable mp3 encoding via libmp3lame [default=no]"
+echo " --enable-vorbis enable vorbis support via libvorbisenc [default=no]"
echo " --enable-win32 enable win32 cross compile"
echo " --disable-a52 disable GPL'ed A52 support [default=no]"
echo " --enable-a52bin open liba52.so.0 at runtime [default=no]"
@@ -344,6 +348,7 @@ echo "MMX enabled $mmx"
echo "gprof enabled $gprof"
echo "zlib enabled $zlib"
echo "mp3lame enabled $mp3lame"
+echo "vorbis enabled $vorbis"
echo "a52 support $a52"
echo "a52 dlopened $a52bin"
# echo "Video hooking $vhook"
@@ -460,6 +465,11 @@ if test "$mp3lame" = "yes" ; then
echo "CONFIG_MP3LAME=yes" >> config.mak
fi
+if test "$vorbis" = "yes" ; then
+ echo "#define CONFIG_VORBIS 1" >> $TMPH
+ echo "CONFIG_VORBIS=yes" >> config.mak
+fi
+
if test "$win32" = "yes" ; then
echo "#define CONFIG_WIN32 1" >> $TMPH
echo "CONFIG_WIN32=yes" >> config.mak
diff --git a/ffserver.c b/ffserver.c
index 8612765da6..0959273e57 100644
--- a/ffserver.c
+++ b/ffserver.c
@@ -3665,6 +3665,11 @@ int parse_ffconfig(const char *filename)
if (stream) {
audio_enc.sample_rate = atoi(arg);
}
+ } else if (!strcasecmp(cmd, "AudioQuality")) {
+ get_arg(arg, sizeof(arg), &p);
+ if (stream) {
+ audio_enc.quality = atof(arg) * 1000;
+ }
} else if (!strcasecmp(cmd, "VideoBitRate")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
diff --git a/libav/Makefile b/libav/Makefile
index eb11986c25..1a535ffb96 100644
--- a/libav/Makefile
+++ b/libav/Makefile
@@ -33,6 +33,10 @@ ifeq ($(CONFIG_NETWORK),yes)
OBJS+= udp.o tcp.o http.o rtsp.o rtp.o rtpproto.o
endif
+ifeq ($(CONFIG_VORBIS),yes)
+OBJS+= ogg.o
+endif
+
LIB= libavformat.a
all: $(LIB)
diff --git a/libav/allformats.c b/libav/allformats.c
index ff40001bd9..3ccc7dc4d7 100644
--- a/libav/allformats.c
+++ b/libav/allformats.c
@@ -45,6 +45,10 @@ void av_register_all(void)
mov_init();
jpeg_init();
+#ifdef CONFIG_VORBIS
+ ogg_init();
+#endif
+
#ifndef CONFIG_WIN32
ffm_init();
#endif
diff --git a/libav/avformat.h b/libav/avformat.h
index 20a3cabbd8..b9a618d35b 100644
--- a/libav/avformat.h
+++ b/libav/avformat.h
@@ -213,6 +213,9 @@ int wav_init(void);
/* raw.c */
int raw_init(void);
+/* ogg.c */
+int ogg_init(void);
+
/* ffm.c */
int ffm_init(void);
diff --git a/libav/ffm.c b/libav/ffm.c
index c6033c5bfc..205626fe67 100644
--- a/libav/ffm.c
+++ b/libav/ffm.c
@@ -151,6 +151,7 @@ static int ffm_write_header(AVFormatContext *s)
put_be32(pb, codec->codec_id);
put_byte(pb, codec->codec_type);
put_be32(pb, codec->bit_rate);
+ put_be32(pb, codec->quality);
put_be32(pb, codec->flags);
/* specific info */
switch(codec->codec_type) {
@@ -393,6 +394,7 @@ static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
st->codec.codec_id = get_be32(pb);
st->codec.codec_type = get_byte(pb); /* codec_type */
codec->bit_rate = get_be32(pb);
+ codec->quality = get_be32(pb);
codec->flags = get_be32(pb);
/* specific info */
switch(codec->codec_type) {
diff --git a/libav/ogg.c b/libav/ogg.c
new file mode 100644
index 0000000000..61d8ebb4e5
--- /dev/null
+++ b/libav/ogg.c
@@ -0,0 +1,168 @@
+/*
+ * Ogg bitstream support
+ * Mark Hills <mark@pogo.org.uk>
+ *
+ * Uses libogg, but requires libvorbisenc to construct correct headers
+ * when containing Vorbis stream -- currently the only format supported
+ */
+
+#include <stdio.h>
+#include <time.h>
+
+#include <ogg/ogg.h>
+#include <vorbis/vorbisenc.h>
+
+#include "avformat.h"
+#include "oggvorbis.h"
+
+
+typedef struct OggContext {
+ ogg_stream_state os ;
+ int header_written ;
+ ogg_int64_t base_packet_no ;
+ ogg_int64_t base_granule_pos ;
+} OggContext ;
+
+
+static int ogg_write_header(AVFormatContext *avfcontext) {
+ OggContext *context ;
+ AVCodecContext *avccontext ;
+ vorbis_info vi ;
+ vorbis_dsp_state vd ;
+ vorbis_comment vc ;
+ vorbis_block vb ;
+ ogg_packet header, header_comm, header_code ;
+ int n ;
+
+ fprintf(stderr, "ogg_write_header\n") ;
+
+ if(!(context = malloc(sizeof(OggContext))))
+ return -1 ;
+ avfcontext->priv_data = context ;
+
+ srand(time(NULL));
+ ogg_stream_init(&context->os, rand());
+
+ for(n = 0 ; n < avfcontext->nb_streams ; n++) {
+ avccontext = &avfcontext->streams[n]->codec ;
+
+ /* begin vorbis specific code */
+
+ vorbis_info_init(&vi) ;
+
+ /* code copied from libavcodec/oggvorbis.c */
+
+ if(oggvorbis_init_encoder(&vi, avccontext) < 0) {
+ fprintf(stderr, "ogg_write_header: init_encoder failed") ;
+ return -1 ;
+ }
+
+ vorbis_analysis_init(&vd, &vi) ;
+ vorbis_block_init(&vd, &vb) ;
+
+ vorbis_comment_init(&vc) ;
+ vorbis_comment_add_tag(&vc, "encoder", "ffmpeg") ;
+ if(*avfcontext->title)
+ vorbis_comment_add_tag(&vc, "title", avfcontext->title) ;
+
+ vorbis_analysis_headerout(&vd, &vc, &header,
+ &header_comm, &header_code) ;
+ ogg_stream_packetin(&context->os, &header) ;
+ ogg_stream_packetin(&context->os, &header_comm) ;
+ ogg_stream_packetin(&context->os, &header_code) ;
+
+ vorbis_comment_clear(&vc) ;
+
+ /* end of vorbis specific code */
+
+ context->header_written = 0 ;
+ context->base_packet_no = 0 ;
+ }
+
+ return 0 ;
+}
+
+
+static int ogg_write_packet(AVFormatContext *avfcontext,
+ int stream_index,
+ unsigned char *buf, int size, int force_pts)
+{
+ OggContext *context = avfcontext->priv_data ;
+ ogg_packet *op ;
+ ogg_page og ;
+ int l = 0 ;
+
+ /* flush header packets so audio starts on a new page */
+
+ if(!context->header_written) {
+ while(ogg_stream_flush(&context->os, &og)) {
+ put_buffer(&avfcontext->pb, og.header, og.header_len) ;
+ put_buffer(&avfcontext->pb, og.body, og.body_len) ;
+ put_flush_packet(&avfcontext->pb);
+ }
+ context->header_written = 1 ;
+ }
+
+ while(l < size) {
+ op = (ogg_packet*)(buf + l) ;
+ op->packet = buf + l + sizeof(ogg_packet) ; /* fix data pointer */
+
+ if(!context->base_packet_no) { /* this is the first packet */
+ context->base_packet_no = op->packetno ;
+ context->base_granule_pos = op->granulepos ;
+ }
+
+ /* correct the fields in the packet -- essential for streaming */
+
+ op->packetno -= context->base_packet_no ;
+ op->granulepos -= context->base_granule_pos ;
+
+ ogg_stream_packetin(&context->os, op) ;
+ l += sizeof(ogg_packet) + op->bytes ;
+
+ while(ogg_stream_pageout(&context->os, &og)) {
+ put_buffer(&avfcontext->pb, og.header, og.header_len) ;
+ put_buffer(&avfcontext->pb, og.body, og.body_len) ;
+ put_flush_packet(&avfcontext->pb);
+ }
+ }
+
+ return 0;
+}
+
+
+static int ogg_write_trailer(AVFormatContext *avfcontext) {
+ OggContext *context = avfcontext->priv_data ;
+ ogg_page og ;
+
+ fprintf(stderr, "ogg_write_trailer\n") ;
+
+ while(ogg_stream_flush(&context->os, &og)) {
+ put_buffer(&avfcontext->pb, og.header, og.header_len) ;
+ put_buffer(&avfcontext->pb, og.body, og.body_len) ;
+ put_flush_packet(&avfcontext->pb);
+ }
+
+ ogg_stream_clear(&context->os) ;
+ return 0 ;
+}
+
+
+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,
+};
+
+
+int ogg_init(void) {
+ av_register_output_format(&ogg_oformat) ;
+ return 0 ;
+}
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 89671dd6f7..2b226bc44f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -34,6 +34,11 @@ OBJS += mp3lameaudio.o
EXTRALIBS += -lmp3lame
endif
+ifeq ($(CONFIG_VORBIS),yes)
+OBJS += oggvorbis.o
+EXTRALIBS += -lvorbis -lvorbisenc
+endif
+
ifeq ($(TARGET_GPROF),yes)
CFLAGS+=-p
LDFLAGS+=-p
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 7f0b1a4c64..39724d24e2 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -39,6 +39,9 @@ void avcodec_register_all(void)
#ifdef CONFIG_MP3LAME
register_avcodec(&mp3lame_encoder);
#endif
+#ifdef CONFIG_VORBIS
+ register_avcodec(&oggvorbis_encoder);
+#endif
register_avcodec(&mpeg1video_encoder);
register_avcodec(&h263_encoder);
register_avcodec(&h263p_encoder);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index b65ac81cec..619623bb74 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -15,6 +15,7 @@ enum CodecID {
CODEC_ID_RV10,
CODEC_ID_MP2,
CODEC_ID_MP3LAME,
+ CODEC_ID_VORBIS,
CODEC_ID_AC3,
CODEC_ID_MJPEG,
CODEC_ID_MPEG4,
@@ -389,6 +390,7 @@ typedef struct AVPicture {
extern AVCodec ac3_encoder;
extern AVCodec mp2_encoder;
extern AVCodec mp3lame_encoder;
+extern AVCodec oggvorbis_encoder;
extern AVCodec mpeg1video_encoder;
extern AVCodec h263_encoder;
extern AVCodec h263p_encoder;
diff --git a/libavcodec/oggvorbis.c b/libavcodec/oggvorbis.c
new file mode 100644
index 0000000000..5b241ed4f1
--- /dev/null
+++ b/libavcodec/oggvorbis.c
@@ -0,0 +1,140 @@
+/*
+ * Ogg Vorbis codec support via libvorbisenc
+ * Mark Hills <mark@pogo.org.uk>
+ */
+
+#include <time.h>
+
+#include <vorbis/vorbisenc.h>
+
+#include "avcodec.h"
+#include "oggvorbis.h"
+
+#define OGGVORBIS_FRAME_SIZE 1024
+
+
+typedef struct OggVorbisContext {
+ vorbis_info vi ;
+ vorbis_dsp_state vd ;
+ vorbis_block vb ;
+} OggVorbisContext ;
+
+
+int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
+ if(avccontext->quality) { /* VBR requested */
+
+ fprintf(stderr, "init_encode: channels=%d quality=%d\n",
+ avccontext->channels, avccontext->quality) ;
+
+ return vorbis_encode_init_vbr(vi, avccontext->channels,
+ avccontext->sample_rate, (float)avccontext->quality / 1000) ;
+ }
+
+ fprintf(stderr, "init_encoder: channels=%d bitrate=%d tolerance=%d\n",
+ avccontext->channels, avccontext->bit_rate,
+ avccontext->bit_rate_tolerance) ;
+
+ return vorbis_encode_init(vi, avccontext->channels,
+ avccontext->sample_rate, -1, avccontext->bit_rate, -1) ;
+}
+
+
+static int oggvorbis_encode_init(AVCodecContext *avccontext) {
+ OggVorbisContext *context = avccontext->priv_data ;
+
+ fprintf(stderr, "oggvorbis_encode_init\n") ;
+
+ vorbis_info_init(&context->vi) ;
+
+ if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
+ fprintf(stderr, "oggvorbis_encode_init: init_encoder failed") ;
+ return -1 ;
+ }
+
+ vorbis_analysis_init(&context->vd, &context->vi) ;
+ vorbis_block_init(&context->vd, &context->vb) ;
+
+ avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
+
+ return 0 ;
+}
+
+
+int oggvorbis_encode_frame(AVCodecContext *avccontext, unsigned char *packets,
+ int buf_size, void *data)
+{
+ OggVorbisContext *context = avccontext->priv_data ;
+ float **buffer ;
+ ogg_packet op ;
+ signed char *audio = data ;
+ int l, samples = buf_size / 16 ; /* samples = OGGVORBIS_FRAME_SIZE */ ;
+
+ buffer = vorbis_analysis_buffer(&context->vd, samples) ;
+
+ if(context->vi.channels == 1) {
+ for(l = 0 ; l < samples ; l++)
+ buffer[0][l]=((audio[l*2+1]<<8)|(0x00ff&(int)audio[l*2]))/32768.f;
+ } else {
+ for(l = 0 ; l < samples ; l++){
+ buffer[0][l]=((audio[l*4+1]<<8)|(0x00ff&(int)audio[l*4]))/32768.f;
+ buffer[1][l]=((audio[l*4+3]<<8)|(0x00ff&(int)audio[l*4+2]))/32768.f;
+ }
+ }
+
+ vorbis_analysis_wrote(&context->vd, samples) ;
+
+ l = 0 ;
+
+ while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
+ vorbis_analysis(&context->vb, NULL);
+ vorbis_bitrate_addblock(&context->vb) ;
+
+ while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
+ memcpy(packets + l, &op, sizeof(ogg_packet)) ;
+ memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
+ l += sizeof(ogg_packet) + op.bytes ;
+ }
+ }
+
+ return l ;
+}
+
+
+int oggvorbis_encode_close(AVCodecContext *avccontext) {
+ OggVorbisContext *context = avccontext->priv_data ;
+/* ogg_packet op ; */
+
+ fprintf(stderr, "oggvorbis_encode_close\n") ;
+
+ vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */
+
+ /* We need to write all the remaining packets into the stream
+ * on closing */
+
+/*
+ while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
+ memcpy(packets + l, &op, sizeof(ogg_packet)) ;
+ memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
+ l += sizeof(ogg_packet) + op.bytes ;
+ }
+*/
+
+ vorbis_block_clear(&context->vb);
+ vorbis_dsp_clear(&context->vd);
+ vorbis_info_clear(&context->vi);
+
+ return 0 ;
+}
+
+
+AVCodec oggvorbis_encoder = {
+ "vorbis",
+ CODEC_TYPE_AUDIO,
+ CODEC_ID_VORBIS,
+ sizeof(OggVorbisContext),
+ oggvorbis_encode_init,
+ oggvorbis_encode_frame,
+ oggvorbis_encode_close
+};
+
+
diff --git a/libavcodec/oggvorbis.h b/libavcodec/oggvorbis.h
new file mode 100644
index 0000000000..0b206a1737
--- /dev/null
+++ b/libavcodec/oggvorbis.h
@@ -0,0 +1,10 @@
+#ifndef AVCODEC_OGGVORBIS_H
+#define AVCODEC_OGGVORBIS_H
+
+#include <vorbis/vorbisenc.h>
+
+#include "avcodec.h"
+
+int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) ;
+
+#endif