[Windows Mobile] Capturing video from device camera C# or DirectShow.NET CF Part II

In previous post i explained how to play video or audio on Windows Mobile devices using DirectShow.
I`ve received some emails with request to explain how preview video from device camera.
First of all in Windows Mobile SDK in examples you can find C++ exmaple. I`ve seen examples that suggest  to compile example from SDK to dll and than importing methos from that dll watch camera preview. I did little bit more, i ported whole code to C# so we dont need any dll. So what do we need? we need import 3 api methods, FindFirstDevice, FindClose and GetClientRect

[DllImport("coredll.dll")]
public static extern int GetClientRect(
[In] IntPtr hWnd,
[Out] out Rect lpRect);

[DllImport("coredll.dll")]
public static extern IntPtr FindFirstDevice(
[In] int searchType,
[In] IntPtr searchParam,
[In, Out] ref DEVMGR_DEVICE_INFORMATION pdi);

[DllImport("coredll.dll")]
public static extern int FindClose([In] IntPtr hFindFile);

also we need 6 more Com Interfaces:
IVideoWindow, IBaseFilter, IPersist, IPersistPropertyBag, IPropertyBag, ICaptureGraphBuilder2

[ComVisible(true), ComImport,
Guid("56A868B4-0AD4-11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IVideoWindow
{
[PreserveSig]
int put_Caption([In] string caption);

[PreserveSig]
int get_Caption([Out] out string caption);

[PreserveSig]
int put_WindowStyle([In] int windowStyle);

[PreserveSig]
int get_WindowStyle([Out] out int windowStyle);

[PreserveSig]
int put_WindowStyleEx([In] int windowStyleEx);

[PreserveSig]
int get_WindowStyleEx(out int windowStyleEx);

[PreserveSig]
int put_AutoShow([In] int autoShow);

[PreserveSig]
int get_AutoShow([Out] out int autoShow);

[PreserveSig]
int put_WindowState([In] int windowState);

[PreserveSig]
int get_WindowState([Out] out int windowState);

[PreserveSig]
int put_BackgroundPalette([In] int backgroundPalette);

[PreserveSig]
int get_BackgroundPalette([Out] out int backgroundPalette);

[PreserveSig]
int put_Visible([In] int visible);

[PreserveSig]
int get_Visible([Out] out int visible);

[PreserveSig]
int put_Left([In] int left);

[PreserveSig]
int get_Left([Out] out int left);

[PreserveSig]
int put_Width([In] int width);

[PreserveSig]
int get_Width([Out] out int width);

[PreserveSig]
int put_Top([In] int top);

[PreserveSig]
int get_Top([Out] out int top);

[PreserveSig]
int put_Height([In] int height);

[PreserveSig]
int get_Height([Out] out int height);

[PreserveSig]
int put_Owner([In] IntPtr owner);

[PreserveSig]
int get_Owner([Out] out IntPtr owner);

[PreserveSig]
int put_MessageDrain([In] IntPtr drain);

[PreserveSig]
int get_MessageDrain([Out] out IntPtr drain);

[PreserveSig]
int get_BorderColor([Out] out int color);

[PreserveSig]
int put_BorderColor([In] int color);

[PreserveSig]
int get_FullScreenMode([Out] out int fullScreenMode);

[PreserveSig]
int put_FullScreenMode([In] int fullScreenMode);

[PreserveSig]
int SetWindowForeground([In] int focus);

[PreserveSig]
int NotifyOwnerMessage(
[In] IntPtr hwnd,
[In] int msg,
[In] IntPtr wParam,
[In] IntPtr lParam);

[PreserveSig]
int SetWindowPosition(
[In] int left,
[In] int top,
[In] int width,
[In] int height);

[PreserveSig]
int GetWindowPosition(
[Out] out int left,
[Out] out int top,
[Out] out int width,
[Out] out int height);

[PreserveSig]
int GetMinIdealImageSize(
[Out] out int width,
[Out] out int height);

[PreserveSig]
int GetMaxIdealImageSize(
[Out] out int width,
[Out] out int height);

[PreserveSig]
int GetRestorePosition(
[Out] out int left,
[Out] out int top,
[Out] out int width,
[Out] out int height);

[PreserveSig]
int HideCursor([In] int hideCursor);

[PreserveSig]
int IsCursorHidden([Out] out int hideCursor);

}

[ComVisible(true), ComImport,
Guid("56A86895-0AD4-11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IBaseFilter
{
[PreserveSig]
int GetClassID([Out] out Guid pClassID);

[PreserveSig]
int Stop();

[PreserveSig]
int Pause();

[PreserveSig]
int Run([In] long tStart);

[PreserveSig]
int GetState(
[In] int dwMilliSecsTimeout,
[Out] out int filtState);

[PreserveSig]
int SetSyncSource([In, MarshalAs(UnmanagedType.Interface)] object pClock);

/// <summary>
///
/// </summary>
[PreserveSig]
int GetSyncSource([Out, MarshalAs(UnmanagedType.Interface)] out object pClock);

[PreserveSig]
int EnumPins([Out, MarshalAs(UnmanagedType.Interface)] out object ppEnum);

[PreserveSig]
int FindPin(
[In, MarshalAs(UnmanagedType.LPWStr)] string Id,
[Out, MarshalAs(UnmanagedType.Interface)] out object ppPin);

[PreserveSig]
int QueryFilterInfo([Out] IntPtr pInfo);

[PreserveSig]
int JoinFilterGraph(
[In, MarshalAs(UnmanagedType.Interface)] object pGraph,
[In, MarshalAs(UnmanagedType.LPWStr)] string pName);

[PreserveSig]
int QueryVendorInfo(
[Out, MarshalAs(UnmanagedType.LPWStr)] out string pVendorInfo);
}

[ComVisible(true), ComImport,
Guid("0000010C-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersist
{
[PreserveSig]
int GetClassID([Out] out Guid pClassID);
}

[ComVisible(true), ComImport,
Guid("37D84F60-42CB-11CE-8135-00AA004BB851"),//Guid("5738E040-B67F-11d0-BD4D-00A0C911CE86"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersistPropertyBag : IPersist
{
#region IPersist
[PreserveSig]
new int GetClassID([Out] out Guid pClassID);
#endregion

[PreserveSig]
int InitNew();

[PreserveSig]
int Load(
[In] IPropertyBag pPropBag,
[In, MarshalAs(UnmanagedType.Interface)] object pErrorLog
);

[PreserveSig]
int Save(
IPropertyBag pPropBag,
[In, MarshalAs(UnmanagedType.Bool)] bool fClearDirty,
[In, MarshalAs(UnmanagedType.Bool)] bool fSaveAllProperties
);
}

[ComVisible(true), ComImport,
Guid("55272A00-42CB-11CE-8135-00AA004BB851"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyBag
{
[PreserveSig]
int Read(
[In, MarshalAs(UnmanagedType.LPWStr)] string pszPropName,
[In, Out, MarshalAs(UnmanagedType.Struct)]    ref    object pVar,
[In] IntPtr pErrorLog);

[PreserveSig]
int Write(
[In, MarshalAs(UnmanagedType.LPWStr)] string pszPropName,
[In, MarshalAs(UnmanagedType.Struct)] ref object pVar);
}

[ComVisible(true), ComImport,
Guid("93E5A4E0-2D50-11D2-ABFA-00A0C9C6E38D"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICaptureGraphBuilder2
{
[PreserveSig]
int SetFiltergraph([In] IGraphBuilder pfg);

[PreserveSig]
int GetFiltergraph([Out] out IGraphBuilder ppfg);

[PreserveSig]
int SetOutputFileName(
[In] ref Guid pType,
[In, MarshalAs(UnmanagedType.LPWStr)] string lpstrFile,
[Out] out IBaseFilter ppbf,
[Out, MarshalAs(UnmanagedType.Interface)] out object ppSink);

[PreserveSig]
int FindInterface(
[In] ref CGuid pCategory,
[In] ref CGuid pType,
[In] IBaseFilter pbf,
[In] ref Guid riid,
[Out, MarshalAs(UnmanagedType.IUnknown)] out object ppint);

[PreserveSig]
int RenderStream(
[In, MarshalAs(UnmanagedType.LPStruct)] CGuid PinCategory,
[In, MarshalAs(UnmanagedType.LPStruct)] CGuid MediaType,
[In, MarshalAs(UnmanagedType.IUnknown)] object pSource,
[In] IBaseFilter pfCompressor,
[In] IBaseFilter pfRenderer
);

[PreserveSig]
int ControlStream(
[In] ref CGuid pCategory,
[In] ref CGuid pType,
[In] IBaseFilter pFilter,
[In] IntPtr pstart,
[In] IntPtr pstop,
[In] short wStartCookie,
[In] short wStopCookie);

[PreserveSig]
int AllocCapFile(
[In, MarshalAs(UnmanagedType.LPWStr)] string lpstrFile,
[In] long dwlSize);

[PreserveSig]
int CopyCaptureFile(
[In, MarshalAs(UnmanagedType.LPWStr)] string lpwstrOld,
[In, MarshalAs(UnmanagedType.LPWStr)] string lpwstrNew,
[In] int fAllowEscAbort,
[In, MarshalAs(UnmanagedType.Interface)] object pFilter);

[PreserveSig]
int FindPin(
[In] object pSource,
[In] int pindir,
[In] ref CGuid pCategory,
[In] ref CGuid pType,
[In, MarshalAs(UnmanagedType.Bool)] bool fUnconnected,
[In] int num,
[Out, MarshalAs(UnmanagedType.Interface)] out object ppPin);
}

Everything else the same as in SDK example + i made class to hide directshow from cant or not going to understand it :)
Class got 3 public methods:
init() - inits camera and builds graph
release() - stops preview and releases all com objects
run(IntPtr owner) - start preview on control

using System;
using System.Runtime.InteropServices;

namespace DirectShowNETCF
{
public class CCamera
{
private IBaseFilter video = null;
private IBaseFilter renderer = null;
private ICaptureGraphBuilder2 capGraph = null;
private IGraphBuilder graph = null;
private IVideoWindow window = null;
private IMediaControl control = null;

public CCamera()
{
}

~CCamera()
{
release();
}

public bool init()
{
object obj = null;
#region FilterGraph
Guid clsid = CLSID_.FilterGraph;
Guid riid = IID_.IFilterGraph2;
PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, (uint)CLSCTX_.INPROC_SERVER, ref riid, out obj);
graph = (IGraphBuilder)obj;
if (graph == null)
{
return false;
}
#endregion
obj = null;
#region CaptureGraph
clsid = CLSID_.CaptureGraphBuilder;
riid = IID_.ICaptuGraphBuilder2;
PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, (uint)CLSCTX_.INPROC_SERVER, ref riid, out obj);
capGraph = (ICaptureGraphBuilder2)obj;
if (capGraph == null)
{
return false;
}
#endregion
obj = null;

int hr = capGraph.SetFiltergraph(graph);
if (hr < 0)
{
return false;
}

if (!getVideoCaptureFilter())
{
return false;
}

hr = graph.AddFilter(video, "Video Capture");
if (hr < 0)
{
return false;
}

if (!getVideoRenderer())
{
return false;
}

hr = graph.AddFilter(renderer, "Video Renderer");
if (hr < 0)
{
return false;
}
hr = capGraph.RenderStream(null, null, video, null, renderer);
if (hr < 0)
{
return false;
}
control = (IMediaControl)graph;
return true;
}

public void release()
{
if (control != null)
{
control.Stop();
}

if (window != null)
{
window.put_Owner(IntPtr.Zero);
window.put_Visible(-1);
}

if (capGraph != null)
{
Marshal.ReleaseComObject(capGraph);
capGraph = null;
}

if (graph != null)
{
Marshal.ReleaseComObject(graph);
graph = null;
control = null;
}

if (video != null)
{
Marshal.ReleaseComObject(video);
video = null;
}

if (renderer != null)
{
Marshal.ReleaseComObject(renderer);
renderer = null;
window = null;
}
}

public bool run(IntPtr owner)
{
if (window != null)
{
Rect rc = new Rect();
PInvoke.GetClientRect(owner, out rc);
window.put_Owner(owner);
window.SetWindowPosition(rc.Left, rc.Top, rc.Right, rc.Bottom);
window.put_WindowStyle(0x40000000 | 0x02000000);
window.put_Visible(0);
}
else
{
return false;
}
return control.Run() >= 0;
}

private bool getVideoCaptureFilter()
{
object obj = null;
Guid clsid = CLSID_.VideoCapture;
Guid riid = IID_.IBaseFilter;
PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, (uint)CLSCTX_.INPROC_SERVER, ref riid, out obj);
if (obj == null)
{
return false;
}
video = (IBaseFilter)obj;
obj = null;
string name_ = "";
if (!getName(ref name_))
{
return false;
}

IPersistPropertyBag propBag = (IPersistPropertyBag)video;
if (propBag == null)
{
return false;
}

CPropertyBag bag = new CPropertyBag();
object oname = name_;
bag.Write("VCapName", ref oname);
int hr = propBag.Load(bag, null);
if (hr < 0)
{
//System.Windows.Forms.MessageBox.Show("cannot load prop bag");
return false;
}
return true;

}

private bool getVideoRenderer()
{
object obj = null;
Guid clsid = CLSID_.VideoRenderer;
Guid riid = IID_.IBaseFilter;
PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, (uint)CLSCTX_.INPROC_SERVER, ref riid, out obj);
if (obj == null)
{
return false;
}
renderer = (IBaseFilter)obj;
window = (IVideoWindow)renderer;
return true;
}

private bool getName(ref string name)
{
IntPtr handle = IntPtr.Zero;
IntPtr guid = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
Marshal.StructureToPtr(CLSID_.Camera, guid, false);
DEVMGR_DEVICE_INFORMATION di = new DEVMGR_DEVICE_INFORMATION();
di.dwSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(DEVMGR_DEVICE_INFORMATION));
handle = PInvoke.FindFirstDevice(3, guid, ref di);
Marshal.FreeHGlobal(guid);
if ((handle == IntPtr.Zero)||(di.hDevice == IntPtr.Zero))
{
return false;
}

PInvoke.FindClose(handle);
name = di.szLegacyName;
return true;
}
}

public class CPropertyBag : IPropertyBag
{
private object pVar_ = null;

public CPropertyBag()
{
pVar_ = new object();
}

~CPropertyBag()
{
pVar_ = null;
}

public int Read(
[In, MarshalAs(UnmanagedType.LPWStr)] string pszPropName,
[In, Out, MarshalAs(UnmanagedType.Struct)]    ref    object pVar,
[In] IntPtr pErrorLog)
{
pVar = pVar_;
return 0;
}

public int Write(
[In, MarshalAs(UnmanagedType.LPWStr)] string pszPropName,
[In, MarshalAs(UnmanagedType.Struct)] ref object pVar)
{
pVar_ = pVar;
return 0;
}
}
}

Last version of DirectShowNETCF

46 Responses to “[Windows Mobile] Capturing video from device camera C# or DirectShow.NET CF Part II”

Pages: « 5 4 3 2 [1] Show All

  1. 10
    KenG Says:

    I downloaded your code, works great on a WM6 device I am developing with. Also nice job on the port to C#. I am new to directshow programming and have managed to piece together a preview and still capture application in VB .NET with the bulk of the work done using directshow in a native C++ DLL, however, the still capture filter (ImageSinkFilter) is too slow for my requrements. I have tried with no success to implement a custom sample grabber filter as a faster alternative…so I am looking forward to article Part III or IV that will hoping shed some light on things. Also it would be great to see IAMStreamConfig and IAMCameraControl interfaces ported to C# as well.

  2. 9
    admin Says:

    I`m going to write next article about that, but dont have enough time now… may be next week.

    Regards,
    Alex

  3. 8
    Toyin Says:

    I downloaded the code, i could view the video frames. My question is how do I implement the camera capture (still Image)? Once I focus the camera on the target, how do i capture the image? A response would be appreciated. Thanks.

  4. 7
    N Says:

    Thank you very much again, I did not understand anything, I am amateur in mobile programming,can you put some code to understand it better?

    Some day you do some example? Would be appreciated greatly.
    Thanks for answering

  5. 6
    admin Says:

    You should connect Video Capture filter to video encoder video encoder to avi (asf) mux and then to file writer, thats all.

    if you need preview and record you have to Inf Tee filter

    If you need just capture frames from time to time use ImageSinkFilter

  6. 5
    N Says:

    Can you tell me how please?
    thanks for reply

  7. 4
    admin Says:

    Yes i can :)

  8. 3
    N Says:

    Hello, thank you very much for the application.
    In particular I would like to save the contents of the panel (video recording)
    You can do this?
    Thank you

  9. 2
    admin Says:

    it wont work on emulator, so max what i can do its picture my cell :)
    anyway thatks for suggestion

  10. 1
    T-Rex Says:

    Cool. But it would be nice if you provide some screenshots :P

Pages: « 5 4 3 2 [1] Show All

Leave a Reply