avi->bmp:
void CMyAviTttDlg::OnOK()
{
//SetTimer ( 1, 1000, NULL) ;
// CString strOpenFileType = "位图文件 (*.bmp;*.dib)|*.bmp;
// *.dib|All Files (*.*)|*.*||";
//打开avi视频文件
CFileDialog FileDlg(TRUE, "*.avi", NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
_T("视频文件(*.avi)|*.avi|"));
CString m_avifile;
if(FileDlg.DoModal() == IDOK){
m_avifile=FileDlg.GetPathName();
//初始化,以及提取信息
PAVIFILE pfile;//Pointer to a buffer that receives the new IAVIFile interface pointer.
AVIFILEINFO pfi;
PAVISTREAM pavi;
PGETFRAME pgf;
long length, start;
//initializes the AVIFile library,同AVIFileExit()对应。
//Call AVIFileInit() before using any other AVIFile functions
AVIFileInit();
AVIFileOpen(&pfile,m_avifile,OF_READ|OF_SHARE_DENY_NONE,NULL);
//obtains information about an AVI file
AVIFileInfo(pfile,&pfi,sizeof(AVIFILEINFO));
AVIFileGetStream(pfile,&pavi,streamtypeVIDEO,0);
length=AVIStreamLength(pavi);
start=AVIStreamStart(pavi);
AVISTREAMINFO si;
AVIStreamInfo(pavi, &si, sizeof(si));
pgf = AVIStreamGetFrameOpen(pavi, NULL);
//先获取第一帧
LPBITMAPINFOHEADER bmp1;
bmp1= (LPBITMAPINFOHEADER)AVIStreamGetFrame(pgf, 1);
CClientDC dc(this);
//定义位图信息头和文件头
BITMAPINFOHEADER bmih;
memset(&bmih,0,sizeof(BITMAPINFOHEADER));
bmih.biBitCount=bmp1->biBitCount;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = pfi.dwWidth;
bmih.biHeight = pfi.dwHeight;
bmih.biPlanes =bmp1->biPlanes;
bmih.biCompression =BI_RGB;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
BITMAPFILEHEADER bmfh;
bmfh.bfSize = sizeof(bmfh);
bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmih);
bmfh.bfType = (int)'M' * 256 + 'B';
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
BYTE *lpbuffa;
lpbuffa=NULL;
//分配位图内存
//lpbuffa=new BYTE[320*240*3];
lpbuffa=new BYTE[pfi.dwWidth * pfi.dwHeight * 3];
BYTE* lpbuff;
//避免生成的位图过多,限制到100
// if (pfi.dwLength>100)
// pfi.dwLength=100;
for(LONG i=1;i<(LONG)pfi.dwLength;i++)
{
lpbuff=lpbuffa;
lpbuff=(BYTE *)AVIStreamGetFrame(pgf,i);//提取i单帧
lpbuff+=40;
//TranslationDIB1(lpbuff,bmih.biWidth,bmih.biHeight,10,50);//自己定义的平移函数
char name1[50];
strcpy(name1,"d://avi//b");//目标地址
/* //不用name2方案:b1.bmp~b99.bmp
static char name2[10]="0";
static int name2=0;
*name2=*name2+1;
name2++;
char namebuf[10];
_itoa(name2,namebuf,10);
strcat(name1,namebuf);
strcat(name1,".bmp");
*/
//name3方案:b00001.bmp~b00099.bmp
TCHAR name3[50];
wsprintf(name3, TEXT("Bitmap%5.5ld.bmp/0"), long( i ) );
strcat(name1,name3);
//写入文件。
CFile ff(name1, CFile::modeWrite | CFile::modeCreate); //写位图
ff.Write(&bmfh, sizeof(bmfh));//bmfh-->ff
ff.Write(&bmih, 40);
ff.Write(lpbuff, pfi.dwWidth * pfi.dwHeight * 3);
ff.Close();
Sleep(10);
}
//关闭文件
AVIStreamGetFrameClose(pgf);
AVIFileRelease(pfile);
//Use the AVIFileExit() function to release the AVIFile library
//and decrement the reference count.同AVIFileInit()对应。
AVIFileExit();
ReleaseDC(&dc);
//CDialog::OnOK();
}
}
PAVIFILE 等在 vfw.h
编译需要:vfw32.lib
__________________________________________
AVI文件就是我们所说的多媒体文件,所谓的AVI图像就是视频图像,该文件是一个RIFF说明文件,它用于获取、编辑、演示音频、视频序列。一般的AVI文件包含音频流和视频流,有的特殊的AVI还包含一个控制路径或MIDI路径作为附加的数据流。
现在播放AVI文件的软件很多,但大多无法从AVI视频文件中读取一帧图像并生成BMP格式的文件。笔者在使用AVI文件开发项目过程中对AVI文件的操作积累了一些经验,对于如何实现从AVI视频流中获取任意帧的图像数据并存储成BMP文件,其中最关键的是要从AVI文件中获取具体某一帧的图像数据,为此我利用Windows提供的API函数实现了自定义的CAvi类,用于操作AVI文件。
在使用API函数操作AVI文件时,一定要注意用AVIFileInit()来初始化AVI库,程序结束时用AVIFileExit()释放AVI库,否则API函数无法使用。现以操作包含真彩色图像的AVI文件为例,给出Cavi类的部分函数的具体实现,其中CaviCreate()函数用于读取AVI文件信息并初始化Cavi类的成员,例如根据AVI文件信息定义每帧图像的宽、高、每帧图像的信息头结构等等;函数AviRead(int mFrame)用于从AVI文件中读取第mFrame帧。实现代码显示如下:
//Cavi类头文件定义;
class CAvi file://AVI类,处理AVI文件
{
public:
int cy;//图象高
int cx;//图象宽
file://long m_maxFrame;
BYTE *pData;//寸储图象数据
BITMAPINFO *m_pBMI;//位图文件信息头
PAVISTREAM pavi;//AVI流
PAVIFILE pfile;//AVI文件指针
AVIFILEINFO * pfi; file://AVI信息
BOOL AviRead(int mFrame);//读AVI文件的第mFrame帧
CAvi();//标准构造函数
CAviCreate(CString &string);//用文件名初始化AVI类的成员
virtual ~CAvi();
};
//Cavi类文件实现部分;
CAvi::CAvi()
{ AVIFileInit();//初始化AVI库
cx=0;//定义图象宽、高、等成员
cy=0;
m_pBMI=NULL;
pData=NULL;
file://m_maxFrame=0;
pfi=NULL;
}
CAvi::~CAvi()//析构、释放指针
{
// AVIFileClose(pfile);
AVIFileExit();
if(pData!=NULL)
delete pData;
pData=NULL;
if(m_pBMI!=NULL)
delete m_pBMI;
m_pBMI=NULL;
if(pfi!=NULL)
delete pfi;
pfi=NULL;
}
CAvi::CAviCreate(CString &string)//读文件初始化该类
{
HRESULT hr;
pfi=new AVIFILEINFO;
hr = AVIFileOpen(&pfile, // returned file pointer
string, // file name
OF_READ, // mode to open file with
NULL);
hr= AVIFileInfo(pfile, file://获取AVI信息,放入pfi中
pfi,
sizeof(AVIFILEINFO)
);
cx=pfi->dwWidth;//图象宽、高
cy=pfi->dwHeight;
hr=AVIFileGetStream(//将AVI变成视频流
pfile,
&pavi,
streamtypeVIDEO,
0//LONG lParam
);
m_pBMI=new BITMAPINFO;//定义BMP信息头
m_pBMI->bmiHeader.biBitCount=24;
m_pBMI->bmiHeader.biClrImportant=0;
m_pBMI->bmiHeader.biClrUsed=0;
m_pBMI->bmiHeader.biCompression=BI_RGB;
m_pBMI->bmiHeader.biHeight=cy;
m_pBMI->bmiHeader.biWidth=cx;
m_pBMI->bmiHeader.biPlanes=1;
m_pBMI->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
m_pBMI->bmiHeader.biXPelsPerMeter=0;
m_pBMI->bmiHeader.biYPelsPerMeter=0;
m_pBMI->bmiHeader.biSizeImage=cx*cy*3;
pData=(BYTE*)new char[cx*cy*3];//根据AVI中BMP图象的信息定义缓冲区
}
BOOL CAvi::AviRead(int mFrame)//将AVI文件的M帧数据读入PData缓冲区
{
HRESULT hr;
hr= AVIStreamRead( pavi,
mFrame,
1,
pData,
cx*cy*3,
NULL,
NULL
);
if(hr==0)
return TRUE;
else
return FALSE;
}
上述Cavi类实现部分所涉及到的API函数可以参考微软提供的MSDN。Cavi类中的pData缓冲区存放AVI文件中的具体某一帧图像数据,同时Cavi类的m_pBMI为BMP图像文件信息结构,这时可以根据图像的大小定义BMP图像文件头结构,关于BMP文件的存储,由于篇幅的原因,我不在多讲了,有兴趣的读者可以参见笔者的拙作"Visual C++6.0开发灰度位图处理"(天极网软件栏目2001.9.10发表),该文里面讲述了如何存取BMP文件。以上程序在Windows2000、Visual C++6.0环境下顺利编译通过,运行正常。
_____________________________________________________