本文共 6757 字,大约阅读时间需要 22 分钟。
之前写的程序里,一直存在两个问题。一个是程序运行时,点击打开视频后,关闭视频。再点击打开视频,就会弹出对话框“can’t build graph"。二是,无法改变采集的图像的大小,总是固定的320*240.注意,此处不是指显示窗口的大小。
结合查找的一些资料,终于解决了。
问题一:是Capturevidieo 类析构函数里,少释放了pVW。晕。网上找的类里,都漏了释放了。
问题二:
结合以下资料,解决了:
1
(1)获得IAMStreamConfig接口
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, gcap.pVCap, IID_IAMStreamConfig, (void **)&gcap.pVSC); (2)控制 if(gcap.pVSC)// && gcap.fUseFrameRate) { hr = gcap.pVSC->GetFormat(&pmt); // DV capture does not use a VIDEOINFOHEADER if(hr == NOERROR) { if(pmt->formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)pmt->pbFormat; pvi->bmiHeader.biWidth=320; pvi->bmiHeader.biHeight =240; pvi->bmiHeader.biSizeImage=320*240*3; hr = gcap.pVSC->SetFormat(pmt); } DeleteMediaType(pmt); } } 2调整视频输出格式
我们知道视频流可以有多种输出格式,一个设备可以支持16-bit RGB, 32-bit RGB, and YUYV,在每一种格式下,设备还可以调整视频桢的大小。 在WDM驱动设备上,IAMStreamConfig 接口用来报告设备输出视频的格式的,VFW设备,可以采用对话框的方式来设置,参见前面的内容。 捕捉Filter的捕捉pin和预览pin都支持IAMStreamConfig 接口,可以通过ICaptureGraphBuilder2::FindInterface获得IAMStreamConfig接口。IAMStreamConfig *pConfig = NULL;
hr = pBuild->FindInterface( &PIN_CATEGORY_PREVIEW, // Preview pin. 0, // Any media type. pCap, // Pointer to the capture filter. IID_IAMStreamConfig, (void**)&pConfig);设备还支持一系列的媒体类型,对于每一个媒体类型,设备都要支持一系列的属性,比如,桢的大小,图像如何缩放,桢率的范围等。
通过IAMStreamConfig::GetNumberOfCapabilities获得设备所支持的媒体类型的数量。这个方法返回两个值,一个是媒体类型的数量,二是属性所需结构的大小。 这个结构的大小很重要,因为这个方法是用于视频和音频的,视频采用的是VIDEO_STREAM_CONFIG_CAPS结构,音频用AUDIO_STREAM_CONFIG_CAPS结构。 通过函数IAMStreamConfig::GetStreamCaps来枚举媒体类型,要给这个函数传递一个序号作为参数,这个函数返回媒体类型和相应的属性结构体。看代码把int iCount = 0, iSize = 0;
hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); // Check the size to make sure we pass in the correct structure. if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS) { // Use the video capabilities structure. for (int iFormat = 0; iFormat < iCount; iFormat++) { VIDEO_STREAM_CONFIG_CAPS scc; AM_MEDIA_TYPE *pmtConfig; hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc); if (SUCCEEDED(hr)) { /* Examine the format, and possibly use it. */ // Delete the media type when you are done. hr = pConfig->SetFormat(pmtConfig);//重新设置视频格式 DeleteMediaType(pmtConfig); } }你可以调用IAMStreamConfig::SetFormat设置新的媒体类型
hr = pConfig->SetFormat(pmtConfig); 如果pin没有连接,当连接的时候就试图用新的格式,如果pin已经在连接了,它就会用的新的媒体格式重新连接。在任何一种情况下,下游的filter都有可能拒绝新的媒体格式。 在SetFormat前你可以修改VIDEO_STREAM_CONFIG_CAPS结构来重新设置媒体类型。 例如: 如果GetStreamCaps返回的是24-bit RGB format,桢的大小是320 x 240 像素,你可以通过检查媒体类型的major type,subtpye,和format等值if ((pmtConfig.majortype == MEDIATYPE_Video) &&
(pmtConfig.subtype == MEDIASUBTYPE_RGB24) && (pmtConfig.formattype == FORMAT_VideoInfo) && (pmtConfig.cbFormat >= sizeof (VIDEOINFOHEADER)) && (pmtConfig.pbFormat != NULL)) { VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig.pbFormat; // pVih contains the detailed format information. LONG lWidth = pVih->bmiHeader.biWidth; LONG lHeight = pVih->bmiHeader.biHeight; }VIDEO_STREAM_CONFIG_CAPS结构里包含了该媒体类型的视频长度和宽度的最大值和最小值,还有递增的幅度值,就是每次调整视频size的幅度,例如,设备可能返回如下的值
? MinOutputSize: 160 x 120 ? MaxOutputSize: 320 x 240 ? OutputGranularityX: 8 pixels (horizontal step size) ? OutputGranularityY: 8 pixels (vertical step size) 这样你可以在(160, 168, 176, ... 304, 312, 320) 范围内设置宽度,在 (120, 128, 136, ... 104, 112, 120).设置高度值,图6
如果想设置新的值,直接修改在GetStreamCaps函数中返回的值即可,pVih->bmiHeader.biWidth = 160;
pVih->bmiHeader.biHeight = 120; pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader);然后将媒体类型传递给SetFormat函数,就可修改视频格式了。
三 自己修改后的程序如下:
cpp
CCaptureVideo::~CCaptureVideo()
{ // Stop media playback if (bIsVideoOpen) { if(m_pMC)m_pMC->Stop(); if(m_pVW) { m_pVW->put_Visible(OAFALSE); m_pVW->put_Owner(NULL); } srelease(m_pBF); } srelease(m_pCapture); srelease(m_pMC); srelease(m_pGB); srelease(m_pVW);//加上这句,就可以了,晕,否则在程序里没法连续打开两次视频 CoUninitialize( );}
HRESULT CCaptureVideo::Init(int iDeviceID, HWND hWnd) { HRESULT hr; hr = InitCaptureGraphBuilder(); if (FAILED(hr)) { AfxMessageBox("Failed to get video interfaces!"); return hr; } // Bind Device Filter. We know the device because the id was passed in if(!BindFilter(iDeviceID, &m_pBF)) { AfxMessageBox("未找到USB摄像头!\n请检查设备后重试!"); //PostQuitMessage(0); return S_FALSE; } hr = m_pGB->AddFilter(m_pBF, L"Capture Filter");// hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
// m_pBF, NULL, NULL);// create a sample grabber
hr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber ); if( !m_pGrabber ) { AfxMessageBox("Fail to create SampleGrabber, maybe qedit.dll is not registered?"); return hr; } CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabBase( m_pGrabber ); //设置视频格式 IAMStreamConfig *pConfig = NULL; hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, 0, // Any media type. m_pBF, // Pointer to the capture filter. IID_IAMStreamConfig, (void**)&pConfig); AM_MEDIA_TYPE *pmt; hr = pConfig ->GetFormat(&pmt); //ZeroMemory(pmt, sizeof(AM_MEDIA_TYPE)); pmt->majortype = MEDIATYPE_Video; pmt->subtype = MEDIASUBTYPE_RGB24; pmt->formattype = FORMAT_VideoInfo; VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)pmt->pbFormat; pvi->bmiHeader.biWidth=640; pvi->bmiHeader.biHeight =480; pvi->bmiHeader.biSizeImage=640*480*3; //设置帧大小,而不是仅仅改变预览窗口大小 hr = pConfig->SetFormat(pmt); FreeMediaType(*pmt); AM_MEDIA_TYPE mt; //ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); //mt.majortype = MEDIATYPE_Video; //mt.subtype = MEDIASUBTYPE_RGB24; // mt.formattype = FORMAT_VideoInfo; // VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;//不能在这里设置图像文件信息 // // hr = m_pGrabber->SetMediaType(&mt);if( FAILED( hr ) )
{ AfxMessageBox("Fail to set media type!"); return hr; }hr = m_pGB->AddFilter( pGrabBase, L"Grabber" );
if( FAILED( hr ) )
{ AfxMessageBox("Fail to put sample grabber in graph"); return hr; }// try to render preview/capture pin
hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL); if( FAILED( hr ) ) hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL); if( FAILED( hr ) ) { AfxMessageBox("Can’t build the graph"); return hr; }hr = m_pGrabber->GetConnectedMediaType( &mt );
if ( FAILED( hr) )
{ AfxMessageBox("Failt to read the connected media type"); return hr; } VIDEOINFOHEADER * vihh = (VIDEOINFOHEADER*) mt.pbFormat; // vihh->bmiHeader.biWidth=320; // vihh->bmiHeader.biHeight=240; // vihh->bmiHeader.biSizeImage=320*240*3; // hr = m_pGrabber->SetMediaType(&mt); mCB.lWidth =vihh->bmiHeader.biWidth; mCB.lHeight =vihh->bmiHeader.biHeight; FreeMediaType(mt);hr = m_pGrabber->SetBufferSamples( false );
hr = m_pGrabber->SetOneShot( FALSE ); hr = m_pGrabber->SetCallback( &mCB, 1 );//影响回调//设置视频捕捉窗口
m_hWnd = hWnd ; SetupVideoWindow(); hr = m_pMC->Run();//开始视频捕捉 if(FAILED(hr)) { AfxMessageBox("Couldn’t run the graph!"); return hr; }bIsVideoOpen = TRUE;
return S_OK;
}本文转自博客园知识天地的博客,原文链接: ,如需转载请自行联系原博主。