教你如何使用VFW调用视频压缩解压缩

来源:互联网 发布:粤语发音翻译软件 编辑:程序博客网 时间:2024/05/18 03:36

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qsycn/archive/2009/06/11/4261617.aspx

 

出处:服务器开发(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; 

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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 3岁胳膊背筋了怎么办 左胳膊筋一直疼怎么办 手臂突然筋扭了怎么办 胳膊扭了肿了怎么办 胖人走路磨大腿怎么办 脖子上长了个淋巴结怎么办 面部危险三角区长痘痘怎么办 儿童脖子上有淋巴结节怎么办 左侧颈根部淋巴结肿大怎么办 人的三角区肿了怎么办 刮三角区肿了怎么办 乳腺增生引起的腋窝淋巴结怎么办 右边脸比左边脸大怎么办 六个月宝宝脖子有点歪怎么办 大人的头偏了怎么办 宝宝脖子睡偏了怎么办 宝宝头歪向左边怎么办 一岁宝宝头歪怎么办 宝宝头往右边歪怎么办 八个月宝宝头歪怎么办 宝宝头往左边偏怎么办 11月婴儿歪脖子怎么办 婴儿头往左边偏怎么办 宝宝头网的高怎么办 宝宝头歪向一边怎么办 2岁宝宝头睡偏了怎么办 6岁儿童头有点歪怎么办 宝宝脖子有点偏左边歪怎么办 宝宝脖子偏了怎么办呢 斜颈导致的脸歪怎么办 斜颈手术后脸部还不对称怎么办 宝宝3个月斜颈怎么办 一岁八个月宝宝斜颈怎么办 四个月宝宝有点斜颈怎么办 一岁宝宝有点偏怎么办 6个月宝宝有点斜颈怎么办 四个月宝宝左侧胸锁乳突肌厚怎么办 脖子疼好几天了怎么办 有双下巴怎么办才能瘦掉 胃突然疼的厉害怎么办 手劳损痛的厉害怎么办