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

求助:将原始视频转I420供VPX编码器及libyuv转换UYVY异常

解决UYVY转I420仅显示左上角区域的问题

嘿,我之前也踩过类似的坑!你现在遇到的这个情况,大概率是内存步长(stride)不匹配或者转换时的尺寸/参数设置错误导致的。Decklink采集的视频帧通常会做字节对齐(比如按16字节对齐),实际stride会比理论计算的(宽度×像素字节数)要大,如果忽略这一点,转换时就只会读取到左上角的有效区域。

常见问题排查与修复步骤

1. 先拿到Decklink帧的真实Stride

Decklink捕获的UYVY格式帧,每个像素占2字节,但实际一行数据的总字节数(也就是stride)可不是简单的width * 2——采集卡会做字节对齐,比如宽度不是16倍数的话,会自动补全到最近的16倍数。你得从Decklink的回调里拿真实的stride值,比如调用IDeckLinkVideoInputFrame::GetBytesPerRow()方法,这个返回值才是UYVY源的正确stride。

2. 正确调用libyuv的转换函数

别随便给转换函数传理论值,一定要把真实的源stride和目标各平面的stride传对。给你一个修正后的代码示例:

#include "libyuv/convert.h"

// 假设已经从Decklink拿到了这些数据
uint8_t* uyvy_raw_data = ...; // 采集到的原始UYVY帧数据指针
int frame_width = 1920;
int frame_height = 1080;
int uyvy_row_stride = ...; // 从GetBytesPerRow()拿到的真实行字节数

// 初始化vpx的I420图像结构
vpx_image_t vpx_img;
// 让vpx自动分配内存并计算合适的stride(推荐用这个方式)
vpx_img_alloc(&vpx_img, VPX_IMG_FMT_I420, frame_width, frame_height, 1);

// 调用libyuv的UYVY转I420函数
libyuv::UYVYToI420(
    uyvy_raw_data, uyvy_row_stride,
    vpx_img.planes[0], vpx_img.stride[0],
    vpx_img.planes[1], vpx_img.stride[1],
    vpx_img.planes[2], vpx_img.stride[2],
    frame_width, frame_height
);

3. 别手动硬编码vpx_image的Stride

如果你是手动初始化vpx_image_t,千万别自己瞎写stride值!vpx的vpx_img_alloc函数会根据格式、宽高自动计算对齐后的stride(符合编码器要求的那种),硬编码很容易出问题。

比如I420格式的话,Y平面的stride是对齐后的宽度,U/V平面是对齐后宽度的一半,这些vpx都会帮你算好。

4. 检查原始帧数据是否完整

有时候也可能是你从Decklink拿到的原始数据不完整——比如只读取了部分缓冲区。你可以核对一下原始UYVY数据的总字节数是不是等于uyvy_row_stride * frame_height,如果字节数不够,转换出来自然只有部分区域有效。

额外小提示

  • 要是你的VPX编码器对分辨率有对齐要求(比如VP9要求宽高是16的倍数),转完I420后可以用libyuv的I420Scale函数做一下缩放调整,确保符合编码器的要求。
  • 调试的时候可以把源stride、目标各平面的stride都打印出来,对比一下理论值和实际值,很快就能定位是不是stride的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:31:34