如何取出VIDEOHDR中的数据,显示出来呢?

时间:2021-05-28 11:01:20
我使用VFW采集视频

用LRESULT CALLBACK capVideoStreamCallback( HWND hWnd, LPVIDEOHDR lpVHdr );
得到了视频缓冲数据,但是该如何从lpVHdr->lpData中取出数据显示在窗口上呢?

这个数据是什么格式?

如果是bmp格式的,我该怎么构造bmp,最终用StretchBlt显示呢?

13 个解决方案

#1


#2


capSetVideoFormat指定的格式即为lpVHdr的格式,不过我一般是指定YUYV,然后Overlap上屏显示。

#3


谢谢 DentistryDoctor!
我现在用StretchBlt来写屏,所以是不是应该在capDriverConnect之后,capSetVideoFormat?

我的目的是分包这一帧数据,然后发送到网络上,最后再组包显示。
目前我已经取出来了这一帧,可以分包租包。

所以我想知道该如何显示这个数据?麻烦你详细指点一下吧!
不论是RGB数据,还是YUV数据,都可以。

谢谢!

#4


Yes,不过还是建议你将数据压后再传!

#5


用双缓存直接绘制到窗口上就是了,不过用DrawDibDraw效率会高一些:
在网络上传输就一定要编码和解码,不然带宽会受不了。

///////////////////////////////////////////////////////////////
HDC hDC = GetDC(m_hWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
// 该位图大小,可以调整到同你采集视频时传递的位图大小一致。
// 这里采用的是默认大小:176*144
HBitmap m_hBitmap = CreateCompatibleBitmap(hDC, 176, 144);

RECT rect;
GetClientRect(m_hWnd, &rect);
      
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap);
        
HDRAWDIB hDib = DrawDibOpen();

// 参数m_bmpInfo是通过视频采集函数capGetVideoFormat得到的位图格式.
DrawDibDraw(hDib, hMemDC, 
        0, 0, rect.right, rect.bottom, 
        &m_bmpInfo.bmiHeader, (LPVOID)lpData, 
        0, 0, m_bmpInfo.bmiHeader.biWidth, m_bmpInfo.bmiHeader.biHeight, 
        DDF_NOTKEYFRAME);

DrawDibClose(hDib);
    
BitBlt(hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, SRCCOPY);

SelectObject(hMemDC, hOldBitmap);

DeleteDC(hMemDC);

ReleaseDC(m_hWnd, hDC);

#6


非常感谢楼上的两位,正在试验你们说的方法!

我正在做的是上层应用,本来只负责视频的播放和音频的采集、播放,视频的采集以及音视频的编解码,同步问题,都由另外一个小组用DSP板来完成,目前因为需要测试,所以,我临时模拟了DSP的部分功能,在局域网上测试。

DrawDibDraw的效率比StretchBlt会高很多吗?主要原理有什么不同?
因为我目前已经用剪贴板共享数据的方法,实现了单帧播放,但是这种方法,无法得知显示的数据Size(我也是初学VC,着了很久,没有找到这个方法),这样无法分包,所以采用回调函数capVideoStreamCallback来取单帧。

capGrabFrameNoStop(hWndCap);
capEditCopy(hWndCap);
//***********************
::OpenClipboard(NULL);
hBitmap = (HBITMAP)::GetClipboardData(CF_BITMAP);
......
::CloseClipboard();

#7


为什么显示不出来呢?黑屏幕。
我改造后的函数:
//*************************************************************
//因为我的视频采集单独用了一个线程,所以用了一个共享缓冲区pVBuffer,
//由FrameCallbackProc来写入,然后发消息给显示窗。
//CopyMemory(pVBufRemote,pVideoHdr->lpData,pVideoHdr->dwBytesUsed);
//::PostMessage(hAVMainWnd, WM_VDSPTOAPPREMOTE, (WPARAM)0, (LPARAM)dwSize);
//Debug中看到共享缓冲区中的数据都传递正常,函数执行正常,为何没反应呢?

//pAVCtrl->PlayRemoteVideo();
HDC hDC = ::GetDC(m_hFrameWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
// 该位图大小,可以调整到同你采集视频时传递的位图大小一致。
// 这里采用的是默认大小:176*144
HBITMAP m_hBitmap = ::CreateCompatibleBitmap(hDC, 240, 180);

RECT rect;
::GetClientRect(m_hFrameWnd, &rect);

HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);

HDRAWDIB hDib = DrawDibOpen();

// 参数m_bmpInfo是通过视频采集函数capGetVideoFormat得到的位图格式.
DrawDibDraw(hDib, hMemDC, 
        0, 0, rect.right, rect.bottom, 
        &m_BitmapInfo.bmiHeader, (LPVOID)pVBufRemote, 
        0, 0, m_BitmapInfo.bmiHeader.biWidth, m_BitmapInfo.bmiHeader.biHeight, 
        DDF_NOTKEYFRAME);

DrawDibClose(hDib);

BitBlt(hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldBitmap);

DeleteDC(hMemDC);

::ReleaseDC(m_hFrameWnd, hDC);
//****************************************************************************

#8


DrawDibDraw具有直接读写显存的能力。

我就是将capVideoStreamCallback回调出来的数据,
COPY到共享内存后作为参数(LPVOID)pVBufRemote来显示的,一切OK。

是不是参数m_bmpInfo的问题?

#9


不是m_bmpInfo的问题,我查看了内存,所有的参数都正确,&m_BitmapInfo.bmiHeader得内容都可以看到,我的那个pVBuffer里的数据也都有,DrawDibDraw()、BitBlt()两个函数返回值都是TRUE.

但是就是没有效果,不知道为什么啊?我还调整了位置参数,也不行。

折腾了一下午了。。。。。。郁闷。。。。。。

不过还是谢谢你!我再看看!

#10


你在capVideoStreamCallback取到了缓冲数据后,是否调整了共享缓冲pVBuffer的大小呢?

我预先分配了一个较大的内存空间,在得到数据后,根据pVideoHdr->dwBytesUsed,realloc了pVBuffer的大小。应该不是这个问题吧?

#11


非常感谢2位的指点,尤其是 freeshoot(巴蒂刘),按照你的方法已经试验成功。

因为我不想用VFW的DrawDibDraw函数,所以我还想请教一下,如果单独用CreateBMP系列的函数,该怎么创建一个hBitmap?然后装入memDC,用StretchBlt显示?

#12


如果你不想用DrawDibDraw, 可以用Win32 GDI函数StretchDIBits实现你想要得功能:
int StretchDIBits(
  HDC hdc,                // handle to device context
  int XDest,              // x-coordinate of upper-left corner of dest. rectangle
  int YDest,              // y-coordinate of upper-left corner of dest. rectangle
  int nDestWidth,         // width of destination rectangle
  int nDestHeight,        // height of destination rectangle
  int XSrc,               // x-coordinate of upper-left corner of source rectangle
  int YSrc,               // y-coordinate of upper-left corner of source rectangle
  int nSrcWidth,          // width of source rectangle
  int nSrcHeight,         // height of source rectangle
  CONST VOID *lpBits,            // address of bitmap bits
  CONST BITMAPINFO *lpBitsInfo,  // address of bitmap data
  UINT iUsage,                   // usage flags
  DWORD dwRop                    // raster operation code
);

#13


已经全部搞定。
非常感谢freeshoot(巴蒂刘) !

#1


#2


capSetVideoFormat指定的格式即为lpVHdr的格式,不过我一般是指定YUYV,然后Overlap上屏显示。

#3


谢谢 DentistryDoctor!
我现在用StretchBlt来写屏,所以是不是应该在capDriverConnect之后,capSetVideoFormat?

我的目的是分包这一帧数据,然后发送到网络上,最后再组包显示。
目前我已经取出来了这一帧,可以分包租包。

所以我想知道该如何显示这个数据?麻烦你详细指点一下吧!
不论是RGB数据,还是YUV数据,都可以。

谢谢!

#4


Yes,不过还是建议你将数据压后再传!

#5


用双缓存直接绘制到窗口上就是了,不过用DrawDibDraw效率会高一些:
在网络上传输就一定要编码和解码,不然带宽会受不了。

///////////////////////////////////////////////////////////////
HDC hDC = GetDC(m_hWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
// 该位图大小,可以调整到同你采集视频时传递的位图大小一致。
// 这里采用的是默认大小:176*144
HBitmap m_hBitmap = CreateCompatibleBitmap(hDC, 176, 144);

RECT rect;
GetClientRect(m_hWnd, &rect);
      
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap);
        
HDRAWDIB hDib = DrawDibOpen();

// 参数m_bmpInfo是通过视频采集函数capGetVideoFormat得到的位图格式.
DrawDibDraw(hDib, hMemDC, 
        0, 0, rect.right, rect.bottom, 
        &m_bmpInfo.bmiHeader, (LPVOID)lpData, 
        0, 0, m_bmpInfo.bmiHeader.biWidth, m_bmpInfo.bmiHeader.biHeight, 
        DDF_NOTKEYFRAME);

DrawDibClose(hDib);
    
BitBlt(hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, SRCCOPY);

SelectObject(hMemDC, hOldBitmap);

DeleteDC(hMemDC);

ReleaseDC(m_hWnd, hDC);

#6


非常感谢楼上的两位,正在试验你们说的方法!

我正在做的是上层应用,本来只负责视频的播放和音频的采集、播放,视频的采集以及音视频的编解码,同步问题,都由另外一个小组用DSP板来完成,目前因为需要测试,所以,我临时模拟了DSP的部分功能,在局域网上测试。

DrawDibDraw的效率比StretchBlt会高很多吗?主要原理有什么不同?
因为我目前已经用剪贴板共享数据的方法,实现了单帧播放,但是这种方法,无法得知显示的数据Size(我也是初学VC,着了很久,没有找到这个方法),这样无法分包,所以采用回调函数capVideoStreamCallback来取单帧。

capGrabFrameNoStop(hWndCap);
capEditCopy(hWndCap);
//***********************
::OpenClipboard(NULL);
hBitmap = (HBITMAP)::GetClipboardData(CF_BITMAP);
......
::CloseClipboard();

#7


为什么显示不出来呢?黑屏幕。
我改造后的函数:
//*************************************************************
//因为我的视频采集单独用了一个线程,所以用了一个共享缓冲区pVBuffer,
//由FrameCallbackProc来写入,然后发消息给显示窗。
//CopyMemory(pVBufRemote,pVideoHdr->lpData,pVideoHdr->dwBytesUsed);
//::PostMessage(hAVMainWnd, WM_VDSPTOAPPREMOTE, (WPARAM)0, (LPARAM)dwSize);
//Debug中看到共享缓冲区中的数据都传递正常,函数执行正常,为何没反应呢?

//pAVCtrl->PlayRemoteVideo();
HDC hDC = ::GetDC(m_hFrameWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
// 该位图大小,可以调整到同你采集视频时传递的位图大小一致。
// 这里采用的是默认大小:176*144
HBITMAP m_hBitmap = ::CreateCompatibleBitmap(hDC, 240, 180);

RECT rect;
::GetClientRect(m_hFrameWnd, &rect);

HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);

HDRAWDIB hDib = DrawDibOpen();

// 参数m_bmpInfo是通过视频采集函数capGetVideoFormat得到的位图格式.
DrawDibDraw(hDib, hMemDC, 
        0, 0, rect.right, rect.bottom, 
        &m_BitmapInfo.bmiHeader, (LPVOID)pVBufRemote, 
        0, 0, m_BitmapInfo.bmiHeader.biWidth, m_BitmapInfo.bmiHeader.biHeight, 
        DDF_NOTKEYFRAME);

DrawDibClose(hDib);

BitBlt(hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldBitmap);

DeleteDC(hMemDC);

::ReleaseDC(m_hFrameWnd, hDC);
//****************************************************************************

#8


DrawDibDraw具有直接读写显存的能力。

我就是将capVideoStreamCallback回调出来的数据,
COPY到共享内存后作为参数(LPVOID)pVBufRemote来显示的,一切OK。

是不是参数m_bmpInfo的问题?

#9


不是m_bmpInfo的问题,我查看了内存,所有的参数都正确,&m_BitmapInfo.bmiHeader得内容都可以看到,我的那个pVBuffer里的数据也都有,DrawDibDraw()、BitBlt()两个函数返回值都是TRUE.

但是就是没有效果,不知道为什么啊?我还调整了位置参数,也不行。

折腾了一下午了。。。。。。郁闷。。。。。。

不过还是谢谢你!我再看看!

#10


你在capVideoStreamCallback取到了缓冲数据后,是否调整了共享缓冲pVBuffer的大小呢?

我预先分配了一个较大的内存空间,在得到数据后,根据pVideoHdr->dwBytesUsed,realloc了pVBuffer的大小。应该不是这个问题吧?

#11


非常感谢2位的指点,尤其是 freeshoot(巴蒂刘),按照你的方法已经试验成功。

因为我不想用VFW的DrawDibDraw函数,所以我还想请教一下,如果单独用CreateBMP系列的函数,该怎么创建一个hBitmap?然后装入memDC,用StretchBlt显示?

#12


如果你不想用DrawDibDraw, 可以用Win32 GDI函数StretchDIBits实现你想要得功能:
int StretchDIBits(
  HDC hdc,                // handle to device context
  int XDest,              // x-coordinate of upper-left corner of dest. rectangle
  int YDest,              // y-coordinate of upper-left corner of dest. rectangle
  int nDestWidth,         // width of destination rectangle
  int nDestHeight,        // height of destination rectangle
  int XSrc,               // x-coordinate of upper-left corner of source rectangle
  int YSrc,               // y-coordinate of upper-left corner of source rectangle
  int nSrcWidth,          // width of source rectangle
  int nSrcHeight,         // height of source rectangle
  CONST VOID *lpBits,            // address of bitmap bits
  CONST BITMAPINFO *lpBitsInfo,  // address of bitmap data
  UINT iUsage,                   // usage flags
  DWORD dwRop                    // raster operation code
);

#13


已经全部搞定。
非常感谢freeshoot(巴蒂刘) !