Microsoft Media Foundation官方文档翻译(14)《Image Stride》
官方英文文档链接:https://docs.microsoft.com/en-us/windows/desktop/medfound/image-stride
基于05/31/2018
当视频图像存储在内存中时,内存缓冲区可能在每行像素后面有额外的填充字节,填充字节会影响图像在内存中的存储方式,但不会影响图像的显示方式。
stride 是从内存中一行像素开头到内存中的下一行像素间隔的字节数。Stride 也可以叫做 pitch。如果存在填充字节,则 stride 就会大于图像宽度,如下图所示:
两个包含相同尺寸图像的 buffer 可能有不同 stride,所以在处理视频图像时必须考虑 stride。
另外,图像在内存中的排列方式有两种。top-down 图像的首行第一个像素先储存在内存中。bottom-up 图像的最后一行像素先存储在内存中。下图显示了两者的区别:
bottom-up 图像具有负的 stride,因为 stride 被定义为从第一行像素到第二行像素需要向后移动的距离。YUV 图像应该始终是top-down,Direct3D surface 则必须是 top-down。而内存中的 RGB 图像则通常是 bottom-up。
做视频转换时尤其需要处理 stride 不匹配的 buffer,(剩下的废话。。), because the input buffer might not match the output buffer. For example, suppose that you want to convert a source image and write the result to a destination image. Assume that both images have the same width and height, but might not have the same pixel format or the same image stride.
下面的代码展示了编写此类函数的一般写法。这不是一个完整的示例,因为这里抽象了很多实现细节。
这个函数需要 6 个参数:
- 指向目标图像首行像素开头位置(scan line 0)的指针
- 目标图像的 stride
- 指向源图像首行像素开头位置(scan line 0)的指针
- 源图像的 stride
- 图像宽度(像素)
- 图像高度(像素)
通常情况下每次处理一行,每次遍历行中的每个像素。假设 SOURCE_PIXEL_TYPE 和 DEST_PIXEL_TYPE 分别是表示源图像和目标图像像素的结构体(例如 32-bit RGB 使用 RGBQUAD structure。不一定每种像素格式都有一个定义好的结构体),则可以将数组指针转换为该结构体的指针,以访问每个像素的 RGB 或 YUV 分量。每行结束时,指针按照 stride 递增,使指针指向下一行。
本例中为每个像素都调用了一个假设的名为 TransformPixelValue 的转换函数。这个可以是任何能把源像素转换为目标像素的函数,当然具体细节取决于需求。例如对于 planar YUV 格式,你必须分别独立处理 luma plane 和 chroma plane;对于视频,可能需要分别处理 field,等等。
下面给出了一个具体的例子,将 32-bit RGB 图像转换成 AYUV 图像。每个 RGB 像素可以通过 RGBQUAD 结构访问,AYUV 像素可以通过 DXVA2_AYUVSample8 结构访问。
下面的例子将 32-bit RGB 图像转换为 YV12 图像。这里展示了如何处理 planar YUV 格式(YV12 是 planar 4:2:0 格式,planar后面会讲《Recommended 8-Bit YUV Formats for Video Rendering》)。本例中的函数中,分别为三个 plane 维护了三个单独的指针,但基本方法与前面的示例相同。
在这篇的所有示例中,都假设应用程序已经确定了 stride。有时可以从 media buffer 中得到这些信息,否则必须根据视频格式进行计算。有关图像 stride 的计算和如何使用 media buffer,参考 Uncompressed Video Buffers。