SVT-AV1编码 递归子块划分

一 函数说明

set_child_to_be_considered

核心递归函数,AV1多叉树划分的递归标记逻辑

本函数只负责递归标记哪些块需要处理,并不计算COST

cost的计算在后续阶段完成,

函数作用

这是AV1编码中实现多叉树(四叉树)递归划分的第一阶段:递归标记。

* 当一个块需要继续划分时(split_flag=TRUE),本函数会递归地将其4个子块

* 标记为需要处理,如果子块也需要继续划分,则继续递归标记子块的子块。

* 【完整递归划分流程(两个阶段)】

阶段1,递归标记,本函数。

set_child_to_be_considered() 递归标记哪些块需要处理

计算4个子块索引

标记子块需要处理consider_block = 2

如果depth_step > 1 递归标记子块子块

结果构建候选列表哪些需要测试

阶段2:构建候选数组

build_cand_block_array() 根据标记构建候选块数组

遍历预定义几何数组

根据consider block标记生成leaf data array 叶子数组

结果, leaf data array 包含所有需要处理的

阶段3 计算Cost

svt_aom_mode_decision_sb()->process_block()->md_encode_block()

遍历lead_data_array 每个

每个执行完整模式决策预测变换量化RDO

计算每个块最佳Cost存储ctx->md_blk_arr_nsq[blk_index].cost

结果每个块都有cost

阶段4:递归决策根据Cost

update_d2_decision() -> svt_aom_d2_inter_depth_block_decision()

当初里一个方形块所有4子块调用深度决策

比较父块cost vs 子块1cost + 子块2cost + 子块3 cost + 子块4 cost +划分码率

如果子块cost更低设置split_flag = TRUE 继续划分

如果父块cost更低设置split_flag = TRUE 不划分

递归向上遍历父块直到到达节点

结果确定最终划分结构

递归划分原理

AV1 划分四叉树每个块可以划分4子块

* - 128x128 -> 4个 64x64

* - 64x64 -> 4个 32x32

* - 32x32 -> 4个 16x16

* - 16x16 -> 4个 8x8

* - 8x8 -> 4个 4x4

递归标记流程本函数

1 计算当前4子块索引child_block_idx 1,2,3,4

2 每个子块标记需要处理consider block = 2

3 如果depth_step > 1 还有更深层次需要处理递归调用函数处理每个子块

4 递归终止条件尺寸 <= 4x4 或者depth_step <= 1

递归标记示例

假设处理一个64x64depth_step=2 需要处理16x16

第一层 递归 64x64

计算432x32子块索引

标记432x32子块需要处理

因为depth_step=2>1 ,递归处理每个32x32子块

2递归32x32

计算416x16子块索引

标记416x16子块需要处理

因为depth_step=1, 不再递归到达目标深度

最终结果64x64所有16x16子块标记需要处理

本函数标记不计算cost

Cost后续md_encode_block计算

最终划分决策svt_aom_d2_inter_depth_block_decision 根据cost决定

pcs: 图像控制指针

ctx: 模式决策上下文指针

results_ptr 候选数组指针

blk_index 当前MDS索引

sb_index SUperBLock尺寸

sb_size SuperBlock 尺寸

pred_depth 预测深度

pred_sq_idx 预测方形索引

depth_step 深度步长 生育需要处理的深度层数递归一次减掉1

disabllw_nsq 是否禁止方形块

二 代码注释

static void set_child_to_be_considered(PictureControlSet *pcs, ModeDecisionContext *ctx, MdcSbData *results_ptr,
                                       uint32_t blk_index, uint32_t sb_index, int32_t sb_size, int8_t pred_depth,
                                       uint8_t pred_sq_idx, int8_t depth_step, const uint8_t disallow_nsq) 
{
//递归终止条件1,4x4块没有子块,或者8x8块且禁止4x4, 直接返回
//这是递归的边界条件,防止无限递归
    if (blk_geom->sq_size <= 4 || (blk_geom->sq_size == 8 && ctx->disallow_4x4))
        return;
    //计算4个子块的索引
    //AV1的块划分是四叉树,每个块划分成4个子块,左上,右上,左下,右下
    //child_block_idx 1 第一个子块 左上的索引 = 父块索引 + d1深度偏移
    const uint32_t child_block_idx_1 = blk_index + blk_geom->d1_depth_offset;
       // child_block_idx_2: 第二个子块(右上)的索引 = 第一个子块索引 + 深度偏移
    const uint32_t child_block_idx_2 = child_block_idx_1 +
        ns_depth_offset[blk_geom->svt_aom_geom_idx][blk_geom->depth + 1];
    // child_block_idx_3: 第三个子块(左下)的索引 = 第二个子块索引 + 深度偏移
    const uint32_t child_block_idx_3 = child_block_idx_2 +
        ns_depth_offset[blk_geom->svt_aom_geom_idx][blk_geom->depth + 1];
    // child_block_idx_4: 第四个子块(右下)的索引 = 第三个子块索引 + 深度偏移
    const uint32_t child_block_idx_4 = child_block_idx_3 +
        ns_depth_offset[blk_geom->svt_aom_geom_idx][blk_geom->depth + 1];

    // 【可选优化:子块可用性检查】
    // 如果启用了深度细化控制,且需要检查子块是否可用
    // 只有当所有4个子块都在PD0阶段被测试过时,才继续递归
    if (ctx->depth_refinement_ctrls.enabled && ctx->depth_refinement_ctrls.prune_child_if_not_avail) {
        // 统计有多少个子块在PD0阶段有成本可用(即被测试过)
        const uint8_t count = ctx->cost_avail[child_block_idx_1] + ctx->cost_avail[child_block_idx_2] +
            ctx->cost_avail[child_block_idx_3] + ctx->cost_avail[child_block_idx_4];
        // LPD0(轻量级PD0)可能跳过某些块,所以如果至少有一个子块被处理过,或者使用常规PD0,才需要检查
        // 如果少于4个子块可用,说明某些子块在PD0阶段被跳过,此时不继续递归(提前终止)
        if ((count || ctx->lpd0_ctrls.pd0_level == REGULAR_PD0) && count < 4)
            return;
    }
    
    // 【标记当前块需要划分】
    // refined_split_flag[blk_index] = TRUE 表示当前块需要继续划分成子块
    results_ptr->refined_split_flag[blk_index] = TRUE;
    
    // ========== 【递归处理第一个子块(左上)】==========
    // 将第一个子块标记为需要处理(consider_block = 2 表示这是子块)
    results_ptr->consider_block[child_block_idx_1]     = 2;
    // 初始时,子块的refined_split_flag设为FALSE(后续会根据成本决定是否继续划分)
    results_ptr->refined_split_flag[child_block_idx_1] = FALSE;
    // 【递归调用】如果还有更深的层次需要处理(depth_step > 1),递归处理第一个子块
    // depth_step - 1: 每递归一次,深度步长减1,直到depth_step=1时停止递归
    if (depth_step > 1)
        set_child_to_be_considered(pcs,
                                   ctx,
                                   results_ptr,
                                   child_block_idx_1,  // 递归处理第一个子块
                                   sb_index,
                                   sb_size,
                                   pred_depth,
                                   pred_sq_idx,
                                   depth_step - 1,     // 深度步长减1
                                   disallow_nsq);
    
    // ========== 【递归处理第二个子块(右上)】==========
    results_ptr->consider_block[child_block_idx_2]     = 2;
    results_ptr->refined_split_flag[child_block_idx_2] = FALSE;
    if (depth_step > 1)
        set_child_to_be_considered(pcs,
                                   ctx,
                                   results_ptr,
                                   child_block_idx_2,  // 递归处理第二个子块
                                   sb_index,
                                   sb_size,
                                   pred_depth,
                                   pred_sq_idx,
                                   depth_step - 1,
                                   disallow_nsq);
    
    // ========== 【递归处理第三个子块(左下)】==========
    results_ptr->consider_block[child_block_idx_3]     = 2;
    results_ptr->refined_split_flag[child_block_idx_3] = FALSE;
    if (depth_step > 1)
        set_child_to_be_considered(pcs,
                                   ctx,
                                   results_ptr,
                                   child_block_idx_3,  // 递归处理第三个子块
                                   sb_index,
                                   sb_size,
                                   pred_depth,
                                   pred_sq_idx,
                                   depth_step - 1,
                                   disallow_nsq);
    
    // ========== 【递归处理第四个子块(右下)】==========
    results_ptr->consider_block[child_block_idx_4]     = 2;
    results_ptr->refined_split_flag[child_block_idx_4] = FALSE;
    if (depth_step > 1)
        set_child_to_be_considered(pcs,
                                   ctx,
                                   results_ptr,
                                   child_block_idx_4,  // 递归处理第四个子块
                                   sb_index,
                                   sb_size,
                                   pred_depth,
                                   pred_sq_idx,
                                   depth_step - 1,
                                   disallow_nsq);
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值