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

如何从uint8类型I420原始视频缓冲区拆分得到YUV分量指针?

回答

可以,只要你持有的是标准连续紧凑存储、无额外行对齐填充的I420(即YUV420P)格式缓冲区,完全可以通过指针偏移计算出Copy函数需要的所有入参。

I420格式内存布局规则

标准I420是平面存储格式,三个分量按Y、U、V的顺序连续排列在缓冲区中:

  • Y(亮度)平面:分辨率和帧尺寸一致,共width * height个字节
  • U(色度Cb)平面:水平、垂直方向均为Y平面的1/2采样,共(width/2) * (height/2)个字节
  • V(色度Cr)平面:尺寸和U平面完全一致,共(width/2) * (height/2)个字节
    整体缓冲区总大小固定为 width * height * 3 / 2,你可以先用已知的缓冲区大小做校验,如果数值不匹配,说明缓冲区带行对齐填充、或者不是标准I420格式,不能直接按下面的方法计算。

各入参计算方式

  • width、height:直接传入你已知的视频帧宽度、高度即可
  • data_y:就是你持有的原始uint8_t缓冲区首地址,Y平面位于缓冲区最开头
  • stride_y:Y平面每行的字节跨度,紧凑无填充场景下等于width
  • data_u:Y平面结束后的首地址,计算方式为 原始指针 + stride_y * height
  • stride_u:U平面每行的字节跨度,紧凑无填充场景下等于width / 2
  • data_v:U平面结束后的首地址,计算方式为 data_u + stride_u * (height / 2)
  • stride_v:V平面每行的字节跨度,和U平面一致,紧凑无填充场景下等于width / 2

参考实现代码

// 已知入参
uint8_t* raw_i420_buf =  /* 你的I420原始缓冲区指针 */;
int known_buf_size =     /* 已知的缓冲区大小 */;
int frame_width =        /* 已知的帧宽度 */;
int frame_height =       /* 已知的帧高度 */;

// 先校验是否为标准紧凑I420
const int expected_buf_size = frame_width * frame_height * 3 / 2;
// 若known_buf_size和expected_buf_size不相等,说明存在行对齐或格式不匹配,禁止直接按以下逻辑传参

// 计算各平面参数
const uint8_t* ptr_y = raw_i420_buf;
const int stride_y = frame_width;

const uint8_t* ptr_u = raw_i420_buf + stride_y * frame_height;
const int stride_u = frame_width / 2;

const uint8_t* ptr_v = ptr_u + stride_u * (frame_height / 2);
const int stride_v = frame_width / 2;

// 调用第三方库接口
Copy(frame_width, frame_height, ptr_y, stride_y, ptr_u, stride_u, ptr_v, stride_v);

注意事项

  • 如果你的I420数据来自硬件解码、渲染接口等场景,很可能存在行对齐要求(比如按16/32/64字节对齐行首),此时stride值会大于对应平面的行宽,不能直接用width/2作为stride,必须拿到源数据实际的行跨度才能正确计算平面偏移,否则会出现画面错位、花屏、内存越界问题。
  • 如果帧宽高为奇数,色度平面尺寸按向下取整计算即可,绝大多数I420实现都遵循这个规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 00:39:26