x264代码剖析(十六):核心算法之宏块编码中的量化编码
为了进一步节省图像的传输码率,需要对图像进行压缩,通常采用变换编码及量化来消除图像中的相关性以减少图像编码的动态范围。本文主要介绍量化的相关内容,并给出x264中量化编码的代码分析。
1、量化编码
量化过程就是根据图像的动态范围大小确定量化参数,既保留图像必要的细节,又可以减少码流。在图像编码中,变换编码和量化从原理上讲是两个独立的过程。但在H.264中,将两个过程中的乘法合二为一,并进一步采用整数运算,减少编解码的运算量,提高图像压缩的实时性,这些措施对峰值信噪比(PSNR)的影响很小,一般低于0.02dB,可不计。下面给出编码器中变换编码及量化过程的流程。
下面给出毕厚杰著作的《新一代视频压缩编码标准——H.264/AVC(第二版)》中量化的相关理论知识,仅供学习参考。
2、量化源码分析
量化的相关函数大都位于common/quant.c中,主要包括以下函数:
x264_quant_init():初始化量化和反量化相关的汇编函数
quant_4x4():对4x4的DCT残差矩阵进行量化
QUANT_ONE():完成一个DCT系数的量化工作
quant_4x4x4():对4个4x4的DCT残差矩阵进行量化
下面对这些函数进行深入分析。
2.1、x264_quant_init()函数
量化模块的初始化函数是x264_quant_init()。该函数对x264_quant_function_t结构体中的函数指针进行了赋值。X264运行的过程中只要调用x264_quant_function_t的函数指针就可以完成相应的功能。对应的代码分析如下:
/******************************************************************/ /******************************************************************/ /* ======Analysed by RuiDong Fang ======Csdn Blog:http://blog.csdn.net/frd2009041510 ======Date:2016.03.25 */ /******************************************************************/ /******************************************************************/ /************====== 量化 ======************/ /* 功能:量化初始化,x264_quant_init()被x264_encoder_open()函数调用 */ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) { /*===== 量化=====*/ pf->quant_8x8 = quant_8x8; /////////////////针对8x8DCT的量化 pf->quant_4x4 = quant_4x4; /////////////////量化4x4=16个 pf->quant_4x4x4 = quant_4x4x4; /////////////////处理4个4x4的块 /////////////////Intra16x16中,16个DC系数Hadamard变换后对的它们量化 pf->quant_4x4_dc = quant_4x4_dc; pf->quant_2x2_dc = quant_2x2_dc; /*===== 反量化=====*/ pf->dequant_4x4 = dequant_4x4; /////////////////反量化4x4=16个 pf->dequant_4x4_dc = dequant_4x4_dc; ///////////////// pf->dequant_8x8 = dequant_8x8; /////////////////处理4个4x4的块针对8x8DCT的反量化 /////////////////Intra16x16中,16个DC系数Hadamard变换后对的它们反量化 pf->idct_dequant_2x4_dc = idct_dequant_2x4_dc; pf->idct_dequant_2x4_dconly = idct_dequant_2x4_dconly; //色度 pf->optimize_chroma_2x2_dc = optimize_chroma_2x2_dc; pf->optimize_chroma_2x4_dc = optimize_chroma_2x4_dc; pf->denoise_dct = x264_denoise_dct; pf->decimate_score15 = x264_decimate_score15; pf->decimate_score16 = x264_decimate_score16; pf->decimate_score64 = x264_decimate_score64; pf->coeff_last4 = x264_coeff_last4; pf->coeff_last8 = x264_coeff_last8; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15; pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16; pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64; pf->coeff_level_run4 = x264_coeff_level_run4; pf->coeff_level_run8 = x264_coeff_level_run8; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15; pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16; #if HIGH_BIT_DEPTH #if HAVE_MMX INIT_TRELLIS( sse2 ); if( cpu&X264_CPU_MMX2 ) { #if ARCH_X86 pf->denoise_dct = x264_denoise_dct_mmx; pf->decimate_score15 = x264_decimate_score15_mmx2; pf->decimate_score16 = x264_decimate_score16_mmx2; pf->decimate_score64 = x264_decimate_score64_mmx2; pf->coeff_last8 = x264_coeff_last8_mmx2; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2; pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2; pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64_mmx2; pf->coeff_level_run8 = x264_coeff_level_run8_mmx2; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_mmx2; pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_mmx2; #endif pf->coeff_last4 = x264_coeff_last4_mmx2; pf->coeff_level_run4 = x264_coeff_level_run4_mmx2; if( cpu&X264_CPU_LZCNT ) pf->coeff_level_run4 = x264_coeff_level_run4_mmx2_lzcnt; } if( cpu&X264_CPU_SSE2 ) { pf->quant_4x4 = x264_quant_4x4_sse2; pf->quant_4x4x4 = x264_quant_4x4x4_sse2; pf->quant_8x8 = x264_quant_8x8_sse2; pf->quant_2x2_dc = x264_quant_2x2_dc_sse2; pf->quant_4x4_dc = x264_quant_4x4_dc_sse2; pf->dequant_4x4 = x264_dequant_4x4_sse2; pf->dequant_8x8 = x264_dequant_8x8_sse2; pf->dequant_4x4_dc = x264_dequant_4x4dc_sse2; pf->denoise_dct = x264_denoise_dct_sse2; pf->decimate_score15 = x264_decimate_score15_sse2; pf->decimate_score16 = x264_decimate_score16_sse2; pf->decimate_score64 = x264_decimate_score64_sse2; pf->coeff_last8 = x264_coeff_last8_sse2; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2; pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2; pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2; pf->coeff_level_run8 = x264_coeff_level_run8_sse2; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2; if( cpu&X264_CPU_LZCNT ) { pf->coeff_last4 = x264_coeff_last4_mmx2_lzcnt; pf->coeff_last8 = x264_coeff_last8_sse2_lzcnt; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2_lzcnt; pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2_lzcnt; pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2_lzcnt; pf->coeff_level_run8 = x264_coeff_level_run8_sse2_lzcnt; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2_lzcnt; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2_lzcnt; } } if( cpu&X264_CPU_SSSE3 ) { pf->quant_4x4 = x264_quant_4x4_ssse3; pf->quant_4x4x4 = x264_quant_4x4x4_ssse3; pf->quant_8x8 = x264_quant_8x8_ssse3; pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3; pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3; pf->denoise_dct = x264_denoise_dct_ssse3; pf->decimate_score15 = x264_decimate_score15_ssse3; pf->decimate_score16 = x264_decimate_score16_ssse3; pf->decimate_score64 = x264_decimate_score64_ssse3; INIT_TRELLIS( ssse3 ); } if( cpu&X264_CPU_SSE4 ) { pf->quant_2x2_dc = x264_quant_2x2_dc_sse4; pf->quant_4x4_dc = x264_quant_4x4_dc_sse4; pf->quant_4x4 = x264_quant_4x4_sse4; pf->quant_4x4x4 = x264_quant_4x4x4_sse4; pf->quant_8x8 = x264_quant_8x8_sse4; } if( cpu&X264_CPU_AVX ) { pf->denoise_dct = x264_denoise_dct_avx; } if( cpu&X264_CPU_XOP ) { pf->dequant_4x4_dc = x264_dequant_4x4dc_xop; if( h->param.i_cqm_preset != X264_CQM_FLAT ) { pf->dequant_4x4 = x264_dequant_4x4_xop; pf->dequant_8x8 = x264_dequant_8x8_xop; } } if( cpu&X264_CPU_AVX2 ) { pf->quant_4x4 = x264_quant_4x4_avx2; pf->quant_4x4_dc = x264_quant_4x4_dc_avx2; pf->quant_8x8 = x264_quant_8x8_avx2; pf->quant_4x4x4 = x264_quant_4x4x4_avx2; pf->dequant_4x4 = x264_dequant_4x4_avx2; pf->dequant_8x8 = x264_dequant_8x8_avx2; pf->dequant_4x4_dc = x264_dequant_4x4dc_avx2; pf->denoise_dct = x264_denoise_dct_avx2; if( cpu&X264_CPU_LZCNT ) pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2_lzcnt; } #endif // HAVE_MMX #else // !HIGH_BIT_DEPTH #if HAVE_MMX INIT_TRELLIS( sse2 ); if( cpu&X264_CPU_MMX ) { #if ARCH_X86 pf->dequant_4x4 = x264_dequant_4x4_mmx; pf->dequant_4x4_dc = x264_dequant_4x4dc_mmx2; pf->dequant_8x8 = x264_dequant_8x8_mmx; if( h->param.i_cqm_preset == X264_CQM_FLAT ) { pf->dequant_4x4 = x264_dequant_4x4_flat16_mmx; pf->dequant_8x8 = x264_dequant_8x8_flat16_mmx; } pf->denoise_dct = x264_denoise_dct_mmx; #endif } if( cpu&X264_CPU_MMX2 ) { pf->quant_2x2_dc = x264_quant_2x2_dc_mmx2; #if ARCH_X86 pf->quant_4x4 = x264_quant_4x4_mmx2; pf->quant_8x8 = x264_quant_8x8_mmx2; pf->quant_4x4_dc = x264_quant_4x4_dc_mmx2; pf->decimate_score15 = x264_decimate_score15_mmx2; pf->decimate_score16 = x264_decimate_score16_mmx2; pf->decimate_score64 = x264_decimate_score64_mmx2; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2; pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2; pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64_mmx2; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_mmx2; pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_mmx2; #endif pf->coeff_last4 = x264_coeff_last4_mmx2; pf->coeff_last8 = x264_coeff_last8_mmx2; pf->coeff_level_run4 = x264_coeff_level_run4_mmx2; pf->coeff_level_run8 = x264_coeff_level_run8_mmx2; if( cpu&X264_CPU_LZCNT ) { pf->coeff_last4 = x264_coeff_last4_mmx2_lzcnt; pf->coeff_last8 = x264_coeff_last8_mmx2_lzcnt; pf->coeff_level_run4 = x264_coeff_level_run4_mmx2_lzcnt; pf->coeff_level_run8 = x264_coeff_level_run8_mmx2_lzcnt; } } if( cpu&X264_CPU_SSE2 ) { pf->quant_4x4_dc = x264_quant_4x4_dc_sse2; pf->quant_4x4 = x264_quant_4x4_sse2; pf->quant_4x4x4 = x264_quant_4x4x4_sse2; pf->quant_8x8 = x264_quant_8x8_sse2; pf->dequant_4x4 = x264_dequant_4x4_sse2; pf->dequant_4x4_dc = x264_dequant_4x4dc_sse2; pf->dequant_8x8 = x264_dequant_8x8_sse2; if( h->param.i_cqm_preset == X264_CQM_FLAT ) { pf->dequant_4x4 = x264_dequant_4x4_flat16_sse2; pf->dequant_8x8 = x264_dequant_8x8_flat16_sse2; } pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_sse2; pf->denoise_dct = x264_denoise_dct_sse2; pf->decimate_score15 = x264_decimate_score15_sse2; pf->decimate_score16 = x264_decimate_score16_sse2; pf->decimate_score64 = x264_decimate_score64_sse2; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2; pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2; pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2; if( cpu&X264_CPU_LZCNT ) { pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2_lzcnt; pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2_lzcnt; pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2_lzcnt; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2_lzcnt; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2_lzcnt; } } if( cpu&X264_CPU_SSSE3 ) { pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3; pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3; pf->quant_4x4 = x264_quant_4x4_ssse3; pf->quant_4x4x4 = x264_quant_4x4x4_ssse3; pf->quant_8x8 = x264_quant_8x8_ssse3; pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_ssse3; pf->denoise_dct = x264_denoise_dct_ssse3; pf->decimate_score15 = x264_decimate_score15_ssse3; pf->decimate_score16 = x264_decimate_score16_ssse3; pf->decimate_score64 = x264_decimate_score64_ssse3; INIT_TRELLIS( ssse3 ); pf->coeff_level_run4 = x264_coeff_level_run4_ssse3; pf->coeff_level_run8 = x264_coeff_level_run8_ssse3; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3; if( cpu&X264_CPU_LZCNT ) { pf->coeff_level_run4 = x264_coeff_level_run4_ssse3; pf->coeff_level_run8 = x264_coeff_level_run8_ssse3; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3_lzcnt; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3_lzcnt; } } if( cpu&X264_CPU_SSE4 ) { pf->quant_4x4_dc = x264_quant_4x4_dc_sse4; pf->quant_4x4 = x264_quant_4x4_sse4; pf->quant_8x8 = x264_quant_8x8_sse4; pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_sse4; } if( cpu&X264_CPU_AVX ) { pf->dequant_4x4_dc = x264_dequant_4x4dc_avx; if( h->param.i_cqm_preset != X264_CQM_FLAT ) { pf->dequant_4x4 = x264_dequant_4x4_avx; pf->dequant_8x8 = x264_dequant_8x8_avx; } pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_avx; pf->denoise_dct = x264_denoise_dct_avx; } if( cpu&X264_CPU_XOP ) { if( h->param.i_cqm_preset != X264_CQM_FLAT ) { pf->dequant_4x4 = x264_dequant_4x4_xop; pf->dequant_8x8 = x264_dequant_8x8_xop; } } if( cpu&X264_CPU_AVX2 ) { pf->quant_4x4 = x264_quant_4x4_avx2; pf->quant_4x4_dc = x264_quant_4x4_dc_avx2; pf->quant_8x8 = x264_quant_8x8_avx2; pf->quant_4x4x4 = x264_quant_4x4x4_avx2; pf->dequant_4x4 = x264_dequant_4x4_avx2; pf->dequant_8x8 = x264_dequant_8x8_avx2; pf->dequant_4x4_dc = x264_dequant_4x4dc_avx2; if( h->param.i_cqm_preset == X264_CQM_FLAT ) { pf->dequant_4x4 = x264_dequant_4x4_flat16_avx2; pf->dequant_8x8 = x264_dequant_8x8_flat16_avx2; } pf->decimate_score64 = x264_decimate_score64_avx2; pf->denoise_dct = x264_denoise_dct_avx2; if( cpu&X264_CPU_LZCNT ) { pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2_lzcnt; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_avx2_lzcnt; pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_avx2_lzcnt; } } #endif // HAVE_MMX #if HAVE_ALTIVEC if( cpu&X264_CPU_ALTIVEC ) { pf->quant_2x2_dc = x264_quant_2x2_dc_altivec; pf->quant_4x4_dc = x264_quant_4x4_dc_altivec; pf->quant_4x4 = x264_quant_4x4_altivec; pf->quant_8x8 = x264_quant_8x8_altivec; pf->dequant_4x4 = x264_dequant_4x4_altivec; pf->dequant_8x8 = x264_dequant_8x8_altivec; } #endif #if HAVE_ARMV6 if( cpu&X264_CPU_ARMV6 ) { pf->coeff_last4 = x264_coeff_last4_arm; pf->coeff_last8 = x264_coeff_last8_arm; } #endif #if HAVE_ARMV6 || ARCH_AARCH64 if( cpu&X264_CPU_NEON ) { pf->quant_2x2_dc = x264_quant_2x2_dc_neon; pf->quant_4x4 = x264_quant_4x4_neon; pf->quant_4x4_dc = x264_quant_4x4_dc_neon; pf->quant_4x4x4 = x264_quant_4x4x4_neon; pf->quant_8x8 = x264_quant_8x8_neon; pf->dequant_4x4 = x264_dequant_4x4_neon; pf->dequant_4x4_dc = x264_dequant_4x4_dc_neon; pf->dequant_8x8 = x264_dequant_8x8_neon; pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_neon; pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_neon; pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_neon; pf->denoise_dct = x264_denoise_dct_neon; pf->decimate_score15 = x264_decimate_score15_neon; pf->decimate_score16 = x264_decimate_score16_neon; pf->decimate_score64 = x264_decimate_score64_neon; } #endif #if ARCH_AARCH64 if( cpu&X264_CPU_ARMV8 ) { pf->coeff_last4 = x264_coeff_last4_aarch64; pf->coeff_last8 = x264_coeff_last8_aarch64; pf->coeff_level_run4 = x264_coeff_level_run4_aarch64; } if( cpu&X264_CPU_NEON ) { pf->coeff_level_run8 = x264_coeff_level_run8_neon; pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_neon; pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_neon; } #endif #if HAVE_MSA if( cpu&X264_CPU_MSA ) { pf->quant_4x4 = x264_quant_4x4_msa; pf->quant_4x4_dc = x264_quant_4x4_dc_msa; pf->quant_4x4x4 = x264_quant_4x4x4_msa; pf->quant_8x8 = x264_quant_8x8_msa; pf->dequant_4x4 = x264_dequant_4x4_msa; pf->dequant_4x4_dc = x264_dequant_4x4_dc_msa; pf->dequant_8x8 = x264_dequant_8x8_msa; pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_msa; pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_msa; } #endif #endif // HIGH_BIT_DEPTH pf->coeff_last[DCT_LUMA_DC] = pf->coeff_last[DCT_CHROMAU_DC] = pf->coeff_last[DCT_CHROMAV_DC] = pf->coeff_last[DCT_CHROMAU_4x4] = pf->coeff_last[DCT_CHROMAV_4x4] = pf->coeff_last[DCT_LUMA_4x4]; pf->coeff_last[DCT_CHROMA_AC] = pf->coeff_last[DCT_CHROMAU_AC] = pf->coeff_last[DCT_CHROMAV_AC] = pf->coeff_last[DCT_LUMA_AC]; pf->coeff_last[DCT_CHROMAU_8x8] = pf->coeff_last[DCT_CHROMAV_8x8] = pf->coeff_last[DCT_LUMA_8x8]; pf->coeff_level_run[DCT_LUMA_DC] = pf->coeff_level_run[DCT_CHROMAU_DC] = pf->coeff_level_run[DCT_CHROMAV_DC] = pf->coeff_level_run[DCT_CHROMAU_4x4] = pf->coeff_level_run[DCT_CHROMAV_4x4] = pf->coeff_level_run[DCT_LUMA_4x4]; pf->coeff_level_run[DCT_CHROMA_AC] = pf->coeff_level_run[DCT_CHROMAU_AC] = pf->coeff_level_run[DCT_CHROMAV_AC] = pf->coeff_level_run[DCT_LUMA_AC]; }
其中, x264_quant_function_t的定义如下:
typedef struct { int (*quant_8x8) ( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); int (*quant_4x4) ( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); int (*quant_4x4x4)( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); int (*quant_4x4_dc)( dctcoef dct[16], int mf, int bias ); int (*quant_2x2_dc)( dctcoef dct[4], int mf, int bias ); void (*dequant_8x8)( dctcoef dct[64], int dequant_mf[6][64], int i_qp ); void (*dequant_4x4)( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); void (*dequant_4x4_dc)( dctcoef dct[16], int dequant_mf[6][16], int i_qp ); void (*idct_dequant_2x4_dc)( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp ); void (*idct_dequant_2x4_dconly)( dctcoef dct[8], int dequant_mf[6][16], int i_qp ); int (*optimize_chroma_2x2_dc)( dctcoef dct[4], int dequant_mf ); int (*optimize_chroma_2x4_dc)( dctcoef dct[8], int dequant_mf ); void (*denoise_dct)( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size ); int (*decimate_score15)( dctcoef *dct ); int (*decimate_score16)( dctcoef *dct ); int (*decimate_score64)( dctcoef *dct ); int (*coeff_last[14])( dctcoef *dct ); int (*coeff_last4)( dctcoef *dct ); int (*coeff_last8)( dctcoef *dct ); int (*coeff_level_run[13])( dctcoef *dct, x264_run_level_t *runlevel ); int (*coeff_level_run4)( dctcoef *dct, x264_run_level_t *runlevel ); int (*coeff_level_run8)( dctcoef *dct, x264_run_level_t *runlevel ); #define TRELLIS_PARAMS const int *unquant_mf, const uint8_t *zigzag, int lambda2,\ int last_nnz, dctcoef *coefs, dctcoef *quant_coefs, dctcoef *dct,\ uint8_t *cabac_state_sig, uint8_t *cabac_state_last,\ uint64_t level_state0, uint16_t level_state1 int (*trellis_cabac_4x4)( TRELLIS_PARAMS, int b_ac ); int (*trellis_cabac_8x8)( TRELLIS_PARAMS, int b_interlaced ); int (*trellis_cabac_4x4_psy)( TRELLIS_PARAMS, int b_ac, dctcoef *fenc_dct, int psy_trellis ); int (*trellis_cabac_8x8_psy)( TRELLIS_PARAMS, int b_interlaced, dctcoef *fenc_dct, int psy_trellis ); int (*trellis_cabac_dc)( TRELLIS_PARAMS, int num_coefs ); int (*trellis_cabac_chroma_422_dc)( TRELLIS_PARAMS ); } x264_quant_function_t;
2.2、quant_4x4()函数
quant_4x4()用于对4x4的DCT残差矩阵进行量化,quant_4x4()循环16次调用了QUANT_ONE()完成了量化工作。并且将DCT系数值,MF值,bias偏移值直接传递给了该宏。对应的代码分析如下:
/************====== 4x4的DCT残差矩阵的量化 ======************/ /* 功能:quant_4x4()用于对4x4的DCT残差矩阵进行量化 */ static int quant_4x4( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] )//输入输出都是dct[16] { int nz = 0; for( int i = 0; i < 16; i++ )//循环16个元素 QUANT_ONE( dct[i], mf[i], bias[i] ); return !!nz; }
其中,QUANT_ONE()完成了一个DCT系数的量化工作,从QUANT_ONE()的定义可以看出,它实现了上文提到的H.264标准中的量化公式。它的定义如下:
/************====== QUANT_ONE() ======************/ /* 功能:量化1个元素 */ #define QUANT_ONE( coef, mf, f ) \ { \ if( (coef) > 0 ) \ (coef) = (f + (coef)) * (mf) >> 16; \ else \ (coef) = - ((f - (coef)) * (mf) >> 16); \ nz |= (coef); \ }
2.3、quant_4x4x4()函数
quant_4x4x4()用于对4个4x4的DCT残差矩阵进行量化。该函数的定义位于common\quant.c,从quant_4x4x4()的定义可以看出,该函数相当于调用了4次quant_4x4()函数。对应的代码分析如下:
/************====== 4个4x4的DCT残差矩阵的量化 ======************/ /* 功能:quant_4x4x4()用于对4个4x4的DCT残差矩阵进行量化,从quant_4x4x4()的定义可以看出,该函数相当于调用了4次quant_4x4()函数。 */ static int quant_4x4x4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] )//输入输出都是dct[4][16] { int nza = 0; for( int j = 0; j < 4; j++ )//处理4个 { int nz = 0; for( int i = 0; i < 16; i++ ) QUANT_ONE( dct[j][i], mf[i], bias[i] );//量化 nza |= (!!nz)<<j; } return nza; }
至此,x264中量化的重点函数就分析完毕了。