04-矩阵变换.md

本文详细介绍了如何使用WebGL进行图形的平移、旋转和缩放操作,包括向量加法、旋转公式、矩阵运算等核心知识点,并提供了GLSL ES着色器和JavaScript代码示例,帮助读者掌握图形变换的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

变换有三种状态:平移、旋转、缩放。

当我们变换一个图形时,实际上就是在移动这个图形的所有顶点。

课堂目标

  1. 掌握图形变换的三种方式。
  2. 可以对图像进行复合变换。

知识点

  1. 平移
  2. 旋转
  3. 缩放

第一章 平移

对图形的平移就是对图形所有顶点的平移。

1-举个例子

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Z5oHcLg-1622251777161)(images/image-20210315105508042.png)]

已知:

  • 顶点p(x,y,z)
  • 在x、y、z 三个方向上,分别将点p 移动tx、ty、tz

求:点p 移动后的位置p’(x’,y’,z’)

解:

x'=x+tx
y'=y+ty
z'=z+tz

如果这个图形中并非只有一个顶点,而是有三个,或者更多,那么所有的顶点也是按照同样原理进行位移。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OnA4LV7O-1622251777163)(images/image-20201016183607576.png)]

2-向量加法

在实际代码中,我们要有一个向量的概念。

比如 (x,y,z) ,我们既可以说它是一个顶点位置,也可以说它是一个向量。

至于 (x,y,z) 到底是什么,要看我们拿它做什么。

比如,把点p(x,y,z) 作为点位时,那它就是点p(x,y,z)

我们把p 的移动距离tx、ty、tz 封装成一个对象pt(tx,ty,tz),那么pt 就是一个向量,一个为点p 指明移动方向和距离的向量。

因此:点p 的移动结果 p’ 就可以这么写:

p'=p+pt

由上可知,顶点的位移就是向量的加法。

3-代码实现

3-1-GLSL ES 语言里的向量运算

在GLSL ES 语言里,是可以直接进行向量运算。

下面的顶点着色器里的代码:

attribute vec4 a_Position;
vec4 translation=vec4(0,0.2,0,0);
void main(){
   
   
    gl_Position = a_Position+translation;
}
  • a_Position 是原始点位,属于attribute 变量
  • translation 是顶点着色器里的私有变量,没有向外部暴露,属于4维向量
  • a_Position+translation 便是着色器内的向量加法,这里是对原始点位进行位移

之后,我们也可以把translation 变量暴露出去,让js可以修改图形位置:

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform vec4 u_Translation;
    void main(){
     
     
        gl_Position = a_Position+u_Translation;
    }
</script>

在js 中修改uniform 变量的方法,我们之前已经说过:

const u_Translation=gl.getUniformLocation(gl.program,'u_Translation');
gl.uniform4f(u_Translation,0,0.5,0,0);

整体代码:

<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform vec4 u_Translation;
    void main(){
     
     
        gl_Position = a_Position+u_Translation;
    }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
    void main(){
     
     
        gl_FragColor=vec4(1,1,0,1);
    }
</script>
<script type="module">
    import {
     
     initShaders} from '../jsm/Utils.js';

    const canvas = document.getElementById('canvas');
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;
    const gl = canvas.getContext('webgl');

    const vsSource = document.getElementById('vertexShader').innerText;
    const fsSource = document.getElementById('fragmentShader').innerText;
    initShaders(gl, vsSource, fsSource);

    const vertices=new Float32Array([
        0,  0.1,
        -0.1,-0.1,
        0.1, -0.1
    ])

    const vertexBuffer=gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
    const a_Position=gl.getAttribLocation(gl.program,'a_Position');
    gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
    gl.enableVertexAttribArray(a_Position);

    const u_Translation=gl.getUniformLocation(gl.program,'u_Translation');
    gl.uniform4f(u_Translation,0,0.5,
int dec_cnk(DEC_CTX * ctx, COM_BITB * bitb, DEC_STAT * stat) { COM_BSR *bs; COM_PIC_HEADER *pic_header; COM_SQH * sqh; #if SVAC_SECURITY_PARAM_SET COM_SEC_PARA_SET* sec_para_set; #endif #if SVAC_AUTHENTICATION COM_AUTH_DATA* auth_data; #endif #if HLS_OPT_PPS COM_PIC_PARA_SET * pps; #endif 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; #if HLS_OPT_PPS pps = &ctx->info.pps[ctx->info.pps_count]; #endif pic_header = &ctx->info.pic_header; shext = &ctx->info.shext; cnkh = &ctx->info.cnkh; #if SVAC_SECURITY_PARAM_SET sec_para_set = &ctx->info.sec_para_set; #endif #if SVAC_AUTHENTICATION auth_data = &ctx->info.auth_data; #endif /* set error status */ 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 /* bitstream reader initialization */ com_bsr_init(bs, bitb->addr, bitb->ssize, NULL); SET_SBAC_DEC(bs, &ctx->sbac_dec); #if SVAC_NAL if (bs->cur[3] == SVAC_SPS) #else if (bs->cur[3] == 0xB0) #endif { #if LIB_PIC_MIXBIN int need_update = COM_CT_CRR_SLICE == cnkh->ctype || COM_CT_CRR_SLICE_IMCOPLETE == cnkh->ctype #if SVAC_SECURITY_PARAM_SET || cnkh->ctype == COM_CT_SEC_PARA_SET #endif ; #endif #if HLS_OPT_PPS ctx->info.pps_count = 0; memset(ctx->info.pps, 0, sizeof(ctx->info.pps)); #endif cnkh->ctype = COM_CT_SQH; ret = dec_eco_sqh(bs, sqh); com_assert_rv(COM_SUCCEEDED(ret), ret); #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); #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); #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 #if HLS_OPT_PPS else if (bs->cur[3] == SVAC_PPS) { cnkh->ctype = COM_CT_PPS; ret = dec_eco_pps(bs, sqh, pps); ctx->info.pps_count++; assert(ctx->info.pps_count <= MAX_PPS_NUM); com_assert_rv(COM_SUCCEEDED(ret), ret); #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 #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); 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); #if HLS_OPT_PPS pps = &ctx->info.pps[ctx->info.normal_pps_idx]; #endif 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; /* decode slice header */ pic_header->low_delay = sqh->low_delay; int need_minus_256 = 0; #if HLS_OPT_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 ret = dec_eco_pic_header(bs, pic_header, sqh, &need_minus_256); #endif 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 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)); 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)); 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 #if HIGH_LEVEL_PRIVACY memset(ctx->ctx_privacy_data.region_max_num, 0, sizeof(int) * 10); #endif #if EXTENSION_USER_DATA && WRITE_MD5_IN_USER_DATA extension_and_user_data(ctx, bs, 1, sqh, pic_header); #endif com_constrcut_ref_list_doi(pic_header); //add by Yuqun Fan, init rpl list at ph instead of sh #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); /* reference picture lists construction */ ret = com_picman_refp_rpl_based_init_decoder(&ctx->dpm, pic_header, ctx->refp); #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); } #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); #if HLS_OPT_PPS pps = &ctx->info.pps[ctx->info.libpic_pps_idx]; #endif 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)); 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)); 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 ); 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)); } 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); 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 } #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.normal_sqh, sizeof(COM_SQH)); ret = sequence_init(ctx, sqh); com_assert_rv(COM_SUCCEEDED(ret), ret); #if HLS_OPT_PPS pps = &ctx->info.pps[ctx->info.normal_pps_idx ]; #endif 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 int is_patch_l = sqh->library_stream_flag && sqh->library_picture_mixbin_flag && ctx->info.sqh.library_picture_mode_index != 1; #else int is_patch_l = sqh->library_stream_flag && sqh->library_picture_mixbin_flag; #endif #endif cnkh->ctype = COM_CT_SLICE; #if SVAC_NAL if (bs->cur[3] == SVAC_IDR) picman_reset_dpb(&ctx->dpm); #endif #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); }; 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); #endif #if MULTI_LAYER_FRAMEWORK assert(layer_id == ctx->info.pic_header.layer_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 /* initialize slice */ 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 /* get available frame buffer for decoded image */ 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 /* get available frame buffer for decoded image */ 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; #endif #if CU_LEVEL_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 /* decode slice layer */ #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 /* deblocking filter */ #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); com_assert_rv(COM_SUCCEEDED(ret), ret); } #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 filter */ if (ctx->info.sqh.sample_adaptive_offset_enable_flag) { ret = dec_sao_avs2(ctx); com_assert_rv(ret == COM_OK, ret); } /* esao filter */ #if ESAO if (ctx->info.sqh.esao_enable_flag) { ret = dec_esao(ctx); com_assert_rv(ret == COM_OK, ret); } #endif #if CCSAO /* ccsao filter */ if (ctx->info.sqh.ccsao_enable_flag) { ret = dec_ccsao(ctx); 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); com_assert_rv(COM_SUCCEEDED(ret), ret); } /* MD5 check for testing encoder-decoder match*/ 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; /* reset flag */ } #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; while ((stream_p - (u8 *)bitb->addr3_beg) < stream_size) { unsigned int nal_size = 1; while (!(stream_p[nal_size + 0] == 0x00 && stream_p[nal_size + 1] == 0x00 && stream_p[nal_size + 2] == 0x00 && stream_p[nal_size + 3] == 0x01) && !(stream_p[nal_size + 0] == 0x00 && stream_p[nal_size + 1] == 0x00 && stream_p[nal_size + 2] == 0x01 && stream_p[nal_size - 1] != 0)) { if (!((stream_p - (u8 *)bitb->addr3_beg) < stream_size - nal_size - 4)) { nal_size += 4; break; } nal_size++; } if (stream_p[4] != (0x0c) && stream_p[3] != (0x0c) //sei && stream_p[4] != (0x20) && stream_p[3] != (0x20) //eocvs && stream_p[4] != (0x16) && stream_p[3] != (0x16) //eos #if SVAC_SECURITY_PARAM_SET && stream_p[4] != (0x52) && stream_p[3] != (0x52) //sec #endif #if SVAC_AUTHENTICATION && stream_p[4] != (0x14) && stream_p[3] != (0x14) //auth #endif ) { int start_code_len = 4; if (stream_p[0] == 0x00 && stream_p[1] == 0x00 && stream_p[2] == 0x01) { start_code_len = 3; } unsigned int raw_nal_size = nal_size - start_code_len; memcpy(buffer_p, stream_p + start_code_len, raw_nal_size); buffer_p += raw_nal_size; } stream_p += nal_size; } int stream_total_size = (int)(buffer_p - concat_buf); 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; /* reset flag */ if (concat_buf) free(concat_buf); } bitb->addr3 = bitb->addr3_beg; #endif #if PIC_PAD_SIZE_L > 0 /* expand pixels to padding area */ 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 /* put decoded picture to 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 ) { 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 { 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 ); #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; }
最新发布
07-16
<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[结束] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值