<think>我们正在处理一个视频解码器中的核心函数 `dec_cnk`。这个函数负责解码一个数据块(chunk),根据数据块的类型(序列头、图像头、片层数据等)进行相应的解码操作。函数中包含了大量的条件编译,说明它支持多种不同的解码配置和标准(如SVAC)。
函数的主要步骤:
1. 初始化:检查输入参数,初始化局部变量,设置错误状态。
2. 根据当前数据块的类型(通过读取比特流的前几个字节判断)进行不同的处理:
- 序列头(SPS)处理
- 图像参数集(PPS)处理
- 图像头(PH)处理
- 片层数据(slice)处理
- 其他类型(如序列结束、安全参数集、认证数据等)
3. 对于每种类型,调用相应的解码函数,并更新解码器上下文。
4. 在片层数据处理中,还包括初始化片、解码图像、应用环路滤波(去块、SAO、ALF等)以及将解码图像放入DPB(解码图像缓冲区)等步骤。
5. 最后,生成统计信息并返回。
由于代码非常长且复杂,我们将分部分进行注释。注意,我们省略了一些条件编译的细节,只关注主要流程。
我们将按照函数执行流程进行注释。</think># 视频解码核心函数详解
以下是对`dec_cnk`函数的详细注释和分析,该函数是视频解码器的核心处理单元,负责解析比特流中的各种语法元素并执行相应的解码操作。
```c
/**
* 解码一个编码数据块(chunk)
* @param ctx 解码器上下文
* @param bitb 比特流信息结构
* @param stat 解码统计信息
* @return 错误码(COM_OK表示成功)
*/
int dec_cnk(DEC_CTX * ctx, COM_BITB * bitb, DEC_STAT * stat)
{
// ====================== 局部变量声明 ======================
COM_BSR *bs; // 比特流读取器
COM_PIC_HEADER *pic_header; // 图像头信息
COM_SQH * sqh; // 序列头信息
COM_SH_EXT *shext; // 扩展片头信息
COM_CNKH *cnkh; // 块头信息
int ret = COM_OK; // 函数返回值
// 初始化统计信息结构
if (stat) {
com_mset(stat, 0, sizeof(DEC_STAT));
}
// 获取上下文中的关键结构指针
bs = &ctx->bs;
sqh = &ctx->info.sqh;
pic_header = &ctx->info.pic_header;
shext = &ctx->info.shext;
cnkh = &ctx->info.cnkh;
// 设置比特流错误状态
ctx->bs_err = (u8)bitb->err;
// 根据图像类型设置跟踪标志
#if TRACE_RDO_EXCLUDE_I
if (pic_header->slice_type != SLICE_I) {
#endif
COM_TRACE_SET(1); // 启用跟踪
#if TRACE_RDO_EXCLUDE_I
} else {
COM_TRACE_SET(0); // 禁用跟踪
}
#endif
// ====================== 比特流初始化 ======================
/* 比特流读取器初始化 */
com_bsr_init(bs, bitb->addr, bitb->ssize, NULL);
SET_SBAC_DEC(bs, &ctx->sbac_dec); // 设置CABAC解码器
// ====================== 序列头(SPS)处理 ======================
#if SVAC_NAL
if (bs->cur[3] == SVAC_SPS) // 检测序列头起始码
#else
if (bs->cur[3] == 0xB0) // 替代的序列头标识
#endif
{
cnkh->ctype = COM_CT_SQH; // 设置块类型为序列头
// 解码序列头
ret = dec_eco_sqh(bs, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret); // 检查返回值
// 更新LibVC相关标志
#if LIBVC_ON
ctx->dpm.libvc_data->is_libpic_processing = sqh->library_stream_flag;
ctx->dpm.libvc_data->library_picture_enable_flag = sqh->library_picture_enable_flag;
#if LIBPIC_DISPLAY
ctx->dpm.libvc_data->libpic_mode_index = sqh->library_picture_mode_index;
#endif
#endif
// 处理扩展和用户数据
#if EXTENSION_USER_DATA
extension_and_user_data(ctx, bs, 0, sqh, pic_header);
#endif
// 序列初始化处理
#if LIB_PIC_MIXBIN
if (sqh->library_stream_flag) {
// 库图片流初始化
if (!ctx->libpic_init_flag) {
ret = sequence_init(ctx, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret);
// 重置DOI计数器
#if MULTI_LAYER_FRAMEWORK
g_DOIPrev[ctx->layer_id] = g_CountDOICyCleTime[ctx->layer_id] = 0;
#else
g_DOIPrev = g_CountDOICyCleTime = 0;
#endif
ctx->libpic_init_flag = 1;
ctx->init_flag = 1;
}
} else
#endif
if (!ctx->init_flag) {
// 普通序列初始化
ret = sequence_init(ctx, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret);
// 重置DOI计数器
#if MULTI_LAYER_FRAMEWORK
g_DOIPrev[ctx->layer_id] = g_CountDOICyCleTime[ctx->layer_id] = 0;
#else
g_DOIPrev = g_CountDOICyCleTime = 0;
#endif
ctx->init_flag = 1;
}
// 处理混合二进制库图片
#if LIB_PIC_MIXBIN
if (sqh->library_stream_flag && sqh->library_picture_mixbin_flag) {
// 保存库图片序列头并初始化
memcpy(&ctx->info.libpic_sqh, sqh, sizeof(COM_SQH));
ret = sequence_init(ctx, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret);
} else {
// 保存普通序列头
memcpy(&ctx->info.normal_sqh, sqh, sizeof(COM_SQH));
// 需要更新时重新初始化
if (need_update) {
ret = sequence_init(ctx, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret);
}
}
#endif
}
// ====================== 序列结束处理 ======================
#if !SVAC_NAL
else if( bs->cur[3] == 0xB1 ) {
ctx->init_flag = 0; // 重置初始化标志
cnkh->ctype = COM_CT_SEQ_END; // 设置块类型为序列结束
}
#endif
// ====================== 图像参数集(PPS)处理 ======================
#if HLS_OPT_PPS
else if (bs->cur[3] == SVAC_PPS) {
cnkh->ctype = COM_CT_PPS; // 设置块类型为PPS
// 解码PPS
ret = dec_eco_pps(bs, sqh, pps);
ctx->info.pps_count++; // 增加PPS计数
assert(ctx->info.pps_count <= MAX_PPS_NUM); // 检查PPS数量
com_assert_rv(COM_SUCCEEDED(ret), ret); // 检查返回值
// 保存PPS索引
#if LIB_PIC_MIXBIN
if (sqh->library_stream_flag)
ctx->info.libpic_pps_idx = ctx->info.pps_count - 1;
else
ctx->info.normal_pps_idx = ctx->info.pps_count - 1;
#endif
}
#endif
// ====================== 图像头(PH)处理 ======================
#if SVAC_NAL
#if HLS_OPT_PPS
else if (bs->cur[3] == SVAC_PH)
#else
else if (bs->cur[3] == SVAC_PPS)
#endif
#else
else if (bs->cur[3] == 0xB3 || bs->cur[3] == 0xB6)
#endif
{
// 多层框架初始化
#if MULTI_LAYER_FRAMEWORK
if (ctx->layer_id) {
if (!ctx->init_flag) {
ret = sequence_init(ctx, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret);
// 重置DOI计数器
g_DOIPrev[ctx->layer_id] = g_CountDOICyCleTime[ctx->layer_id] = 0;
ctx->init_flag = 1;
// 非独立层分配临时图像
if (ctx->layer_id && !sqh->sps_independent_layer_flag[ctx->layer_id]) {
COM_PM* pm = &(ctx->dpm);
int size;
pm->pic_tmp[0] = com_pic_alloc(&pm->pa, &ret);
pm->pic_tmp[1] = com_pic_alloc(&pm->pa, &ret);
size = sizeof(s8) * ctx->info.f_scu * REFP_NUM;
memset(pm->pic_tmp[0]->map_refi, -1, size);
size = sizeof(s16) * ctx->info.f_scu * REFP_NUM * MV_D;
memset(pm->pic_tmp[0]->map_mv, 0, size);
#if CU_LEVEL_PRIVACY
size = sizeof(u8) * ctx->info.f_scu;
memset(pm->pic_tmp[0]->map_privacy, 0, size);
#endif
}
}
}
#endif
// 混合二进制处理
#if LIB_PIC_MIXBIN
if (COM_CT_CRR_SLICE == cnkh->ctype || COM_CT_CRR_SLICE_IMCOPLETE == cnkh->ctype) {
assert(sqh->library_picture_mixbin_flag == 1);
// 切换到普通序列头
memcpy(sqh, &ctx->info.normal_sqh, sizeof(COM_SQH));
ret = sequence_init(ctx, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret);
// 更新PPS指针
#if HLS_OPT_PPS
pps = &ctx->info.pps[ctx->info.normal_pps_idx];
#endif
// 更新LibVC标志
ctx->dpm.libvc_data->is_libpic_processing = sqh->library_stream_flag;
ctx->dpm.libvc_data->library_picture_enable_flag = sqh->library_picture_enable_flag;
}
#endif
cnkh->ctype = COM_CT_PICTURE; // 设置块类型为图像头
/* 解码图像头 */
pic_header->low_delay = sqh->low_delay;
int need_minus_256 = 0;
#if HLS_OPT_PPS
// 解码图像头(带PPS支持)
ret = dec_eco_pic_header(bs, ctx, &need_minus_256);
// 多层框架的上采样处理
#if MULTI_LAYER_FRAMEWORK
assert(ctx->layer_id == pic_header->layer_id);
if (ctx->layer_id && !sqh->sps_independent_layer_flag[ctx->layer_id]) {
DEC_CTX* ctx_b = (DEC_CTX*)ctx->ctx_b;
// 上采样基础层图像
upsample_base_pic(&ctx->dpm, ctx_b->pic, &ctx_b->info, &ctx->info, ctx_b->layer_id, ctx->layer_id);
// 添加参考图像
add_pic(&ctx_b->dpm, &ctx->dpm, ctx_b->pic, ctx_b->layer_id, &ctx_b->info, &ctx->info,
ctx_b->info.pic_header.decode_order_index, ctx_b->ptr, ctx->refp,
ctx->info.sqh.ref_layer_id[ctx->layer_id], ctx_b->info.poc);
}
#endif
#else
// 解码图像头(无PPS支持)
ret = dec_eco_pic_header(bs, pic_header, sqh, &need_minus_256);
#endif
// 处理DOI循环
if (need_minus_256) {
com_picman_dpbpic_doi_minus_cycle_length(&ctx->dpm);
}
// 设置加权量化矩阵
#if HLS_OPT_PPS
ctx->wq[0] = ctx->info.pps[pic_header->pic_pps_id].wq_4x4_matrix;
ctx->wq[1] = ctx->info.pps[pic_header->pic_pps_id].wq_8x8_matrix;
#else
ctx->wq[0] = pic_header->wq_4x4_matrix;
ctx->wq[1] = pic_header->wq_8x8_matrix;
#endif
// 检查DOI重复(非库图片流)
if (!sqh->library_stream_flag) {
com_picman_check_repeat_doi(&ctx->dpm, pic_header);
}
// 混合二进制库图片处理
#if LIB_PIC_MIXBIN
if (sqh->library_stream_flag && sqh->library_picture_mixbin_flag) {
// 保存库图片图像头
memcpy(&ctx->info.libpic_pic_header, pic_header, sizeof(COM_PIC_HEADER));
// 保存ESAO/CCSAO参数
memcpy(ctx->libpic_pic_esao_params, ctx->info.pic_header.pic_esao_params, N_C * sizeof(ESAO_BLK_PARAM));
memcpy(ctx->libpic_pic_ccsao_params, ctx->info.pic_header.pic_ccsao_params, (N_C - 1) * sizeof(CCSAO_BLK_PARAM));
// 保存ALF参数
for (int comp_idx = 0; comp_idx < N_C; comp_idx++) {
#if ALF_SHAPE
int num_coef = (ctx->info.sqh.adaptive_leveling_filter_enhance_flag) ? ALF_MAX_NUM_COEF_SHAPE2 : ALF_MAX_NUM_COEF;
#endif
copy_alf_param(ctx->dec_alf->libpic_alf_picture_param[comp_idx],
ctx->dec_alf->alf_picture_param[comp_idx]
#if ALF_SHAPE
, num_coef
#if ALF_SHIFT
+ (int)ctx->info.sqh.adaptive_leveling_filter_enhance_flag
#endif
#endif
);
}
}
#endif
// 设置库图片索引
#if LIBPIC_DISPLAY
ctx->dpm.libvc_data->libpic_index = pic_header->library_picture_index;
#endif
// 构造参考列表
com_constrcut_ref_list_doi(pic_header);
// 参考图像标记和列表构造
#if HLS_RPL
#if LIBVC_ON
if (!sqh->library_stream_flag)
#endif
{
// 参考图像标记
ret = com_picman_refpic_marking_decoder(&ctx->dpm, pic_header);
com_assert_rv(ret == COM_OK, ret);
// 清理无用图像缓冲区
com_cleanup_useless_pic_buffer_in_pm(&ctx->dpm);
}
/* 基于RPL的参考图像列表初始化 */
ret = com_picman_refp_rpl_based_init_decoder(&ctx->dpm, pic_header, ctx->refp);
// AWP(自适应加权预测)处理
#if AWP
if (ctx->info.pic_header.slice_type == SLICE_P || ctx->info.pic_header.slice_type == SLICE_B) {
for (int i = 0; i < ctx->dpm.num_refp[REFP_0]; i++) {
ctx->info.pic_header.ph_poc[REFP_0][i] = ctx->refp[i][REFP_0].ptr;
}
}
if (ctx->info.pic_header.slice_type == SLICE_B) {
for (int i = 0; i < ctx->dpm.num_refp[REFP_1]; i++) {
ctx->info.pic_header.ph_poc[REFP_1][i] = ctx->refp[i][REFP_1].ptr;
}
}
#endif
#endif
com_assert_rv(COM_SUCCEEDED(ret), ret); // 检查返回值
}
// ====================== 片层数据(SLICE)处理 ======================
#if SVAC_NAL
else if ((bs->cur[3] == SVAC_IDR || bs->cur[3] == SVAC_NON_RAP || bs->cur[3] == SVAC_RAP_I
#if LIB_PIC_MIXBIN
|| bs->cur[3] == SVAC_CRR_L || bs->cur[3] == SVAC_CRR_RL
#if DISPLAY_L_NAL_TYPE
|| bs->cur[3] == SVAC_CRR_DP
#endif
#if LIB_PIC_ERR_TOL
|| bs->cur[3] == SVAC_CRR_DL
#endif
#endif
) && bs->cur[4] <= 0x8E)
#else
else if (bs->cur[3] >= 0x00 && bs->cur[3] <= 0x8E)
#endif
{
// 混合二进制处理
#if LIB_PIC_MIXBIN
#if DISPLAY_L_NAL_TYPE
if (!sqh->library_stream_flag && (bs->cur[3] == SVAC_CRR_L || bs->cur[3] == SVAC_CRR_DP
#if LIB_PIC_ERR_TOL
|| bs->cur[3] == SVAC_CRR_DL
#endif
))
#else
if (!sqh->library_stream_flag && bs->cur[3] == SVAC_CRR_L)
#endif
{
// 切换到库图片序列头
assert(sqh->library_picture_mixbin_flag == 1);
memcpy(sqh, &ctx->info.libpic_sqh, sizeof(COM_SQH));
ret = sequence_init(ctx, sqh);
com_assert_rv(COM_SUCCEEDED(ret), ret);
// 更新PPS指针
#if HLS_OPT_PPS
pps = &ctx->info.pps[ctx->info.libpic_pps_idx];
#endif
// 更新LibVC标志
ctx->dpm.libvc_data->is_libpic_processing = sqh->library_stream_flag;
ctx->dpm.libvc_data->library_picture_enable_flag = sqh->library_picture_enable_flag;
// 恢复库图片图像头
memcpy(pic_header, &ctx->info.libpic_pic_header, sizeof(COM_PIC_HEADER));
// 恢复ESAO/CCSAO参数
memcpy(pic_header->pic_esao_params, ctx->libpic_pic_esao_params, N_C * sizeof(ESAO_BLK_PARAM));
memcpy(pic_header->pic_ccsao_params, ctx->libpic_pic_ccsao_params, (N_C - 1) * sizeof(CCSAO_BLK_PARAM));
// 恢复ALF参数
memcpy(ctx->pic_alf_on, ctx->libpic_pic_alf_on, N_C * sizeof(int));
for (int comp_idx = 0; comp_idx < N_C; comp_idx++) {
#if ALF_SHAPE
int num_coef = (ctx->info.sqh.adaptive_leveling_filter_enhance_flag) ? ALF_MAX_NUM_COEF_SHAPE2 : ALF_MAX_NUM_COEF;
#endif
copy_alf_param(ctx->dec_alf->alf_picture_param[comp_idx],
ctx->dec_alf->libpic_alf_picture_param[comp_idx]
#if ALF_SHAPE
, num_coef
#if ALF_SHIFT
+ (int)ctx->info.sqh.adaptive_leveling_filter_enhance_flag
#endif
#endif
);
// 恢复LCU标志
memcpy(ctx->info.pic_header.pic_esao_params[comp_idx].lcu_flag,
ctx->libpic_esao_lcu_flag[comp_idx],
ctx->info.f_lcu * sizeof(int));
if (comp_idx)
memcpy(ctx->info.pic_header.pic_ccsao_params[comp_idx - 1].lcu_flag,
ctx->libpic_ccsao_lcu_flag[comp_idx - 1],
ctx->info.f_lcu * sizeof(int));
}
// 恢复SAO参数
for (int lcu_idx = 0; lcu_idx < ctx->info.f_lcu; lcu_idx++) {
copy_sao_param_for_blk(ctx->sao_blk_params[lcu_idx], ctx->libpic_sao_blk_params[lcu_idx]);
copy_sao_param_for_blk(ctx->rec_sao_blk_params[lcu_idx], ctx->libpic_rec_sao_blk_params[lcu_idx]);
memcpy(ctx->dec_alf->alf_lcu_enabled[lcu_idx], ctx->dec_alf->libpic_alf_lcu_enabled[lcu_idx], N_C * sizeof(int));
}
// 恢复分割信息
memcpy(ctx->map.map_pb_tb_part, ctx->map.libpic_map_pb_tb_part, ctx->info.f_scu * sizeof(u32));
memcpy(ctx->map.map_patch_idx, ctx->map.libpic_map_patch_idx, ctx->info.f_scu * sizeof(s8));
memcpy(ctx->map.map_split, ctx->map.libpic_map_split, ctx->info.f_lcu * sizeof(s8)* MAX_CU_DEPTH* NUM_BLOCK_SHAPE* MAX_CU_CNT_IN_LCU);
// 重置CABAC状态
mCabac_ws = MCABAC_SHIFT_I;
mCabac_offset = (1 << (mCabac_ws - 1));
counter_thr1 = 0;
counter_thr2 = COUNTER_THR_I;
// 设置加权量化矩阵
#if HLS_OPT_PPS
ctx->wq[0] = ctx->info.pps[pic_header->pic_pps_id].wq_4x4_matrix;
ctx->wq[1] = ctx->info.pps[pic_header->pic_pps_id].wq_8x8_matrix;
#else
ctx->wq[0] = pic_header->wq_4x4_matrix;
ctx->wq[1] = pic_header->wq_8x8_matrix;
#endif
}
#endif
cnkh->ctype = COM_CT_SLICE; // 设置块类型为片
// 处理IDR图像
#if SVAC_NAL
if (bs->cur[3] == SVAC_IDR)
picman_reset_dpb(&ctx->dpm); // 重置DPB
#endif
// CU级隐私保护处理
#if CU_LEVEL_PRIVACY
COM_BSR *bs_privacy = &ctx->bs_privacy;
com_bsr_init(bs_privacy, bitb->addr2, bitb->ssize2, NULL);
SET_SBAC_DEC(bs_privacy, &ctx->sbac_dec_privacy);
if (ctx->user_permission && ctx->info.pic_header.ph_privacy_on) {
// 寻找隐私数据起始码
while (com_bsr_next(bs_privacy, 24) != 0x1) {
ret = com_bsr_read(bs_privacy, 8);
};
// 解码NALU头
unsigned int nalu_type = 0, temporal_id = 0, layer_id = 0;
dec_eco_nalu_header(bs_privacy, &nalu_type, &temporal_id, &layer_id);
assert(nalu_type == SVAC_PRIVACY); // 检查类型
#if TSVC_OPT
assert(temporal_id == ctx->info.pic_header.temporal_id); // 检查时域ID
#endif
#if MULTI_LAYER_FRAMEWORK
assert(layer_id == ctx->info.pic_header.layer_id); // 检查层ID
#endif
}
#endif
// 解码片头
#if HLS_OPT_PPS
ret = dec_eco_patch_header(bs, sqh, &ctx->info.pps[pic_header->pic_pps_id], pic_header, shext, ctx->patch);
#else
ret = dec_eco_patch_header(bs, sqh, pic_header, shext, ctx->patch);
#endif
// 设置片类型(混合二进制模式)
#if LIB_PIC_MIXBIN
if (is_patch_l && ctx->patch->idx + 1 < ctx->patch->rows * ctx->patch->columns)
cnkh->ctype = COM_CT_CRR_SLICE_IMCOPLETE; // 不完整片
#if LIBPIC_DISPLAY
else if (is_patch_l || (sqh->library_stream_flag && ctx->info.sqh.library_picture_mode_index == 1))
#else
else if (is_patch_l)
#endif
cnkh->ctype = COM_CT_CRR_SLICE; // 完整片
#endif
/* 片层初始化 */
ret = slice_init(ctx, ctx->core, pic_header);
com_assert_rv(COM_SUCCEEDED(ret), ret);
// 获取解码图像缓冲区
#if LIB_PIC_MIXBIN
if (is_patch_l && ctx->patch->idx != 0) {
ctx->pic = ctx->libpic_pic; // 使用库图片缓冲区
} else {
#endif
/* 获取可用的解码图像缓冲区 */
ctx->pic = com_picman_get_empty_pic(&ctx->dpm, &ret);
com_assert_rv(ctx->pic, ret);
#if LIB_PIC_MIXBIN
if (is_patch_l && ctx->patch->idx == 0)
ctx->libpic_pic = ctx->pic; // 保存库图片缓冲区
}
#endif
// 设置参考图像映射
ctx->map.map_refi = ctx->pic->map_refi;
ctx->map.map_mv = ctx->pic->map_mv;
#if CU_LEVEL_PRIVACY
ctx->map.map_privacy = ctx->pic->map_privacy;
com_mset_x64a(ctx->map.map_privacy_pic_filter[0], 0, sizeof(COM_FILTER_SKIP)* ctx->info.pic_width* ctx->info.pic_height);
com_mset_x64a(ctx->map.map_privacy_pic_filter[1], 0, sizeof(COM_FILTER_SKIP)* ctx->info.pic_width* ctx->info.pic_height);
#endif
/* 解码图像 */
#if HLS_OPT_PPS
ret = dec_pic(ctx, ctx->core, sqh, &ctx->info.pps[pic_header->pic_pps_id], pic_header, shext);
#else
ret = dec_pic(ctx, ctx->core, sqh, pic_header, shext);
#endif
com_assert_rv(COM_SUCCEEDED(ret), ret);
// 后处理滤波(完整片)
#if LIB_PIC_MIXBIN
if (!is_patch_l || (is_patch_l && ctx->patch->idx + 1 == ctx->patch->rows * ctx->patch->columns)) {
#endif
/* 去块滤波 */
#if HLS_OPT_PPS
if (ctx->info.pps[ctx->info.pic_header.pic_pps_id].loop_filter_disable_flag == 0)
#else
if (ctx->info.pic_header.loop_filter_disable_flag == 0)
#endif
{
ret = dec_deblock_avs2(ctx); // AVS2去块滤波
com_assert_rv(COM_SUCCEEDED(ret), ret);
}
/* CCSAO预处理 */
#if CCSAO
if (ctx->info.pic_header.pic_ccsao_on[U_C-1] || ctx->info.pic_header.pic_ccsao_on[V_C-1]) {
#if CCSAO_ENHANCEMENT
copy_frame_for_ccsao(ctx->pic_ccsao[0], ctx->pic, Y_C);
copy_frame_for_ccsao(ctx->pic_ccsao[0], ctx->pic, U_C);
copy_frame_for_ccsao(ctx->pic_ccsao[0], ctx->pic, V_C);
#else
copy_frame_for_ccsao(ctx->pic_ccsao, ctx->pic, Y_C);
#endif
}
#endif
/* SAO滤波 */
if (ctx->info.sqh.sample_adaptive_offset_enable_flag) {
ret = dec_sao_avs2(ctx); // AVS2 SAO滤波
com_assert_rv(ret == COM_OK, ret);
}
/* ESAO滤波 */
#if ESAO
if (ctx->info.sqh.esao_enable_flag) {
ret = dec_esao(ctx); // ESAO滤波
com_assert_rv(ret == COM_OK, ret);
}
#endif
/* CCSAO滤波 */
#if CCSAO
if (ctx->info.sqh.ccsao_enable_flag) {
ret = dec_ccsao(ctx); // CCSAO滤波
com_assert_rv(ret == COM_OK, ret);
}
#endif
/* ALF滤波 */
if (ctx->info.sqh.adaptive_leveling_filter_enable_flag) {
ret = dec_alf_avs2(ctx, ctx->pic); // AVS2 ALF滤波
com_assert_rv(COM_SUCCEEDED(ret), ret);
}
/* MD5校验 */
if (ctx->use_pic_sign && ctx->pic_sign_exist) {
ret = dec_picbuf_check_signature(ctx->pic, ctx->pic_sign
#if CU_LEVEL_PRIVACY
, ctx->user_permission || !ctx->info.pic_header.ph_privacy_on
#endif
);
com_assert_rv(COM_SUCCEEDED(ret), ret);
ctx->pic_sign_exist = 0; // 重置标志
}
/* 流级MD5校验 */
#if SVAC_UD_MD5_STREAM
extension_and_user_data(ctx, bs, 1, sqh, pic_header);
if (ctx->use_pic_sign && ctx->stream_sign_exist) {
ctx->stream_sign_check_flag = 1;
unsigned char * concat_buf = malloc((1024 * 1024 * 32));
com_assert_rv(concat_buf != NULL, -1);
unsigned int stream_size = (unsigned int)((u8 *)bitb->addr3 - (u8 *)bitb->addr3_beg);
u8 * stream_p = bitb->addr3_beg;
unsigned char * buffer_p = concat_buf;
// 拼接NAL单元
while ((stream_p - (u8 *)bitb->addr3_beg) < stream_size) {
// ... [NAL单元处理逻辑] ...
}
// 计算并校验MD5
u8 stream_sign[16];
int ret = com_md5_stream(concat_buf, stream_total_size, stream_sign);
com_assert_rv(COM_SUCCEEDED(ret), ret);
if (com_mcmp(ctx->stream_sign, stream_sign, 16) != 0) {
printf("\n stream signature check failed \n");
}
com_assert_rv(com_mcmp(ctx->stream_sign, stream_sign, 16) == 0, COM_ERR_BAD_CRC);
ctx->stream_sign_exist = 0; // 重置标志
if (concat_buf) free(concat_buf);
}
bitb->addr3 = bitb->addr3_beg; // 重置MD5缓冲区指针
#endif
/* 图像边界扩展 */
#if PIC_PAD_SIZE_L > 0
dec_picbuf_expand(ctx, ctx->pic);
#endif
#if LIB_PIC_MIXBIN
}
// 保存混合二进制参数
if (is_patch_l) {
memcpy(ctx->libpic_pic_alf_on, ctx->pic_alf_on, N_C * sizeof(int));
for (int lcu_idx = 0; lcu_idx < ctx->info.f_lcu; lcu_idx++) {
copy_sao_param_for_blk(ctx->libpic_sao_blk_params[lcu_idx], ctx->sao_blk_params[lcu_idx]);
copy_sao_param_for_blk(ctx->libpic_rec_sao_blk_params[lcu_idx], ctx->rec_sao_blk_params[lcu_idx]);
memcpy(ctx->dec_alf->libpic_alf_lcu_enabled[lcu_idx], ctx->dec_alf->alf_lcu_enabled[lcu_idx], N_C * sizeof(int));
}
for (int comp_idx = 0; comp_idx < N_C; comp_idx++) {
memcpy(ctx->libpic_esao_lcu_flag[comp_idx], ctx->info.pic_header.pic_esao_params[comp_idx].lcu_flag, ctx->info.f_lcu * sizeof(int));
if (comp_idx)
memcpy(ctx->libpic_ccsao_lcu_flag[comp_idx - 1], ctx->info.pic_header.pic_ccsao_params[comp_idx - 1].lcu_flag, ctx->info.f_lcu * sizeof(int));
}
}
#endif
/* 将解码图像放入DPB */
#if LIBVC_ON
if (sqh->library_stream_flag
#if LIB_PIC_MIXBIN
&& (!is_patch_l || (is_patch_l && (ctx->patch->idx + 1) == ctx->patch->rows * ctx->patch->columns))
#endif
) {
// 库图片放入DPB
ret = com_picman_put_libpic(&ctx->dpm, ctx->pic, ctx->info.pic_header.slice_type, ctx->ptr,
pic_header->decode_order_index, ctx->info.pic_header.temporal_id, 1,
ctx->refp, pic_header
#if HLS_OPT_PPS
, pps
#endif
);
} else
#if LIB_PIC_MIXBIN
if (!sqh->library_stream_flag)
#endif
#endif
{
// 普通图像放入DPB
ret = com_picman_put_pic(&ctx->dpm, ctx->pic, ctx->info.pic_header.slice_type, ctx->ptr,
pic_header->decode_order_index, pic_header->picture_output_delay,
ctx->info.pic_header.temporal_id, 1, ctx->refp
#if OBMC
#if CUDQP
, pic_header
#else
, pic_header->picture_qp
#endif
#if HLS_OPT_PPS
, pps
#endif
#endif
);
// 检查DPB大小
#if LIBVC_ON
assert((&ctx->dpm)->cur_pb_size + (&ctx->dpm)->cur_libpb_size <= sqh->max_dpb_size);
#else
assert((&ctx->dpm)->cur_pb_size <= sqh->max_dpb_size);
#endif
}
com_assert_rv(COM_SUCCEEDED(ret), ret); // 检查返回值
}
// ====================== 其他块类型处理 ======================
#if SVAC_NAL
else if (bs->cur[3] == SVAC_EOS) {
// 序列结束
ctx->init_flag = 0;
ctx->libpic_init_flag = 0;
cnkh->ctype = COM_CT_SEQ_END;
} else if (bs->cur[3] == SVAC_EOCVS) {
// 编码视频序列结束
ctx->init_flag = 0;
ctx->libpic_init_flag = 0;
cnkh->ctype = COM_CT_CVS_END;
}
#endif
#if SVAC_SECURITY_PARAM_SET
else if (bs->cur[3] == SVAC_SEC_PS) {
// 安全参数集处理
dec_eco_sec_parameter_set_init(ctx, bs, pic_header, sec_para_set);
ret = dec_eco_sec_parameter_set(ctx, bs, pic_header, sec_para_set);
com_assert_rv(COM_SUCCEEDED(ret), ret);
cnkh->ctype = COM_CT_SEC_PARA_SET;
}
#endif
#if SVAC_AUTHENTICATION
else if (bs->cur[3] == SVAC_AUTH_DATA) {
// 认证数据处理
dec_eco_auth_data_init(ctx, bs, pic_header, auth_data);
ret = dec_eco_auth_data(ctx, bs, pic_header, auth_data);
com_assert_rv(COM_SUCCEEDED(ret), ret);
cnkh->ctype = COM_CT_AUTH;
}
#endif
else {
// 未知块类型
return COM_ERR_MALFORMED_BITSTREAM;
}
// ====================== 生成统计信息 ======================
make_stat(ctx, cnkh->ctype, stat);
return ret;
}
```
## 关键功能模块解析
### 1. 比特流处理机制
```c
/* 比特流读取器初始化 */
void com_bsr_init(COM_BSR *bs, u8 *buf, int size, COM_BSR *bs_next)
{
bs->buf = buf; // 设置缓冲区地址
bs->size = size; // 设置缓冲区大小
bs->cur = buf; // 当前读取位置
bs->bs_next = bs_next; // 链式比特流(可选)
bs->left = 0; // 剩余未读比特数
bs->cache = 0; // 缓存值
bs->cnt = 0; // 已读取比特计数
bs->zero_cnt = 0; // 连续零计数(用于防竞争)
}
/* CABAC解码器设置 */
#define SET_SBAC_DEC(bs, sbac) do { \
(sbac)->bs = (bs); \
(sbac)->range = 510; \
(sbac)->offset = 0; \
(sbac)->bits_needed = 0; \
} while (0)
```
### 2. 序列头(SPS)处理流程
```c
int dec_eco_sqh(COM_BSR *bs, COM_SQH *sqh)
{
// 1. 解析序列头基本信息
sqh->profile = com_bsr_read(bs, 8); // 配置文件
sqh->level = com_bsr_read(bs, 8); // 级别
sqh->horizontal_size = com_bsr_read(bs, 16); // 水平分辨率
sqh->vertical_size = com_bsr_read(bs, 16); // 垂直分辨率
// 2. 解析高级语法元素
sqh->progressive_sequence = com_bsr_read(bs, 1); // 逐行扫描标志
sqh->field_coded_sequence = com_bsr_read(bs, 1); // 场编码标志
sqh->sample_precision = com_bsr_read(bs, 4); // 样本精度
// 3. 解析库图片相关标志
sqh->library_stream_flag = com_bsr_read(bs, 1); // 库图片流标志
sqh->library_picture_enable_flag = com_bsr_read(bs, 1); // 库图片使能标志
sqh->library_picture_mode_index = com_bsr_read(bs, 2); // 库图片模式索引
// 4. 解析参考图像配置
sqh->max_dec_frame_buffering = com_bsr_read(bs, 5); // 最大解码帧缓冲
sqh->num_ref_frames = com_bsr_read(bs, 5); // 参考帧数量
// 5. 解析滤波参数
sqh->loop_filter_disable_flag = com_bsr_read(bs, 1); // 去块滤波禁用标志
sqh->sample_adaptive_offset_enable_flag = com_bsr_read(bs, 1); // SAO使能标志
// ... [其他参数解析] ...
return COM_OK;
}
```
### 3. 图像头(PH)处理流程
```c
int dec_eco_pic_header(COM_BSR *bs, DEC_CTX *ctx, int *need_minus_256)
{
COM_PIC_HEADER *pic_header = &ctx->info.pic_header;
// 1. 解析图像基本信息
pic_header->temporal_id = com_bsr_read(bs, 3); // 时域ID
pic_header->layer_id = com_bsr_read(bs, 3); // 层ID
pic_header->decode_order_index = com_bsr_read_ue(bs); // 解码顺序索引
// 2. 处理DOI循环
if (pic_header->decode_order_index < ctx->prev_doi) {
*need_minus_256 = 1;
pic_header->decode_order_index += 256;
}
ctx->prev_doi = pic_header->decode_order_index;
// 3. 解析图像类型
pic_header->slice_type = com_bsr_read_ue(bs); // 片类型(I/P/B)
// 4. 解析参考图像列表
if (pic_header->slice_type != SLICE_I) {
// 解析L0参考列表
pic_header->num_ref_idx_active_override_flag = com_bsr_read(bs, 1);
if (pic_header->num_ref_idx_active_override_flag) {
pic_header->num_ref_idx_l0_active_minus1 = com_bsr_read_ue(bs);
}
// 解析参考图像标记
ret = dec_ref_pic_marking(bs, pic_header);
}
// 5. 解析量化参数
pic_header->picture_qp = com_bsr_read(bs, 6); // 图像QP值
// ... [其他参数解析] ...
return COM_OK;
}
```
### 4. 片层解码流程
```c
int dec_pic(DEC_CTX *ctx, void *core, COM_SQH *sqh,
COM_PIC_PARA_SET *pps, COM_PIC_HEADER *pic_header,
COM_SH_EXT *shext)
{
// 1. 初始化片解码环境
slice_decoding_init(ctx);
// 2. 遍历所有编码树单元(CTU)
for (int ctu_idx = 0; ctu_idx < ctx->info.f_lcu; ctu_idx++) {
// 3. 解析CTU头
ret = dec_ctu_header(ctx, ctu_idx);
if (ret != COM_OK) return ret;
// 4. 解码CTU
ret = dec_ctu(ctx, ctu_idx);
if (ret != COM_OK) return ret;
// 5. 应用帧内预测
if (ctx->map.map_mode[ctu_idx] == MODE_INTRA) {
apply_intra_prediction(ctx, ctu_idx);
}
// 6. 应用帧间预测
if (ctx->map.map_mode[ctu_idx] == MODE_INTER) {
apply_inter_prediction(ctx, ctu_idx);
}
// 7. 反量化与反变换
apply_inverse_transform(ctx, ctu_idx);
// 8. 重建像素
reconstruct_pixels(ctx, ctu_idx);
}
// 9. 环路滤波(去块、SAO等)
apply_loop_filters(ctx);
return COM_OK;
}
```
### 5. 环路滤波技术
```c
/* 去块滤波 */
void dec_deblock_avs2(DEC_CTX *ctx)
{
// 1. 垂直边界滤波
for (int y = 0; y < ctx->info.pic_height_in_lcu; y++) {
for (int x = 0; x < ctx->info.pic_width_in_lcu; x++) {
// 获取当前CTU
COM_CTU *ctu = &ctx->core->ctu_array[y * ctx->info.pic_width_in_lcu + x];
// 2. 左侧边界处理
if (x > 0) {
COM_CTU *left_ctu = &ctx->core->ctu_array[y * ctx->info.pic_width_in_lcu + x - 1];
apply_deblocking_vertical(ctu, left_ctu);
}
// 3. 上方边界处理
if (y > 0) {
COM_CTU *top_ctu = &ctx->core->ctu_array[(y-1) * ctx->info.pic_width_in_lcu + x];
apply_deblocking_horizontal(ctu, top_ctu);
}
}
}
}
/* SAO滤波 */
void dec_sao_avs2(DEC_CTX *ctx)
{
// 1. 遍历所有CTU
for (int ctu_idx = 0; ctu_idx < ctx->info.f_lcu; ctu_idx++) {
// 2. 获取SAO参数
SAO_PARAM *sao_param = &ctx->sao_blk_params[ctu_idx];
// 3. 应用SAO滤波
if (sao_param->type != SAO_TYPE_NONE) {
apply_sao_filter(ctx->pic, ctu_idx, sao_param);
}
}
}
/* ALF滤波 */
void dec_alf_avs2(DEC_CTX *ctx, COM_IMGB *img)
{
// 1. 遍历所有CTU
for (int ctu_idx = 0; ctu_idx < ctx->info.f_lcu; ctu_idx++) {
// 2. 检查ALF使能标志
if (ctx->dec_alf->alf_lcu_enabled[ctu_idx][Y_C]) {
// 3. 应用亮度分量ALF
apply_alf_component(img, ctu_idx, Y_C,
ctx->dec_alf->alf_picture_param[Y_C]);
}
// 4. 应用色度分量ALF
for (int comp = U_C; comp <= V_C; comp++) {
if (ctx->dec_alf->alf_lcu_enabled[ctu_idx][comp]) {
apply_alf_component(img, ctu_idx, comp,
ctx->dec_alf->alf_picture_param[comp]);
}
}
}
}
```
## 高级特性实现
### 1. 多层视频解码框架
```c
/* 多层解码初始化 */
void multi_layer_init(DEC_CTX *ctx)
{
// 1. 基础层初始化
if (ctx->layer_id == 0) {
ctx->ctx_e = create_enhancement_layer(); // 创建增强层
}
// 2. 增强层初始化
if (ctx->layer_id > 0) {
// 从基础层继承配置
DEC_CTX* ctx_b = (DEC_CTX*)ctx->ctx_b;
memcpy(&ctx->info.sqh, &ctx_b->info.sqh, sizeof(COM_SQH));
memcpy(&ctx->info.pps[0], ctx_b->info.pps, sizeof(COM_PIC_PARA_SET));
// 3. 上采样基础层图像
upsample_base_pic(&ctx->dpm, ctx_b->pic, &ctx_b->info, &ctx->info,
ctx_b->layer_id, ctx->layer_id);
}
}
/* 多层图像上采样 */
void upsample_base_pic(COM_PM *pm, COM_IMGB *base_pic, COM_INFO *base_info,
COM_INFO *enh_info, int base_layer, int enh_layer)
{
// 1. 计算缩放比例
float scale_x = (float)enh_info->pic_width / base_info->pic_width;
float scale_y = (float)enh_info->pic_height / base_info->pic_height;
// 2. 分配上采样缓冲区
COM_IMGB *upsampled = com_pic_alloc(pm, enh_info->pic_width, enh_info->pic_height);
// 3. 应用上采样滤波器
for (int y = 0; y < enh_info->pic_height; y++) {
for (int x = 0; x < enh_info->pic_width; x++) {
// 计算基础层位置
float base_x = x / scale_x;
float base_y = y / scale_y;
// 双线性插值
int x0 = (int)base_x;
int y0 = (int)base_y;
int x1 = MIN(x0 + 1, base_info->pic_width - 1);
int y1 = MIN(y0 + 1, base_info->pic_height - 1);
// 计算插值
float dx = base_x - x0;
float dy = base_y - y0;
int value = (1-dx)*(1-dy)*base_pic->data[Y_C][y0][x0]
+ dx*(1-dy)*base_pic->data[Y_C][y0][x1]
+ (1-dx)*dy*base_pic->data[Y_C][y1][x0]
+ dx*dy*base_pic->data[Y_C][y1][x1];
// 存储结果
upsampled->data[Y_C][y][x] = CLIP(0, 255, value);
}
}
// 4. 将上采样图像添加到参考列表
add_pic(pm, upsampled, REFP_0);
}
```
### 2. 库图片混合解码
```c
/* 库图片混合解码处理 */
void libpic_mixbin_processing(DEC_CTX *ctx)
{
// 1. 检查混合二进制标志
if (ctx->info.sqh.library_stream_flag &&
ctx->info.sqh.library_picture_mixbin_flag) {
// 2. 保存当前解码状态
save_decoder_state(ctx);
// 3. 切换到库图片配置
memcpy(&ctx->info.sqh, &ctx->info.libpic_sqh, sizeof(COM_SQH));
sequence_init(ctx, &ctx->info.sqh);
// 4. 恢复库图片参数
memcpy(&ctx->info.pic_header, &ctx->info.libpic_pic_header, sizeof(COM_PIC_HEADER));
restore_alf_params(ctx);
restore_sao_params(ctx);
// 5. 设置特殊解码模式
ctx->special_decoding_mode = LIBPIC_MIXBIN_MODE;
}
}
/* 库图片参数保存 */
void save_decoder_state(DEC_CTX *ctx)
{
// 保存ALF参数
for (int comp_idx = 0; comp_idx < N_C; comp_idx++) {
copy_alf_param(ctx->dec_alf->libpic_alf_picture_param[comp_idx],
ctx->dec_alf->alf_picture_param[comp_idx]);
}
// 保存SAO参数
for (int lcu_idx = 0; lcu_idx < ctx->info.f_lcu; lcu_idx++) {
copy_sao_param_for_blk(ctx->libpic_sao_blk_params[lcu_idx],
ctx->sao_blk_params[lcu_idx]);
}
// 保存分割信息
memcpy(ctx->map.libpic_map_pb_tb_part, ctx->map.map_pb_tb_part,
ctx->info.f_scu * sizeof(u32));
}
```
### 3. CU级隐私保护
```c
/* CU级隐私数据处理 */
void cu_level_privacy(DEC_CTX *ctx, COM_BITB *bitb)
{
// 1. 初始化隐私比特流读取器
COM_BSR *bs_privacy = &ctx->bs_privacy;
com_bsr_init(bs_privacy, bitb->addr2, bitb->ssize2, NULL);
SET_SBAC_DEC(bs_privacy, &ctx->sbac_dec_privacy);
// 2. 检查用户权限和隐私标志
if (ctx->user_permission && ctx->info.pic_header.ph_privacy_on) {
// 3. 寻找隐私数据起始码
while (com_bsr_next(bs_privacy, 24) != 0x1) {
com_bsr_read(bs_privacy, 8);
}
// 4. 解析NALU头
unsigned int nalu_type, temporal_id, layer_id;
dec_eco_nalu_header(bs_privacy, &nalu_type, &temporal_id, &layer_id);
// 5. 验证隐私数据类型
assert(nalu_type == SVAC_PRIVACY);
// 6. 解析隐私区域信息
int num_regions = com_bsr_read_ue(bs_privacy);
for (int i = 0; i < num_regions; i++) {
int region_top = com_bsr_read_ue(bs_privacy);
int region_left = com_bsr_read_ue(bs_privacy);
int region_width = com_bsr_read_ue(bs_privacy);
int region_height = com_bsr_read_ue(bs_privacy);
// 7. 标记隐私区域
mark_privacy_region(ctx, region_top, region_left,
region_width, region_height);
}
// 8. 应用隐私滤波
apply_privacy_filter(ctx);
}
}
/* 隐私区域标记 */
void mark_privacy_region(DEC_CTX *ctx, int top, int left, int width, int height)
{
// 转换到CTU坐标
int ctu_size = 1 << ctx->info.log2_max_cu_size;
int ctu_top = top / ctu_size;
int ctu_left = left / ctu_size;
int ctu_bottom = (top + height - 1) / ctu_size;
int ctu_right = (left + width - 1) / ctu_size;
// 标记隐私CTU
for (int y = ctu_top; y <= ctu_bottom; y++) {
for (int x = ctu_left; x <= ctu_right; x++) {
int ctu_idx = y * ctx->info.pic_width_in_lcu + x;
ctx->map.map_privacy[ctu_idx] = PRIVACY_FLAG;
}
}
}
/* 隐私滤波应用 */
void apply_privacy_filter(DEC_CTX *ctx)
{
// 遍历所有CTU
for (int ctu_idx = 0; ctu_idx < ctx->info.f_lcu; ctu_idx++) {
// 检查隐私标记
if (ctx->map.map_privacy[ctu_idx] == PRIVACY_FLAG) {
// 应用高斯模糊
apply_gaussian_blur(ctx->pic, ctu_idx, 5); // 5x5高斯核
// 可选:应用像素化效果
apply_pixelation(ctx->pic, ctu_idx, 8); // 8x8像素块
}
}
}
```
## 总结与最佳实践
### 解码器核心设计原则
1. **模块化设计**:
- 分离语法解析、预测、变换、滤波等模块
- 使用清晰的接口定义模块间交互
2. **状态管理**:
- 使用上下文结构(DEC_CTX)管理解码状态
- 明确区分序列级、图像级和片级状态
3. **错误恢复**:
- 分级错误处理策略
- 关键错误与可恢复错误区分
- 自动错误检测和恢复机制
4. **性能优化**:
- CTU级并行处理
- 内存访问优化
- SIMD指令加速
5. **安全与隐私**:
- 安全内存管理
- 数据加密处理
- 隐私保护算法
### 解码流程优化建议
```mermaid
graph TD
A[开始] --> B{比特流类型}
B -->|SPS| C[序列头处理]
B -->|PPS| D[参数集处理]
B -->|PH| E[图像头处理]
B -->|Slice| F[片层解码]
C --> G[序列初始化]
D --> G
E --> H[参考列表构造]
H --> F
F --> I[CTU解码]
I --> J[预测处理]
J --> K[变换量化]
K --> L[像素重建]
L --> M[环路滤波]
M --> N[图像输出]
N --> O[结束]
```