📄 cook.c
字号:
* @param mlt_buffer1 pointer to left channel mlt coefficients * @param mlt_buffer2 pointer to right channel mlt coefficients */static void joint_decode(COOKContext *q, float* mlt_buffer1, float* mlt_buffer2) { int i,j; int decouple_tab[SUBBAND_SIZE]; float *decode_buffer = q->decode_buffer_0; int idx, cpl_tmp; float f1,f2; const 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 = q->cplscales[q->js_vlc_bits-2]; //choose decoupler table f1 = cplscale[decouple_tab[cpl_tmp]]; f2 = cplscale[idx-1]; q->decouple (q, i, f1, f2, decode_buffer, mlt_buffer1, mlt_buffer2); 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 voiddecode_bytes_and_gain(COOKContext *q, const uint8_t *inbuffer, cook_gains *gains_ptr){ 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);} /** * Saturate the output signal to signed 16bit integers. * * @param q pointer to the COOKContext * @param chan channel to saturate * @param out pointer to the output vector */static voidsaturate_output_float (COOKContext *q, int chan, int16_t *out){ int j; float *output = q->mono_mdct_output + q->samples_per_channel; /* Clip and convert floats to 16 bits. */ for (j = 0; j < q->samples_per_channel; j++) { out[chan + q->nb_channels * j] = av_clip_int16(lrintf(output[j])); }}/** * Final part of subpacket decoding: * Apply modulated lapped transform, gain compensation, * clip and convert to integer. * * @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 voidmlt_compensate_output(COOKContext *q, float *decode_buffer, cook_gains *gains, float *previous_buffer, int16_t *out, int chan){ imlt_gain(q, decode_buffer, gains, previous_buffer); q->saturate_output (q, chan, out);}/** * 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, const 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, const 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 COOKDEBUGstatic 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; const 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_pow2table(); init_gain_table(q); init_cplscales_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; /* Initialize COOK signal arithmetic handling */ if (1) { q->scalar_dequant = scalar_dequant_float; q->decouple = decouple_float; q->imlt_window = imlt_window_float; q->interpolate = interpolate_float; q->saturate_output = saturate_output_float; } /* 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 ={#ifdef __CW32__ "cook", CODEC_TYPE_AUDIO, CODEC_ID_COOK, sizeof(COOKContext), cook_decode_init, 0, cook_decode_close, cook_decode_frame, 0, 0, 0, 0, 0, NULL_IF_CONFIG_SMALL("COOK"),#else .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, .long_name = NULL_IF_CONFIG_SMALL("COOK"),#endif};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -