libaom 源码分析:av1_get_one_pass_rt_params 函数分析
函数作用该函数通过根据帧类型关键帧或帧间帧、活动块检测、场景检测、分辨率调整等动态调整编码参数确保编码过程在实时模式下高效进行。在支持 SVC可扩展视频编码的情况下还会根据不同的时域和空域层配置调整参考帧结构和帧类型。通过实时的码率控制和分辨率调整使得编码器能够根据网络带宽和设备条件调整输出质量和压缩率。函数调用关系图is_one_pass_rt_params 函数此函数用于检查编码器是否使用特定的实时参数配置/*!\endcond *//*!\brief Check if the current stage has statistics * *\ingroup two_pass_algo * * \param[in] cpi Top - level encoder instance structure * * \return 0 if no stats for current stage else 1 * 处于单pass速率控制模式兵器没有启用前瞻式编码 */staticINLINEinthas_no_stats_stage(constAV1_COMP*constcpi){assert(IMPLIES(!cpi-ppi-lap_enabled,cpi-compressor_stageENCODE_STAGE));return(cpi-oxcf.passAOM_RC_ONE_PASS!cpi-ppi-lap_enabled);}/*!\cond * 单pass 速率控制模式并且没有启用前瞻式编码、且是实时模式 REATIME并确保 lag_in_frames(编码器能够提前缓存的帧数)为 0 */staticINLINEintis_one_pass_rt_params(constAV1_COMP*cpi){returnhas_no_stats_stage(cpi)cpi-oxcf.modeREALTIMEcpi-oxcf.gf_cfg.lag_in_frames0;}av1_get_one_pass_rt_params 函数SVC 配置支持启用了svc更新时域层的帧率、恢复层的上下文。帧类型判断根据当前帧的类型关键帧或帧间帧设置视频编码的参数并根据 SVC可伸缩视频编码 的状态调整时域层和空间层的配置。关键帧在编码过程中起着重要的作用它是视频的参考点而帧间帧则通过预测与参考帧进行编码从而提高编码效率。在SVC 模式下帧的处理还考虑了多层次的编码结构确保空间和时域层的兼容性。活动块检测和场景检测活动块检测确保对静止帧进行优化减少不必要的编码资源消耗。场景检测提高编码器在场景切换或内容变化时的响应能力特别是在实时编码的多层SVC 中优先处理基准层的场景变化。动态调整分辨率根据不同的状态调整分辨率确保编码器可以实时适应带宽变化或其他条件。例如在实时编码场景中如果视频内容需要更多的压缩或质量变化时分辨率会动态调整。设置 GF 间隔和更新标识基于一定的条件更新GF基准间隔GOP interval。GF间隔控制关键帧Key Frame和插值帧Inter Frame的生成频率它在视频编码中非常重要影响视频的压缩效率和质量。根据不同速率模式和帧类型计算帧目标大小是根据不同的编码模式和帧类型来计算目标帧大小并设置相关的编码参数。它考虑了恒定比特率模式CBR、可变比特率模式VBR和量化模式CQ。帧目标更新设置当前帧的目标大小。SVC 固定模式处理处理 KSVC 固定模式 下的特定逻辑即在空间增强层高分辨率层对于非关键帧的情况下移除 跨层参考帧的预测特别是移除 金帧参考。voidav1_get_one_pass_rt_params(AV1_COMP*cpi,FRAME_TYPE*constframe_type,constEncodeFrameInput*frame_input,unsignedintframe_flags){RATE_CONTROL*constrccpi-rc;PRIMARY_RATE_CONTROL*constp_rccpi-ppi-p_rc;AV1_COMMON*constcmcpi-common;GF_GROUP*constgf_groupcpi-ppi-gf_group;SVC*constsvccpi-svc;ResizePendingParams*constresize_pending_paramscpi-resize_pending_params;inttarget;constintlayerLAYER_IDS_TO_IDX(svc-spatial_layer_id,svc-temporal_layer_id,svc-number_temporal_layers);//启用了svc更新时域层的帧率、恢复层的上下文if(cpi-ppi-use_svc){av1_update_temporal_layer_framerate(cpi);av1_restore_layer_context(cpi);}cpi-ppi-rtc_ref.bias_recovery_frameset_flag_rps_bias_recovery_frame(cpi);// Set frame type.if(set_key_frame(cpi,frame_flags)){//关键帧处理*frame_typeKEY_FRAME;p_rc-this_key_frame_forcedcm-current_frame.frame_number!0rc-frames_to_key0;rc-frames_to_keycpi-oxcf.kf_cfg.key_freq_max;p_rc-kf_boostDEFAULT_KF_BOOST_RT;gf_group-update_type[cpi-gf_frame_index]KF_UPDATE;gf_group-frame_type[cpi-gf_frame_index]KEY_FRAME;gf_group-refbuf_state[cpi-gf_frame_index]REFBUF_RESET;if(cpi-ppi-use_svc){if(cm-current_frame.frame_number0)av1_svc_reset_temporal_layers(cpi,1);//必要是重置 svc 的时域层svc-layer_context[layer].is_key_frame1;}rc-frame_number_encoded0;cpi-ppi-rtc_ref.non_reference_frame0;}else{//帧间帧处理*frame_typeINTER_FRAME;gf_group-update_type[cpi-gf_frame_index]LF_UPDATE;//标记当前帧为层内更新表示这是一帧普通的非关键帧gf_group-frame_type[cpi-gf_frame_index]INTER_FRAME;//设置当前帧为帧间帧gf_group-refbuf_state[cpi-gf_frame_index]REFBUF_UPDATE;//更新参考帧缓冲区的状态表示帧间帧可能会依赖于之前的参考帧//开启 svc编码时需要重新配置参考帧if(cpi-ppi-use_svc){LAYER_CONTEXT*lcsvc-layer_context[layer];lc-is_key_framesvc-spatial_layer_id0?0:svc-layer_context[svc-temporal_layer_id].is_key_frame;//当前层的当前帧是否关键帧判断// If the user is setting the reference structure with// set_ref_frame_config and did not set any references, set the// frame type to Intra-only.if(cpi-ppi-rtc_ref.set_ref_frame_config){intno_references_set1;for(inti0;iINTER_REFS_PER_FRAME;i){if(cpi-ppi-rtc_ref.reference[i]){no_references_set0;break;}}// Set to intra_only_frame if no references are set.// The stream can start decoding on INTRA_ONLY_FRAME so long as the// layer with the intra_only_frame doesnt signal a reference to a slot// that hasnt been set yet.if(no_references_set)*frame_typeINTRA_ONLY_FRAME;}}}//活动块检测如果当前帧没有任何活动区域比如静止内容编码器可以减少资源消耗或选择更低的比特率编码if(cpi-active_map.enabledcpi-rc.percent_blocks_inactive100){rc-frame_source_sad0;rc-avg_source_sad(3*rc-avg_source_sadrc-frame_source_sad)2;rc-percent_blocks_with_motion0;rc-high_source_sad0;}elseif(cpi-sf.rt_sf.check_scene_detectionsvc-spatial_layer_id0){//场景检测发生场景切换时会在场景切换点调整比特率分配或参考帧结构只准在空域 0 层进行检测if(rc-prev_coded_widthcm-widthrc-prev_coded_heightcm-height){rc_scene_detection_onepass_rt(cpi,frame_input);//场景检测函数}else{aom_free(cpi-src_sad_blk_64x64);cpi-src_sad_blk_64x64NULL;}}//动态调整分辨率仅在当空间层处理动态调整分辨率且时域 ID 为 0// Check for dynamic resize, for single spatial layer for now.// For temporal layers only check on base temporal layer.if(cpi-oxcf.resize_cfg.resize_modeRESIZE_DYNAMIC){if(svc-number_spatial_layers1svc-temporal_layer_id0)dynamic_resize_one_pass_cbr(cpi);//动态跳帧分辨率1/4分辨率、1/2分辨率、原始分辨率if(rc-resize_stateTHREE_QUARTER){resize_pending_params-width(3cpi-oxcf.frm_dim_cfg.width*3)2;resize_pending_params-height(3cpi-oxcf.frm_dim_cfg.height*3)2;}elseif(rc-resize_stateONE_HALF){resize_pending_params-width(1cpi-oxcf.frm_dim_cfg.width)1;resize_pending_params-height(1cpi-oxcf.frm_dim_cfg.height)1;}else{resize_pending_params-widthcpi-oxcf.frm_dim_cfg.width;resize_pending_params-heightcpi-oxcf.frm_dim_cfg.height;}}elseif(is_frame_resize_pending(cpi)){resize_reset_rc(cpi,resize_pending_params-width,resize_pending_params-height,cm-width,cm-height);//检查到当前帧需要调整分辨率即此时分辨率调整已经挂起则更新速率控制参数适应新的分辨率}// Set the GF interval and update flag.if(!rc-rtc_external_ratectrl)set_gf_interval_update_onepass_rt(cpi,*frame_type);//设置GF帧间隔和更新标识// Set target size. 根据不同码控模式和帧类型计算不同帧目标大小if(cpi-oxcf.rc_cfg.modeAOM_CBR){if(*frame_typeKEY_FRAME||*frame_typeINTRA_ONLY_FRAME){targetav1_calc_iframe_target_size_one_pass_cbr(cpi);}else{targetav1_calc_pframe_target_size_one_pass_cbr(cpi,gf_group-update_type[cpi-gf_frame_index]);}}else{if(*frame_typeKEY_FRAME||*frame_typeINTRA_ONLY_FRAME){targetav1_calc_iframe_target_size_one_pass_vbr(cpi);}else{targetav1_calc_pframe_target_size_one_pass_vbr(cpi,gf_group-update_type[cpi-gf_frame_index]);}}if(cpi-oxcf.rc_cfg.modeAOM_Q)rc-active_worst_qualitycpi-oxcf.rc_cfg.cq_level;av1_rc_set_frame_target(cpi,target,cm-width,cm-height);//设置当前帧的目标大小rc-base_frame_targettarget;cm-current_frame.frame_type*frame_type;//处理 KSVC 固定模式 下的特定逻辑即在空间增强层高分辨率层对于非关键帧的情况下移除 跨层参考帧的预测特别是移除 金帧参考。// For fixed mode SVC: if KSVC is enabled remove inter layer// prediction on spatial enhancement layer frames for frames// whose base is not KEY frame.if(cpi-ppi-use_svc!svc-use_flexible_modesvc-ksvc_fixed_modesvc-number_spatial_layers1!svc-layer_context[layer].is_key_frame){ExternalFlags*constext_flagscpi-ext_flags;ext_flags-ref_frame_flags^AOM_GOLD_FLAG;}}