如何用VFW SDK进行AVI视频剪切?

bigbear 教师  2013-01-25 10:45:32
有知道的给提示一下呗!
...全文
589 6 点赞 打赏 收藏 举报
写回复
6 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
bigbear 2013-09-06
谢谢各位的回复.不过我现在不用VFW了,直接改用Videograbber了,视频处理方便多了.
  • 打赏
  • 举报
回复
u010245650 2013-07-10
谢谢2楼 很好,很详细
  • 打赏
  • 举报
回复
zzhong2 2013-03-04
VFW好像没有对视频进行编辑的功能,你得去找怎么生成AVI文件(AVI格式剖析),怎么把两个AVI合成一个AVI以及相关的音、视频压缩解压如何实现 据说微软已经用DirectShow代替了VFW,DirectShow可以实现二次录像(对一个现有的视频录像)
  • 打赏
  • 举报
回复
bigbear 2013-03-01
谢谢楼上的回复,不过,这些我已经知道了!我说得是如何对视频文件进行剪切,合并等等的剪辑功能。
  • 打赏
  • 举报
回复
我不懂电脑 2013-01-28
我在做一个小的视频聊天软件的过程中,充分利用了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不断地被调用。这个函数不会把视频流存入文件。显然这个函数适用于视频聊天程序,不断地通过回调函数获取视频帧,然后......
  • 打赏
  • 举报
回复
bigbear 2013-01-26
自己顶一下!
  • 打赏
  • 举报
回复
相关推荐
发帖
Windows SDK/API
加入

1211

社区成员

C++ Builder Windows SDK/API
申请成为版主
帖子事件
创建了帖子
2013-01-25 10:45
社区公告
暂无公告