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
相关产品推荐
相关产品推荐

