Windows CE6.0下使用IAMStreamConfig接口更改拍攝圖像的分辨率

        我的開發環境:飛凌6410開發板,WinCE6.0操作系統,OV9650攝像頭,DirectShow編程,飛凌攝像頭測試程序Camera_App

         在對飛凌OK6410開發板自帶的攝像頭測試程序進行修改後,進行調試時發現拍攝的圖像有點小,分辨率爲320*240,我考慮能否修改這個值。在網上查找了一番,有個帖子(http://www.devdiv.com/thread-8755-1-1.html)有這麼一段話:

         一般來說, video capture filter會提供capture pin、Preview pin、Still pin等輸出pin, 你可以選擇一個輸出pin來捕獲圖片, 不過一般都選擇capture pin或Still pin(這要看你的設備是否支持)。

        可以用IAMStreamConfig::GetNumberOfCapabilities、IAMStreamConfig::GetStreamCaps方法枚舉這個輸出pin支持的caps(結構:VIDEO_STREAM_CONFIG_CAPS)。

        這段闡述給我了一些啓發,我考慮首先編寫代碼查看設備支持哪些caps,然後確定如何修改。

      一、 IAMStreamConfig接口方法:

      IAMStreamConfig下有四個方法,具體的可以進一步查看MSDN,雖然能看懂,但是我還是不知道如何去翻譯。只能說說我的理解。

      ① GetStreamCaps函數用來獲取指定索引的format capability,三個參數:

      第一個參數iIndex即爲指定的索引,其大小範圍由GetNumberOfCapabilities函數的第一個參數iCount獲取。

      第二個參數pmt爲AM_MEDIA_TYPE**類型,AM_MEDIA_TYPE爲一個結構體。 The pmt parameter receives a filled-in AM_MEDIA_TYPE structure, which describes one supported output format。 值得注意的是AM_MEDIA_TYPE本身不是通過new獲得的,而有專門的函數:CreateMediaType,其在GetStreamCaps內調用,因此,對應的內存釋放也不是簡單的調用delete,而是調用DeleteMediaType

      第三個參數pSCC爲BYTE*類型,The pSCC parameter receives a structure that contains additional format information.

For video, pSCC receives a VIDEO_STREAM_CONFIG_CAPS structure. For audio, it receives an AUDIO_STREAM_CONFIG_CAPS  structure.

pSCC由new分配內存,其大小有GetNumberOfCapabilities函數的第二個參數iSize獲取。

      MSDN上有這麼一段值得注意:

      The method allocates the memory for the AM_MEDIA_TYPE structure that is returned in the pmt parameter. The caller must release the memory, including the format block. You can use theDeleteMediaType helper function in the base class library. The caller must allocate the memory for thepSCC parameter.

      ② SetFormat 用於設置相應的format,其參數爲AM_MEDIA_TYPE *pmt,MSDN上有這麼一段,因此應該儘量在RenderStream之前調用SetFormat函數進行設置

      This method specifies the format for the output pin. If the pin is not connected, it will use this format for its next connection. If the pin is already connected, it will attempt to reconnect with this format.

      ③來自MSDN的一段示例,相信能說明很多問題,可以幫助理解。

int iCount, iSize;
BYTE *pSCC = NULL;
AM_MEDIA_TYPE *pmt;

hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);

pSCC = new BYTE[iSize];
if (pSCC == NULL)
{
    // TODO: Out of memory error.
}

// Get the first format.
hr = pConfig->GetStreamCaps(0, &pmt, pSCC));
if (hr == S_OK)
{
    // TODO: Examine the format. If it's not suitable for some
    // reason, call GetStreamCaps with the next index value (up
    // to iCount). Otherwise, set the format:
    hr = pConfig->SetFormat(pmt);
    if (FAILED(hr))
    {
        // TODO: Error handling.
    }
    DeleteMediaType(pmt);
}
delete [] pSCC;

      二、如何獲取 IAMStreamConfig接口

      如何在filter中獲取 IAMStreamConfig接口(即上述例程中的pConfig)是個比較困惑的問題,網上搜了一些帖子,很多人都因爲無法正確獲取接口而無法實現更改攝像頭分辨率。這裏談談我的理解和實現。

      MSDN上有這麼一段:

    To use the interface, enumerate the filter's pins and query for IAMStreamConfig. Or, if you are using the Capture Graph Builder object to build the filter graph, you can call the ICaptureGraphBuilder2::FindInterface  method.

      我是使用ICaptureGraphBuilder2::FindInterface來獲取 IAMStreamConfig接口的,該函數有五個參數:

      第一個參數是GUID* pCategory,既然是通過輸出pin來獲取圖像,那麼這裏應該是PIN_CATEGORY_PREVIEW 或 PIN_CATEGORY_CAPTURE 或 PIN_CATEGORY_STILL

      第二個參數GUID* pType。Pointer to a GUID that specifies the major media type of an output pin, or NULL。網上有帖子使用MEDIATYPE_Interleaved,但是我用這個沒有成功,後來使用MEDIATYPE_Video調用成功

     第三個參數 Pointer to the IBaseFilter interface of the filter. The method begins searching from this filter。 注意:這個參數要使用從video capture filter獲取的IBaseFilter接口,網上有人直接定義一個IBaseFilter* pBase 作爲該參數,顯然是無法調用成功的。我這裏使用的是飛凌測試程序Camera_App中的成員變量m_pVideoCaptureFilter,即視頻捕捉Filter

     第四個參數爲IID_IAMStreamConfig。

     第五個參數爲IAMStreamConfig的接口指針。

     三、關於DeleteMediaType函數

     程序中直接使用DeleteMediaType函數時,在鏈接時會出現如下錯誤:

 error LNK2019: unresolved external symbol "void __cdecl DeleteMediaType(struct _AMMediaType *)" (?DeleteMediaType@@YAXPAU_AMMediaType@@@Z) referenced in function "public: int __cdecl CCamera::EnumCaps(class ATL::CStringT<wchar_t,class StrTraitMFC<wchar_t,class ATL::ChTraitsOS<wchar_t> > > &)" (?EnumCaps@CCamera@@QAAHAAV?$CStringT@_WV?$StrTraitMFC@_WV?$ChTraitsOS@_W@ATL@@@@@ATL@@@Z)

     主要是沒有調用正確的庫函數,在MSDN中給出了替代的代碼,在應用程序中可以替代DeleteMediaType,使用下面定義的_DeleteMediaType函數。

// Delete a media type structure that was allocated on the heap.
void _DeleteMediaType(AM_MEDIA_TYPE *pmt)
{
    if (pmt != NULL)
    {
        _FreeMediaType(*pmt); 
        CoTaskMemFree(pmt);
    }
}

// Release the format block for a media type.

void _FreeMediaType(AM_MEDIA_TYPE& mt)
{
    if (mt.cbFormat != 0)
    {
        CoTaskMemFree((PVOID)mt.pbFormat);
        mt.cbFormat = 0;
        mt.pbFormat = NULL;
    }
    if (mt.pUnk != NULL)
    {
        // pUnk should not be used.
        mt.pUnk->Release();
        mt.pUnk = NULL;
    }
}

   四、例程

     這裏是我的部分測試代碼。

    ①枚舉設備支持的Caps。代碼中的HrCheck函數是我定義的一個內聯函數,用於判斷返回值是否FAILED,從而拋出異常,可以不用管之,不耽誤理解。

BOOL CCamera::EnumCaps(CString& szOutput)
{
	CComPtr<IAMStreamConfig> pConfig;
	try
	{
		//找到IAMStreamConfig接口
		HrCheck(m_pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL, &MEDIATYPE_Video,
			m_pVideoCaptureFilter,IID_IAMStreamConfig, (void**)&pConfig));

		//獲取number數
		int iCnt, iSize;
		HrCheck(pConfig->GetNumberOfCapabilities(&iCnt, &iSize));

		//獲取cps信息
		BYTE *pSCC = NULL;
		AM_MEDIA_TYPE *pmt;
		pSCC = new BYTE [iSize];
		if(pSCC == NULL)
			throw std::runtime_error("Allocate Memory Error");
		//遍歷
		for(int i=0; i<iCnt; i++)
		{
			HrCheck(pConfig->GetStreamCaps(i, &pmt, pSCC));	//獲取信息
			//形成信息字符串,用於打印顯示
			CString str;
			str.Format(L"Cap index: %d \r\nMinOutputSize: %ld*%ld \r\nMaxOutputSize: %ld*%ld \r\nMinCroppingSize: %ld*%ld\r\nMaxCroppingSize: %ld*%ld\r\n",
				i, 
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MinOutputSize.cx, 
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MinOutputSize.cy,
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MaxOutputSize.cx,
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MaxOutputSize.cy,
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MinCroppingSize.cx,
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MinCroppingSize.cy,
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MaxCroppingSize.cx,
				((VIDEO_STREAM_CONFIG_CAPS*)pSCC)->MaxCroppingSize.cy);
			szOutput+=str;
			
			_DeleteMediaType(pmt);	//刪除
		}

		delete [] pSCC;
	}
	catch(std::runtime_error err)
	{
		MessageBox(NULL, _T("枚舉Cap信息失敗!"), CString(err.what()), MB_OK);
		return FALSE;
	}
	
	return TRUE;
}

    我的測試結果如下所示:

   


      ②我的分辨率設置程序代碼。通過輸入index,選擇枚舉出來的可以支持的Caps。當然你也可以進一步自己設置寬和高,只要設備支持就行。

//設置圖像分辨率
//輸入參數:index-0:表示320*240;1:-表示640*480
BOOL CCamera::SetCaps(int index)
{
	CComPtr<IAMStreamConfig> pConfig;
	try
	{
		//找到IAMStreamConfig接口
		HrCheck(m_pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL, &MEDIATYPE_Video,
			m_pVideoCaptureFilter,IID_IAMStreamConfig, (void**)&pConfig));

		//獲取number數
		int iCnt, iSize;
		HrCheck(pConfig->GetNumberOfCapabilities(&iCnt, &iSize));

		//獲取cps信息
		BYTE *pSCC = NULL;
		AM_MEDIA_TYPE *pmt;
		pSCC = new BYTE [iSize];
		if(pSCC == NULL)
			throw std::runtime_error("Allocate Memory Error");

		HrCheck(pConfig->GetStreamCaps(index, &pmt, pSCC));	//獲取信息
		HrCheck(pConfig->SetFormat(pmt));		//設置信息

		_DeleteMediaType(pmt);	//刪除
		delete [] pSCC;
	}
	catch(std::runtime_error err)
	{
		MessageBox(NULL, _T("設置Cap失敗!"), CString(err.what()), MB_OK);
		return FALSE;
	}
	
	return TRUE;
}



發佈了37 篇原創文章 · 獲贊 199 · 訪問量 43萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章