📄 cook.c
字号:
static void decouple_info(COOKContext *q, int* decouple_tab){ int length, i; if(get_bits1(&q->gb)) { 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_vlc2(&q->gb, q->ccpl.table, q->ccpl.bits, 2); } return; } 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 * * @param q pointer to the COOKContext * @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[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; }}/** * 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) { int i,j; int value; float* tmp_ptr; /* 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(inbuffer, q->decoded_bytes_buffer, sub_packet_size); init_get_bits(&q->gb, q->decoded_bytes_buffer, sub_packet_size*8); decode_gain_info(&q->gb, &q->gain_current); if(q->nb_channels==2 && q->joint_stereo==1){ joint_decode(q, q->decode_buf_ptr[0], q->decode_buf_ptr[2]); /* Swap buffer pointers. */ tmp_ptr = q->decode_buf_ptr[1]; q->decode_buf_ptr[1] = q->decode_buf_ptr[0]; q->decode_buf_ptr[0] = tmp_ptr; tmp_ptr = q->decode_buf_ptr[3]; q->decode_buf_ptr[3] = q->decode_buf_ptr[2]; q->decode_buf_ptr[2] = tmp_ptr; /* FIXME: Rethink the gainbuffer handling, maybe a rename? now/previous swap */ q->gain_now_ptr = &q->gain_now; q->gain_previous_ptr = &q->gain_previous; for (i=0 ; i<q->nb_channels ; i++){ cook_imlt(q, q->decode_buf_ptr[i*2], q->mono_mdct_output, q->mlt_tmp); gain_compensate(q, q->mono_mdct_output, q->gain_now_ptr, q->gain_previous_ptr, q->previous_buffer_ptr[0]); /* Swap out the previous buffer. */ tmp_ptr = q->previous_buffer_ptr[0]; q->previous_buffer_ptr[0] = q->previous_buffer_ptr[1]; q->previous_buffer_ptr[1] = tmp_ptr; /* Clip and convert the floats to 16 bits. */ for (j=0 ; j<q->samples_per_frame ; j++){ value = lrintf(q->mono_mdct_output[j]); if(value < -32768) value = -32768; else if(value > 32767) value = 32767; outbuffer[2*j+i] = value; } } memcpy(&q->gain_now, &q->gain_previous, sizeof(COOKgain)); memcpy(&q->gain_previous, &q->gain_current, sizeof(COOKgain)); } else if (q->nb_channels==2 && q->joint_stereo==0) { /* channel 0 */ mono_decode(q, q->decode_buf_ptr2[0]); tmp_ptr = q->decode_buf_ptr2[0]; q->decode_buf_ptr2[0] = q->decode_buf_ptr2[1]; q->decode_buf_ptr2[1] = tmp_ptr; memcpy(&q->gain_channel1[0], &q->gain_current ,sizeof(COOKgain)); q->gain_now_ptr = &q->gain_channel1[0]; q->gain_previous_ptr = &q->gain_channel1[1]; cook_imlt(q, q->decode_buf_ptr2[0], q->mono_mdct_output,q->mlt_tmp); gain_compensate(q, q->mono_mdct_output, q->gain_now_ptr, q->gain_previous_ptr, q->mono_previous_buffer1); memcpy(&q->gain_channel1[1], &q->gain_channel1[0],sizeof(COOKgain)); for (j=0 ; j<q->samples_per_frame ; j++){ value = lrintf(q->mono_mdct_output[j]); if(value < -32768) value = -32768; else if(value > 32767) value = 32767; outbuffer[2*j+1] = value; } /* channel 1 */ //av_log(NULL,AV_LOG_ERROR,"bits = %d\n",get_bits_count(&q->gb)); init_get_bits(&q->gb, q->decoded_bytes_buffer, sub_packet_size*8+q->bits_per_subpacket); q->gain_now_ptr = &q->gain_channel2[0]; q->gain_previous_ptr = &q->gain_channel2[1]; decode_gain_info(&q->gb, &q->gain_channel2[0]); mono_decode(q, q->decode_buf_ptr[0]); tmp_ptr = q->decode_buf_ptr[0]; q->decode_buf_ptr[0] = q->decode_buf_ptr[1]; q->decode_buf_ptr[1] = tmp_ptr; cook_imlt(q, q->decode_buf_ptr[0], q->mono_mdct_output,q->mlt_tmp); gain_compensate(q, q->mono_mdct_output, q->gain_now_ptr, q->gain_previous_ptr, q->mono_previous_buffer2); /* Swap out the previous buffer. */ tmp_ptr = q->previous_buffer_ptr[0]; q->previous_buffer_ptr[0] = q->previous_buffer_ptr[1]; q->previous_buffer_ptr[1] = tmp_ptr; memcpy(&q->gain_channel2[1], &q->gain_channel2[0] ,sizeof(COOKgain)); for (j=0 ; j<q->samples_per_frame ; j++){ value = lrintf(q->mono_mdct_output[j]); if(value < -32768) value = -32768; else if(value > 32767) value = 32767; outbuffer[2*j] = value; } } else { mono_decode(q, q->decode_buf_ptr[0]); /* Swap buffer pointers. */ tmp_ptr = q->decode_buf_ptr[1]; q->decode_buf_ptr[1] = q->decode_buf_ptr[0]; q->decode_buf_ptr[0] = tmp_ptr; /* FIXME: Rethink the gainbuffer handling, maybe a rename? now/previous swap */ q->gain_now_ptr = &q->gain_now; q->gain_previous_ptr = &q->gain_previous; cook_imlt(q, q->decode_buf_ptr[0], q->mono_mdct_output,q->mlt_tmp); gain_compensate(q, q->mono_mdct_output, q->gain_now_ptr, q->gain_previous_ptr, q->mono_previous_buffer1); /* Clip and convert the floats to 16 bits */ for (j=0 ; j<q->samples_per_frame ; j++){ value = lrintf(q->mono_mdct_output[j]); if(value < -32768) value = -32768; else if(value > 32767) value = 32767; outbuffer[j] = value; } memcpy(&q->gain_now, &q->gain_previous, sizeof(COOKgain)); memcpy(&q->gain_previous, &q->gain_current, sizeof(COOKgain)); } 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); return avctx->block_align;}#ifdef COOKDEBUGstatic void dump_cook_context(COOKContext *q, COOKextradata *e){ //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",e->cookversion); if (e->cookversion > MONO_COOK2) { PRINT("js_subband_start",e->js_subband_start); PRINT("js_vlc_bits",e->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("mlt_size",q->mlt_size); 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){ COOKextradata *e = avctx->extradata; COOKContext *q = avctx->priv_data; /* Take care of the codec specific extradata. */ if (avctx->extradata_size <= 0) { av_log(NULL,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(NULL,AV_LOG_DEBUG,"codecdata_length=%d\n",avctx->extradata_size); if (avctx->extradata_size >= 8){ e->cookversion = be2me_32(e->cookversion); e->samples_per_frame = be2me_16(e->samples_per_frame); e->subbands = be2me_16(e->subbands); } if (avctx->extradata_size >= 16){ e->js_subband_start = be2me_16(e->js_subband_start); e->js_vlc_bits = be2me_16(e->js_vlc_bits); } } /* 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 state. */ q->random_state = 1; /* Initialize extradata related variables. */ q->samples_per_channel = e->samples_per_frame / q->nb_channels; q->samples_per_frame = e->samples_per_frame; q->subbands = e->subbands; q->bits_per_subpacket = avctx->block_align * 8; /* Initialize default data states. */ q->js_subband_start = 0; q->log2_numvector_size = 5; q->total_subbands = q->subbands; /* Initialize version-dependent variables */ av_log(NULL,AV_LOG_DEBUG,"e->cookversion=%x\n",e->cookversion); switch (e->cookversion) { case MONO_COOK1: if (q->nb_channels != 1) { av_log(NULL,AV_LOG_ERROR,"Container channels != 1, report sample!\n"); return -1; } av_log(NULL,AV_LOG_DEBUG,"MONO_COOK1\n"); break; case MONO_COOK2: if (q->nb_channels != 1) { q->joint_stereo = 0; q->bits_per_subpacket = q->bits_per_subpacket/2; } av_log(NULL,AV_LOG_DEBUG,"MONO_COOK2\n"); break; case JOINT_STEREO: if (q->nb_channels != 2) { av_log(NULL,AV_LOG_ERROR,"Container channels != 2, report sample!\n"); return -1; } av_log(NULL,AV_LOG_DEBUG,"JOINT_STEREO\n"); if (avctx->extradata_size >= 16){ q->total_subbands = q->subbands + e->js_subband_start; q->js_subband_start = e->js_subband_start; q->joint_stereo = 1; q->js_vlc_bits = e->js_vlc_bits; } 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(NULL,AV_LOG_ERROR,"MC_COOK not supported!\n"); return -1; break; default: av_log(NULL,AV_LOG_ERROR,"Unknown Cook version, report sample!\n"); return -1; break; } /* Initialize variable relations */ q->mlt_size = q->samples_per_channel; 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; /* Pad the databuffer with FF_INPUT_BUFFER_PADDING_SIZE, this is for the bitstreamreader. */ if ((q->decoded_bytes_buffer = av_mallocz((avctx->block_align+(4-avctx->block_align%4) + FF_INPUT_BUFFER_PADDING_SIZE)*sizeof(uint8_t))) == NULL) return -1; q->decode_buf_ptr[0] = q->decode_buffer_1; q->decode_buf_ptr[1] = q->decode_buffer_2; q->decode_buf_ptr[2] = q->decode_buffer_3; q->decode_buf_ptr[3] = q->decode_buffer_4; q->decode_buf_ptr2[0] = q->decode_buffer_3; q->decode_buf_ptr2[1] = q->decode_buffer_4; q->previous_buffer_ptr[0] = q->mono_previous_buffer1; q->previous_buffer_ptr[1] = q->mono_previous_buffer2; /* 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(NULL,AV_LOG_ERROR,"total_subbands > 53, report sample!\n"); return -1; } if (q->subbands > 50) { av_log(NULL,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(NULL,AV_LOG_ERROR,"unknown amount of samples_per_channel = %d, report sample!\n",q->samples_per_channel); return -1; }#ifdef COOKDEBUG dump_cook_context(q,e);#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 + -