3 * Ogg Vorbis codec support via libvorbisenc.
4 * @author Mark Hills <mark@pogo.org.uk>
7 #include <vorbis/vorbisenc.h>
14 #define OGGVORBIS_FRAME_SIZE 64
16 #define BUFFER_SIZE (1024*64)
18 typedef struct OggVorbisContext
{
22 uint8_t buffer
[BUFFER_SIZE
];
31 static int oggvorbis_init_encoder(vorbis_info
*vi
, AVCodecContext
*avccontext
) {
33 #ifdef OGGVORBIS_VBR_BY_ESTIMATE
34 /* variable bitrate by estimate */
36 return (vorbis_encode_setup_managed(vi
, avccontext
->channels
,
37 avccontext
->sample_rate
, -1, avccontext
->bit_rate
, -1) ||
38 vorbis_encode_ctl(vi
, OV_ECTL_RATEMANAGE_AVG
, NULL
) ||
39 vorbis_encode_setup_init(vi
)) ;
41 /* constant bitrate */
43 return vorbis_encode_init(vi
, avccontext
->channels
,
44 avccontext
->sample_rate
, -1, avccontext
->bit_rate
, -1) ;
48 static int oggvorbis_encode_init(AVCodecContext
*avccontext
) {
49 OggVorbisContext
*context
= avccontext
->priv_data
;
50 ogg_packet header
, header_comm
, header_code
;
52 unsigned int offset
, len
;
54 vorbis_info_init(&context
->vi
) ;
55 if(oggvorbis_init_encoder(&context
->vi
, avccontext
) < 0) {
56 av_log(avccontext
, AV_LOG_ERROR
, "oggvorbis_encode_init: init_encoder failed") ;
59 vorbis_analysis_init(&context
->vd
, &context
->vi
) ;
60 vorbis_block_init(&context
->vd
, &context
->vb
) ;
62 vorbis_comment_init(&context
->vc
);
63 vorbis_comment_add_tag(&context
->vc
, "encoder", LIBAVCODEC_IDENT
) ;
65 vorbis_analysis_headerout(&context
->vd
, &context
->vc
, &header
,
66 &header_comm
, &header_code
);
68 len
= header
.bytes
+ header_comm
.bytes
+ header_code
.bytes
;
69 avccontext
->extradata_size
= 64 + len
+ len
/255;
70 p
= avccontext
->extradata
= av_mallocz(avccontext
->extradata_size
);
73 offset
+= av_xiphlacing(&p
[offset
], header
.bytes
);
74 offset
+= av_xiphlacing(&p
[offset
], header_comm
.bytes
);
75 memcpy(&p
[offset
], header
.packet
, header
.bytes
);
76 offset
+= header
.bytes
;
77 memcpy(&p
[offset
], header_comm
.packet
, header_comm
.bytes
);
78 offset
+= header_comm
.bytes
;
79 memcpy(&p
[offset
], header_code
.packet
, header_code
.bytes
);
80 offset
+= header_code
.bytes
;
81 avccontext
->extradata_size
= offset
;
82 avccontext
->extradata
= av_realloc(avccontext
->extradata
, avccontext
->extradata_size
);
84 /* vorbis_block_clear(&context->vb);
85 vorbis_dsp_clear(&context->vd);
86 vorbis_info_clear(&context->vi);*/
87 vorbis_comment_clear(&context
->vc
);
89 avccontext
->frame_size
= OGGVORBIS_FRAME_SIZE
;
91 avccontext
->coded_frame
= avcodec_alloc_frame();
92 avccontext
->coded_frame
->key_frame
= 1;
98 static int oggvorbis_encode_frame(AVCodecContext
*avccontext
,
99 unsigned char *packets
,
100 int buf_size
, void *data
)
102 OggVorbisContext
*context
= avccontext
->priv_data
;
105 signed short *audio
= data
;
106 int l
, samples
= data
? OGGVORBIS_FRAME_SIZE
: 0;
108 buffer
= vorbis_analysis_buffer(&context
->vd
, samples
) ;
110 if(context
->vi
.channels
== 1) {
111 for(l
= 0 ; l
< samples
; l
++)
112 buffer
[0][l
]=audio
[l
]/32768.f
;
114 for(l
= 0 ; l
< samples
; l
++){
115 buffer
[0][l
]=audio
[l
*2]/32768.f
;
116 buffer
[1][l
]=audio
[l
*2+1]/32768.f
;
120 vorbis_analysis_wrote(&context
->vd
, samples
) ;
122 while(vorbis_analysis_blockout(&context
->vd
, &context
->vb
) == 1) {
123 vorbis_analysis(&context
->vb
, NULL
);
124 vorbis_bitrate_addblock(&context
->vb
) ;
126 while(vorbis_bitrate_flushpacket(&context
->vd
, &op
)) {
127 if(op
.bytes
==1) //id love to say this is a hack, bad sadly its not, appearently the end of stream decission is in libogg
129 memcpy(context
->buffer
+ context
->buffer_index
, &op
, sizeof(ogg_packet
));
130 context
->buffer_index
+= sizeof(ogg_packet
);
131 memcpy(context
->buffer
+ context
->buffer_index
, op
.packet
, op
.bytes
);
132 context
->buffer_index
+= op
.bytes
;
133 // av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes);
138 if(context
->buffer_index
){
139 ogg_packet
*op2
= (ogg_packet
*)context
->buffer
;
140 op2
->packet
= context
->buffer
+ sizeof(ogg_packet
);
143 avccontext
->coded_frame
->pts
= op2
->granulepos
;
145 memcpy(packets
, op2
->packet
, l
);
146 context
->buffer_index
-= l
+ sizeof(ogg_packet
);
147 memcpy(context
->buffer
, context
->buffer
+ l
+ sizeof(ogg_packet
), context
->buffer_index
);
148 // av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l);
155 static int oggvorbis_encode_close(AVCodecContext
*avccontext
) {
156 OggVorbisContext
*context
= avccontext
->priv_data
;
157 /* ogg_packet op ; */
159 vorbis_analysis_wrote(&context
->vd
, 0) ; /* notify vorbisenc this is EOF */
161 vorbis_block_clear(&context
->vb
);
162 vorbis_dsp_clear(&context
->vd
);
163 vorbis_info_clear(&context
->vi
);
165 av_freep(&avccontext
->coded_frame
);
166 av_freep(&avccontext
->extradata
);
172 AVCodec oggvorbis_encoder
= {
176 sizeof(OggVorbisContext
),
177 oggvorbis_encode_init
,
178 oggvorbis_encode_frame
,
179 oggvorbis_encode_close
,
180 .capabilities
= CODEC_CAP_DELAY
,
183 static int oggvorbis_decode_init(AVCodecContext
*avccontext
) {
184 OggVorbisContext
*context
= avccontext
->priv_data
;
185 uint8_t *p
= avccontext
->extradata
;
187 unsigned char *headers
[3], *extradata
= avccontext
->extradata
;
189 vorbis_info_init(&context
->vi
) ;
190 vorbis_comment_init(&context
->vc
) ;
192 if(! avccontext
->extradata_size
|| ! p
) {
193 av_log(avccontext
, AV_LOG_ERROR
, "vorbis extradata absent\n");
197 if(p
[0] == 0 && p
[1] == 30) {
198 for(i
= 0; i
< 3; i
++){
199 hsizes
[i
] = *p
++ << 8;
205 unsigned int offset
= 1;
209 while((*p
== 0xFF) && (offset
< avccontext
->extradata_size
)) {
214 if(offset
>= avccontext
->extradata_size
- 1) {
215 av_log(avccontext
, AV_LOG_ERROR
,
216 "vorbis header sizes damaged\n");
223 hsizes
[2] = avccontext
->extradata_size
- hsizes
[0]-hsizes
[1]-offset
;
225 av_log(avccontext
, AV_LOG_DEBUG
,
226 "vorbis header sizes: %d, %d, %d, / extradata_len is %d \n",
227 hsizes
[0], hsizes
[1], hsizes
[2], avccontext
->extradata_size
);
229 headers
[0] = extradata
+ offset
;
230 headers
[1] = extradata
+ offset
+ hsizes
[0];
231 headers
[2] = extradata
+ offset
+ hsizes
[0] + hsizes
[1];
233 av_log(avccontext
, AV_LOG_ERROR
,
234 "vorbis initial header len is wrong: %d\n", *p
);
239 context
->op
.b_o_s
= i
==0;
240 context
->op
.bytes
= hsizes
[i
];
241 context
->op
.packet
= headers
[i
];
242 if(vorbis_synthesis_headerin(&context
->vi
, &context
->vc
, &context
->op
)<0){
243 av_log(avccontext
, AV_LOG_ERROR
, "%d. vorbis header damaged\n", i
+1);
248 avccontext
->channels
= context
->vi
.channels
;
249 avccontext
->sample_rate
= context
->vi
.rate
;
250 avccontext
->time_base
= (AVRational
){1, avccontext
->sample_rate
};
252 vorbis_synthesis_init(&context
->vd
, &context
->vi
);
253 vorbis_block_init(&context
->vd
, &context
->vb
);
259 static inline int conv(int samples
, float **pcm
, char *buf
, int channels
) {
261 ogg_int16_t
*ptr
, *data
= (ogg_int16_t
*)buf
;
264 for(i
= 0 ; i
< channels
; i
++){
268 for(j
= 0 ; j
< samples
; j
++) {
270 val
= mono
[j
] * 32767.f
;
272 if(val
> 32767) val
= 32767 ;
273 if(val
< -32768) val
= -32768 ;
284 static int oggvorbis_decode_frame(AVCodecContext
*avccontext
,
285 void *data
, int *data_size
,
286 uint8_t *buf
, int buf_size
)
288 OggVorbisContext
*context
= avccontext
->priv_data
;
290 ogg_packet
*op
= &context
->op
;
291 int samples
, total_samples
, total_bytes
,i
;
299 op
->bytes
= buf_size
;
301 // av_log(avccontext, AV_LOG_DEBUG, "%d %d %d %lld %lld %d %d\n", op->bytes, op->b_o_s, op->e_o_s, op->granulepos, op->packetno, buf_size, context->vi.rate);
303 /* for(i=0; i<op->bytes; i++)
304 av_log(avccontext, AV_LOG_DEBUG, "%02X ", op->packet[i]);
305 av_log(avccontext, AV_LOG_DEBUG, "\n");*/
307 if(vorbis_synthesis(&context
->vb
, op
) == 0)
308 vorbis_synthesis_blockin(&context
->vd
, &context
->vb
) ;
313 while((samples
= vorbis_synthesis_pcmout(&context
->vd
, &pcm
)) > 0) {
314 conv(samples
, pcm
, (char*)data
+ total_bytes
, context
->vi
.channels
) ;
315 total_bytes
+= samples
* 2 * context
->vi
.channels
;
316 total_samples
+= samples
;
317 vorbis_synthesis_read(&context
->vd
, samples
) ;
320 *data_size
= total_bytes
;
325 static int oggvorbis_decode_close(AVCodecContext
*avccontext
) {
326 OggVorbisContext
*context
= avccontext
->priv_data
;
328 vorbis_info_clear(&context
->vi
) ;
329 vorbis_comment_clear(&context
->vc
) ;
335 AVCodec oggvorbis_decoder
= {
339 sizeof(OggVorbisContext
),
340 oggvorbis_decode_init
,
342 oggvorbis_decode_close
,
343 oggvorbis_decode_frame
,
344 .capabilities
= CODEC_CAP_DELAY
,