DirectShow抓取视频帧 ISampleGrabber

DirectShow抓取视频帧 ISampleGrabber
2010-04-25 16:46

下面是根据msdn(参见http://msdn.microsoft.com/en-us/library/dd407288(v=VS.85).aspx)
的帮助文档写的抓取视频某一帧的程序,并将帧以.bmp文件的形式存储起来。开始的时候,由于
不知道directshow版本的差异,花了n久的时间来配置开发环境。

一种是实现ISampleGrabberCB接口,然后调用ISampleGrabber的SetCallBack
方法,详情请参见SDK中的示例程序(DXSDK ROOT/Samples/C++/DirectShow/Editing/GrabBitmaps)。
这样当视频流经过filter时,会自动调用在SetCallBack设置的对应的方法进行数据处理。
    另一种是直接使用ISampleGrabber的GetCurrentBuffer的法获取数据然后写入文件,其实二者
的本质是相同的。


环境 
vs2008

directshow版本
dxsdk_feb2005.exe
dxsdk_feb2005_extras.exe

//grabber.h
#pragma once
#include "qedit.h"
#include "dshow.h"

class VideoFrameGrabber
{
private:
IGraphBuilder *pGraph;
IBaseFilter    *pGrabberF;
IBaseFilter    *pNullRender;
IMediaControl *pControl;
IMediaEvent    *pEvent;
IMediaSeeking *pSeeking;
ISampleGrabber *pGrabber;
IBaseFilter *pSource;
IEnumPins *pEnum;
    AM_MEDIA_TYPE mt;
LONGLONG totalFrame;
boolean initFailed;
CString source;
bool graphStatus;
private:
HRESULT Init();
HRESULT IsPinConnected(IPin *pPin, bool *connected);
HRESULT IsPinDirection(IPin *pPin, PIN_DIRECTION pDir, bool *result);
HRESULT FindUnconnectedPin(IBaseFilter *pFilter, PIN_DIRECTION pDir, IPin **ppPin);
HRESULT MatchPin(IPin *pPin, PIN_DIRECTION pinDir, bool connected, bool *result);
HRESULT ConnectFilters(IGraphBuilder *pGraph, IPin *pPout, IBaseFilter *pDest);
HRESULT ConnectFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IPin *pPin);
HRESULT ConnectFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest);
HRESULT WriteBitmap(CString dest, BITMAPINFOHEADER *pBMI, size_t cbBMI,
   LONG *pData, size_t cbData);
public:
/*VideoFrameGrabber(void);*/
VideoFrameGrabber(CString source);
~VideoFrameGrabber(void);
void ReleaseResource(); 
HRESULT GrabberGrameFromVideo(CString dest, LONGLONG *frame);
LONGLONG GetTotalFrame();
};

 

//grabber.cpp

#include "StdAfx.h"
#include "grabber.h"

template <class T> 
void SafeRelease(T **ppT)
{
if (*ppT)
{
   (*ppT)->Release();
   *ppT = NULL;
}
}


void FreeMediaType(AM_MEDIA_TYPE &mt)
{
if (mt.cbFormat != 0)
{
   CoTaskMemFree((PVOID)mt.pbFormat);
   mt.cbFormat = 0;
   mt.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
   mt.pUnk->Release();
   mt.pUnk = NULL;
}
}

// VideoFrameGrabber::VideoFrameGrabber(void)
// { 
// }

/*
* graphStatus = true means graph is running, else isn't running
*/
VideoFrameGrabber::VideoFrameGrabber(CString source)
{
initFailed = false; 
this->source = source;
graphStatus = false;
totalFrame = 0;
HRESULT hr = Init();
if(FAILED(hr))
{
   ReleaseResource();
}
}

VideoFrameGrabber::~VideoFrameGrabber(void)
{
ReleaseResource();
}

/*
* initializes interface and create object
*/
HRESULT VideoFrameGrabber::Init()
{
if (!AfxOleInit())
{
   AfxMessageBox(100);
   AfxMessageBox(CString("can not initialize ole controls for application"));
   return S_FALSE;
}
AfxEnableControlContainer();

CString frames;
HRESULT hr;
hr = CoCreateInstance(CLSID_FilterGraph, NULL,CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph);
if(FAILED(hr))
   goto done;
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
if(FAILED(hr))
   goto done;
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
if(FAILED(hr))
   goto done;
hr = pGraph->QueryInterface(IID_IMediaSeeking, (void **)&pSeeking);
if(FAILED(hr))
   goto done;

// create the Sample Grabber filter.
    hr =CoCreateInstance(CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pGrabberF);
if(FAILED(hr))
   goto done;
hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
if(FAILED(hr))
   goto done;
hr = pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber); 
if(FAILED(hr))
   goto done;

//set grabber media type 
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = pGrabber->SetMediaType(&mt);
if(FAILED(hr))
   goto done;

//add source filter and connect filter to filter
hr = pGraph->AddSourceFilter(source, _T("Source Filter"), &pSource); 
if(FAILED(hr))
   goto done;
hr = pSource->EnumPins(&pEnum);
if(FAILED(hr))
   goto done;

IPin *pPin = NULL;
while(S_OK == pEnum->Next(1, &pPin, NULL))
{
   hr = ConnectFilters(pGraph, pPin, pGrabberF);
   SafeRelease(&pPin);
   if(SUCCEEDED(hr))
    break;
}

//create null renderer and add to filter graph
hr = CoCreateInstance(CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pNullRender);
if(FAILED(hr))
   goto done;

hr = pGraph->AddFilter(pNullRender, L"Null Renderer");
if(FAILED(hr))
   goto done;
hr = ConnectFilters(pGraph, pGrabberF, pNullRender);
if(FAILED(hr))
   goto done;

hr = pGrabber->SetOneShot(true);
if(FAILED(hr))
   goto done;

hr = pGrabber->SetBufferSamples(true);
if(FAILED(hr))
   goto done;

/*
* it is pivotal to put this statement here, but i don't know the reason.
*/
hr = pSeeking->SetTimeFormat(&TIME_FORMAT_FRAME);
if(FAILED(hr))
   goto done;
hr = pSeeking->GetDuration(&totalFrame);
if(FAILED(hr))
   goto done; 
frames.Format(_T("%I64d"), totalFrame);
AfxMessageBox(frames);

done:
if(FAILED(hr))
{
   initFailed = true;
     ReleaseResource();
}
return hr;
}

HRESULT VideoFrameGrabber::GrabberGrameFromVideo(CString dest, LONGLONG *frame)
{
if(initFailed)
{
   AfxMessageBox(CString("an error occured whern initialization"));
   return S_FALSE;
}
HRESULT hr = pSeeking->SetPositions(frame, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
if(FAILED(hr))
{
   goto done;
}
if(graphStatus == false)
   hr = pControl->Run();
if(FAILED(hr))
{
   goto done;
}
long ecode;
hr = pEvent->WaitForCompletion(INFINITE, &ecode);
if(FAILED(hr))
{
   goto done;
}
long bufferSize;
hr = pGrabber->GetCurrentBuffer(&bufferSize, NULL);
if(FAILED(hr))
{
   goto done;
}
long *pBuffer = new long[bufferSize];
hr = pGrabber->GetCurrentBuffer(&bufferSize, (long*)pBuffer);
if(FAILED(hr))
{
   goto done;
}
hr = pGrabber->GetConnectedMediaType(&mt);
if(FAILED(hr))
{
   goto done;
}
if((mt.formattype == FORMAT_VideoInfo) && 
    (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
   (mt.pbFormat != NULL))

   VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;

   hr = WriteBitmap(dest, &pVih->bmiHeader, 
    mt.cbFormat - SIZE_PREHEADER, pBuffer, bufferSize);
}
else 
{
   // Invalid format.
   hr = VFW_E_INVALIDMEDIATYPE; 
}
delete pBuffer;
pBuffer = NULL;
done:
if(FAILED(hr))
{
   ReleaseResource();
   CString msg;
   msg.Format(_T("%I64d"), *frame);
   msg = CString("an error occured when grabber frame ") + msg;
   AfxMessageBox(msg);
}
return S_OK;
}

HRESULT VideoFrameGrabber::WriteBitmap(CString dest, BITMAPINFOHEADER *pBMI, size_t cbBMI,
            LONG *pData, size_t cbData)
{
HANDLE hFile = CreateFile(dest, GENERIC_WRITE, 0, NULL, 
   CREATE_ALWAYS, 0, NULL);
if (hFile == NULL)
{
   return HRESULT_FROM_WIN32(GetLastError());
}

BITMAPFILEHEADER bmf = { };

bmf.bfType = 'MB';
bmf.bfSize = cbBMI + cbData + sizeof(bmf); 
bmf.bfOffBits = sizeof(bmf) + cbBMI;

DWORD cbWritten = 0;
BOOL result = WriteFile(hFile, &bmf, sizeof(bmf), &cbWritten, NULL);
if (result)
{
   result = WriteFile(hFile, pBMI, cbBMI, &cbWritten, NULL);
}
if (result)
{
   result = WriteFile(hFile, pData, cbData, &cbWritten, NULL);
}

HRESULT hr = result ? S_OK : HRESULT_FROM_WIN32(GetLastError());

CloseHandle(hFile);

return hr;
}

/* 
* judge whether a pin is connected to another a pin 
* by calling ConnectedTo(IPin **ppPin) method of IPin 
*/
HRESULT VideoFrameGrabber::IsPinConnected(IPin *pPin, bool *connected)
{
IPin *pTmp = NULL;
HRESULT hr = pPin->ConnectedTo(&pPin);
if(SUCCEEDED(hr))
   *connected = true;
else if(VFW_E_NOT_CONNECTED == hr) // this pin is not connected. it's not an error for our purpose, 
{
   *connected = false;
   hr = S_OK;
}
SafeRelease(&pTmp);
return hr;
}

/*
*judge whether a pin has a specficed direction(input or output)
*/
HRESULT VideoFrameGrabber::IsPinDirection(IPin *pPin, PIN_DIRECTION Dir, bool *result)
{
PIN_DIRECTION tmpDir;
HRESULT hr = pPin->QueryDirection(&tmpDir);
if(SUCCEEDED(hr))
{
   *result = (Dir == tmpDir);
}
return hr;
}

/*
* judge whether a pin is matched by pin direction and connection status
*/
HRESULT VideoFrameGrabber::MatchPin(IPin *pPin, PIN_DIRECTION pinDir, bool connected, bool *result)
{
bool isConnected = false;
bool match = false;
HRESULT hr = IsPinConnected(pPin, &isConnected);
if(SUCCEEDED(hr))
{
   if(isConnected == connected)
    hr = IsPinDirection(pPin, pinDir, &match);
}
if(SUCCEEDED(hr))
   *result = match;
return hr;
}

/*
* find the first unconnected input pin or ouput pin of a base filter
*/
HRESULT VideoFrameGrabber::FindUnconnectedPin(IBaseFilter *pFilter, PIN_DIRECTION pDir, IPin **ppPin)
{
IEnumPins *pEunm;
IPin *pPin = NULL;
bool found = false;

HRESULT hr = pFilter->EnumPins(&pEunm);
if(FAILED(hr))
   goto done; 
while(S_OK == pEunm->Next(1, &pPin, NULL))
{
   hr = MatchPin(pPin, pDir, false, &found);
   if(FAILED(hr)) 
    goto done;
   if(found)
   {
    *ppPin = pPin;
    (*ppPin)->AddRef();
    break;
   }
   SafeRelease(&pPin);
}
if (!found)
{
   hr = VFW_E_NOT_FOUND;
}
done:
SafeRelease(&pPin);
SafeRelease(&pEunm);
return hr;
}

void VideoFrameGrabber::ReleaseResource()
{
SafeRelease(&pEnum);
SafeRelease(&pNullRender);
SafeRelease(&pSeeking);
SafeRelease(&pSource);
SafeRelease(&pGrabberF);
SafeRelease(&pGrabber);
SafeRelease(&pControl);
SafeRelease(&pEvent); 
SafeRelease(&pGraph);
}

/*
*connect a out pin to a filter
*/
HRESULT VideoFrameGrabber::ConnectFilters(IGraphBuilder *pGraph, IPin *pOut, IBaseFilter *pDest)
{
IPin *pIn = NULL;

// Find an input pin on the downstream filter.
HRESULT hr = FindUnconnectedPin(pDest, PINDIR_INPUT, &pIn);
if (SUCCEEDED(hr))
{
   // Try to connect them.
   hr = pGraph->Connect(pOut, pIn);
   pIn->Release();
}
return hr;
}


/*
* find a input pin of a filter and then connect it to a pin
* in other word, it connects a filter to a pin
*/
HRESULT VideoFrameGrabber::ConnectFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IPin *pPin)
{
IPin *pOut = NULL;
HRESULT hr = FindUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut);
if(SUCCEEDED(hr))
{
   hr = pGraph->Connect(pOut, pPin);
   pOut->Release();
}
return hr;
}

/*
* connect a filter to a filter
*/
HRESULT VideoFrameGrabber::ConnectFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest)
{
IPin *pOut = NULL; 
HRESULT hr = FindUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut);
if(SUCCEEDED(hr))
{
   hr = ConnectFilters(pGraph, pOut, pDest);
   pOut->Release();
}
return hr;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DirectShow是Windows平台上的一个多媒体框架,用于处理音频和视频流。使用DirectShow捕捉摄像头视频数据需要以下步骤: 1. 枚举可用的视频捕捉设备并选择需要使用的设备。 2. 创建一个Filter Graph Manager对象,用于管理DirectShow图形。 3. 创建一个视频捕捉设备的Filter对象,并添加到Filter Graph Manager中。 4. 创建一个Sample Grabber Filter对象,用于获取视频数据。 5. 创建一个Null Renderer对象,用于显示视频数据。 6. 将Sample Grabber Filter对象和Null Renderer对象添加到Filter Graph Manager中,并建立连接。 7. 设置Sample Grabber Filter对象的回调函数,用于处理视频数据。 8. 开始视频捕捉。 以下是C++代码示例: ```cpp #include <dshow.h> // 枚举可用的视频捕捉设备 HRESULT EnumerateDevices(REFGUID category, IEnumMoniker** ppEnum) { // 创建系统设备枚举器 HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pDevEnum); if (FAILED(hr)) { return hr; } // 枚举视频捕捉设备 hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0); if (hr == S_FALSE) { hr = VFW_E_NOT_FOUND; } pDevEnum->Release(); return hr; } // 创建Filter Graph Manager对象 IGraphBuilder* pGraphBuilder = NULL; IMediaControl* pMediaControl = NULL; IMediaEventEx* pMediaEvent = NULL; HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraphBuilder); if (FAILED(hr)) { return hr; } // 创建视频捕捉设备的Filter对象 IEnumMoniker* pEnumMoniker = NULL; hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnumMoniker); if (FAILED(hr)) { return hr; } IMoniker* pMoniker = NULL; ULONG cFetched; while (pEnumMoniker->Next(1, &pMoniker, &cFetched) == S_OK) { IBaseFilter* pFilter = NULL; hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pFilter); if (SUCCEEDED(hr)) { // 添加到Filter Graph Manager中 pGraphBuilder->AddFilter(pFilter, L"Video Capture"); pFilter->Release(); } pMoniker->Release(); } pEnumMoniker->Release(); // 创建Sample Grabber Filter对象 ISampleGrabber* pSampleGrabber = NULL; hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pSampleGrabber); if (FAILED(hr)) { return hr; } // 设置Sample Grabber Filter对象的回调函数 hr = pSampleGrabber->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber); if (FAILED(hr)) { return hr; } AM_MEDIA_TYPE mt; ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); mt.majortype = MEDIATYPE_Video; mt.subtype = MEDIASUBTYPE_RGB24; mt.formattype = FORMAT_VideoInfo; hr = pGrabber->SetMediaType(&mt); if (FAILED(hr)) { return hr; } hr = pGrabber->SetCallback(&SampleGrabberCallback, 0); if (FAILED(hr)) { return hr; } // 创建Null Renderer对象 IBaseFilter* pNullRenderer = NULL; hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pNullRenderer); if (FAILED(hr)) { return hr; } // 将Sample Grabber Filter对象和Null Renderer对象添加到Filter Graph Manager中,并建立连接 hr = pGraphBuilder->AddFilter(pSampleGrabber, L"Sample Grabber"); if (FAILED(hr)) { return hr; } hr = pGraphBuilder->AddFilter(pNullRenderer, L"Null Renderer"); if (FAILED(hr)) { return hr; } IPin* pGrabberOut = GetPin(pSampleGrabber, PINDIR_OUTPUT); IPin* pRendererIn = GetPin(pNullRenderer, PINDIR_INPUT); hr = pGraphBuilder->Connect(pGrabberOut, pRendererIn); if (FAILED(hr)) { return hr; } // 开始视频捕捉 hr = pGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&pMediaControl); if (FAILED(hr)) { return hr; } hr = pMediaControl->Run(); if (FAILED(hr)) { return hr; } // 处理视频数据的回调函数 HRESULT SampleGrabberCallback::SampleCB(double Time, IMediaSample *pSample) { BYTE* pData = NULL; pSample->GetPointer(&pData); long lDataLen = pSample->GetActualDataLength(); // 处理视频数据 return S_OK; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值