yuv
含义
Y: 表示明亮度(Luminance或Luma)
U和V: 色度(Chrominance或者Chroma)
YUV420
yuv420是YUV像素格式的一种。
大小:
对于分辨率为 W×H 的图像:
-
Y 分量大小:W × H 字节(每个像素 1 字节)。
-
U 分量大小:(W/2) × (H/2) = W×H/4 字节。
-
V 分量大小:(W/2) × (H/2) = W×H/4 字节。
yuv420p => I420
yuv420 planar代表内存分布是有y u v三个平面,代码理解就是有yuv三个不同指针,分别记录存放着对应分量数据的地址。
存放为图片分量数据排布 
YUV420SP =>nv12/nv21为 semi-planar 模式。代码理解是有两个不同指针,记录着两块地址,一款放y分量数据,一路放UV数据,UV交错放在一起。
存放为图片分量数据排布 
问题
将内存中一帧数据(格式是yuv420p,有stride,w按512字节对齐),保存为yuv格式图片。
思路:获取y数据写入,然后获取u数据写入,然后获取v数据写入文件。
1.获取y数据,大小为width * height
2.获取u数据,大小为width/2 * height/2
3.获取v数据,大小为width/2 * height/2
疑问:这里是不是直接对应分量地址去取对于大小的数据即可?
答:并不是,有stride,这个是步长,意思是内存中有字节对齐,w按512字节对齐就是每一行的数据是512的倍数,不足的会自动填充数据的。
代码理解就是例如1920 * 1080的图像数据。y分量数据大小是1920 * 1080字节,1920就是它的一行,从y地址从一次取一行数据,然后取1080次。但是有步长,正常你第一个从ptr_y地址取第一行数据,第二次是从ptr_y+1920取数据是吧,但是有步长,这个就变为ptr_y+2048取数据。 uv分量同理。
2048就是1920向上512倍数最近的值。一般帧结构体中会给出计算好对于分量的stride。
示例代码如下:
void save_yuv420_frame(VIDEO_FRAME_INFO_S *stFrameInfom, const char* filename) {
FILE* pfd = fopen(filename, "wb");
if (!pfd) {
perror("Failed to open file");
return;
}
VIDEO_FRAME_S *pVBuf = &(stFrameInfom->stVFrame);
U32 u32ChromaPicW = 0;
U32 u32ChromaPicH = 0;
U8 *pVirAddr_Y = (U8 *) pVBuf->u64VirAddr[0];
U8 *pVirAddr_U = (U8 *) pVBuf->u64VirAddr[1];
U8 *pVirAddr_V = (U8 *) pVBuf->u64VirAddr[2];
u32ChromaPicW = pVBuf->u32Width/2;
u32ChromaPicH = pVBuf->u32Height/2;
fprintf(stderr, "saving......Y......\n");
fflush(stderr);
for (int i = 0; i < pVBuf->u32Height; i++) {
fwrite(pVirAddr_Y, pVBuf->u32Width, 1, pfd);
pVirAddr_Y += pVBuf->u32Stride[0];
}
fflush(pfd);
fprintf(stderr, "saving......U......\n");
fflush(stderr);
for (int i = 0; i < u32ChromaPicH; i++) {
fwrite(pVirAddr_U, u32ChromaPicW, 1, pfd);
pVirAddr_U += pVBuf->u32Stride[1];
}
fflush(pfd);
fprintf(stderr, "saving......V......\n");
fflush(stderr);
for (int i = 0; i < u32ChromaPicH; i++) {
fwrite(pVirAddr_V, u32ChromaPicW, 1, pfd);
pVirAddr_V += pVBuf->u32Stride[2];
}
fflush(pfd);
fprintf(stderr, "save %dth yuv data done !\n", 10);
fflush(stderr);
fclose(pfd);
return 0;
}
将内存中一帧数据(格式是yuv420p,有stride,w按512字节对齐),保存为nv12的yuv格式图片
思路:
NV12 y分量数据和I420一样 ,uv数据量和I420也是一样,只是交错放在一起。
1.先存放y数据
2.交错存放UV数据
示例代码如下。
int save_nv12_frame(VIDEO_FRAME_INFO_S *stFrameInfom, const char* filename) {
FILE* pfd = fopen(filename, "wb");
if (!pfd) {
perror("Failed to open file");
return -1;
}
VIDEO_FRAME_S *pVBuf = &(stFrameInfom->stVFrame);
U32 width = pVBuf->u32Width;
U32 height = pVBuf->u32Height;
U32 chromaWidth = width/2;
U32 chromaHeight = height/2;
U8 *pY = (AR_U8 *)pVBuf->u64VirAddr[0];
U8 *pU = (AR_U8 *)pVBuf->u64VirAddr[1];
U8 *pV = (AR_U8 *)pVBuf->u64VirAddr[2];
U32 yStride = pVBuf->u32Stride[0];
U32 uStride = pVBuf->u32Stride[1];
U32 vStride = pVBuf->u32Stride[2];
// 写入Y平面数据
fprintf(stderr, "Writing Y plane...\n");
for (int i = 0; i < height; i++) {
fwrite(pY, width, 1, pfd);
pY += yStride;
}
// 分配临时缓冲区存储UV交错数据
U32 uvSize = chromaWidth * chromaHeight * 2;
U8 *uvBuffer = (U8 *)malloc(uvSize);
if (!uvBuffer) {
fprintf(stderr, "Memory allocation failed\n");
fclose(pfd);
return -1;
}
// 生成NV12格式的UV数据 (U和V交替存储)
fprintf(stderr, "Generating NV12 UV data...\n");
U8 *uvPtr = uvBuffer;
for (int i = 0; i < chromaHeight; i++) {
for (int j = 0; j < chromaWidth; j++) {
*uvPtr++ = *pU++; // U分量
*uvPtr++ = *pV++; // V分量
}
pU += uStride - chromaWidth;
pV += vStride - chromaWidth;
}
// 写入UV数据
fprintf(stderr, "Writing UV data...\n");
fwrite(uvBuffer, uvSize, 1, pfd);
// 释放资源
free(uvBuffer);
fclose(pfd);
fprintf(stderr, "NV12 frame saved successfully\n");
return 0;
}
1437

被折叠的 条评论
为什么被折叠?



