📄 cook_fix.c
字号:
if(cplband[q->js_subband_start] > cplband[q->subbands-1]) return;
length = cplband[q->subbands-1] - cplband[q->js_subband_start] + 1;
for (i=0 ; i<length ; i++) {
decouple_tab[cplband[q->js_subband_start] + i] = get_bits(&q->gb, q->js_vlc_bits);
}
return;
}
/**
* function for decoding joint stereo data
* Decoupling calculation for joint stereo coefficients.
*
* @param q pointer to the COOKContext
* @param mlt_buffer1 pointer to left channel mlt coefficients
* @param mlt_buffer2 pointer to right channel mlt coefficients
* @param x mono coefficient
* @param table number of decoupling table
* @param i table index
*/
static void joint_decode(COOKContext *q, float* mlt_buffer1,
float* mlt_buffer2) {
int i,j;
int decouple_tab[SUBBAND_SIZE];
float decode_buffer[1060];
int idx, cpl_tmp,tmp_idx;
float f1,f2;
float* cplscale;
memset(decouple_tab, 0, sizeof(decouple_tab));
memset(decode_buffer, 0, sizeof(decode_buffer));
/* Make sure the buffers are zeroed out. */
memset(mlt_buffer1,0, 1024*sizeof(float));
memset(mlt_buffer2,0, 1024*sizeof(float));
decouple_info(q, decouple_tab);
mono_decode(q, decode_buffer);
/* The two channels are stored interleaved in decode_buffer. */
for (i=0 ; i<q->js_subband_start ; i++) {
for (j=0 ; j<SUBBAND_SIZE ; j++) {
mlt_buffer1[i*20+j] = decode_buffer[i*40+j];
mlt_buffer2[i*20+j] = decode_buffer[i*40+20+j];
}
}
/* When we reach js_subband_start (the higher frequencies)
the coefficients are stored in a coupling scheme. */
idx = (1 << q->js_vlc_bits) - 1;
for (i=q->js_subband_start ; i<q->subbands ; i++) {
cpl_tmp = cplband[i];
idx -=decouple_tab[cpl_tmp];
cplscale = (float*)cplscales[q->js_vlc_bits-2]; //choose decoupler table
f1 = cplscale[decouple_tab[cpl_tmp]];
f2 = cplscale[idx-1];
for (j=0 ; j<SUBBAND_SIZE ; j++) {
tmp_idx = ((q->js_subband_start + i)*20)+j;
mlt_buffer1[20*i + j] = f1 * decode_buffer[tmp_idx];
mlt_buffer2[20*i + j] = f2 * decode_buffer[tmp_idx];
}
idx = (1 << q->js_vlc_bits) - 1;
}
}
/**
* First part of subpacket decoding:
* decode raw stream bytes and read gain info.
*
* @param q pointer to the COOKContext
* @param inbuffer pointer to raw stream data
* @param gain_ptr array of current/prev gain pointers
*/
static inline void
decode_bytes_and_gain(COOKContext *q, uint8_t *inbuffer,
cook_gains *gains_ptr)
static inline float cplscale_math(float x, int table, int i)
{
int offset;
offset = decode_bytes(inbuffer, q->decoded_bytes_buffer,
q->bits_per_subpacket/8);
init_get_bits(&q->gb, q->decoded_bytes_buffer + offset,
q->bits_per_subpacket);
decode_gain_info(&q->gb, gains_ptr->now);
/* Swap current and previous gains */
FFSWAP(int *, gains_ptr->now, gains_ptr->previous);
return x * cplscales[table-2][i];
}
/**
* Final part of subpacket decoding:
* Apply modulated lapped transform, gain compensation,
* clip and convert to integer.
* Final converion from floating point values to
* signed, 16 bit sound samples. Round and clip.
*
* @param q pointer to the COOKContext
* @param decode_buffer pointer to the mlt coefficients
* @param gain_ptr array of current/prev gain pointers
* @param previous_buffer pointer to the previous buffer to be used for overlapping
* @param out pointer to the output buffer
* @param chan 0: left or single channel, 1: right channel
*/
static inline void
mlt_compensate_output(COOKContext *q, float *decode_buffer,
cook_gains *gains, float *previous_buffer,
int16_t *out, int chan)
static inline void output_math(COOKContext *q, int16_t *out, int chan)
{
float *output = q->mono_mdct_output + q->samples_per_channel;
int j;
imlt_gain(q, decode_buffer, gains, previous_buffer);
/* Clip and convert floats to 16 bits.
/* FIXME: Should use DSPContext.float_to_int16() here.
*/
for (j = 0; j < q->samples_per_channel; j++) {
out[chan + q->nb_channels * j] =
av_clip(lrintf(output[j]), -32768, 32767);
}
}
/**
* Cook subpacket decoding. This function returns one decoded subpacket,
* usually 1024 samples per channel.
*
* @param q pointer to the COOKContext
* @param inbuffer pointer to the inbuffer
* @param sub_packet_size subpacket size
* @param outbuffer pointer to the outbuffer
*/
static int decode_subpacket(COOKContext *q, uint8_t *inbuffer,
int sub_packet_size, int16_t *outbuffer) {
/* packet dump */
// for (i=0 ; i<sub_packet_size ; i++) {
// av_log(NULL, AV_LOG_ERROR, "%02x", inbuffer[i]);
// }
// av_log(NULL, AV_LOG_ERROR, "\n");
decode_bytes_and_gain(q, inbuffer, &q->gains1);
if (q->joint_stereo) {
joint_decode(q, q->decode_buffer_1, q->decode_buffer_2);
} else {
mono_decode(q, q->decode_buffer_1);
if (q->nb_channels == 2) {
decode_bytes_and_gain(q, inbuffer + sub_packet_size/2, &q->gains2);
mono_decode(q, q->decode_buffer_2);
}
}
mlt_compensate_output(q, q->decode_buffer_1, &q->gains1,
q->mono_previous_buffer1, outbuffer, 0);
if (q->nb_channels == 2) {
if (q->joint_stereo) {
mlt_compensate_output(q, q->decode_buffer_2, &q->gains1,
q->mono_previous_buffer2, outbuffer, 1);
} else {
mlt_compensate_output(q, q->decode_buffer_2, &q->gains2,
q->mono_previous_buffer2, outbuffer, 1);
}
}
return q->samples_per_frame * sizeof(int16_t);
}
/**
* Cook frame decoding
*
* @param avctx pointer to the AVCodecContext
*/
static int cook_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size) {
COOKContext *q = avctx->priv_data;
if (buf_size < avctx->block_align)
return buf_size;
*data_size = decode_subpacket(q, buf, avctx->block_align, data);
/* Discard the first two frames: no valid audio. */
if (avctx->frame_number < 2) *data_size = 0;
return avctx->block_align;
}
#ifdef COOKDEBUG
static void dump_cook_context(COOKContext *q)
{
//int i=0;
#define PRINT(a,b) av_log(NULL,AV_LOG_ERROR," %s = %d\n", a, b);
av_log(NULL,AV_LOG_ERROR,"COOKextradata\n");
av_log(NULL,AV_LOG_ERROR,"cookversion=%x\n",q->cookversion);
if (q->cookversion > STEREO) {
PRINT("js_subband_start",q->js_subband_start);
PRINT("js_vlc_bits",q->js_vlc_bits);
}
av_log(NULL,AV_LOG_ERROR,"COOKContext\n");
PRINT("nb_channels",q->nb_channels);
PRINT("bit_rate",q->bit_rate);
PRINT("sample_rate",q->sample_rate);
PRINT("samples_per_channel",q->samples_per_channel);
PRINT("samples_per_frame",q->samples_per_frame);
PRINT("subbands",q->subbands);
PRINT("random_state",q->random_state);
PRINT("js_subband_start",q->js_subband_start);
PRINT("log2_numvector_size",q->log2_numvector_size);
PRINT("numvector_size",q->numvector_size);
PRINT("total_subbands",q->total_subbands);
}
#endif
/**
* Cook initialization
*
* @param avctx pointer to the AVCodecContext
*/
static int cook_decode_init(AVCodecContext *avctx)
{
COOKContext *q = avctx->priv_data;
uint8_t *edata_ptr = avctx->extradata;
/* Take care of the codec specific extradata. */
if (avctx->extradata_size <= 0) {
av_log(avctx,AV_LOG_ERROR,"Necessary extradata missing!\n");
return -1;
} else {
/* 8 for mono, 16 for stereo, ? for multichannel
Swap to right endianness so we don't need to care later on. */
av_log(avctx,AV_LOG_DEBUG,"codecdata_length=%d\n",avctx->extradata_size);
if (avctx->extradata_size >= 8){
q->cookversion = bytestream_get_be32(&edata_ptr);
q->samples_per_frame = bytestream_get_be16(&edata_ptr);
q->subbands = bytestream_get_be16(&edata_ptr);
}
if (avctx->extradata_size >= 16){
bytestream_get_be32(&edata_ptr); //Unknown unused
q->js_subband_start = bytestream_get_be16(&edata_ptr);
q->js_vlc_bits = bytestream_get_be16(&edata_ptr);
}
}
/* Take data from the AVCodecContext (RM container). */
q->sample_rate = avctx->sample_rate;
q->nb_channels = avctx->channels;
q->bit_rate = avctx->bit_rate;
/* Initialize RNG. */
av_init_random(1, &q->random_state);
/* Initialize extradata related variables. */
q->samples_per_channel = q->samples_per_frame / q->nb_channels;
q->bits_per_subpacket = avctx->block_align * 8;
/* Initialize default data states. */
q->log2_numvector_size = 5;
q->total_subbands = q->subbands;
/* Initialize version-dependent variables */
av_log(NULL,AV_LOG_DEBUG,"q->cookversion=%x\n",q->cookversion);
q->joint_stereo = 0;
switch (q->cookversion) {
case MONO:
if (q->nb_channels != 1) {
av_log(avctx,AV_LOG_ERROR,"Container channels != 1, report sample!\n");
return -1;
}
av_log(avctx,AV_LOG_DEBUG,"MONO\n");
break;
case STEREO:
if (q->nb_channels != 1) {
q->bits_per_subpacket = q->bits_per_subpacket/2;
}
av_log(avctx,AV_LOG_DEBUG,"STEREO\n");
break;
case JOINT_STEREO:
if (q->nb_channels != 2) {
av_log(avctx,AV_LOG_ERROR,"Container channels != 2, report sample!\n");
return -1;
}
av_log(avctx,AV_LOG_DEBUG,"JOINT_STEREO\n");
if (avctx->extradata_size >= 16){
q->total_subbands = q->subbands + q->js_subband_start;
q->joint_stereo = 1;
}
if (q->samples_per_channel > 256) {
q->log2_numvector_size = 6;
}
if (q->samples_per_channel > 512) {
q->log2_numvector_size = 7;
}
break;
case MC_COOK:
av_log(avctx,AV_LOG_ERROR,"MC_COOK not supported!\n");
return -1;
break;
default:
av_log(avctx,AV_LOG_ERROR,"Unknown Cook version, report sample!\n");
return -1;
break;
}
/* Initialize variable relations */
q->numvector_size = (1 << q->log2_numvector_size);
/* Generate tables */
init_rootpow2table(q);
init_pow2table(q);
init_gain_table(q);
if (init_cook_vlc_tables(q) != 0)
return -1;
if(avctx->block_align >= UINT_MAX/2)
return -1;
/* Pad the databuffer with:
DECODE_BYTES_PAD1 or DECODE_BYTES_PAD2 for decode_bytes(),
FF_INPUT_BUFFER_PADDING_SIZE, for the bitstreamreader. */
if (q->nb_channels==2 && q->joint_stereo==0) {
q->decoded_bytes_buffer =
av_mallocz(avctx->block_align/2
+ DECODE_BYTES_PAD2(avctx->block_align/2)
+ FF_INPUT_BUFFER_PADDING_SIZE);
} else {
q->decoded_bytes_buffer =
av_mallocz(avctx->block_align
+ DECODE_BYTES_PAD1(avctx->block_align)
+ FF_INPUT_BUFFER_PADDING_SIZE);
}
if (q->decoded_bytes_buffer == NULL)
return -1;
q->gains1.now = q->gain_1;
q->gains1.previous = q->gain_2;
q->gains2.now = q->gain_3;
q->gains2.previous = q->gain_4;
/* Initialize transform. */
if ( init_cook_mlt(q) != 0 )
return -1;
/* Try to catch some obviously faulty streams, othervise it might be exploitable */
if (q->total_subbands > 53) {
av_log(avctx,AV_LOG_ERROR,"total_subbands > 53, report sample!\n");
return -1;
}
if (q->subbands > 50) {
av_log(avctx,AV_LOG_ERROR,"subbands > 50, report sample!\n");
return -1;
}
if ((q->samples_per_channel == 256) || (q->samples_per_channel == 512) || (q->samples_per_channel == 1024)) {
} else {
av_log(avctx,AV_LOG_ERROR,"unknown amount of samples_per_channel = %d, report sample!\n",q->samples_per_channel);
return -1;
}
if ((q->js_vlc_bits > 6) || (q->js_vlc_bits < 0)) {
av_log(avctx,AV_LOG_ERROR,"q->js_vlc_bits = %d, only >= 0 and <= 6 allowed!\n",q->js_vlc_bits);
return -1;
}
#ifdef COOKDEBUG
dump_cook_context(q);
#endif
return 0;
}
AVCodec cook_decoder =
{
.name = "cook",
.type = CODEC_TYPE_AUDIO,
.id = CODEC_ID_COOK,
.priv_data_size = sizeof(COOKContext),
.init = cook_decode_init,
.close = cook_decode_close,
.decode = cook_decode_frame,
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -