FFmpeg crop裁剪原理&记录一个bug

147 阅读2分钟

FFmpeg crop相关记录

FFmpeg crop相关:

ffmpeg frame crop分为两种情况设置 1、NALU读取SPS、PPS获取到的crop参数,avcodec_send_packet时设置,avcodec_receive_frame时获取crop参数,判断是否裁剪。 2、初始化编码器阶段(h264_decode_init)设置H264Context->width_from_caller、H264Context->height_from_caller参数,在decode(如:h264_decode_frame)阶段(init_dimensions函数)会用H264Context->width_from_caller、H264Context->height_from_caller和当前接收流的H264Context->width、H264Context->height匹配,如果小于则裁剪。


问题描述

实践发现问题:初始化codec一个尺寸,然后运行过程中切换输入流尺寸(变大)、sps、pps参数也都修改,但是输出流还是被裁剪。原因基本如上面分析所致。

static int h264_init_context(AVCodecContext *avctx, H264Context *h)
{
    int i;
    
    h->avctx                 = avctx;
    h->cur_chroma_format_idc = -1;

    h->width_from_caller     = avctx->width;
    h->height_from_caller    = avctx->height;
    略...
}
static void init_dimensions(H264Context *h)
{
    const SPS *sps = (const SPS*)h->ps.sps;
    int cr = sps->crop_right;
    int cl = sps->crop_left;
    int ct = sps->crop_top;
    int cb = sps->crop_bottom;
    int width  = h->width  - (cr + cl);
    int height = h->height - (ct + cb);
    av_assert0(sps->crop_right + sps->crop_left < (unsigned)h->width);
    av_assert0(sps->crop_top + sps->crop_bottom < (unsigned)h->height);
    /* handle container cropping */
    if (h->width_from_caller > 0 && h->height_from_caller > 0     &&
        !sps->crop_top && !sps->crop_left                         &&
        FFALIGN(h->width_from_caller,  16) == FFALIGN(width,  16) &&
        FFALIGN(h->height_from_caller, 16) == FFALIGN(height, 16) &&
        h->width_from_caller  <= width &&
        h->height_from_caller <= height) {
        width  = h->width_from_caller;
        height = h->height_from_caller;
        cl = 0;
        ct = 0;
        cr = h->width - width;
        cb = h->height - height;
    } else {
        h->width_from_caller  = 0;
        h->height_from_caller = 0;
    }
    略...
}

原因分析

如上


解决方案

1、解码器初始化有设置一个参数:.update_thread_context 猜测可以用来更新AVCodecContext,使得尺寸一致。

.update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context),

2、ffmpeg内部修改(不推荐),可能导致未知错误(目前还没细看解码器尺寸修改是否影响到解码数据读取、字节对齐等)。 3、修改操作方法,播放过程中修改尺寸,未从新初始化、resize理论上不太合理。

参考文献

ffmpeg解码器参考雷神(RIP)文章: 链接: link. 链接: link.