Originally committed as revision 896 to svn://svn.ffmpeg.org/ffmpeg/trunk
Mark Hills authored on 2002/09/02 03:07:56... | ... |
@@ -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) { |
... | ... |
@@ -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 |
+} |
... | ... |
@@ -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 |
+ |