c -使用SDL播放YUV视频:当分辨率不是4的倍数时,行换行太晚



我一直在与SDL_Overlay (SDL 1.2.5)播放未压缩YUV 4:2:0平面视频数据的某些来源的问题作斗争。

我没有问题播放,说,640x480视频。但我刚刚尝试播放分辨率为854x480的视频,我得到了一个奇怪的效果。线条包装1-2个像素太晚(导致类似剪切的转换),色度消失,在每条线上交替使用R, G或B代替。请看这个截图

YUV数据本身是正确的,因为我可以将其保存到一个文件并在另一个播放器中播放。此时没有填充- 间距与行长度匹配。

我怀疑当分辨率不是4的倍数时,会发生一些问题。也许SDL_Surface期望SDL_Overlay的色度分辨率是2的倍数?

增加我的怀疑,我注意到我以854*480的大小创建的RGB SDL_Surface具有2564的音高,而不是3*854 = 2562我所期望的。

如果我在SDL_Surface的宽度上添加1或2个像素(但保持覆盖和矩形相同),它会工作得很好,尽管右边有一个黑色的边框。当然,当是4的倍数时,这就打破了。

设置
screen = SDL_SetVideoMode(width, height, 24, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_ASYNCBLIT);
if ( screen == NULL ) {
  return 0;
}
YUVOverlay = SDL_CreateYUVOverlay(width, height, SDL_IYUV_OVERLAY, screen);
Ydata = new unsigned char[luma_size];
Udata = new unsigned char[chroma_size];
Vdata = new unsigned char[chroma_size];
YUVOverlay->pixels[0] = Ydata;
YUVOverlay->pixels[1] = Udata;
YUVOverlay->pixels[2] = Vdata;
SDL_DisplayYUVOverlay(YUVOverlay, dest);

渲染循环:

SDL_LockYUVOverlay(YUVOverlay);
memcpy(Ydata, buffer, luma_size);
memcpy(Udata, buffer+luma_size, chroma_size);
memcpy(Vdata, buffer+luma_size+chroma_size, chroma_size);
int i = SDL_DisplayYUVOverlay(YUVOverlay, dest);
SDL_UnlockYUVOverlay(YUVOverlay);

我要做的最简单的修复是增加RGB SDL_Surface大小,使其在每个维度上都是4的倍数。然后添加一个黑色边框。

是否有正确的方法来解决这个问题?我应该尝试在我的YUV数据上填充吗?

输入数据的每个平面必须从可被8整除的地址开始,并且每行的步长必须能被8整除。需要明确的是:你的色度平面也需要遵守这个规则。

这个要求似乎来自于SDL库在x86 cpu上使用MMX多媒体指令。请参阅发行版中src/video/SDL_yuv_mmx.c中的注释。

update:我查看了实际的汇编代码,还有一些在源代码注释中没有提到的额外假设。这是针对SDL 1.2.14的。除了上面描述的模8假设之外,代码还假设输入亮度和输入色度平面都被完美地包装(即宽度== stride)。

最新更新