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);

3 comments:

  1. Thanks for your post. Using this article and some other resources online I was able to create this simple but functional VB.NET class. I hope it helps some one out there. For more code and .NET Stuff visit www.eKoshka.com

    ------------------------------------------------
    Imports System.Runtime.InteropServices

    Public Class CameraControl

    ' Nested Types
    Public Enum FlashModes As Integer
    [On] = 1
    Off = 2
    End Enum

    Public Enum FlashLightCommands As Integer
    DisableNormal = 2
    EnableBright = 3
    EnableNormal = 1
    ResetBright = 4
    End Enum

    Private enmFlashMode As FlashModes = FlashModes.Off
    Private blnCameraIsInitialized As Boolean = False

    ' Methods
    Public Sub New()
    'Me.Initialize()
    End Sub

    Protected Overrides Sub Finalize()
    Me.Deinitialize()

    MyBase.Finalize()
    End Sub

    Public Sub Initialize()
    ' check if camera is available
    Dim num As UInteger = 1
    Dim num2 As UInteger = 0
    Dim num3 As Integer = 0

    Try
    ' try to initialize camera
    num3 = CameraControl.Camera_Init(num, num2)
    Catch ex As Exception
    MessageBox.Show("Error finding the DLL or the 'Camera_Deinit' entry point: " + ex.Message)
    End Try

    If num3 = 1 Then
    blnCameraIsInitialized = True
    Else
    MessageBox.Show("Error initializing the camera, received error code: " + num3.ToString(), "Error")
    End If
    End Sub

    Public Sub Deinitialize()
    ' deinitialize camera
    If blnCameraIsInitialized Then
    CameraControl.Camera_Deinit()
    blnCameraIsInitialized = False
    End If
    End Sub

    Public Property FlashMode() As FlashModes
    Get
    Return Me.enmFlashMode
    End Get
    Set(ByVal value As FlashModes)
    Me.enmFlashMode = value

    If blnCameraIsInitialized Then
    If Me.enmFlashMode = FlashModes.On Then
    Camera_FlashLight(FlashLightCommands.EnableNormal)
    ElseIf Me.enmFlashMode = FlashModes.Off Then
    Camera_FlashLight(FlashLightCommands.DisableNormal)
    End If
    End If
    End Set
    End Property

    #Region "Win32 Wrapers"
    _
    Shared Function Camera_Init(ByVal param1 As Integer, ByRef param2 As Integer) As Integer
    End Function

    _
    Shared Function Camera_Begin(ByRef input As Int32) As Integer
    End Function

    _
    Shared Function Camera_End(ByRef input As Int32) As Integer
    End Function

    _
    Private Shared Function Camera_FlashLight(ByVal state As FlashLightCommands) As Integer
    End Function

    _
    Shared Function Camera_Deinit() As Integer
    End Function
    #End Region

    End Class

    ------------------------------------------------

    ReplyDelete
  2. Thanks for your comment. This is the first comment ever on my blog :) I believe your camera class will help other readers as well.

    On a side note, your DllImport declarations are not displayed properly, probably because of a bug in blogspot (see http://minhdanh2002.blogspot.com/2009/05/inconveniences-while-posting-to-blogger.html) that handles the 'less than sign' incorrectly.

    ReplyDelete
  3. It's OK. People can see this post correctly on my blog at http://ekoshka.com/?p=144

    ReplyDelete

Note: Only a member of this blog may post a comment.