Stride的来由
我们都知道现在计算机的cpu都是32位或者64位的cpu,他们一次最少读取4、8个字节,如果少于这些,反而要做一些额外的工作,会花更长的时间。所有会有一个概念叫做内存对齐,将结构体的长度设为4、8的倍数。Stride也是因为同样的理由出现的。因为图像的操作通常按行操作的,如果图像的所有数据都紧密排列,那么会发生非常多次的读取非对齐内存,从而影响效率。而图像的处理本就是一个分秒必争的操作,所以为了性能的提高就引入了Stride这个概念。
Stride的含义
- Stride就是指图像中的一行图像数据所占的存储空间的长度,它是一个大于等于图像宽度的内存对齐的长度。这样每次以行为基准读取数据的时候就能内存对齐,虽然可能会有一点内存浪费,但是在内存充裕的今天已经无所谓了。
- 当视频图像存储在内存时,图像的每一行末尾也许包含一些扩展的内容,这些扩展的内容只影响图像如何存储在内存中,但是不影响图像如何显示出来。如果图像的每一行像素末尾拥有扩展内容,Stride 的值一定大于图像的宽度(byte)值。
- 两个缓冲区包含同样大小(宽度和高度)的视频帧,却不一定拥有同样的 Stride 值,如果你处理一个视频帧,你必须在计算的时候把 Stride 考虑进去;
- 尤其是视频变换,特别需要处理不同 Stride 值的图像,因为输入缓冲也许与输出缓冲不匹配,举个例子,假设你想要将源图像转换并且将结果写入到目标图像,假设两个图像拥有相同的宽度和高度,但是其像素格式与 Stride 值也许不同;
Stride的值
如果图像的宽度 (byte) 是内存对齐长度的整数倍,那么Stride就会等于宽度 (byte),举个例子,某个Master对DDR的一次读取/写入都是8个字节,而我们通常见到的分辨率都是8的整数倍,所以我们通常发现Stride和图像的字节宽度一样(这里通常指rgb32格式或者以通道表示的yuv420p格式的y通道)。但是如果遇到一些少见的分辨率时Stride和图像的字节宽度时就不一样了。
Stride的计算方法与约束
-
按照有气泡的方式向DDR中存放数据
每像素占用字节数Bpc: 1(DW<=8), 2(8<DW<=16), 4(16<DW<=32) Stride = Bpc * PicWidth
-
按照无气泡的方式向DDR中存放数据
Stride = (PicWidth * DW + 7) / 8
-
确定一次读写内存的字节数,若一笔Burst为64位,则Stride要8Byte对齐,即
Stride[2:0] = 0
若计算出来的Stride不满足对齐约束,一定要进行相应的放大取整!否则stride小了,会丢数据。
通过Stride计算地址
- 计算每行的结束地址
endaddr_line = startaddr_line + Stride * PicHeigh
- 计算图像的的结束地址
endaddr_pic = startaddr_pic + Stride * PicHeigh
PS. 关于Stride的符号说明
Stride其实是一个有符号数,这要举一个例子来说明。一张图像在内存中有两种不同的存储序列(arranged),对于一个从上而下存储(Top-Down) 的图像,最顶行的像素保存在内存中最开头的部分,对于一张从下而上存储(Bottom-Up)的图像,最后一行的像素保存在内存中最开头的部分,下面图示展示了这两种情况:
一张从下而上的图像拥有一个负的 Stride 值!因为 Stride 被定义为“从一行像素移动到下一行像素时需要跨过多少个像素”,仅相对于被显示出来的图像而言;而 YUV 图像永远都是从上而下表示的,RGB 图像保存在系统内存时通常是从下而上;
参考文献
https://blog.csdn.net/bjrxyz/article/details/52690661
http://vegetable.wodekouwei.com/2017/06/27/media-graphic-image-stride/