Browse code

oggvorbis support patch by (Mark Hills <mark at pogo dot org dot uk>)

Originally committed as revision 896 to svn://svn.ffmpeg.org/ffmpeg/trunk

Mark Hills authored on 2002/09/02 03:07:56
Showing 13 changed files
... ...
@@ -36,6 +36,9 @@ DEP_LIBS=libavcodec/libavcodec.a libav/libavformat.a
36 36
 ifeq ($(CONFIG_MP3LAME),yes)
37 37
 EXTRALIBS+=-lmp3lame
38 38
 endif
39
+ifeq ($(CONFIG_VORBIS),yes)
40
+EXTRALIBS+=-logg -lvorbis -lvorbisenc
41
+endif
39 42
 endif
40 43
 
41 44
 OBJS = ffmpeg.o ffserver.o
... ...
@@ -48,6 +48,7 @@ audio_oss="yes"
48 48
 network="yes"
49 49
 zlib="yes"
50 50
 mp3lame="no"
51
+vorbis="no"
51 52
 a52="yes"
52 53
 a52bin="no"
53 54
 win32="no"
... ...
@@ -176,6 +177,8 @@ for opt do
176 176
   ;;
177 177
   --enable-mp3lame) mp3lame="yes"
178 178
   ;;
179
+  --enable-vorbis) vorbis="yes"
180
+  ;;
179 181
   --disable-vhook) vhook="no"
180 182
   ;;
181 183
   --disable-simple_idct) simpleidct="no"
... ...
@@ -305,6 +308,7 @@ echo "Standard options:"
305 305
 echo "  --help                   print this message"
306 306
 echo "  --prefix=PREFIX          install in PREFIX [$prefix]"
307 307
 echo "  --enable-mp3lame         enable mp3 encoding via libmp3lame [default=no]"
308
+echo "  --enable-vorbis          enable vorbis support via libvorbisenc [default=no]"
308 309
 echo "  --enable-win32           enable win32 cross compile"
309 310
 echo "  --disable-a52            disable GPL'ed A52 support [default=no]"
310 311
 echo "  --enable-a52bin          open liba52.so.0 at runtime [default=no]"
... ...
@@ -344,6 +348,7 @@ echo "MMX enabled      $mmx"
344 344
 echo "gprof enabled    $gprof"
345 345
 echo "zlib enabled     $zlib"
346 346
 echo "mp3lame enabled  $mp3lame"
347
+echo "vorbis enabled   $vorbis"
347 348
 echo "a52 support      $a52"
348 349
 echo "a52 dlopened     $a52bin"
349 350
 # echo "Video hooking    $vhook"
... ...
@@ -460,6 +465,11 @@ if test "$mp3lame" = "yes" ; then
460 460
   echo "CONFIG_MP3LAME=yes" >> config.mak
461 461
 fi
462 462
 
463
+if test "$vorbis" = "yes" ; then
464
+  echo "#define CONFIG_VORBIS 1" >> $TMPH
465
+  echo "CONFIG_VORBIS=yes" >> config.mak
466
+fi
467
+
463 468
 if test "$win32" = "yes" ; then
464 469
   echo "#define CONFIG_WIN32 1" >> $TMPH
465 470
   echo "CONFIG_WIN32=yes" >> config.mak
... ...
@@ -3665,6 +3665,11 @@ int parse_ffconfig(const char *filename)
3665 3665
             if (stream) {
3666 3666
                 audio_enc.sample_rate = atoi(arg);
3667 3667
             }
3668
+	} else if (!strcasecmp(cmd, "AudioQuality")) {
3669
+	    get_arg(arg, sizeof(arg), &p);
3670
+            if (stream) {
3671
+                audio_enc.quality = atof(arg) * 1000;
3672
+            }
3668 3673
         } else if (!strcasecmp(cmd, "VideoBitRate")) {
3669 3674
             get_arg(arg, sizeof(arg), &p);
3670 3675
             if (stream) {
... ...
@@ -33,6 +33,10 @@ ifeq ($(CONFIG_NETWORK),yes)
33 33
 OBJS+= udp.o tcp.o http.o rtsp.o rtp.o rtpproto.o
34 34
 endif
35 35
 
36
+ifeq ($(CONFIG_VORBIS),yes)
37
+OBJS+= ogg.o
38
+endif
39
+
36 40
 LIB= libavformat.a
37 41
 
38 42
 all: $(LIB)
... ...
@@ -45,6 +45,10 @@ void av_register_all(void)
45 45
     mov_init();
46 46
     jpeg_init();
47 47
 
48
+#ifdef CONFIG_VORBIS
49
+    ogg_init();
50
+#endif
51
+
48 52
 #ifndef CONFIG_WIN32
49 53
     ffm_init();
50 54
 #endif
... ...
@@ -213,6 +213,9 @@ int wav_init(void);
213 213
 /* raw.c */
214 214
 int raw_init(void);
215 215
 
216
+/* ogg.c */
217
+int ogg_init(void);
218
+
216 219
 /* ffm.c */
217 220
 int ffm_init(void);
218 221
 
... ...
@@ -151,6 +151,7 @@ static int ffm_write_header(AVFormatContext *s)
151 151
         put_be32(pb, codec->codec_id);
152 152
         put_byte(pb, codec->codec_type);
153 153
         put_be32(pb, codec->bit_rate);
154
+	put_be32(pb, codec->quality);
154 155
         put_be32(pb, codec->flags);
155 156
         /* specific info */
156 157
         switch(codec->codec_type) {
... ...
@@ -393,6 +394,7 @@ static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
393 393
         st->codec.codec_id = get_be32(pb);
394 394
         st->codec.codec_type = get_byte(pb); /* codec_type */
395 395
         codec->bit_rate = get_be32(pb);
396
+	codec->quality = get_be32(pb);
396 397
         codec->flags = get_be32(pb);
397 398
         /* specific info */
398 399
         switch(codec->codec_type) {
399 400
new file mode 100644
... ...
@@ -0,0 +1,168 @@
0
+/*
1
+ * Ogg bitstream support
2
+ * Mark Hills <mark@pogo.org.uk>
3
+ *
4
+ * Uses libogg, but requires libvorbisenc to construct correct headers
5
+ * when containing Vorbis stream -- currently the only format supported
6
+ */
7
+
8
+#include <stdio.h>
9
+#include <time.h>
10
+
11
+#include <ogg/ogg.h>
12
+#include <vorbis/vorbisenc.h>
13
+
14
+#include "avformat.h"
15
+#include "oggvorbis.h"
16
+
17
+
18
+typedef struct OggContext {
19
+    ogg_stream_state os ;
20
+    int header_written ;
21
+    ogg_int64_t base_packet_no ;
22
+    ogg_int64_t base_granule_pos ;
23
+} OggContext ;
24
+
25
+
26
+static int ogg_write_header(AVFormatContext *avfcontext) {
27
+    OggContext *context ;
28
+    AVCodecContext *avccontext ;
29
+    vorbis_info vi ;
30
+    vorbis_dsp_state vd ;
31
+    vorbis_comment vc ;
32
+    vorbis_block vb ;
33
+    ogg_packet header, header_comm, header_code ; 
34
+    int n ;
35
+    
36
+    fprintf(stderr, "ogg_write_header\n") ;
37
+    
38
+    if(!(context = malloc(sizeof(OggContext))))
39
+	return -1 ;
40
+    avfcontext->priv_data = context ;
41
+    
42
+    srand(time(NULL));
43
+    ogg_stream_init(&context->os, rand());
44
+    
45
+    for(n = 0 ; n < avfcontext->nb_streams ; n++) {
46
+	avccontext = &avfcontext->streams[n]->codec ;
47
+
48
+	/* begin vorbis specific code */
49
+		
50
+	vorbis_info_init(&vi) ;
51
+
52
+	/* code copied from libavcodec/oggvorbis.c */
53
+
54
+	if(oggvorbis_init_encoder(&vi, avccontext) < 0) {
55
+	    fprintf(stderr, "ogg_write_header: init_encoder failed") ;
56
+	    return -1 ;
57
+	}
58
+
59
+	vorbis_analysis_init(&vd, &vi) ;
60
+	vorbis_block_init(&vd, &vb) ;
61
+	
62
+	vorbis_comment_init(&vc) ;
63
+	vorbis_comment_add_tag(&vc, "encoder", "ffmpeg") ;
64
+	if(*avfcontext->title)
65
+	    vorbis_comment_add_tag(&vc, "title", avfcontext->title) ;
66
+
67
+	vorbis_analysis_headerout(&vd, &vc, &header,
68
+				  &header_comm, &header_code) ;
69
+	ogg_stream_packetin(&context->os, &header) ;
70
+	ogg_stream_packetin(&context->os, &header_comm) ;
71
+	ogg_stream_packetin(&context->os, &header_code) ;  
72
+	
73
+	vorbis_comment_clear(&vc) ;
74
+
75
+	/* end of vorbis specific code */
76
+
77
+	context->header_written = 0 ;
78
+	context->base_packet_no = 0 ;
79
+    }
80
+    
81
+    return 0 ;
82
+}
83
+
84
+
85
+static int ogg_write_packet(AVFormatContext *avfcontext,
86
+			    int stream_index,
87
+			    unsigned char *buf, int size, int force_pts)
88
+{
89
+    OggContext *context = avfcontext->priv_data ;
90
+    ogg_packet *op ;
91
+    ogg_page og ;
92
+    int l = 0 ;
93
+    
94
+    /* flush header packets so audio starts on a new page */
95
+
96
+    if(!context->header_written) {
97
+	while(ogg_stream_flush(&context->os, &og)) {
98
+	    put_buffer(&avfcontext->pb, og.header, og.header_len) ;
99
+	    put_buffer(&avfcontext->pb, og.body, og.body_len) ;
100
+	    put_flush_packet(&avfcontext->pb);
101
+	}
102
+	context->header_written = 1 ;
103
+    }
104
+
105
+    while(l < size) {
106
+	op = (ogg_packet*)(buf + l) ;
107
+	op->packet = buf + l + sizeof(ogg_packet) ; /* fix data pointer */
108
+
109
+	if(!context->base_packet_no) { /* this is the first packet */
110
+	    context->base_packet_no = op->packetno ; 
111
+	    context->base_granule_pos = op->granulepos ;
112
+	}
113
+
114
+	/* correct the fields in the packet -- essential for streaming */
115
+
116
+	op->packetno -= context->base_packet_no ;
117
+	op->granulepos -= context->base_granule_pos ;
118
+
119
+	ogg_stream_packetin(&context->os, op) ;
120
+	l += sizeof(ogg_packet) + op->bytes ;
121
+
122
+	while(ogg_stream_pageout(&context->os, &og)) {
123
+	    put_buffer(&avfcontext->pb, og.header, og.header_len) ;
124
+	    put_buffer(&avfcontext->pb, og.body, og.body_len) ;
125
+	    put_flush_packet(&avfcontext->pb);
126
+	}
127
+    }
128
+
129
+    return 0;
130
+}
131
+
132
+
133
+static int ogg_write_trailer(AVFormatContext *avfcontext) {
134
+    OggContext *context = avfcontext->priv_data ;
135
+    ogg_page og ;
136
+
137
+    fprintf(stderr, "ogg_write_trailer\n") ;
138
+
139
+    while(ogg_stream_flush(&context->os, &og)) {
140
+	put_buffer(&avfcontext->pb, og.header, og.header_len) ;
141
+	put_buffer(&avfcontext->pb, og.body, og.body_len) ;
142
+	put_flush_packet(&avfcontext->pb);
143
+    }
144
+
145
+    ogg_stream_clear(&context->os) ;
146
+    return 0 ;
147
+}
148
+
149
+
150
+AVOutputFormat ogg_oformat = {
151
+    "ogg",
152
+    "Ogg Vorbis",
153
+    "audio/x-vorbis",
154
+    "ogg",
155
+    sizeof(OggContext),
156
+    CODEC_ID_VORBIS,
157
+    0,
158
+    ogg_write_header,
159
+    ogg_write_packet,
160
+    ogg_write_trailer,
161
+};
162
+
163
+
164
+int ogg_init(void) {
165
+    av_register_output_format(&ogg_oformat) ;
166
+    return 0 ;
167
+}
... ...
@@ -34,6 +34,11 @@ OBJS += mp3lameaudio.o
34 34
 EXTRALIBS += -lmp3lame
35 35
 endif
36 36
 
37
+ifeq ($(CONFIG_VORBIS),yes)
38
+OBJS += oggvorbis.o
39
+EXTRALIBS += -lvorbis -lvorbisenc
40
+endif
41
+
37 42
 ifeq ($(TARGET_GPROF),yes)
38 43
 CFLAGS+=-p
39 44
 LDFLAGS+=-p
... ...
@@ -39,6 +39,9 @@ void avcodec_register_all(void)
39 39
 #ifdef CONFIG_MP3LAME
40 40
     register_avcodec(&mp3lame_encoder);
41 41
 #endif
42
+#ifdef CONFIG_VORBIS
43
+    register_avcodec(&oggvorbis_encoder);
44
+#endif
42 45
     register_avcodec(&mpeg1video_encoder);
43 46
     register_avcodec(&h263_encoder);
44 47
     register_avcodec(&h263p_encoder);
... ...
@@ -15,6 +15,7 @@ enum CodecID {
15 15
     CODEC_ID_RV10,
16 16
     CODEC_ID_MP2,
17 17
     CODEC_ID_MP3LAME,
18
+    CODEC_ID_VORBIS,
18 19
     CODEC_ID_AC3,
19 20
     CODEC_ID_MJPEG,
20 21
     CODEC_ID_MPEG4,
... ...
@@ -389,6 +390,7 @@ typedef struct AVPicture {
389 389
 extern AVCodec ac3_encoder;
390 390
 extern AVCodec mp2_encoder;
391 391
 extern AVCodec mp3lame_encoder;
392
+extern AVCodec oggvorbis_encoder;
392 393
 extern AVCodec mpeg1video_encoder;
393 394
 extern AVCodec h263_encoder;
394 395
 extern AVCodec h263p_encoder;
395 396
new file mode 100644
... ...
@@ -0,0 +1,140 @@
0
+/*
1
+ * Ogg Vorbis codec support via libvorbisenc
2
+ * Mark Hills <mark@pogo.org.uk>
3
+ */
4
+
5
+#include <time.h>
6
+
7
+#include <vorbis/vorbisenc.h>
8
+
9
+#include "avcodec.h"
10
+#include "oggvorbis.h"
11
+
12
+#define OGGVORBIS_FRAME_SIZE 1024
13
+
14
+
15
+typedef struct OggVorbisContext {
16
+    vorbis_info vi ;
17
+    vorbis_dsp_state vd ;
18
+    vorbis_block vb ;
19
+} OggVorbisContext ;
20
+
21
+
22
+int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
23
+    if(avccontext->quality) { /* VBR requested */
24
+
25
+	fprintf(stderr, "init_encode: channels=%d quality=%d\n", 
26
+		avccontext->channels, avccontext->quality) ;
27
+
28
+	return vorbis_encode_init_vbr(vi, avccontext->channels,
29
+		  avccontext->sample_rate, (float)avccontext->quality / 1000) ;
30
+    }
31
+
32
+    fprintf(stderr, "init_encoder: channels=%d bitrate=%d tolerance=%d\n", 
33
+	    avccontext->channels, avccontext->bit_rate,
34
+	    avccontext->bit_rate_tolerance) ;
35
+
36
+    return vorbis_encode_init(vi, avccontext->channels,
37
+	          avccontext->sample_rate, -1, avccontext->bit_rate, -1) ;
38
+}
39
+
40
+
41
+static int oggvorbis_encode_init(AVCodecContext *avccontext) {
42
+    OggVorbisContext *context = avccontext->priv_data ;
43
+
44
+    fprintf(stderr, "oggvorbis_encode_init\n") ;
45
+
46
+    vorbis_info_init(&context->vi) ;
47
+
48
+    if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
49
+	fprintf(stderr, "oggvorbis_encode_init: init_encoder failed") ;
50
+	return -1 ;
51
+    }
52
+
53
+    vorbis_analysis_init(&context->vd, &context->vi) ;
54
+    vorbis_block_init(&context->vd, &context->vb) ;
55
+
56
+    avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
57
+    
58
+    return 0 ;
59
+}
60
+
61
+
62
+int oggvorbis_encode_frame(AVCodecContext *avccontext, unsigned char *packets,
63
+			   int buf_size, void *data)
64
+{
65
+    OggVorbisContext *context = avccontext->priv_data ;
66
+    float **buffer ;
67
+    ogg_packet op ;
68
+    signed char *audio = data ;
69
+    int l, samples = buf_size / 16 ; /* samples = OGGVORBIS_FRAME_SIZE */ ;
70
+
71
+    buffer = vorbis_analysis_buffer(&context->vd, samples) ;
72
+
73
+    if(context->vi.channels == 1) {
74
+	for(l = 0 ; l < samples ; l++)
75
+	    buffer[0][l]=((audio[l*2+1]<<8)|(0x00ff&(int)audio[l*2]))/32768.f;
76
+    } else {
77
+	for(l = 0 ; l < samples ; l++){
78
+	    buffer[0][l]=((audio[l*4+1]<<8)|(0x00ff&(int)audio[l*4]))/32768.f;
79
+	    buffer[1][l]=((audio[l*4+3]<<8)|(0x00ff&(int)audio[l*4+2]))/32768.f;
80
+	}
81
+    }
82
+    
83
+    vorbis_analysis_wrote(&context->vd, samples) ; 
84
+
85
+    l = 0 ;
86
+
87
+    while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
88
+	vorbis_analysis(&context->vb, NULL);
89
+	vorbis_bitrate_addblock(&context->vb) ;
90
+
91
+	while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
92
+	    memcpy(packets + l, &op, sizeof(ogg_packet)) ;
93
+	    memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
94
+	    l += sizeof(ogg_packet) + op.bytes ;
95
+	}
96
+    }
97
+
98
+    return l ;
99
+}
100
+
101
+
102
+int oggvorbis_encode_close(AVCodecContext *avccontext) {
103
+    OggVorbisContext *context = avccontext->priv_data ;
104
+/*  ogg_packet op ; */
105
+    
106
+    fprintf(stderr, "oggvorbis_encode_close\n") ;
107
+    
108
+    vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */
109
+
110
+    /* We need to write all the remaining packets into the stream
111
+     * on closing */
112
+    
113
+/*
114
+    while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
115
+	memcpy(packets + l, &op, sizeof(ogg_packet)) ;
116
+	memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
117
+	l += sizeof(ogg_packet) + op.bytes ;	
118
+    }
119
+*/
120
+
121
+    vorbis_block_clear(&context->vb);
122
+    vorbis_dsp_clear(&context->vd);
123
+    vorbis_info_clear(&context->vi);
124
+  
125
+    return 0 ;
126
+}
127
+
128
+
129
+AVCodec oggvorbis_encoder = {
130
+    "vorbis",
131
+    CODEC_TYPE_AUDIO,
132
+    CODEC_ID_VORBIS,
133
+    sizeof(OggVorbisContext),
134
+    oggvorbis_encode_init,
135
+    oggvorbis_encode_frame,
136
+    oggvorbis_encode_close
137
+};
138
+
139
+
0 140
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+#ifndef AVCODEC_OGGVORBIS_H
1
+#define AVCODEC_OGGVORBIS_H
2
+
3
+#include <vorbis/vorbisenc.h>
4
+
5
+#include "avcodec.h"
6
+
7
+int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) ;
8
+
9
+#endif