首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ Builder >

怎么用VFW SDK进行AVI视频剪切

2013-12-13 
如何用VFW SDK进行AVI视频剪切?有知道的给提示一下呗!VFW??视频剪切?avi[解决办法]我在做一个小的视频聊天

如何用VFW SDK进行AVI视频剪切?
有知道的给提示一下呗! VFW??视频剪切? avi
[解决办法]
我在做一个小的视频聊天软件的过程中,充分利用了vfw提供的各种特性。下面分几个部分讲述我对vfw的认识。比较适合入门级别。
视频截取
       视频聊天软件中,由一端到另一端的视频流先后要经历 视频截获、视频帧压缩、视频帧传输、视频帧解压缩、视频显示。这里就讲述视频截取我的看法。
       第一,由视频设备(usb摄像头或者其他)抓取模拟视频数据并转化为适于计算机处理的数字视频数据。
       第二,把原始的视频数据传至视频驱动程序的缓存区。
       第三,进过我的实践,在调用vfw的进程空间内,会有个缓存区,用于保存从驱动程序传过来的视频数据。
       第四,进程通过vfw窗口把进程缓存区里面的视频帧数据提取出来并且显示。
       第五,通过注册回调函数,可是处理各种情况,状态回调,错误回调,视频流回调,视频帧回调,让步回调。
(1)创建cap窗口
HWND VFWAPI capCreateCaptureWindow( LPCSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWnd, int nID );
       这个函数创建截取窗口,这个窗口也就是用来显示截取的视频。
       可以通过
       CAPSTATUS CapStatus;
       capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));
       组合来获取截取窗口的状态,在程序中,每当需要知道窗口的状态,就必须实时调用capGetStatus函数,因为窗口的状态是随时可能改变的。
       CAPSTATUS 结构的说明:
typedef struct { UINT uiImageWidth; UINT uiImageHeight; BOOL fLiveWindow; BOOL fOverlayWindow; BOOL fScale; POINT ptScroll; BOOL fUsingDefaultPalette; BOOL fAudioHardware; BOOL fCapFileExists; DWORD dwCurrentVideoFrame; DWORD dwCurrentVideoFramesDropped; DWORD dwCurrentWaveSamples; DWORD dwCurrentTimeElapsedMS; HPALETTE hPalCurrent; BOOL fCapturingNow; DWORD dwReturn; UINT wNumVideoAllocated; UINT wNumAudioAllocated; } CAPSTATUS;
       uiImageWidth
             窗口的像素宽度,也就是窗口显示的图像的像素宽度。
      uiImageHeight
            窗口的像素高度,也就是窗口显示的图像的像素高度。
      fLiveWindow
            如果窗口使用预览模式(capPreview)来显示视频,那么这项为true,否则false。
      fOverlayWindow
            如果窗口使用重叠模式(capOverlay)来显示视频,那么这项为true,否则false。
      fScale
             如果窗口使用重叠模式,则此项无效。若true,图像的显示被比例被改变(capPreviewScale),即原始图像被改变比例以适应截取窗口的大小,若false,则显示原始图像比例。
     ptScroll
             截取窗口左上角像素相对于原始图像左上角的偏移(应该是因为fScale的原因)。
     fUsingDefaultPalette
             若true,驱动使用默认的调色板。
     fAudioHardware
              我不关心。
     fCapFileExists
             我不关心。
     dwCurrentVideoFrame
            当前视频截取时得到的总的帧数,包括丢失的。
     dwCurrentVideoFramesDropped
            当前视频截取时丢失的总帧数。
      dwCurrentWaveSamples
             不关心。
       dwCurrentTimeElapsedMS
             从当前视频截取开始到当前的微秒数。
       hPalCurrent
              当前调色板的句柄。
       fCapturingNow
            若true,视频截取正在进行中。
       dwReturn
             不关心。
        wNumVideoAllocated
              进程内视频缓存区的大小。
       wNumAudioAllocated
             不关心。
(2)枚举驱动-获取驱动的参数
char szDeviceName[80]; char szDeviceVersion[80]; for (wIndex = 0; wIndex < 10; wIndex++) { if (capGetDriverDescription( wIndex, szDeviceName, sizeof (szDeviceName), szDeviceVersion, sizeof (szDeviceVersion) )) { // Append name to list of installed capture drivers // and then let the user select a driver to use. } }


以上代码段获取每一个视频驱动的描述信息 驱动名字 以及 驱动的版本号。
capGetDriverDescription的wIndex参数只能是0、1....、9,可能是系统最多支持10类型视频设备的驱动。并且capGetDriverDescription优先获取热拔插视频设备的驱动信息,比如usb视频设备。
CAPDRIVERCAPS cps;
capDriverGetCaps(hCaptureWindow,&cps,sizeof(CAPDRIVERCAPS));
以上代码用于获取 截取窗口所连接的驱动的 参数。
以下是CAPDRIVERCAPS说明:
typedef struct { UINT wDeviceIndex; BOOL fHasOverlay;
wDeviceIndex
驱动序号,即0-9之一。
fHasOverlay
此驱动是否支持重叠模式。
fHasDlgVideoSource
此驱动是否支持视频源选择对话框。
fHasDlgVideoFormat
此驱动是否支持视频帧格式设置对话框。
fHasDlgVideoDisplay
此驱动是否支持视频控制对话框。
fCaptureInitialized
若true,则视频设备已经初始化完成。
fDriverSuppliesPalettes
若true,此驱动可以创建调色板。
hVideoIn
忽略。
hVideoOut
忽略。
hVideoExtIn
忽略。
hVideoExtOut
忽略。
(3)窗口连接驱动
      使用capDriverConnect(hCaptureWindow,wIndex)即可完成窗口hCaptureWindow和第wIndex号驱动的连接。窗口在现实视频之前必须先和一个驱动连接,因为视频数据由驱动程序提供给窗口,然后由窗口显示。
(4)获取并视频帧格式
     DWORD dwSize =capGetVideoFormatSize(hCaptureWindow);
     lpbi=(LPBITMAPINFO)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
[解决办法]
HEAP_NO_SERIALIZE,dwSize);
     capGetVideoFormat(hCaptureWindow, lpbi, dwSize); 
     以上代码段获取截 取窗口连接的 驱动的 视频帧格式。是一个BITMAPINFO可变长度结构。
     lpbi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
     lpbi->bmiHeader.biBitCount=8;
     lpbi->bmiHeader.biWidth=200;
     lpbi->bmiHeader.biHeight=400;
     lpbi->bmiHeader.biPlanes=1;
     lpbi->bmiHeader.biCompression=BI_RGB;
     lpbi->bmiHeader.biClrImportant=0;
     lpbi->bmiHeader.biClrUsed=0;
     lpbi->bmiHeader.biSizeImage=lpbi->bmiHeader.biWidth*lpbi->bmiHeader.biHeight;
     以上设置BITMAPINFO可变长度结构的各个项,按照自己的需求来改,但是一定要是驱动程序支持的。一般都可以使用默认值,不需要改。改的话一般只改长宽值。
     capSetVideoFormat(hCaptureWindow, lpbi, dwSize); 
     以上设置更改后的视频帧格式。
     从驱动程序截取过来的帧都是以上设置的格式。
(5)预览视频
    CAPDRIVERCAPS cps;
    capDriverGetCaps(hCaptureWindow,&cps,sizeof(CAPDRIVERCAPS));
    if (cps.fHasOverlay)  //如果驱动支持重叠模式的话,就优先选择重叠模式,我的机器不支持,仅凭msdn上的一点洋文,我无法理解何为重叠模式。
                                           一般来说,可能就是重叠模式更多的利用了硬件特性,效率速度比预览模式要高。              
      capOverlay(hCaptureWindow, TRUE);
    else
    {
               capPreviewScale(hCaptureWindow,true); //设置预览模式拓展源图像比例以适应截取窗口的大小。显示出来后会失调。
               capPreviewRate(hCaptureWindow,30);  
               capPreview(hCaptureWindow,TRUE);     //开启预览模式。
    }
    这样之后,就可以在截取窗口中看见视频了。
(6)回调函数
     回调函数是vfw里面重要的一环,很多重要的功能都需要回调函数才能完成。
     状态回调:
BOOL capSetCallbackOnStatus( hwnd, fpProc );
     设置状态回调函数。
// StatusCallbackProc: 状态回调函数 // hWnd: capture window handle // nID: 状态码,一个状态码对应一个特定的状态改变。 // lpStatusText: 与状态相关的文本信息。 // LRESULT PASCAL StatusCallbackProc(HWND hWnd, int nID, LPSTR lpStatusText) { if (!hWnd) return FALSE; if (nID == 0) { // Clear old status messages. SetWindowText(hWnd, (LPSTR) gachAppName); return (LRESULT) TRUE; } // Show the status ID and status text... wsprintf(gachBuffer, "Status# %d: %s", nID, lpStatusText); SetWindowText(hWnd, (LPSTR)gachBuffer); return (LRESULT) TRUE; }
  错误回调:
BOOL capSetCallbackOnError( hwnd, fpProc );
以上设置错误回调函数。
LRESULT CALLBACK capErrorCallback( HWND hWnd, int nID, LPCSTR lpsz );
  相关的参数和状态回调意义相同。
 下面重点说明视频流回调,和帧回调,这也是视频截取中最最重要的部分,主要是因为msdn是说的实在是太过简单,聊聊几句带过。而网上也都是些粘贴党。
BOOL capSetCallbackOnFrame( hwnd, fpProc );
   以上设置帧回调函数。下面是回调函数的原型。
LRESULT CALLBACK capFrameCallback( HWND hWnd, LPVIDEOHDR lpVHdr );
    hWnd就是截取窗口的句柄值。
    lpVHdr基本上我们只关心它的两个成员即lpVHdr->lpData,lpVHdr->dwBufferLength。lpVHdr->lpData是一个指针,指向进程空间内的视频缓存区内,
    lpVHdr-  >dwBufferLength是这个缓冲区的长度。但是实际的数据长度却要通过strlen(lpVHdr->lpData)来获取。lpVHdr->lpData指向的数据仅仅是图像的实际数据,就是说不包括 BITMAPINFO结构。如果要传输的话,还需要获取当前驱动的截取的视频格式capGetVideoFormat()来得到 BITMAPINFO结构,然后把BITMAPINFO和lpVHdr->lpData数据组合起来成为一幅位图经过压缩后发送。
    capFrameCallback在什么时候被调用呢?这是个很重要的问题。看了下msdn说这个函数只用在预览模式下。在视频帧从内存缓存区传送的窗口显示之前被调用。有两点很重要条件,一是视频帧要是从内存缓存区出来的(不是直接从驱动缓存区出来的。貌似重叠模式下就是视频数据不经过进程空间的内存缓存区,而是直接由驱动缓存直送窗口显示,这样就提高了效率)。二是,帧要被送往窗口显示。这两点是我自己总结的,只要符合这两个条件,capFrameCallback就会被调用。


    那么就顺便讨论一下几个截取视频的函数capCaptureSingleFrame(),capGrabFrame(),capGrabFrameNoStop()。
    capCaptureSingleFrame(),就是用来提取单帧,这个函数就是从视频驱动缓存提出视频帧数据,然后存入内存缓存区,然后从内存缓存区送至窗口显示,也就是说满足了capFrameCallback调用的两个条件。真实的结果也是如此。
     capGrabFrame(),工作方式与capCaptureSingleFrame()一样,唯一不同的是capGrabFrame()执行完后会禁止重叠模式以及预览模式(msnd上如是说,我就不明白了,两种模式都禁止了,那之后还怎么截取视频流啊?可能这个函数可以专门用来截单帧图像,类似于QQ截图,框选完后整个画面就静止了,应该就是禁止了重叠模式以及预览模式,之后就不再需要这两种模式了,因为接完一张图我就不干了,再截图的时候再开启就可以了)。
     capGrabFrameNoStop(),capGrabFrame()工作的时候进程内其他事务就暂停就像死机一样,而这个函数之所以NoStop就是 它会开辟一个新线程来执行capGrabFrame()所干的事情。
     我觉得理解到这个程度只要对编程没有影响就可以了。
     最后是视频流回调:
BOOL capSetCallbackOnVideoStream( hwnd, fpProc );
LRESULT CALLBACK capVideoStreamCallback( HWND hWnd, LPVIDEOHDR lpVHdr );
以上设置了视频流回调。
     这个回调函数在进程视频缓存区可用(应该就是满的时候)的时候才被调用。所以才能体现 流 这一概念。像水一样,把缓存区流满了要溢出的时候就要采取措施了,于是capVideoStreamCallback被调用了用以处理缓存区满或者可用的情况。
     也有相关的函数capCaptureSequence(),capCaptureSequenceNoFile()。
     capCaptureSequence(),作用就是从进程缓存区把视频流存入一个AVI文件(由capFileSetCaptureFile指定)。
     capCaptureSequenceNoFile(),的作用应该来说仅仅是通过不断地截取视频使内存缓存区满,来使capVideoStreamCallback不断地被调用。这个函数不会把视频流存入文件。显然这个函数适用于视频聊天程序,不断地通过回调函数获取视频帧,然后......
[解决办法]
VFW好像没有对视频进行编辑的功能,你得去找怎么生成AVI文件(AVI格式剖析),怎么把两个AVI合成一个AVI以及相关的音、视频压缩解压如何实现
据说微软已经用DirectShow代替了VFW,DirectShow可以实现二次录像(对一个现有的视频录像)
[解决办法]
谢谢2楼 很好,很详细

热点排行