于3G手机应用视频电话的时候要双camera,那么就存在切换的问题,我就在开发板上进行了调试。marvell的zylonite开发板Windows Mobile6.0 BSP关于camera的驱动变化还是很明显的,采用了wince6.0的camera驱动。
找了半天才在微软的MSDN上看到了各个pdd函数的说明。整个设计的原理就是APP先停止preview,发出切换sensor的指令,驱动响应,把sensor相关的都换成另外一个sensor,然后再重新preview。
首先camera的应用程序得自己写,不然双camera的切换无法在应用上修改,于是找了个camera的应用代码参考了下,居然都编译不过,晕,我不是做app的,但是又没有人帮我,只好硬着头皮看资料看代码。幸好自己也做过一点PC上的应用程序,终于看懂,原来采用WTL+directshow写的camera应用,mainframe+manager+ view+setting结构很清晰。应用程序写上如下代码:
{
LRESULT hr;
CComPtr<IAMCameraControl> pCameraControl;
long lCurrentVal,lCurrentFlags;
long CameraControl_Switch=CameraControl_Flash+0xff;
if(sensor>=SENSOR_MAX)
return FALSE;
CHK(m_pVideoCapFilter->QueryInterface(&pCameraControl));
CHK(pCameraControl->Get(CameraControl_Switch, &lCurrentVal, &lCurrentFlags));
if(lCurrentVal == sensor)
{
//return TRUE;
}
CHK(pCameraControl->Set(CameraControl_Switch, sensor, CameraControl_Flags_Manual));
err_exit:
if( FAILED( hr ))
{
CCameraParam::GetCameraParam()->GetErrorlog()->WriteLog(L"Error: CCameraManager::CameraSwitchSensor");
return FALSE;
}
return TRUE;
}
红色字体为关键,由于通过dshow才控制camera,所以得找到dshow动作对应于驱动的接口,参考wm的文档并调试,发现这个可以控制camera,会调用CAM_IOControl,Ioctl=IOCTL_CS_PROPERTY,
BOOL
CAM_IOControl(
DWORD dwContext,
DWORD Ioctl,
UCHAR * pInBufUnmapped,
DWORD InBufLen,
UCHAR * pOutBufUnmapped,
DWORD OutBufLen,
DWORD * pdwBytesTransferred
)
{
DEBUGMSG( ZONE_FUNCTION, ( _T("CAM_IOControl(%08x): IOCTL:0x%x, InBuf:0x%x, InBufLen:%d, OutBuf:0x%x, OutBufLen:0x%x) "), dwContext, Ioctl, pInBufUnmapped, InBufLen, pOutBufUnmapped, OutBufLen ) );
//NKDbgPrintfW(L"CAM_IOControl 0x%x", Ioctl);
UCHAR * pInBuf = NULL;
UCHAR * pOutBuf = NULL;
DWORD dwErr = ERROR_INVALID_PARAMETER;
BOOL bRc = FALSE;
if ( ( NULL == pInBufUnmapped )
|| ( InBufLen < sizeof ( CSPROPERTY ) )
|| ( NULL == pdwBytesTransferred ) )
{
SetLastError( dwErr );
return bRc;
}
//All buffer accesses need to be protected by try/except
pInBuf = pInBufUnmapped;
pOutBuf = pOutBufUnmapped;
CAMERAOPENHANDLE * pCamOpenHandle = reinterpret_cast<CAMERAOPENHANDLE *>( dwContext );
CAMERADEVICE * pCamDevice = pCamOpenHandle->pCamDevice;
CSPROPERTY * pCsProp = reinterpret_cast<CSPROPERTY *>(pInBuf);
if ( NULL == pCsProp )
{
DEBUGMSG( ZONE_IOCTL|ZONE_ERROR, (_T("CAM_IOControl(%08x): Invalid Parameter. "), dwContext ) );
return dwErr;
}
switch ( Ioctl )
{
// Power Management Support.
case IOCTL_POWER_CAPABILITIES:
case IOCTL_POWER_QUERY:
case IOCTL_POWER_SET:
case IOCTL_POWER_GET:
{
NKDbgPrintfW(L"camera IOCTL_POWER+");
DEBUGMSG( ZONE_IOCTL, ( _T("CAM_IOControl(%08x): Power Management IOCTL "), dwContext ) );
__try
{
dwErr = pCamDevice->AdapterHandlePowerRequests(Ioctl, pInBuf, InBufLen, pOutBuf, OutBufLen, pdwBytesTransferred );
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
DEBUGMSG( ZONE_IOCTL, ( _T("CAM_IOControl(%08x):Exception in Power Management IOCTL"), dwContext ) );
}
break;
}
case IOCTL_CS_PROPERTY:
{
DEBUGMSG( ZONE_IOCTL, ( _T("CAM_IOControl(%08x): IOCTL_CS_PROPERTY "), dwContext ) );
__try
{
dwErr = pCamDevice->AdapterHandleCustomRequests( pInBuf,InBufLen, pOutBuf, OutBufLen, pdwBytesTransferred );
if ( ERROR_NOT_SUPPORTED == dwErr )
{
if ( TRUE == IsEqualGUID( pCsProp->Set, CSPROPSETID_Pin ) )
{
dwErr = pCamDevice->AdapterHandlePinRequests( pInBuf, InBufLen, pOutBuf, OutBufLen, pdwBytesTransferred );
}
else if ( TRUE == IsEqualGUID( pCsProp->Set, CSPROPSETID_VERSION ) )
{
dwErr = pCamDevice->AdapterHandleVersion( pOutBuf, OutBufLen, pdwBytesTransferred );
}
else if ( TRUE == IsEqualGUID( pCsProp->Set, PROPSETID_VIDCAP_VIDEOPROCAMP ) )
{
dwErr = pCamDevice->AdapterHandleVidProcAmpRequests( pInBuf,InBufLen, pOutBuf, OutBufLen, pdwBytesTransferred );
}
else if ( TRUE == IsEqualGUID( pCsProp->Set, PROPSETID_VIDCAP_CAMERACONTROL ) )
{
dwErr = pCamDevice->AdapterHandleCamControlRequests( pInBuf,InBufLen, pOutBuf, OutBufLen, pdwBytesTransferred );
}
else if ( TRUE == IsEqualGUID( pCsProp->Set, PROPSETID_VIDCAP_VIDEOCONTROL ) )
{
dwErr = pCamDevice->AdapterHandleVideoControlRequests( pInBuf,InBufLen, pOutBuf, OutBufLen, pdwBytesTransferred );
}
else if ( TRUE == IsEqualGUID( pCsProp->Set, PROPSETID_VIDCAP_DROPPEDFRAMES) )
{
dwErr = pCamDevice->AdapterHandleDroppedFramesRequests( pInBuf,InBufLen, pOutBuf, OutBufLen, pdwBytesTransferred );
}
}
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
DEBUGMSG( ZONE_IOCTL, ( _T("CAM_IOControl(%08x):Exception in IOCTL_CS_PROPERTY"), dwContext ) );
}
break;
}
default:
{
DEBUGMSG( ZONE_IOCTL, (_T("CAM_IOControl(%08x): Unsupported IOCTL code %u "), dwContext, Ioctl ) );
dwErr = ERROR_NOT_SUPPORTED;
break;
}
}
// pass back appropriate response codes
SetLastError( dwErr );
return ( ( dwErr == ERROR_SUCCESS ) ? TRUE : FALSE );
}
哈哈,红色字体就是IAMCameraControl的set接口对应于driver会被调用的地方,由于这里还是driver的mdd层,所以尽量不改,于是放到pdd层来实现,很自然的想到AdapterHandleCustomRequests,该函数会调用pdd的DWORD CCameraPdd::HandleAdapterCustomProperties( PUCHAR pInBuf, DWORD InBufLen, PUCHAR pOutBuf, DWORD OutBufLen, PDWORD pdwBytesTransferred ),本来这函数是空函数,结果这里就可以放入双camera的切换代码了(不知道是微软写的还是marvell写的,想的真周到,以前还没有的,现在就有了,赞一个),实现如下:
{
typedef enum
{
SENSOR_FRONT,
SENSOR_REAR,
SENSOR_MAX,
}CAMERA_SWITCH;
CONST LONG CAMERACONTROL_SWITCH = CSPROPERTY_CAMERACONTROL_FLASH+0XFF;
PCSPROPERTY_CAMERACONTROL_S pCsPropCamControlInput = NULL;
CSPROPERTY * pCsProp = reinterpret_cast<CSPROPERTY *>(pInBuf);
if( ( TRUE == IsEqualGUID( pCsProp->Set, PROPSETID_VIDCAP_CAMERACONTROL ) )
&& (pCsProp->Id == CAMERACONTROL_SWITCH))
{
pCsPropCamControlInput = reinterpret_cast<PCSPROPERTY_CAMERACONTROL_S>(pInBuf);
switch(pCsProp->Flags)