:定义COMPVARS对象
view plain copy to clipboard print ?
- typedef struct {
- LONG cbSize;
- DWORD dwFlags;
- HIC hic;
- DWORD fccType;
- DWORD fccHandler;
- LPBITMAPINFO lpbiIn;
- LPBITMAPINFO lpbiOut;
- LPVOID lpBitsOut;
- LPVOID lpBitsPrev;
- LONG lFrame;
- LONG lKey;
- LONG lDataRate;
- LONG lQ;
- LONG lKeyCount;
- LPVOID lpState;
- LONG cbState;
- } COMPVARS;
typedef struct { LONG cbSize; DWORD dwFlags; HIC hic; DWORD fccType; DWORD fccHandler; LPBITMAPINFO lpbiIn; LPBITMAPINFO lpbiOut; LPVOID lpBitsOut; LPVOID lpBitsPrev; LONG lFrame; LONG lKey; LONG lDataRate; LONG lQ; LONG lKeyCount; LPVOID lpState; LONG cbState;} COMPVARS;
cbSize:
必须设置该值为一个正确的值.
或者cbSize = sizeof(COMPVARS);
dwFlags:
ICMF_COMPVARS_VALID
如果你使用ICCompressorChoose 函数来初始化结构,请不要设置这个值.
hic:压缩的句柄,你可以使用ICOpen去获得一个句柄
fccType: ICTYPE_VIDEO
当然也可以设置为zero
fccHandler:四个字符的压缩引擎
lpbiIn:保留
lpbiOut:BITMAPINFO结构的指针,包含了输出图象格式,也可以通过使用函数ICCompressorChoose设置输出格式
lpBitsOut:保留
lpBitsPrev:保留
lFrame:保留
lKey:关键帧速率 ICSeqCompressFrameStart 函数使用这个值来创建关键帧
lDataRate:数据速率,可以通过ICCompressorChoose设置
lQ:质量设置.可以使用ICQUALITY_DEFAULT 默认. ICSeqCompressFrameStart 函数使用这个值来产生数据质量
lKeyCount:保留
lpState:保留
cbState:保留
引用
重要:
如果你要手动设置这个结构,你必须提供如下成员的值:
cbSize, hic, lpbiOut, lKey, and lQ.还有dwFlags为ICMF_COMPVARS_VALID.
对Video Compression Manager(VCM)要熟悉,你还需要了解如下几个结构:
1:BITMAPINFO
2:BITMAPINFOHEADER
VCM工作在应用程序以压缩解压缩驱动之间. 当一个程序调用VCM时候,VCM翻译成一个消息,消息通过ICSendMessage函数去选择调用相应的压缩解压缩器.
VCM服务,一般来说,一个应用程序使用VCM去处理如下的工作:
1:定位,打开,安装一个压缩解压缩器.
2:配置或者获取压缩解压缩器的配置信息.
3:使用一系列的函数去压缩,解压缩,显示数据.
一般显示数据是使用函数DrawDIB.
压缩解压缩基本信息:
你可以使用ICLocate和ICOpen函数定位打开一个压缩器.你可以使用ICLocate去找到一个特定类型的压缩器并获得她的句柄为下一步的VCM函数做准备.你还可以使用ICOpen去打开一个压缩器,你的程序使用ICOpen返回来的句柄来完成更多VCM的功能.
用户如何选择一个压缩器:
当压缩数据时候,你的应用程序可以使用ICCompressorChoose 函数去打开一个对话框去选择一个压缩器,然后返回一个句柄给COMPVARS 结构的hic成员.后面压缩的时候就可以使用这个句柄.
应用程序可以定位和打开一个已经安装的压缩解压缩器,通过使用函数ICLocate和ICOpen函数,当一个应用程序完成使用压缩解压缩器以后,要使用ICClose来关闭.
单图象压缩:
可以使用ICImageCompress 函数来完成单幅图片的压缩.
下面来讨论一下关键的问题:
流压缩的问题
你的程序可以使用 ICSeqCompressFrame, ICSeqCompressFrameStart, and ICSeqCompressFrameEnd函数去压缩一系列的帧.这些函数使用存储在COMPVARS结构中的数据,应用程序可以使用ICCompressorChoose去让用户选择一个压缩器.
在应用程序开始压缩一系列帧之前,必须使用ICSeqCompressFrameStart函数去分配必须的资源.资源分配以后,应用程序可以使用ICSeqCompressFrame去压缩.帧速率和关键帧参数以及其他的一系列参数都存储在COMPVARS结构中,最后程序要使用ICCompressorFree 释放资源.
下面的内容是图象压缩,暂时不翻译,感兴趣的可以去看MSDN.
如何将数据显示出来:
可以使用ICDraw.ICDrawStart.ICDrawBegin.
下面的方法使用ICLocate找到一个压缩器能够压缩8bits的图象的:
view plain copy to clipboard print ?
- BITMAPINFOHEADER bih;
- HIC hIC
-
-
- bih.biSize = sizeof(BITMAPINFOHEADER);
- bih.biWidth = bih.biHeight = 0;
- bih.biPlanes = 1;
- bih.biCompression = BI_RGB;
- bih.biBitcount = 8;
- bih.biSizeImage = 0;
- bih.biXPelsPerMeter = bih.biYPelsPerMeter = 0;
- bih.biClrUsed = bih.biClrImportant = 256;
-
- hIC = ICLocate (ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER) &bih,
- NULL, ICMODE_COMPRESS);
-
- 下面的例子定位一个压缩器去压缩一个8bitRGB 为 8bit RLE格式
- BITMAPINFOHEADER bihIn, bihOut;
- HIC hIC
-
-
-
- biSize = bihOut.biSize = sizeof(BITMAPINFOHEADER);
- bihIn.biWidth = bihIn.biHeight = bihOut.biWidth = bihOut.biHeight = 0;
- bihIn.biPlanes = bihOut.biPlanes= 1;
- bihIn.biCompression = BI_RGB;
- bihOut.biCompression = BI_RLE8;
- bihIn.biBitcount = bihOut.biBitCount = 8;
- bihIn.biSizeImage = bihOut.biSizeImage = 0;
- bihIn.biXPelsPerMeter = bih.biYPelsPerMeter =
- bihOut.biXPelsPerMeter = bihOut.biYPelsPerMeter = 0;
- bihIn.biClrUsed = bih.biClrImportant =
- bihOut.biClrUsed = bihOut.biClrImportant = 256;
-
- hIC = ICLocate (ICTYPE_VIDEO, 0L,
- (LPBITMAPINFOHEADER)&bihIn,
- (LPBITMAPINFOHEADER)&bihOut, ICMODE_COMPRESS);
-
- 下面的函数完成一个安装压缩器:
-
-
- LRESULT MyCodecFunction(DWORD dwID, HDRVR hDriver,
- UINT uiMessage, LPARAM lParam1, LPARAM lParam2);
-
-
-
- result = ICInstall ( ICTYPE_VIDEO, mmioFOURCC('s','a','m','p'),
- (LPARAM)(FARPROC)&MyCodecFunction, NULL, ICINSTALL_FUNCTION);
-
BITMAPINFOHEADER bih;HIC hIC// Initialize the bitmap structure.bih.biSize = sizeof(BITMAPINFOHEADER);bih.biWidth = bih.biHeight = 0;bih.biPlanes = 1;bih.biCompression = BI_RGB; // standard RGB bitmapbih.biBitcount = 8; // 8 bits-per-pixel formatbih.biSizeImage = 0;bih.biXPelsPerMeter = bih.biYPelsPerMeter = 0;bih.biClrUsed = bih.biClrImportant = 256;hIC = ICLocate (ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER) &bih, NULL, ICMODE_COMPRESS);下面的例子定位一个压缩器去压缩一个8bitRGB 为 8bit RLE格式BITMAPINFOHEADER bihIn, bihOut;HIC hIC// Initialize the bitmap structure.biSize = bihOut.biSize = sizeof(BITMAPINFOHEADER);bihIn.biWidth = bihIn.biHeight = bihOut.biWidth = bihOut.biHeight = 0;bihIn.biPlanes = bihOut.biPlanes= 1;bihIn.biCompression = BI_RGB; // standard RGB bitmap for inputbihOut.biCompression = BI_RLE8; // 8-bit RLE for output formatbihIn.biBitcount = bihOut.biBitCount = 8; // 8 bits-per-pixel formatbihIn.biSizeImage = bihOut.biSizeImage = 0;bihIn.biXPelsPerMeter = bih.biYPelsPerMeter = bihOut.biXPelsPerMeter = bihOut.biYPelsPerMeter = 0;bihIn.biClrUsed = bih.biClrImportant = bihOut.biClrUsed = bihOut.biClrImportant = 256;hIC = ICLocate (ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER)&bihIn, (LPBITMAPINFOHEADER)&bihOut, ICMODE_COMPRESS);下面的函数完成一个安装压缩器:// This function looks like a DriverProc entry point.LRESULT MyCodecFunction(DWORD dwID, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2);// This function installs the MyCodecFunction as a compressor.result = ICInstall ( ICTYPE_VIDEO, mmioFOURCC('s','a','m','p'), (LPARAM)(FARPROC)&MyCodecFunction, NULL, ICINSTALL_FUNCTION);
设置一个压缩器的输出格式:
view plain copy to clipboard print ?
- LPBITMAPINFOHEADER lpbiIn, lpbiOut;
-
-
-
- dwFormatSize = ICCompressGetFormatSize(hIC, lpbiIn);
- h = GlobalAlloc(GHND, dwFormatSize);
- lpbiOut = (LPBITMAPINFOHEADER)GlobalLock(h);
- ICCompressGetFormat(hIC, lpbiIn, lpbiOut);
-
LPBITMAPINFOHEADER lpbiIn, lpbiOut;// *lpbiIn must be initialized to the input format.dwFormatSize = ICCompressGetFormatSize(hIC, lpbiIn);h = GlobalAlloc(GHND, dwFormatSize);lpbiOut = (LPBITMAPINFOHEADER)GlobalLock(h);ICCompressGetFormat(hIC, lpbiIn, lpbiOut);
这里很重要
引用
方法是先使用ICCompressGetFormat 去获得压缩格式所需要的空间大小,然后使用GlobalAlloc 分配内存,最后使用ICCompressGetFormat去设置压缩信息.
下面是压缩数据的最最关键的代码:
view plain copy to clipboard print ?
- DWORD dwCkID;
- DWORD dwCompFlags;
- DWORD dwQuality;
- LONG lNumFrames, lFrameNum;
-
-
-
-
-
- if (ICCompressBegin(hIC, lpbiIn, lpbiOut) == ICERR_OK)
- {
- for ( lFrameNum = 0; lFrameNum < lNumFrames; lFrameNum++)
- {
- if (ICCompress(hIC, 0, lpbiOut, lpOut, lpbiIn, lpIn,
- &dwCkID, &dwCompFlags, lFrameNum,
- 0, dwQuality, NULL, NULL) == ICERR_OK)
- {
-
-
-
-
- }
- else
- {
-
- }
- }
- ICCompressEnd(hIC);
- }
- else
- {
-
- }
-
DWORD dwCkID;DWORD dwCompFlags;DWORD dwQuality;LONG lNumFrames, lFrameNum;// Assume dwNumFrames is initialized to the total number of frames.// Assume dwQuality holds the proper quality value (0-10000).// Assume lpbiOut, lpOut, lpbiIn, and lpIn are initialized properly.// If OK to start, compress each frame.if (ICCompressBegin(hIC, lpbiIn, lpbiOut) == ICERR_OK){ for ( lFrameNum = 0; lFrameNum < lNumFrames; lFrameNum++) { if (ICCompress(hIC, 0, lpbiOut, lpOut, lpbiIn, lpIn, &dwCkID, &dwCompFlags, lFrameNum, 0, dwQuality, NULL, NULL) == ICERR_OK) { // Write compressed data to the AVI file. // Set lpIn to the next frame in the sequence. } else { // Handle compressor error. } } ICCompressEnd(hIC); // terminate compression}else{ // Handle the error identifying the unsupported format.}
上面的压缩只是一定方式的,压缩视频帧的时候应该使用ICSeqCompressFrame
view plain copy to clipboard print ?
- LPVOID ICSeqCompressFrame(
- PCOMPVARS pc,
- UINT uiFlags,
- LPVOID lpBits,
- BOOL * pfKey,
- LONG * plSize
- );
LPVOID ICSeqCompressFrame( PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL * pfKey, LONG * plSize );
参数:
pc:一个COMPVARS结构的指针,必须先初始化一些压缩参数.
uiFlags:必须为0
lpBits:指向待压缩数据的指针,数据不包含header以及format格式
pfKey:返回是否该帧压缩为关键帧.
plSize:返回用户压缩数据的大小
该函数使用一个COMPVARS结构提供压缩器以及关键帧,速率,速率通过函数 ICSeqCompressorFrameStart 设置.
当压缩一系列视频流的时候,要使用这个函数去代替ICCompress函数.
你也可以通过使用函数ICCompressorChoose去让用户选择结构.你也可以自己手动设置这个参数.
使用ICSeqCompressFrameStart, ICSeqCompressFrame, and ICSeqCompressFrameEnd函数去压缩一系列帧,每出现一帧数据使用ICSeqCompressFrame 一次.
当完成了压缩,使用ICCompressorFree去释放COMPVARS的资源.
2:设置COMPVARS对象的参数:
1:cbSize
2:dwFlags
3:cbState
4:fccHandler
5:fccType
6:hic
1:使用ICOpen
2:使用ICLocate
3:使用ICCompressGetFormatSize获得数据大小
4:分配内存
5:ICCompressGetFormat 设置参数
6:ICCompressGetSize设置参数
7:ICSeqCompressFrameStart开始
8:断开连接的时候需要如下:
引用
1:ICSeqCompressFrameEnd
2:ICCompressorFree
3:ICClose
9:然后在回调函数里面使用:
ICSeqCompressFrame来压缩.
这里要注意有一个参数是是否为关键帧.bKeyFrame!
一定要将这个参数传递给服务器端.
ICSeqCompressFrame函数返回的BUF也要发送到服务器端.这里就算是开发完毕了!
ICSeqCompressFrame的最后一个参数是压缩后数据的大小.
10:服务器端解压数据处理:
view plain copy to clipboard print ?
-
-
-
-
-
-
- CapVar.hic := ICOpen(CapVar.fccType,CapVar.fccHandler,ICMODE_DECOMPRESS);
-
-
-
- OutFormatSize:=ICDecompressGetFormatSize(CapVar.hic,@BmpInInfo.bmiHeader);
-
- GetMem(BmpOutInfo,OutFormatSize);
-
- zeromemory(BmpOutInfo,OutFormatSize);
-
- ICDecompressGetFormat(CapVar.hic, @BmpInInfo.bmiHeader, @BmpOutInfo^.bmiHeader);
-
- OutBufferSize:=BmpOutInfo^.bmiHeader.biSizeImage;
-
- getmem(OutBuffer,OutBufferSize);
-
- zeromemory(OutBuffer,OutBufferSize);
-
- ICDecompressBegin(CapVar.hic,@BmpInInfo.bmiHeader, @BmpOutInfo^.bmiHeader);
-
-
-
-
- if VIDEO_DATA.bKeyFrame then
- Result:=ICDecompress(CapVar.hic,0,@BmpInInfo,@VIDEO_DATA.Buf,@BmpOutInfo.bmiHeader,OutBuffer)
-
- else
- Result:=ICDecompress(CapVar.hic,ICDECOMPRESS_NOTKEYFRAME,@BmpInInfo,@VIDEO_DATA.Buf,@BmpOutInfo.bmiHeader,OutBuffer);
-
- if (Result=ICERR_OK) then
- begin
-
- SetDIBitsToDevice(Canvas.Handle,0,0,bmptmp.Width,bmptmp.Height,0,0,0,BmpOutInfo^.bmiHeader.biHeight ,OutBuffer,BmpOutInfo^,DIB_RGB_COLORS);
- end;
//下面的代码是Delphi的处理方法: //接着,一起来看看客户端的图像显示过程: //CapVar是COMPVARS对象 C++的定义为 COMPVARS CapVar; //先用取得的CapVar来连接视频编码器 //Capvar.fccHandler是使用客户端一样的解码器 CapVar.hic := ICOpen(CapVar.fccType,CapVar.fccHandler,ICMODE_DECOMPRESS); //成功后,用服务器传来的BmpOutInfo当作客户端的BmpInInfo来取得解压输出的图像头BmpOutInfo //获得参数 OutFormatSize:=ICDecompressGetFormatSize(CapVar.hic,@BmpInInfo.bmiHeader); //分配内存 GetMem(BmpOutInfo,OutFormatSize); //初始化 zeromemory(BmpOutInfo,OutFormatSize); //设置参数 ICDecompressGetFormat(CapVar.hic, @BmpInInfo.bmiHeader, @BmpOutInfo^.bmiHeader); //设置参数 OutBufferSize:=BmpOutInfo^.bmiHeader.biSizeImage; //分配内存 getmem(OutBuffer,OutBufferSize); //初始化 zeromemory(OutBuffer,OutBufferSize); //解压缩开始 ICDecompressBegin(CapVar.hic,@BmpInInfo.bmiHeader, @BmpOutInfo^.bmiHeader); //最后,当然是视频数据的解压过程 //如果是关键帧 if VIDEO_DATA.bKeyFrame then Result:=ICDecompress(CapVar.hic,0,@BmpInInfo,@VIDEO_DATA.Buf,@BmpOutInfo.bmiHeader,OutBuffer) //如果是普通帧 else Result:=ICDecompress(CapVar.hic,ICDECOMPRESS_NOTKEYFRAME,@BmpInInfo,@VIDEO_DATA.Buf,@BmpOutInfo.bmiHeader,OutBuffer); //如果解压成功 if (Result=ICERR_OK) then begin //将图象画出来 SetDIBitsToDevice(Canvas.Handle,0,0,bmptmp.Width,bmptmp.Height,0,0,0,BmpOutInfo^.bmiHeader.biHeight ,OutBuffer,BmpOutInfo^,DIB_RGB_COLORS); end;