x264 slicetype选择

x264 如何判断当前帧要不要编码出IDR

x264_slicetype_analyse()->scenecut() 

判断场景是否切换了,这种是opengop的方式,

还有一种是固定gop的方式,gop之间的帧数是固定的,不是由scenecut决定的。

看下scenecut函数实现

static int scenecut_internal( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int real_scenecut )
{
    x264_frame_t *frame = frames[p1];

    /* Don't do scenecuts on the right view of a frame-packed video. */
    if( real_scenecut && h->param.i_frame_packing == 5 && (frame->i_frame&1) )
        return 0;

    slicetype_frame_cost( h, a, frames, p0, p1, p1 );

    int icost = frame->i_cost_est[0][0];// 向前的参考
    int pcost = frame->i_cost_est[p1-p0][0];// 计算两个前后参考帧之间的残差
    float f_bias;
    int i_gop_size = frame->i_frame - h->lookahead->i_last_keyframe;
    float f_thresh_max = h->param.i_scenecut_threshold / 100.0;// scenecut_hold 默认 40
    /* magic numbers pulled out of thin air */
    float f_thresh_min = f_thresh_max * 0.25;
    int res;

    if( h->param.i_keyint_min == h->param.i_keyint_max )
        f_thresh_min = f_thresh_max;
    if( i_gop_size <= h->param.i_keyint_min / 4 || h->param.b_intra_refresh )
        f_bias = f_thresh_min / 4;
    else if( i_gop_size <= h->param.i_keyint_min )
        f_bias = f_thresh_min * i_gop_size / h->param.i_keyint_min;
    else
    {
        f_bias = f_thresh_min
                 + ( f_thresh_max - f_thresh_min )
                 * ( i_gop_size - h->param.i_keyint_min )
                 / ( h->param.i_keyint_max - h->param.i_keyint_min );
    }

// 上面根据不同的情况计算 f_bias ,如果f_bias 为1,则一定是I帧

//比如当

    res = pcost >= (1.0 - f_bias) * icost;// 帧间cost 大于带权的帧内cost ,则为场景切换了
    if( res && real_scenecut )
    {
        int imb = frame->i_intra_mbs[p1-p0];
        int pmb = NUM_MBS - imb;
        x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%d Pcost:%d ratio:%.4f bias:%.4f gop:%d (imb:%d pmb:%d)\n",
                  frame->i_frame,
                  icost, pcost, 1. - (double)pcost / icost,
                  f_bias, i_gop_size, imb, pmb );
    }
    return res;
}

看这个函数调用的地方

if( IS_X264_TYPE_AUTO_OR_I( frames[1]->i_type ) &&
        h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) )
    {// 
        if( frames[1]->i_type == X264_TYPE_AUTO )
            frames[1]->i_type = X264_TYPE_I;
        return;
    }

 

/* Check scenecut on the first minigop. */
        for( int j = 1; j < num_bframes+1; j++ )
        {
            if( frames[j]->i_forced_type == X264_TYPE_AUTO && IS_X264_TYPE_AUTO_OR_I( frames[j+1]->i_forced_type ) &&
                h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1, 0, orig_num_frames, i_max_search ) )
            {
                frames[j]->i_type = X264_TYPE_P;
                num_analysed_frames = j;
                break;
            }
        }

为什么上面两个都是scenecut条件成立,但是设置的slice 类型不同呢?

注意看上面一个调用的地方,设置的是p1 的slice 类型,也就是后面一帧,下面这个是判断j + 1帧是场景切换后,设置j帧为P帧。

因为一个miniGOp必须以P帧结尾,B帧会前后参考,下一个gop的I帧不能被前面的B帧参考。

### x264 源码中 GOP 的实现详解 在视频编码领域,GOP(Group of Pictures)是一个重要的概念,表示一组连续的画面帧序列。对于 H.264 编码器而言,x264 是其开源实现之一,在源码层面实现了 GOP 结构及其控制逻辑。 #### 1. GOP 定义与作用 GOP 是由一系列 I 帧、P 帧和 B 帧组成的结构化单元。I 帧作为关键帧,不依赖其他帧即可解码;P 帧基于前一帧预测生成;B 帧则可以利用前后两帧的信息进行双向预测。这种设计显著降低了存储空间需求并提高了压缩效率[^1]。 #### 2. 参数配置中的 GOP 控制 通过命令行工具或者 API 接口调用时,可以通过 `--keyint` 和 `--min-keyint` 来设定最大及最小的关键帧间隔长度。这直接影响到最终输出流里的 GOP 长度以及复杂程度: - **`--keyint`**: 设定两个相邻 I 帧之间的最大距离。 - **`--min-keyint`**: 规定了场景切换检测触发新 I 帧所需的最短时间跨度。 这些参数共同决定了实际应用过程中 GOP 的具体表现形式。 #### 3. 源码分析:GOP 架构的核心部分 深入研究 x264 的 C 源文件可以看到如下几个重要模块参与了整个过程: ##### (1) Rate Control Module (`ratecontrol.c`) 该模块负责管理比特率分配策略,其中包括如何安排不同类型帧的位置关系来构建合理的 GOP 序列。例如函数 `x264_ratecontrol_init()` 初始化速率控制器实例,并依据用户指定的目标质量等级调整内部变量取值范围。 ```c void x264_ratecontrol_init( x264_t *h ) { h->rc.i_keyframe_max = h->param.i_keyint_max; h->rc.i_keyframe_min = MAX(h->param.i_keyint_min, 1); } ``` 上述代码片段展示了初始化阶段设置的最大/最小关键帧间距操作。 ##### (2) Slice Type Decision Logic (`slice_type_decide.c`) 此组件专注于决定当前待编码图像应该被标记为什么样的切片类型——即它是属于 I 切片还是 P/B 类型的一部分。这部分逻辑紧密关联着前面提到过的 rate control mechanism ,从而确保整体性能达到预期效果。 ```c int x264_slice_type_decide( x264_t *h ) { int i_frame_num_offset = h->fenc->i_poc % h->sh.i_idr_pic_flag ? h->param.i_bframes : 0; if( h->fenc->b_scene_cut || !h->fenc->i_poc ){ return SLICE_TYPE_I; // 当发生场景切换或首个画面时强制采用 I 帧 } ... } ``` 这里简单列举了一个判断条件:如果检测到了场景变化或者是序列开头,则无条件选择生成一个新的 I 帧。 #### 4. 海思 SDK 下的应用实践 当使用海思系列芯片配合 MPP 平台开发项目时,由于底层硬件加速特性已被集成至 Linux 内核驱动层面上,因此开发者只需关注高层软件接口的设计工作即可完成复杂的多媒体处理任务[^2]。针对自定义 GOP 设置的需求,可通过修改对应编译选项传递给 x264 encoder 实例对象的方式快速达成目标。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值