Code Repo    |     RSS
MD's Technical Sharing



Thursday, November 6, 2008

DirectShow & OEM Camera API

Most 3rd party camera applications relies on DirectShow to control the camera. However, on some devices, DirectShow doesn't expose the full camera capabilities. For example, on a Dopod 838Pro, DirectShow only allows recording up to 176x144 7.5fps while the built-in camera can do much better. Further investigation shows that the built-in camera app (and some 3rd party apps such as CoolCamera) do not use DirectShow but instead relies on a proprietary camera API to control the camera. This API exposes the full capabilities of the camera. This web page lists which devices expose usable camera modes via DirectShow and those which cause problems.

On a Dopod 838Pro device, the camera API is hidden in \Windows\HTCCamera1.dll. Calling several functions inside this dll could turn on the camera and the flashlight. However, getting the camera to work properly without proper API documentation seems to be an impossible task. Attempt was made to reverse engineering the HTCCamera1.dll and CoolCamera using Interactive Disassembler (IDA). However, it was not clear from the disassembly how the camera raw frame buffer was retrieved. The part of the code which retrieves the camera data has probably been obfuscated.

The following code shows how to init the camera, turn on the flashlight and then turn it off:

test = 1
result = Camera_Init(test)
test = 0
result = Camera_Begin(test)
result = Camera_FlashLight(CameraPropertyState.STATE_ON)
MessageBox.Show("Flashligh ON. Click OK to turn off.")
result = Camera_FlashLight(CameraPropertyState.STATE_OFF)
result = Camera_Deinit()

<DllImport("HTCCamera1.dll")> _
Private Shared Function Camera_Init(ByRef input As Int32) As Boolean
End Function

<DllImport("HTCCamera1.dll")> _
Private Shared Function Camera_Begin(ByRef input As Int32) As Boolean
End Function

<DllImport("HTCCamera1.dll")> _
Private Shared Function Camera_End(ByRef input As Int32) As Boolean
End Function

Enum CameraPropertyState As Integer
STATE_ON = 1
STATE_OFF = 2
End Enum

<DllImport("HTCCamera1.dll")> _
Private Shared Function Camera_FlashLight(ByVal state As CameraPropertyState) As Boolean
End Function

<DllImport("HTCCamera1.dll")> _
Private Shared Function Camera_Deinit() As Boolean
End Function

Another way to control the flashlight is to use DeviceIOControl. This does not rely on HTCCamera1.dll but is still device-specific

DWORD dwDIOC=0x90002024; //device io (device specific)
int Mode_int = 1;
DeviceIoControl(hCam, dwDIOC, LPVOID(&Mode_int), sizeof(Mode_int), 0, NULL, NULL, NULL);
MessageBox(GetActiveWindow(), L"OK to turn off", L"Flash Light", MB_OK);
Mode_int = 2;
DeviceIoControl(hCam, dwDIOC, LPVOID(&Mode_int), sizeof(Mode_int), 0, NULL, NULL, NULL);
Read More »

Monday, June 2, 2008

DirectShow: Null Renderer for Windows CE

This filter is a renderer that discards every sample it receives, without displaying or rendering the sample data. Even though this filter does not render any samples, it does wait for each sample's presentation time before discarding the sample. Therefore, the graph will run at the normal rate. If you want the graph the run as quickly as possible, set the reference clock to NULL.

A null renderer helps retrieve the frame buffer data as if they were displayed on screen with an actual render. The buffer retrieved may or may not be the same as that retrieved by a null transform filter, depending on the graph, and in particular the media type produced the raw camera data and the type required by the display driver. For example, if the camera produces YV12 but the display driver requires RGB565, there needs to be a color space conversion filter before the renderer. In that case, the buffer retrieved by the null-transform filter will be YV12 but a null-renderer will return RGB565. The position of each filter in the graph (which is determined by Intelligent Connect if the graph was built automatically via RenderStream) will also affect the type of the buffer.

The code for a null renderer is similar to that of a null-transform filter, except that the class needs to inherit CBaseVideoRenderer:

class CNullRenderer
:
public CBaseVideoRenderer, public INullRenderer
{
}

The actual rendering work is done in DoRenderSample

HRESULT DoRenderSample(IMediaSample* pMediaSample)
{
}

To tell Intelligent Connect which media type the filter will accept and which will be rejected, code the function CheckMediaType and declare sudIpPinTypes accordingly. For example, the following declaration will cause the filter to only accept (MEDIATYPE_Video, MEDIASUBTYPE_YV12):

const AMOVIESETUP_MEDIATYPE sudIpPinTypes =
{
&MEDIATYPE_Video
, // MajorType
&MEDIASUBTYPE_YV12
// MinorType
};

const AMOVIESETUP_PIN sudIpPin =
{
L
"Input", // The Pins name
TRUE
, // Is rendered
FALSE
, // Is an output pin
FALSE
, // Allowed none
FALSE
, // Allowed many
&CLSID_NULL
, // Connects to filter
NULL
, // Connects to pin
1, // Number of types
&sudIpPinTypes
// Pin details
};

const AMOVIESETUP_FILTER sudNullRenderer =
{
&CLSID_NullRenderer
, // Filter CLSID
L
"Null Renderer", // String name
MERIT_NORMAL
, // Filter merit
1, // Number of pins
&sudIpPin
// Pin details
};

HRESULT
CheckMediaType(const CMediaType* pMediaType)
{
if (pMediaType->majortype == MEDIATYPE_Video && pMediaType->subtype == MEDIASUBTYPE_YV12)
{
return S_OK;
} else return S_FALSE;
}

The full project can be download here 

See also

Read More »

Wednesday, May 28, 2008

DirectShow: Null Transform filter for Windows CE

A null-transform filter helps retrieve the raw camera frame buffer as well as perform necessary conversion in the buffer data.

Compilation

Most of the source codes are taken from the NullNull sample of the DirectShow for Windows XP SDK (\DX90SDK\Samples\C++\DirectShow\Filters\NullNull)

The class-library solution must be built in release mode and must export itself via COM using a module definition file. It can either be deployed by Visual Studio by setting COM Self Register to TRUE or by using regsvrce.exe

To prevent compile errors about string types, go to Project Properties>Configuration Properties>C/C++>Language and change Treat wchar_t as built-in type to No
To control which media type the filter will accept and which will be rejected, modify the function CheckInputType. Return S_OK to accept the media and S_FALSE to reject.


HRESULT CheckInputType(const CMediaType* mtIn)
{
if (mtIn->majortype == MEDIATYPE_Video && mtIn->subtype == MEDIASUBTYPE_YV12)
return S_OK;
else
return S_FALSE;
}

Usage

The DLL exports 2 interfaces:

DEFINE_GUID(CLSID_NullNull, 0xba1864f4, 0x6988, 0x4e86, 0xb2, 0x8f, 0x60, 0x33, 0x5b, 0xae, 0x85, 0x5f);
DEFINE_GUID(IID_ITransformFilter, 0x6b652fff, 0x11fe, 0x4fce, 0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f);

CLSID_NullNull identifies the filter when added to the graph whereas IID_ITransformFilter defines an interface providing a call-back function which will invokes when the camera data is available. To create a new GUID, use the Visual Studio menu Tools->Create GUID

To add the filter to the graph, use:

CComPtr
<IBaseFilter> pNullTransform;
hr
= pNullTransform.CoCreateInstance(CLSID_NullNull);
hr
= pFilterGraph->AddFilter(pNullTransform, L"NullNull");

To get the callback function when the camera data is available. CameraSampleReceived will be called when a frame is received from the camera

hr = pNullTransform->QueryInterface(IID_ITransformFilter, (void**)&pTransform);
hr
= pTransform->SetCallback(&CameraSampleReceived);

HRESULT
CameraSampleReceived(IMediaSample *pSample, int width, int height)
{
}
 
The source code can be download here


See also

Read More »