一 函数主要调用
复制代码
//确定是否可以从预分配缓冲区释放图片`
`//满足以下任一条件时,可以开始处理预分配缓冲区中的图片`
`1 缓冲区中有帧内帧IDR或CRA`
`2 缓冲区中的帧数达到Mini-GOP的大小`
`3 到达序列结束EOS`
`4 预测结构时低延迟P或者低延迟B,低延迟模式立即处理`
`if (enc_ctx->pre_assignment_buffer_intra_count > 0 || //如果缓冲区中有帧内帧`
`(enc_ctx->pre_assignment_buffer_count == (1 << next_mg_hierarchical_levels)) || //或者缓冲区帧数达到mini-GOP大小`
`(enc_ctx->pre_assignment_buffer_eos_flag == TRUE) || /或到达序列结束`
`(pcs->pred_structure == SVT_AV1_pred_LOW_DELAY_P) //或是低延迟P结构`
`(pcs->pred_structure == SVT_AV1_PRED_LOW_DELAY_B) //或是低延迟B结构`
`)`
`{`
`//一旦预分配缓冲区中有足够的帧,可以设置mini-GOP结构`
`set_mini_gop_structure(scs, enc_ctx, pcs, ctx);//设置Mini_gop结构,确定每个mini-GOP的起始和结束索引`
`//遍历所有mini-gop`
`for (unsigned int mini_gop_index = 0; mini_gop_index < ctx->total_number_of_mini_gops; ++mini_gop_index) {`
`//遍历每个mini-GOP`
`bool pre_assignment_buffer_first_pass_flag = true;//标记这是预分配缓冲区的第一遍处理`
`//获取mini-GOP中的第一个PCS`
` pcs = (PictureParentControlSet*)enc_ctx->pre_assignment_buffer[ctx->mini_gop_start_index[mini_gop_index]]->object_ptr; // 从预分配缓冲区中获取mini-GOP起始位置的PCS`
`//计算当前mini-gop和上一个mini-gop之间的时间层差异`
`pcs->hierarchical_layers_diff = (int32_t)enc_ctx->previous_mini_gop_hierarchical_levels - (int32_t)pcs->hierarchical_levels; // 计算层次级别差值(用于检测mini-GOP切换)`
`//如果mini-gop切换,设置init_pred_struct_position_flag为True`
`pcs->init_pred_struct_position_flag = enc_ctx->is_mini_gop_changed = (pcs->hierarchical_layers_diff != 0);//如果层次几倍差值不为0,说明mini-gop切换了`
`//跟踪最新实现的Mini-gop的层次级别数`
`enc_ctx->previous_mini_gop_hierarchical_levels = ctx->mini_gop_hierarchical_levels[mini_gop_index];//更新上一个mini-gop的层级别数`
`ctx->cut_short_ra_mg = 0;//重置随机访问mini-GOP被提前结束标志`
`}`
`}`
`
二 mini-GOP的决策
复制代码
1 set_mini_gop_structure`
`这是mini-gop决策的主函数,决定如何将预分配缓冲区中的图片组织成mini-gop`
`主要功能:`
`确定mini-gop的层次级别`
`确定mini-gop 的起始和结束索引`
`调用相关函数进行图片窗口分割`
`2 generate_picture_window_split `
`生成图片窗口分割,决定如何将图片分割成多个mini-gop`
`主要功能:`
`根据mini_gop_activity_array 决定哪些mini-gop配置可用`
`确定每个mini-gop的起始,结束索引和长度`
`确定每个mini-gop的层次级别`
`3 get_pred_struct_for_all_frames`
`为mini-gop中的所有帧获取预测结构`
`主要功能:`
`为每个帧分配预测结构指针`
`设置每个帧的层次级别`
`层次级别决定B帧的数量和位置。`
`4 update_pred_struct_and_pic_type`
`根据预测结构设置帧类型IPB`
`主要功能:`
`根据预测结构位置决定帧类型`
`层次级别越高,B帧越多`
`B帧决策机制`
`B帧决策不是单独的函数,而是通过层次结构,hierarchical levels`
`层次级别=0,只有P帧`
`层次级别=1, 少量B帧`
`层次级别=2-5:更多B帧,形成层次化B帧结构`
`svt_aom_picture_decision_kernel`
`->set_mini_gop_structure 决定mini-GOP结构`
`->initialize_mini_gop_activity_array 初始化mini-gop活动数组`
`->generate_picture_window_split 生成图片窗口分割`
`->handle_incomplete_picture_window_map 处理不完整的图片窗口`
`->get_pred_struct_for_all_frames 为所有帧获取预测结构`
`->update_pred_struct_and_pic_type 根据预测结构设置IPB类型`
`
三 核心决策函数 calc_mini_gop_activity
复制代码
功能:计算并决策mini-GOP的活动度,决定是使用6层,还是5层的mini-GOP结构`
`这个函数是动态mini-GOP决策核心函数,通过比较6层结构和5层结构的活动度,复杂度,运动向量等信息,来决定使用哪种结构,6层结构可以提供更好的压缩效率,需要更多的参考帧和更复杂的预测结构,5层结构更简单,压缩效率可能略低。`
`决策逻辑:`
`如果6层结构的活动度很高,两个5层子结构的活动度相似且较低,则倾向于使用6层结构,`
`如果6层结构的距离较大,而两个5层结构的距离较小,则倾向使用6层结构,如果两个5层结构都有较高的zoom` `out活动,则倾向于使用6层结构。`
`输入参数:`
`ctx` `图像决策上下文指针,包含mini-gop活动数组等状态信息`
`enc_ctx` `编码上下文指针,包含mini-gop计数,前一个mini-gop的层次级别等信息。`
`top_layer_idx` `顶层,在mini-gop活动数组中的索引`
`top_layer_dist` `顶层的平均距离,通过early` `HME计算得出`
`top_layer_perc_active` `顶层6层结构,的活动度百分比0-100,表示有运动向量的块的比例`
`top_layer_perc_cplx` `顶层` `6层结构,的复杂度百分比0-100,基于运动估计的失真`
`sub_layer_idx0` `第一个字层5层结构,在mini-gop活动数组中的索引`
`sub_layer_dist0` `第一个字层` `5层结构的平均距离distortion`
`sub_layer_perc_active` `第一个字层` `5层结构,的活动度百分比`
`sub_layer_perc_cplx` `第一个字层` `5层结构的复杂度百分比`
`sub_layer_idx1` `第二个字层` `5层结构,在mini-gop活动数组中的索引`
`sub_layer_dist1` `第二个子层` `5层结构的平均距离distortion`
`sub_layer1_perc_active` `第二个子层` `的活动度百分比`
`sub_layer1_perc_cplx` `第二个字层` `5层结构的负责度百分比`
`top_layer_mv_in_out_count` `顶层6层结构,的运动向量进出计算当前未使用`
`sub_layer_mv_in_out_count1` `第一个子层` `5层结构的运动向量进出计算,用于检测zoom` `out活动`
`sub_layer_mv_in_out_count2` `第二个子层5层结构的运动向量进出计算,用于检测zoom out活动`
`返回值`
`决策结果`
`如果满足条件,将top_layer_idx对应的活动数组项设置为TRUE` `使用6层结构`
`同时将sub_layer_idx0` `和sub_layer_idx1` `对应的活动更数组项设置为False`
`如果不满足条件,保持活动数组不变` `默认使用5层结构`
`static void` `calc_mini_gop_activity(`
`PictureDecisionContext*` `ctx,` `//图像决策上下文指针,包含`
`EncodeContext*` `enc_ctx,` `//编码上下文指针,包含Mini-GOP计数,前一个mini-gop的层次级别等信息`
`uint64_t` `top_layer_idx,` `//顶层` `6层结构,在mini-gop活动数组中的索引`
`uint64_t` `top_layer_dist;//顶层` `6层结构,的活动度百分比` `0` `-100,` `表示有运动向量的块的比例`
`uint8_t` `top_layer_perc_active,` `//顶层` `6层结构,的活动度百分比0` `-` `100,表示有运动向量的块的比例`
`uint8_t` `top_layer_perc_cplx,` `//顶层` `6层结构,的复杂度百分比0-100。基于运动估计的失真`
`uint64_t` `sub_layer_idx0,` `//第一个子层在mini-gop活动数组中的索引`
`uint8_t` `sub_layer0_perc_active,` `//第一个子层` `5层结构` `的活动度百分比`
`uint8_t sub_layer0_perc_cplx,` `//第一个子层复杂度百分比`
`uint64_t sub_layer_idx1, //第二个子层` `5层结构,在mini-gop活动数组中的索引`
`uint64_t sub_layer_dist1,` `//第二个子层` `5层结构,的平均距离distortion`
`uint8_t sub_layer1_perc_active, //第二个子层` `5层结构的活动度百分比`
`uint8_t sub_layer1_perc_cplx,` `//第二个子层的复杂度百分比`
`int16_t top_layer_mv_in_out_count, //顶层` `6层结构,的运动向量进出计数,当前未使用,用于未来扩展`
`int16_t sub_layer_mv_in_out_count1,` `//第二个子层` `5层结构,的运动向量进出计数,用于检测zoom out,` `活动`
`int16_t sub_layer_mv_in_out_count2` `//第二个子层` `5层结构,的运动向量进出计数,用于检测zoom out` `活动`
`)` `{`
`top_layer_mv_in_out_count;//标记top_layer_mv_in_out_count` `参数当前未使用,避免编译器警告`
`//计算偏置` `bias值,用于在比较6层和5层结构时给6层结构一定的优势`
`//偏置的作用是模拟6层结构在码率方面的优势,因为6层结构可以提供更好的压缩率`
`//偏置是前一个mini-gop结构的函数,目的是减少在同一个GOP内的切换`
`//除非与前一个mini-GOP相比有显著变化,否则将保持6层结构`
`//todo:` `使偏置成为预设的函数,预设越高,偏置越倾向于不使用6层结构`
`int bias` `= (enc_ctx->mini_gop_cnt_per_gop > 1 && enc_ctx->previous_mini_gop_hierarchical_levels == 5)` `? 25:75;`
`//如果当前GOP中已经有多个mini-gop,且前一个mini-gop使用的5层结构,则偏置设为25` `更倾向于保持5层结构`
`//否则偏置设为75,更倾向于使用6层结构,因为6层结构在码率方面有优势`
`//条件1,检查活动度的分布情况`
`//这个条件要求:`
`//1` `顶层` `6层结构的活动度很高` `>=` `95%,` `说明6层结构中有很多块运动`
`//2` `两个子层` `5层结构,的活动度不能差异太大,不能一个很高` `>= 95%,而另一个很低` `<` `75%`
`//这样可以确保两个5层子结构的活动度相似,避免因为活动度差异导致的不平衡。`
`const bool` `cond1` `= top_layer_perc_active` `>=` `95 &&` `//顶层活动度必须很高` `>=` `95%`
`!(sub_layer0_perc_active >= 95 && sub_layer1_perc_active < 75)` `&&` `//不能是,第一个子层很高` `>= 95%.` `而第二个子层很低`
`!(sub_layer0_perc_active < 75 && sub_layer1_perc_active >= 95); //不能是,第一个子层很低` `< 75%,而第二个子层很高,` `>= 95%`
`//这个条件的目的是确保两个5层子结构的活动度相似,如果差异太大,说明不适合使用6层结构`
`//条件2` `cond2,` `检查距离,复杂度和偏置的综合情况`
`//这个条件要求:`
`//1 顶层` `6层结构,的距离较大` `> LOW_DIST_TH` `= 512,说明6层结构的跨度较大`
`//2两个子层` `5层结构,的距离都较小` `< HIGH_DIST_TH` `= 4608` `说明子层内部的相关性较高`
`//3` `顶层有复杂度` ` >` `0 说明6层结构有一定的编码复杂度`
`//4 两个子层的复杂度都较低` `<` `25%,` `说明5层结构的编码复杂度较低`
`//5 两个子层的平均距离小于顶层结构在码率方面的优势,通过偏置来模拟`
`//这个条件考虑了6层结构在码率方面的优势,通过偏置来模拟`
`//如果 (sub_layer_dist0 + sub_layer_dist1) / 2 < (bias * top_layer_dist) / 100`
`//说明即使考虑了6层结构的码率优势,5层结构的平均距离仍然更小,因此倾向于使用6层结构`
`const bool` `cond2` `= top_layer_dist > LOW_DIST_TH` `&& //顶层距离必须较大` `> 512,说明6层结构宽度大`
`sub_layer_dist0` `< HIGH_DIST_TH` `&& //第一个子层距离必须较小,` `说明子层内部相关性高`
`sub_layer_dist1 < HIGH_DIST_TH &&` `//第二个子层距离必须较小,说明子层内部相关性高`
`top_layer_perc_cplx` `> 0 &&//顶层必须有复杂度,说明6层结构有一定的编码复杂度`
`sub_layer0_perc_cplx` `< 25` `&& //第一个子层复杂度必须较低(< 25%),说明5层结构编码复杂度低`
`sub_layer1_perc_cplx` `<` `25` `&&` `//第二个子层复杂度必须较低` `< 25%,说明5层结构编码复杂度低`
`(sub_layer_dist0 + sub_layer_dist1)/2)` `<` `(bias * top_layer_dist)/100;` `//两个子层的平均距离必须小于顶层的距离乘以偏置百分比`
`//这个条件买的目的是,如果6层结构的跨度大,但是两个5层子结构的内部相关性高且复杂度低`
`//且即使考虑了6层结构的码率优势,5层结构的平均距离仍然较小,则倾向于使用6层结构`
`//条件3,cond3,` `检查zoom` `out活动,运动向量向外的情况`
`//这个条件要求:`
`//1 两个子层的最小运动向量进出计算都较大` `> 40,` `说明两个子层都有较多的zoom` `out活动`
`//2两个子层的最大运动向量进出计算也较大` `> 55, 进一步确认zoom out活动的存在`
`//zoom out活动通常发生在场景中有物体远离相机或场景整体缩小的情形`
`//这种情况下,使用6层结构更合适,因为6层结构可以更好处理这种大范围的运动`
`const bool cond3 = MIN(sub_layer_mv_in_out_count1, sub_layer_mv_in_out_count2)` `>` `40` `&&` `//两个子层的最小运动向量进出计数必须较大` `> 40`
`MAX(sub_layer_mv_in_out_count1, sub_layer_mv_in_out_count2)` `> 55;//两个子层的最大运行向量进出计数必须较大` `> 55`
`//这个条件的目的是检测` `zoom out活动,如果两个子层都有较多的zoom out活动,则倾向于使用6层结构`
`//最终决策:如果满足条件1,并且满足条件2或者条件3中的任意一个`
`if (convd1 && (cond2 || cond3))` `{`
`/如果满足条件1,并且满足条件2或者条件3中的任意一个`
`/将顶层` `层结构,的活动数组设置为TRUE,表示使用6层结构`
`ctx->mini_gop_activity_array[top_layer_idx]` `= TRUE;`
`//将第一个子层` `层结构` `的活动数组项设置为FALSE,表示不使用5层结构`
`ctx->mini_gop_activity_array[sub_layer_idx0]` `=` `FALSE;`
`//将第二层` `层5结构,的活动数组项设置为FALSE,表示不使用5层结构`
`ctx->mini_gop_activity_array[sub_layer_idx1]` `= FALSE;`
`}`
`//如果条件不满足,则保持活动数组不变,默认使用5层结构因为5层结构在活动数组中的初始值可能是TRUE`
`}`
`
四 调用关系
复制代码
eval_sub_mini_gop()`
`->early_hme()二分计算cost和统计信息`
`calc_mini_gop_activity()->根据上面计算的结果,判断minigo结构`
`eval_sub_mini_gop(//二分判断`
` ctx,`
` enc_ctx,`
` L6_INDEX,`
` L5_0_INDEX,`
` L5_1_INDEX,`
` start_pcs,`
` mid_pcs,`
` end_pcs);`
`