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

SDL_LockTexture返回异常pitch值求助:Android原生相机预览场景

问题分析与解决方案

你的假设确实存在偏差,而且对SDL处理NV21格式纹理的内存布局和pitch的定义理解有误,同时数据拷贝逻辑也需要调整。下面一步步拆解问题:

1. SDL与Android对NV21格式的pitch定义差异

你预期的720*12/8=1080是基于Android ImageFormat.getBitsPerPixel(NV21)的总位深计算的整个帧的平均行字节数,但SDL中SDL_LockTexture返回的pitch对于半平面YUV格式有完全不同的含义:

  • SDL的SDL_PIXELFORMAT_NV21属于半平面格式,内存布局是:先存完整的Y分量平面(每个Y像素占1字节,共720*480字节),之后紧跟VU交错的UV分量平面(每2x2像素共享一组VU,共720*480/2字节)。
  • 此时SDL_LockTexture返回的pitch是Y分量平面的行字节数,也就是你的宽度值720(因为每个Y像素1字节,每行Y刚好是720字节),而非整个帧的行字节数。

2. 画面偏绿的核心原因

当你使用SDL返回的pitch=720时,大概率是你的数据拷贝逻辑出了问题:

  • 如果你循环480次(对应画面高度),每次拷贝pitch字节,那你只拷贝了Y分量的全部数据,UV分量完全没被写入纹理内存。缺失UV分量会导致色彩异常,偏绿是这类问题的典型表现。
  • 而当你手动用1080作为pitch时,480*1080刚好等于NV21帧的总字节数(720*480*3/2),相当于完整拷贝了整个NV21数据到纹理内存,巧合匹配了SDL的半平面布局,所以画面显示正常。但这不是正确的用法,你只是歪打正着绕过了pitch的误解。

3. 正确的处理方式

针对SDL的NV21纹理,推荐两种正确的数据拷贝方式:

方式一:分平面拷贝(更贴合SDL的内存布局)

// 锁定纹理
void* pixels;
int pitch;
SDL_LockTexture(texture, nullptr, &pixels, &pitch);

// 假设camera_data是Android相机输出的NV21数据指针
size_t y_plane_size = 720 * 480;
size_t uv_plane_size = 720 * 480 / 2;

// 拷贝Y分量:每行pitch字节,共480行
memcpy(pixels, camera_data, y_plane_size);

// 拷贝UV分量:UV平面起始地址是pixels + Y平面大小,每行同样是pitch字节,共240行
memcpy((uint8_t*)pixels + y_plane_size, camera_data + y_plane_size, uv_plane_size);

// 解锁纹理
SDL_UnlockTexture(texture);

方式二:直接完整拷贝(更简洁)

因为总字节数完全匹配,你可以跳过pitch的逐行处理,直接拷贝整个NV21数据:

SDL_LockTexture(texture, nullptr, &pixels, &pitch);
memcpy(pixels, camera_data, 720 * 480 * 3 / 2);
SDL_UnlockTexture(texture);

额外提示

你使用的SDL2.0.7版本相对老旧,Android平台的NV21格式支持可能存在细节瑕疵,如果后续遇到其他异常,可以尝试升级到SDL2.26+的新版本。另外,Android相机输出的NV21布局和SDL的SDL_PIXELFORMAT_NV21完全一致(Y在前、VU交错在后),不需要调整UV顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:08:19