根据工作要求,得到视频数据。那么怎么证明视频数据是对的?转为BMP最简单了。这样一个想法,折腾了吾很久,找到了快10种代码,结果都不能用。后来终于找到了一个可用的(代码是部分的),看到保存出来的BMP图片,终于松了一口气。
个人发现关键地方有:
1、文件头。
2、文件头的对齐。
3、每行数据的对齐。
取之于网络,用之于网络,吾将代码公布出来:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef int LONG;
#define BITS_PER_PIXCEL 24
/** 必须对齐,所以用这个来对齐 */
#pragma pack(1)
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BMP_FILE_HEADER;
typedef struct{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BMP_INFO_HEADER;
#pragma pack()
int rgbaToBmpFile(char *pFileName, unsigned char* pRgbaData, int nWidth , int nHeight)
{
BMP_FILE_HEADER bmpHeader;
BMP_INFO_HEADER bmpInfo;
FILE* fp = NULL;
char* pBmpSource = NULL;
char* pBmpData = NULL;
int i = 0, j=0;
//4字节对齐。每一行必须是4的倍数。
int bytesPerLine = (nWidth*BITS_PER_PIXCEL+31)/32*4;
int pixcelBytes = bytesPerLine*nHeight;
bmpHeader.bfType = 0x4D42;
bmpHeader.bfReserved1 = 0;
bmpHeader.bfReserved2 = 0;
bmpHeader.bfOffBits = sizeof(BMP_FILE_HEADER) + sizeof(BMP_INFO_HEADER);
bmpHeader.bfSize = bmpHeader.bfOffBits + pixcelBytes;
bmpInfo.biSize = sizeof(BMP_INFO_HEADER);
bmpInfo.biWidth = nWidth;
/** 这样图片才不会倒置 */
bmpInfo.biHeight = -nHeight;
bmpInfo.biPlanes = 1;
bmpInfo.biBitCount = BITS_PER_PIXCEL;
bmpInfo.biCompression = 0;
bmpInfo.biSizeImage = pixcelBytes;
bmpInfo.biXPelsPerMeter = 100;
bmpInfo.biYPelsPerMeter = 100;
bmpInfo.biClrUsed = 0;
bmpInfo.biClrImportant = 0;
/** 先在内存中进行转换,完成之后,写到文件中。*/
pBmpSource = malloc(pixcelBytes);
if (!pBmpSource)
{
return -1;
}
/** 打开文件 */
fp = fopen(pFileName,"wb+");
if (!fp)
{
return -1;
}
fwrite(&bmpHeader, sizeof(BMP_FILE_HEADER), 1, fp);
fwrite(&bmpInfo, sizeof(BMP_INFO_HEADER), 1, fp);
/** 此处根据传递的颜色格式进行处理。这里的处理逻辑是:
传入的颜色格式是RGBA。
写到文件的格式BGR(否则会红蓝颠倒)*/
pBmpData = pBmpSource;
for (i=0; i<nHeight; i++)
{
for (j=0; j<nWidth; j++)
{
pBmpData[0] = pRgbaData[2];
pBmpData[1] = pRgbaData[1];
pBmpData[2] = pRgbaData[0];
pRgbaData += 4;
pBmpData += 3;
}
//必须4字节对齐,否则会显示错误。
pBmpData +=(bytesPerLine - nWidth*3);
}
fwrite(pBmpSource, pixcelBytes, 1, fp);
/** 清理资源。 */
fclose(fp);
free(pBmpSource);
return 0;
}
如果要剪切一部分呢?代码如下:
int clipRgbaToBmpFile(char *pFileName, unsigned char* pRgbaData, int nWidth , int nHeight,
int nClipLeft, int nClipTop, int nClipWidth, int nClipHeight)
{
char* pClipSource = NULL;
char* pClipData = NULL;
int pixcelBytes = nClipWidth*nClipHeight*4;
int i = 0;
pClipSource = malloc(pixcelBytes);
if (!pClipSource)
{
return -1;
}
//移动到制定位置
pRgbaData += nClipTop * nWidth * 4;
pRgbaData += nClipLeft * 4;
pClipData = pClipSource;
for (i=0; i<nClipHeight; i++)
{
memcpy(pClipData, pRgbaData, nClipWidth*4);
pRgbaData += nWidth * 4;
pClipData += nClipWidth* 4;
}
rgbaToBmpFile(pFileName, pClipSource, nClipWidth, nClipHeight);
//释放资源
free(pClipSource);
return 0;
}
祝愿大家身体健康,工作顺利。