You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x264编码非4整除分辨率(1366x768)画面失真问题求助

问题描述

使用H264 High预设将BGRA格式帧编码为Yuv420p格式时,多数分辨率运行正常,但1366x768这类宽/高无法被4整除的分辨率会出现严重画面失真。

失真画面

相关代码

stride = this.width * 4;

encoder = new CodecContext(Codec.FindEncoderById(AVCodecID.H264))
{
    Width = this.width,
    Height = this.height,
    Framerate = new AVRational(1, framerate),
    TimeBase = new AVRational(1, framerate),
    PixelFormat = AVPixelFormat.Yuv420p,
    Profile = (int)FF_PROFILE.H264High,
    MaxBFrames = 0,
    GopSize = 10,
};

encoder.Open(null, new MediaDictionary
{
    ["crf"] = "22",
    ["tune"] = "zerolatency",
    ["preset"] = "veryfast",
    ["subme"] = "5"
});

rgbFrame.Width = width;
rgbFrame.Height = height;
rgbFrame.Format = (int)AVPixelFormat.Bgra;
unsafe
{
    fixed (byte* ptr = frame)
    {
        rgbFrame.Data[0] = (nint)ptr;
    }
}
rgbFrame.Linesize[0] = stride;
rgbFrame.Pts = pts++;

yuvFrame.Width = width;
yuvFrame.Height = height;
yuvFrame.Format = (int)AVPixelFormat.Yuv420p;

yuvFrame.EnsureBuffer();
yuvFrame.MakeWritable();
videoFrameConverter.ConvertFrame(rgbFrame, yuvFrame);
yuvFrame.Pts = pts;

var encodedFrames = encoder.EncodeFrame(yuvFrame, packetRef);
var packet = encodedFrames.FirstOrDefault();
var data = packet?.Data.ToArray() ?? [];
解决方法

1. 调整分辨率到编码对齐要求

H264 High Profile结合Yuv420p采样特性,要求分辨率的宽和高必须是4的整数倍(色度分量为亮度分量的1/4,内存与编码逻辑需要对齐)。可直接修改原始分辨率:

  • 对1366x768这类分辨率,向上取整为1368x768,或向下取整为1364x768
  • 若需保持比例,可同步调整宽高至均为4的倍数,比如1360x764

2. 让编码器自动处理分辨率对齐

初始化编码器时,直接使用对齐后的宽高参数,避免手动适配误差:

int alignedWidth = FFmpeg.Align(width, 4);
int alignedHeight = FFmpeg.Align(height, 4);

encoder = new CodecContext(Codec.FindEncoderById(AVCodecID.H264))
{
    Width = alignedWidth,
    Height = alignedHeight,
    Framerate = new AVRational(1, framerate),
    TimeBase = new AVRational(1, framerate),
    PixelFormat = AVPixelFormat.Yuv420p,
    Profile = (int)FF_PROFILE.H264High,
    MaxBFrames = 0,
    GopSize = 10,
};

也可在打开编码器时通过参数强制对齐:

encoder.Open(null, new MediaDictionary
{
    ["crf"] = "22",
    ["tune"] = "zerolatency",
    ["preset"] = "veryfast",
    ["subme"] = "5",
    ["width"] = FFmpeg.Align(width,4).ToString(),
    ["height"] = FFmpeg.Align(height,4).ToString()
});

3. 同步调整YUV转换帧的分辨率

创建yuvFrame时使用对齐后的宽高,保证输入帧与编码器参数匹配:

int alignedWidth = FFmpeg.Align(width, 4);
int alignedHeight = FFmpeg.Align(height, 4);

yuvFrame.Width = alignedWidth;
yuvFrame.Height = alignedHeight;
yuvFrame.Format = (int)AVPixelFormat.Yuv420p;

yuvFrame.EnsureBuffer();
yuvFrame.MakeWritable();
videoFrameConverter.ConvertFrame(rgbFrame, yuvFrame);

转换过程中工具会自动处理边缘的填充或裁剪,避免画面错位。

4. 检查像素格式转换的行跨度(stride)

确认videoFrameConverter在转换时正确处理了对齐后的行跨度,避免因内存对齐问题导致的画面失真。


内容的提问来源于stack exchange,提问作者Valentin Maschenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:36:17