1 实验目的
理解bmp文件的基本组成;
实现bmp序列向yuv文件的转换(基本要求为24bit的bmp文件,进阶要求为支持小于24bit的bmp文件),并用YUV Viewer播放验证。
2 bmp文件格式
bmp文件大体上分为4个部分:
位图文件头BITMAPFILEHEADER
位图信息头BITMAPINFOHEADER
调色板Palette
实际的位图数据ImageData
2.1 位图文件头BITMAPFILEHEADER
2.2 位图信息头BITMAPINFOHEADER
2.3 调色板Palette
调色板实际上是一个数组,它所包含的元素与位图所具有的颜色数相同,决定于biClrUsed和biBitCount字段。数组中每个元素的类型是一个RGBQUAD结构。
真彩色无调色板部分。
2.4 实际的位图数据
- 对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值(逻辑色)。
- 对于真彩色图,图像数据就是实际的R、G、B值。
- 图像每一扫描行的字节数必须是4的整数倍,也就是DWORD对齐的。
- 扫描行是由底向上存储的,这就是说,阵列的第一个字节是位图左下角的像素。(只针对倒向DIB,如果是正向DIB,则扫描行是由顶向下存储的)
3 实验准备
想法:产生10张bmp图片,每张图片播放30帧,则最终会产生300帧的bmp序列,转换后为300帧的yuv文件。
4 实验思路及实验代码
4.1 主函数
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
#include"bmp2yuv.h"
int main(char argc,char *argv[])
{
int height,width;
BITMAPFILEHEADER File_header;
BITMAPINFOHEADER Info_header;
char* bmpfile_name[10];
char* yuvfile_name=NULL;
FILE* bmp;
FILE* yuv;
unsigned char *rgb_buffer,*y_buffer,*u_buffer,*v_buffer;
bool flip=true;
yuvfile_name=argv[11];
yuv=fopen(yuvfile_name,"wb");
if(yuv==NULL)
{
printf("cannot find yuv file!\n");
exit(1);
}
else
{
printf("The input yuv file is %s\n",yuvfile_name);
}
/*一共10张bmp图片*/
/*argv[1]到argv[10]用来表示这10张bmp图片*/
for(int num=0;num<10;num++)
{
bmpfile_name[num]=argv[num+1];
}
height=atoi(argv[12]);
width=atoi(argv[13]);
for(int i=0;i<10;i++)
{
bmp=fopen(bmpfile_name[i],"rb");
if(bmp==NULL)
{
printf("cannot find bmp file!\n");
exit(1);
}
else
{
printf("The input bmp file is %s\n",bmpfile_name[i]);
}
if((fread(&File_header,sizeof(BITMAPFILEHEADER),1,bmp))!=1)
{
printf("Read File header error!");
exit(0);
}
/*判断是否为bmp文件*/
if(File_header.bfType!=0x4D42)
{
printf("Not bmp file!");
exit(0);
}
else
{
printf("This is bmp file!\n");
}
if((fread(&Info_header,sizeof(BITMAPINFOHEADER),1,bmp))!=1)
{
printf("Read Info header error!");
exit(0);
}
/*判断行数是否为4的倍数*/
if(Info_header.biWidth%4==0)
{
width=Info_header.biWidth;
}
else
{
width=(Info_header.biWidth*Info_header.biBitCount+31)/32*(