第六章多媒体编程基础6.1多媒体文件多媒体文件一般被称为RIFF文件,即资源交互文件格式(Resource interchange file format)。
RIFF格式是面向部分(Chunk)的。
一个RIFF文件是由一个或多个部分组成的,每个部分都有一个类型,后面跟着一些数据。
typedef struct{FOURCC ckID; //4字符字段,标志类型(比如波形音频为WA VE)DWORD cksize; //部分中数据的大小}CK;MFC为处理RIFF文件专门提供了一套多媒体I/O函数,这些函数都有前缀mmio。
比如mmioOpen是打开RIFF文件,mmioDescend可以进入RIFF文件的部分。
HMMIO h;CString path;……If ((h=mmioOpen(path,NULL,MMIO_READ))==NULL)return FALSE;……If (mmioRead(h,&dataformat,(long)n)!=(long)n){ mmio Close(h,0);return FALSE;}WA V文件开始是46个字节的文件头,之后是波形数据。
文件头如下:Typedef struct {DWORD rftype; //固定为字符串“RIFF”DWORD wbSize; //波形块的大小DWORD wftype; //wav文件标志,固定为字符串“WA VE”DWORD ftype; //固定为字符串“fmt”DWORD BlockSize; //格式块的大小WORD wFormatTag; //记录波形编码格式。
为WA VE_FORMAT_PCM WORD nChannels; //记录波形文件数据中的通道数DWORD nSamplesPerSec; //记录波形文件的采样率DWORD nAvgBytesPerSec;//平均每秒波形音频数据所需要的字节数DWORD nBlockAlign; //记录一个采样所需要的字节数WORD wBitsPerSample; //每个采样的位数DWORD dataflag; //固定为字符串“data”DWORD fSize; //波形文件大小}PCMWA VEFORMAT;BMP文件开始通常依次是14字节的文件头,40字节的位图信息,颜色表(真彩位图没有),最后是图像数据,对于用到调色板的位图,实际的图象数据ImageDate为该象素的颜色在调色板中的索引值;对于真彩色图,图象数据则为实际的R、G、B值。
位图数据每一行的字节数必须为4的整倍数,如果不是,则需要补齐;位图文件中的数据是从下到上(而不是从上到下)、从左到右方式存储的。
图像数据或者不压缩,或者使用RLE压缩。
文件头如下:typedef struct tagBITMAPFILEHEADER {WORD bftype; // 固定为字符串“BM”DWORD bfsize; // 字节为单位的位图文件大小WORD bfReserved1; // 位图文件保留字,必须为0WORD bfReserved2; // 位图文件保留字,必须为0DWORD bfoffBits; // 指出图像数据针对文件头的偏移量}BITMAPFILEHEADER;typedef struct tagBITMAPINFOHEADER{DWORD biSize; //本结构的长度,为40LONG biWidth; //图象的宽度,单位是象素LONG biHeight; //图象的高度,单位是象素WORD biPlanes; //必须是1WORD biBitCount;//表示颜色时要用到的位数,1(单色), 4(16色), 8(256色), 24(真彩色) DWORD biCompression;//指定位图是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS 等,BI_RGB表示不压缩DWORD biSizeImage;//实际的位图数据占用的字节数,即biSizeImage=biWidth’×biHeight,biWidth’是biWidth 按照4的整倍数调整后的结果LONG biXPelsPerMeter; //目标设备的水平分辨率,单位是每米的象素个数LONG biYPelsPerMeter; //目标设备的垂直分辨率,单位是每米的象素个数DWORD biClrUsed; //位图实际用到的颜色数,0表示颜色数为2biBitCount DWORD biClrImportant; //位图中重要的颜色数,0表示所有颜色都重要} BITMAPINFOHEADER;调色板Palette针对的是需要调色板的位图,即单色、16色和256色位图。
对于不以调色板方式存储的位图,则无此项信息。
调色板是一个数组,共有biClrUsed 个元素(如果该值为0,则有2biBitCount个元素)。
数组中每个元素是一个RGBQUAD结构体,长度为4个字节,定义为:typedef struct tagRGBQUAD{BYTE rgbBlue; //蓝色分量BYTE rgbGreen; //绿色分量BYTE rgbRed; //红色分量BYTE rgbReserved; //保留值} RGBQUAD;6.2 WINDOWS位图WINSOWS位图编程的方法主要分为设备相关位图与设备无关位图。
DDB 设备相关位图由MFC中CBitmap类表示,从应用程序的资源里获得完全依赖于设备的数据结构,很方便,但是局限性大。
DIB设备无关位图拥有位图的所有信息,此格式为所有位图文件所包含,也被WIN32 API所支持,比GDI位图有更多的编程优势。
例:DDB位图的显示void CGDIbmpView::OnDraw(CDC* pDC){CGDIbmpDoc* pDoc = GetDocument();ASSERT_V ALID(pDoc);// TODO: add draw code for native data hereCBitmap bm;CDC dcMem;bm.LoadBitmap(IDB_BITMAP2);dcMem.CreateCompatibleDC(pDC);dcMem.SelectObject(&bm);pDC->BitBlt(20,20,400,600,&dcMem,0,0,SRCCOPY);}Visual C++ MFC中没有提供一个专门的类来处理DIB位图,因此,为了方便地使用位图文件,一般派生一个CDib类。
最简单的如下所示:class CDib{public: CDib();~CDib();BOOL Load( const char * ); //用来载入一个BMP文件BOOL Save( const char * );BOOL Draw( CDC *, int nX = 0, int nY = 0, int nWidth = -1, int nHeight = -1, int mode = SRCCOPY); //在相应的设备中绘制BOOL SetPalette( CDC * ); //根据图象的调色板信息设定当前调色板private: CPalette m_Palette;unsigned char *m_pDib, *m_pDibBits; // m_pDib指向图象文件中从文件头以后的所有信息,包括图象信息、调色板、图象数据;载入文件的时候分配空间,析构函数中释放空间。
DWORD m_dwDibSize;BITMAPINFOHEADER *m_pBIH; //指向信息头的指针RGBQUAD *m_pPalette; //指向图象调色板的指针int m_nPaletteEntries;};6.3媒体控制接口MCIMCI(Media Control Interface,媒体控制接口)向Windows程序提供了在高层次上控制媒体设备接口的能力。
程序不必关心具体设备,就可以对激光唱机(CD)、视盘机、波形音频设备、视频播放设备和MIDI设备等媒体设备进行控制。
核心是用于解释和执行MCI命令的MCI设备驱动程序。
简单设备:如激光唱机等在播放时不要求数据文件。
复合设备:如MIDI以及波形音响设备在播放的时候需要数据文件。
为了唯一地区分MCI驱动程序,MCI引入设备名,放在SYSTEM.INI文件的[MCI]段中。
设备类型和设备名是不同的概念。
设备类型是指响应一组共用命令的一类MCI设备,而设备名则是某一个MCI设备的名字。
[mci]cdaudio=mcicda.drvsequencer=mciseq.drvwaveaudio=mciwave.drvavivideo=mciavi.drvvideodisc=mcipionr.drvMCI编程接口可以利用近似英语的句法与MCI设备通信,被称为串方式。
有以下2个API:BOOL mciExecute(lpstrCommand)MCIERROR mciSendString( lpszCommand, lpszReturnString,cchReturn, hwndCallback)第一个参数指向以NULL结尾的MCI命令字符串,若成功则返回0,否则返回错误码BOOL mciGetErrorString(dwError, lpstrBuffer, wLength)第一个参数为错误码。
第二个参数指向系统返回的错误描述文字串的缓存。
第三个参数指定缓存的长度。
函数调用成功返回TRUE,否则返回FALSE。
例如:我们用“open cdaudio”串打开CD驱动器准备读取char buf[50];MCIERROR mciError;mciError=mciSendString(“open cdaudio”,buf,strlen(buf),NULL);if(mciError){mciGetErrorString(mciError,buf,strlen(buf));AfxMessageBox(buf);return;}MCI最常用的另一种方式是消息方式,即发送WINDOWS消息,传递相应的数据结构通知设备进行操作。
MCIERROR mciSendCommand(MCIDEVICEID IDDevice, //设备的ID,在打开设备时不用该参数UINT uMsg, //命令消息DWORD dwCommand, //命令消息的标志DWORD dwParam//指向包含命令消息参数的结构); //若成功则返回0,否则返回错误码MCI的消息和命令有很多,下表显示了主要的指令。