视频问题,从摄像头流中捕捉一张图片。用ISampleGrabber方法

Atomictry 2004-10-28 07:43:07
用ISampleGrabber方法。 显示窗口已经能显示图像。

HRESULT StartDisplay(HWND hwnd) // 显示
{
HRESULT hr = S_OK;
hr = BuilderSendGraph(); // 建立Graph

//Create Display Windows
pSendWindow->put_Owner((OAHWND)hwnd);
pSendWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
pSendWindow->SetWindowPosition(0,0,300,300);
pSendWindow->put_Visible(OATRUE);

//Begin Send
hr = pSendControl->Run();
SnapStill(); // 此处开始抓取一张图片
}

以下是SnapStill()函数:
HRESULT SnapStill()
{
HRESULT hr;
long cbBuffer = 0;

/********** -->>>>>这句有问题************/
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);

char *pBuffer = new char[cbBuffer];
if (!pBuffer) {
// Out of memory. Return an error code.
}
hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
if(FAILED(hr)) return E_FAIL;

...... // 生成bmp文件
}

BuilderSendGraph()中的函数实现:
HRESULT BuilderSendGraph()
{
// 建立 Filter Graph
hr = CoCreateInstance((REFCLSID)CLSID_FilterGraph,NULL,
CLSCTX_INPROC_SERVER,
(REFIID)IID_IGraphBuilder,
(void**)&pSendGraph);

// 建立 Caputer Filter
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,
CLSCTX_INPROC,IID_ICaptureGraphBuilder2,
(void**)&pCaputerBuilder);

hr = pCaputerBuilder->SetFiltergraph(pSendGraph);

// 建立 SampleGrabber Filter
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pGrabberSample)

// 把pCaputerFilter和pGrabberSample加入filter
hr = pSendGraph->AddFilter(pCaputerFilter,L"Caputer Filter");
hr = pSendGraph->AddFilter(pGrabberSample, L"Sample Grabber");

// 查询各个接口
hr=pSendGraph->QueryInterface(IID_IMediaControl,(void**)&pSendControl);
hr=pSendGraph->QueryInterface(IID_IVideoWindow,(void**)&pSendWindow);
hr=pSendGraph->QueryInterface(IID_IMediaEvent,(void**)&pSendEvent);
hr=pGrabberSample->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);

/***请问这里是不是还需要什么代码?***/

// 根据色深设置媒体类型
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
HDC hdc = GetDC(NULL);
int iBitDepth = GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(NULL, hdc);
mt.majortype = MEDIATYPE_Video;
switch (iBitDepth)
{
case 8:
mt.subtype = MEDIASUBTYPE_RGB8;
break;
case 16:
mt.subtype = MEDIASUBTYPE_RGB555;
break;
case 24:
mt.subtype = MEDIASUBTYPE_RGB24;
break;
case 32:
mt.subtype = MEDIASUBTYPE_RGB32;
break;
default:
return E_FAIL;
}
hr = pGrabber->SetMediaType(&mt);
if(FAILED(hr)) return E_FAIL;

// 显示本地视频
hr = pCaputerBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,NULL,pCaputerFilter,NULL,NULL);
if(FAILED(hr)) return S_FALSE;

// 准备一祯
hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE);
}

问题出在SnapStill()函数中的第一个GetCurrentBuffer处:
cbBuffer得到的值为空,这里hr返回的值VFW_E_WRONG_STATE,
msdn说:The filter has not received any samples yet. To deliver a sample, run or pause the graph.
但是在StartDisplay()中已经hr = pSendControl->Run();了.

请各位兄弟,前辈帮帮忙, 查了一个星期的资料了,又郁闷一个星期了。 谢谢~
...全文
957 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
ywybetter 2005-01-11
  • 打赏
  • 举报
回复
楼主是好人
先顶一下
Atomictry 2004-11-04
  • 打赏
  • 举报
回复
经过n天努力,问题解决,发现网上使用ISampleGrabber接口进行捕获的代码好少,感觉又不是关键技术,DirectShow已经包含大部分代码,怎么都藏着?
期间还用VFW的宏来做,修改分辨率后本地可以正常显示各种分辨率,可惜拍照又有问题,最后作罢,还是用ISampleGrabber比较彻底。

现总结如下:
关键字: 视频 捕获 拍照 ISampleGrabber

函数说明
/*
* 本地显示函数
*/
HRESULT StartDisplay(HWND hwnd);

/*
* 建立链路
*/
HRESULT BuilderGraph()

/*
* 拍照
*/
HRESULT SnapStill()

/*
* 修改摄像头分辨率,色深,频率
*/
BOOL SetFormat(ICaptureGraphBuilder2* pBuilder, IBaseFilter* pCap, long lWidth, long lHeight, unsigned short iColorBit, __int64 iRate )

HRESULT StartDisplay(HWND hwnd)
{
HRESULT hr = S_OK;
hr = BuilderGraph();
if(hr==S_FALSE) return S_FALSE;

//Create Display Windows
pSendWindow->put_Owner((OAHWND)hwnd);
pSendWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
pSendWindow->SetWindowPosition(0,0,250,250);
pSendWindow->put_Visible(OATRUE);

hr = pGrabber->SetOneShot(FALSE);
hr = pGrabber->SetBufferSamples(TRUE);

//Begin display
hr=pSendControl->Run();
Sleep(500);
SnapStill();

return S_OK;
}

HRESULT BuilderGraph()
{
HRESULT hr=S_OK;

pSendGraph = NULL;
pCaputerFilter = NULL;
pCaputerBuilder = NULL;
pSendWindow = NULL;
pSendControl = NULL;
pSendEvent = NULL;
pGrabberSample = NULL;

//1.Builder Filter Graph
hr=CoCreateInstance((REFCLSID)CLSID_FilterGraph,NULL,
CLSCTX_INPROC_SERVER,
(REFIID)IID_IGraphBuilder,
(void**)&pSendGraph);
if(FAILED(hr)) return S_FALSE;

//2.Builder Caputer Filter
hr=CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,
CLSCTX_INPROC,IID_ICaptureGraphBuilder2,
(void**)&pCaputerBuilder);
if(FAILED(hr)) return S_FALSE;

//3.Builder SampleGrabber Filter
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pGrabberSample);
if(FAILED(hr)) return S_FALSE;

hr=pCaputerBuilder->SetFiltergraph(pSendGraph);
if(FAILED(hr)) return S_FALSE;

//Find Caputer Filter
hr=FindCaputerDevice();
if(FAILED(hr)) {
SAFE_RELEASE(pCaputerBuilder);
SAFE_RELEASE(pSendGraph);
return S_FALSE;
}

hr = pSendGraph->AddFilter(pNetSend,NULL);
hr = pSendGraph->AddFilter(pCaputerFilter,L"Caputer Filter");
hr = pSendGraph->AddFilter(pCompressor,L"Compressor Filter");
hr = pSendGraph->AddFilter(pGrabberSample, L"Sample Grabber");

hr=pSendGraph->QueryInterface(IID_IMediaControl,(void**)&pSendControl);
if(FAILED(hr)) return S_FALSE;

hr=pSendGraph->QueryInterface(IID_IVideoWindow,(void**)&pSendWindow);
if(FAILED(hr)) return S_FALSE;

hr=pSendGraph->QueryInterface(IID_IMediaEvent,(void**)&pSendEvent);
if(FAILED(hr)) return S_FALSE;

hr=pGrabberSample->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);
if(FAILED(hr)) return S_FALSE;

// 修改分辨率
SetFormat(pCaputerBuilder, pCaputerFilter, 640, 480, 24, 30);

//Display local video
hr=pCaputerBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,NULL,pCaputerFilter,pGrabberSample,NULL);
if(FAILED(hr)) return S_FALSE;

return S_OK;
}

HRESULT SnapStill()
{
HRESULT hr;

long cbBuffer = 0;
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
if(FAILED(hr)) return E_FAIL;

char *pBuffer = new char[cbBuffer];
if (!pBuffer) {
// Deal Out of memory. Return an error code.
}
hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
if(FAILED(hr)) return E_FAIL;

//生成Bitmap
AM_MEDIA_TYPE mt;
hr = pGrabber->GetConnectedMediaType(&mt);
if (FAILED(hr)) return E_FAIL;

VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)mt.pbFormat;
if(pVideoHeader==NULL) return E_FAIL;

BITMAPINFO BitmapInfo;
ZeroMemory(&BitmapInfo, sizeof(BitmapInfo));
CopyMemory(&BitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader), sizeof(BITMAPINFOHEADER));

HBITMAP hBitmap;
hBitmap = ::CreateDIBitmap(::GetDC(NULL), &(pVideoHeader->bmiHeader), CBM_INIT, pBuffer, &BitmapInfo, DIB_RGB_COLORS);

if(hBitmap==NULL) return E_FAIL;
CString strSaveFileName="";
CFileDialog filedlg(FALSE,_T("bmp"),_T(""),OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,_T("BMP(*.bmp)"));
if(filedlg.DoModal()==IDOK){
strSaveFileName=filedlg.GetPathName();
SaveBitmapToFile(hBitmap,strSaveFileName.GetBuffer(0));
}

return hr;
}

BOOL SetFormat(ICaptureGraphBuilder2* pBuilder, IBaseFilter* pCap, long lWidth, long lHeight, unsigned short iColorBit, __int64 iRate )
{
VIDEOINFOHEADER* phead;
IAMStreamConfig* iconfig;

HRESULT hr;
hr = pBuilder -> FindInterface( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Interleaved,
pCap, IID_IAMStreamConfig, (void **)&iconfig );
if ( hr != NOERROR )
{
hr = pBuilder -> FindInterface( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, pCap,
IID_IAMStreamConfig, (void **)&iconfig);
}

if ( FAILED( hr ) )
return FALSE;

AM_MEDIA_TYPE* pmt;
if ( iconfig -> GetFormat( &pmt ) != S_OK )
return FALSE;

if ( pmt -> formattype == FORMAT_VideoInfo)
{
phead = ( VIDEOINFOHEADER* )pmt -> pbFormat;
phead -> bmiHeader.biBitCount = iColorBit;
phead -> bmiHeader.biWidth = lWidth;
phead -> bmiHeader.biHeight = lHeight;
phead -> bmiHeader.biSizeImage = lWidth * lHeight * iColorBit / 8;
phead -> AvgTimePerFrame = iRate;
if ( ( hr = iconfig -> SetFormat( pmt ) ) != S_OK )
return FALSE;
}
iconfig -> Release();
iconfig = NULL;
FreeMediaType( *pmt );
return TRUE;
}
51flyou 2004-11-02
  • 打赏
  • 举报
回复
从你上面的代码好象有点难看出问题在哪儿?帮你顶
Atomictry 2004-11-01
  • 打赏
  • 举报
回复
to 51flyou(while(1){study++;}) :
谢谢你,在程序中
hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE); 函数hr = BuilderSendGraph();中有这两句的,
放在SnapStill之前了。

各路兄弟们, 大家都有个难处, 相帮一下。 谢谢了。
Atomictry 2004-11-01
  • 打赏
  • 举报
回复
vicky_jam 2004-10-31
  • 打赏
  • 举报
回复
up
GameWeaverDummy 2004-10-30
  • 打赏
  • 举报
回复
Atomictry 2004-10-30
  • 打赏
  • 举报
回复
to pGrabber: 在dll中,跟踪不进去。

我相信这里肯定有人做过的,是不是不愿意相告呢? 这又不是什么关键技术,DS中已经包含了大量代码了。

还请各位同仁,老师不吝赐教~
fcf128 2004-10-30
  • 打赏
  • 举报
回复
想知道, 关注!
51flyou 2004-10-30
  • 打赏
  • 举报
回复
你的GetCurrentBuffer是SampleGrabber Filter中的方法,可能需要看看GetCurrentBuffer的实现以及调用方法啦。从你的调用方法来看GetCurrentBuffer类似于IID_IBasicVideo 上的方法GetCurrentImage

BOOL Grab(const char * inFile)
{
if (!mBasicVideo)
{
return FALSE;
}

long bitmapSize = 0;
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))
{
BOOL pass = FALSE;
BYTE * buffer = new BYTE[bitmapSize];
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer)))
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;

lpbi = (LPBITMAPINFOHEADER)buffer;

int nColors = 1 << lpbi->biBitCount;
if (nColors > 256)
nColors = 0;

hdr.bfType = ((WORD) ('M' << 8) | 'B'); // always is "BM"
hdr.bfSize = bitmapSize + sizeof( hdr );
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize +
nColors * sizeof(RGBQUAD));

CFile bmpFile(inFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary);
bmpFile.Write(&hdr, sizeof(BITMAPFILEHEADER));
bmpFile.Write(buffer, bitmapSize);
bmpFile.Close();
pass = TRUE;
}
delete [] buffer;
return pass;
}
return TRUE;
}
你可以用用这个方法。

另外在SampleGrabber Filter中提供抓图,可能需要什么条件,比如成功传入缓冲区, hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);

char *pBuffer = new char[cbBuffer];这是获得大小设置缓冲区,但你失败.可以尝试把
hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE)
放在
SnapStill(); 之前.
syy64 2004-10-29
  • 打赏
  • 举报
回复
看看pGrabber里面的值。

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧