stride可以翻譯為:跨距
stride指在內存中每行像素所占的空間。如下圖所示,為了實現內存對齊(或者其它的什么原因),每行像素在內存中所占的空間並不是圖像的寬度。
plane一般是以luma plane、chroma plane的形式出現,其實就是luma層和chroma層,就像RGB,要用三個plane來存。
最近在做HI5321的一個項目,其中遇到一個關鍵性的技術問題,我們的圖像處理程序需 要的是rgb888格式的圖像文件,而我從hi3521獲取的視頻流是yuv420sp格式的圖片幀,問題來了,現在我需要將yuv420sp格式的一幀 圖像轉換成rgb888格式的圖片,其實我的目的是要rgb888圖像數據。yuv420sp的yuv分量在內存儲存的方式是y分量單獨存儲,uv分量交 叉存儲。好了,可以做了,但是當我打印yuv420sp幀信息的時候發現這個720*576的一幀圖片的stride(也就是跨距)居然是768,不解, 知道現在即便我已經成功將yuv420sp的一幀圖片轉成了bmp位圖,我依然不明白這個多出來的768-720=48字節是什么。在沒有考慮跨距的情況 下,我直接從yuv分量的地址出讀取個分量而后獲取rgb數據保存成bmp位圖,但bmp完全錯亂,哪里出了問題。肯定是跨距,跨距:一定會大於等於幀寬 度並且是4的倍數,720和768之間是4的倍數的數多了,為什么是768?好吧!既然是在不足4的倍數的情況下需要在行末補0,那我權當這48字節就在 每行的末尾。那么在讀取yuv分量的時候必定要偏移地址。試一試,bmp果真保存成功,就像抓拍的圖片一樣,當然其中技術細節大家都知道,yuv換算成 rgb的公式我知道的不少於3個。
寫這段記錄的目的就是想說這個stride的問題,所以在進行yuv420p,yuv420sp,等視頻幀轉換時一定要注意跨距stride這個參數。
When a video image is stored in memory, the memory buffer might contain extra padding bytes after each row of pixels. The padding bytes affect how the image is stored in memory, but do not affect how the image is displayed.
The stride is the number of bytes from one row of pixels in memory to the next row of pixels in memory. Stride is also called pitch. If padding bytes are present, the stride is wider than the width of the image, as shown in the following illustration.
Two buffers that contain video frames with equal dimensions can have two different strides. If you process a video image, you must take the stride into account.
In addition, there are two ways that an image can be arranged in memory. In a top-down image, the top row of pixels in the image appears first in memory. In a bottom-up image, the last row of pixels appears first in memory. The following illustration shows the difference between a top-down image and a bottom-up image.
A bottom-up image has a negative stride, because stride is defined as the number of bytes need to move down a row of pixels, relative to the displayed image. YUV images should always be top-down, and any image that is contained in a Direct3D surface must be top-down. RGB images in system memory are usually bottom-up.
Video transforms in particular need to handle buffers with mismatched strides, 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.
The following example code shows a generalized approach for writing this kind of function. This is not a complete working example, because it abstracts many of the specific details.
下面是一個轉換的例子,可以通過它很好的理解
最近拿到了一塊液晶顯示屏,采用NTSC隔行掃描制式輸出圖像,其采用的顏色格式為YUV4:2:2的UYVY格式,可是某視頻解碼器輸出的顏色格式是YUV4:2:0的I420格式。那么,就必須在兩者之間進行一次轉換,其中I420是以平面(planner)格式存放的,而UYVY則是以緊縮(packet)格式存放的。這個轉換過程並不復雜,原理如圖 1所示。
圖2中的每一個顏色分量都采用一個字節表示,U0Y0V0Y1這樣一個存放序列表示的實際上是兩個像素點,總共需要4個字節表示。因此,每一個像素點平均占據的空間是2字節。YUV這種顏色格式的理論依據是HVS(Human Visual System,人類視覺系統)對亮度敏感,而對色度的敏感程度次之。因此通過對每一行像素點的色差分量亞采樣來減少所需的存儲空間。YUV4:2:2緊縮格式的顏色占據的存儲空間是YUV4:4:4格式占據的存儲空間的2/3。比如,如果采用YUV4:4:4格式,則每個像素點都需要用三個分量表示,也即需要用3字節表示一個像素點。
代碼實現
void rv_csp_i420_uyvy( uint8_t *y_plane, // Y plane of I420 uint8_t *u_plane, // U plane of I420 uint8_t *v_plane, // V plane of I420 int y_stride, // Y stride of I420, in pixel int uv_stride, // U and V stride of I420, in pixel uint8_t *image, // output UYVY image int width, // image width int height) // image height { int row; int col; uint8_t *pImg = image; for (row = 0; row < height; row = row+1)
{ for (col = 0; col < width; col = col+2)
{ pImg[0] = u_plane[row/2 * uv_stride + col/2]; pImg[1] = y_plane[row * y_stride + col]; pImg[2] = v_plane[row/2 * uv_stride + col/2]; pImg[3] = y_plane[row * y_stride + col + 1]; pImg += 4; } } }
代碼好像有點問題,保存的時候沒有考慮YUV4:2:2的stride,不過上面的代碼已經把原理說的很清除了。