您的位置:首页 > 其它

如何使用VFW调用视频压缩解压缩(转)

2011-01-05 17:38 357 查看
更多请参考:VCM视频压缩管理:http://hi.baidu.com/sahlee/blog/item/365ccaf92f80bd6f034f56aa.html

出处:服务器开发(Server Development)

时间:Sun, 18 Mar 2007 17:24:10 +0000

作者:huzhangyou2002

地址:http://doserver.net/read.php/1015.htm

内容:

为了深入了解如何开发视频传输,一个下午看MSDN加上网上的资料进行整理,得出如下文档,甚为欣慰,希望能够帮助到别人开发!

数据压缩步骤:

1:定义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的图象的:

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 bitmap

bih.biBitcount = 8; // 8 bits-per-pixel format

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

// 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 input

bihOut.biCompression = BI_RLE8; // 8-bit RLE for output format

bihIn.biBitcount = bihOut.biBitCount = 8; // 8 bits-per-pixel format

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);

下面的函数完成一个安装压缩器:

// 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);

设置一个压缩器的输出格式:

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去设置压缩信息.

下面是压缩数据的最最关键的代码:

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

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:服务器端解压数据处理:

//下面的代码是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;

现在有一个问题就是服务器端多少时间画一次,是什么驱动他开始画的!

Powered by Zoundry Raven
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: