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 > > &)" (?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 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; iGetStreamCaps(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 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;
}



你可能感兴趣的:(Windows CE6.0下使用IAMStreamConfig接口更改拍摄图像的分辨率)