Directshow 捕捉程序的兩個問題


之前寫的程序里,一直存在兩個問題。一個是程序運行時,點擊打開視頻后,關閉視頻。再點擊打開視頻,就會彈出對話框“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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM