您的位置:首页 > 其它

RGB数据写bmp图片文件遇到的这些坑

2016-09-12 19:03 399 查看
用ffmpeg解码MP4后,得到YUV数据,然后YUV转换成RGB.

没隔一段时间需要保存一张图片,这里就打算直接将RGB数据写成BMP文件。

因为BMP文件是直接写RGB数据,并不编码,减少CPU的损耗。

就这么一个功能,遇到了好多坑。

一,如何用RGB写BMP文件

BMP文件的图片数据是原始RGB数据,不需要编码。但是需要在文件最开始打上BMP文件头,后面直接写RGB的数据就可以了。

BMP文件头信息如下:

typedef struct {
WORD    bfType;//0x4d42
DWORD   bfSize;//sizeof(BMPFILEHEADER_T)+sizeof(BMPINFOHEADER_T)+width*height*3, 整个文件的大小
WORD    bfReserved1;
WORD    bfReserved2;
DWORD   bfOffBits;//sizeof(BMPFILEHEADER_T)+sizeof(BMPINFOHEADER_T),就是RGB数据的偏移量, 偏移这两个数据结构
} BMPFILEHEADER_T;

typedef struct{
DWORD      biSize;//sizeof(BMPINFOHEADER_T)
LONG       biWidth;
LONG       biHeight;
WORD       biPlanes;
WORD       biBitCount;//RGB24, 就是24位
DWORD      biCompression;//0, 不压缩
DWORD      biSizeImage;//RGB24数据大小
LONG       biXPelsPerMeter;//
LONG       biYPelsPerMeter;//
DWORD      biClrUsed;//0
DWORD      biClrImportant;//0
} BMPINFOHEADER_T;


也就是说,整个BMP文件就是:BMPFILEHEADER_T+BMPINFOHEADER_T+RGB原始数据。简单吧。

然后直接写文件就可以了:

bmpheader.bfType = 0x4d42;
bmpheader.bfReserved1 = 0;
bmpheader.bfReserved2 = 0;
bmpheader.bfOffBits = <span style="font-family: Arial, Helvetica, sans-serif;">sizeof(BMPFILEHEADER_T) </span>+ sizeof(BMPINFOHEADER_T);
bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;

bmpinfo.biSize = sizeof(BMPINFOHEADER_T);
bmpinfo.biWidth = width;
bmpinfo.biHeight = -height;
bmpinfo.biPlanes = 1;
bmpinfo.biBitCount = bpp;
bmpinfo.biCompression = 0;
bmpinfo.biSizeImage = (width*bpp+31)/32*4*height;
bmpinfo.biXPelsPerMeter = 100;
bmpinfo.biYPelsPerMeter = 100;
bmpinfo.biClrUsed = 0;
bmpinfo.biClrImportant = 0;

fwrite(&bmpheader, sizeof(BMPFILEHEADER_T), 1, fp);
fwrite(&bmpinfo, sizeof(bmpinfo), 1, fp);
fwrite(pFrameRGB, width*height*bpp/8, 1, fp);

fclose(fp);


二,坑一:4字节对齐
按照上面的代码写出来的文件,文件图片打开失败,说文件破损。

后来才发现BMPFILEHEADER_T这个数据接口的内部变量排序,并没有4字节对齐,导致sizeof(BMPFILEHEADER_T)比预想的大!

所以直接用宏设置数据结构的字节对齐方式为:1字节对齐。

#pragma pack(1)
typedef struct {
WORD    bfType;
DWORD   bfSize;
WORD    bfReserved1;
WORD    bfReserved2;
DWORD   bfOffBits;
} BMPFILEHEADER_T;

typedef struct{
DWORD      biSize;
LONG       biWidth;
LONG       biHeight;
WORD       biPlanes;
WORD       biBitCount;
DWORD      biCompression;
DWORD      biSizeImage;
LONG       biXPelsPerMeter;
LONG       biYPelsPerMeter;
DWORD      biClrUsed;
DWORD      biClrImportant;
} BMPINFOHEADER_T;
#pragma pack()
这些好了,程序运行图片可以打开了,但是还有另外一个坑。

现在图片可以打开,但是人物的颜色都是绿色,都变成“绿巨人”

三、坑二:图片颜色不对--RGB24还是BRG24?

YUV转RGB用的是ffmpeg的swscale代码:

_swsContext = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, <span style="background-color: rgb(51, 51, 255);">AV_PIX_FMT_RGB24</span>, SWS_BICUBIC, NULL, NULL, NULL);
YUV转换的结果是RGB24,但是这样出来的RGB数据,写成的BMP文件,显然是颜色错误。

修改成BRG24问题得到解决,如下:

_swsContext = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);


今后还是需要确认一下BMP文件内部不压缩图片的格式是BGR24,而不是RGB24.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  图片 rgb bmp ffmpeg swscale