[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
Filed under: Programming
November 4th, 2010 at 3:51 pm
hello, Im very new in this, can you give me a simple example on how to get an imagen from the camera and store it to memory(ram) as fast it can?
considering the resolution, I means, if the camera is a 5 Megapixel, I wanna to get the whole picture, then reduce it to 640×480 or 320×240, then store to ram, and last I write in raw format to a file
my mail is vengador_virtual@yahoo.com.ar
thanks
August 25th, 2010 at 6:25 pm
Hello
I want to use your code for streaming video from windows phone 5
but don’t know how I can use DEVMGR_DEVICE_INFORMATION
because my program can’t define it
how can i declare DEVMGR_DEVICE_INFORMATION in my program
also for Rect Class or Struct
Thank in Advance
May 6th, 2010 at 3:35 am
Did some more experimenting - It looks like the culprits are the first two parameters. When I pass them as IntPtr the call works. Very odd - I don’t know why it’s working for everyone else as CGuids, but not for me…
So something is not marshaling correctly for the first two GUID parameters. Any ideas?
May 6th, 2010 at 3:20 am
If it helps any, I get this in the Interop error log:
JIT ERROR FOR RCW COM METHOD:
(Managed -> Native):
DirectShowLib.ICaptureGraphBuilder2::RenderStream
I can’t seem to find much on this error though.
May 6th, 2010 at 2:53 am
Hi - thanks for all your hard work and for sharing with everyone!
I am however having difficulty getting the Camera capture sample to run on two different phones - one running WM6 and one running WM6.5 as well as the emulator. I can’t init() the camera. Since you don’t release the source code to the libraries, I implemented the code from this page to see where it was failing, and when it gets to the RenderFile() call, I get a NotSupportedException in the CLR. It appears to be creating all the COM objects correctly, but for some reason when I call RenderFile() it throws the exception.
Any ideas?
April 30th, 2010 at 6:14 pm
1. Have tryed to comment this line?
if resolutions stays empty then probably it cant find still pin or pin enumerator does not return anything… anyway seems like this is device problem, because all old HTC devices got far from perfect DirectShow drivers…
P.S. why do you need sdk for C# code?
April 30th, 2010 at 4:07 pm
Hi, I tried to deploy examples to HTC TyTn 2 but it didn’t work.
1. Camera example
- it producies unhandled exception in line
resolutionCombo.SelectedIndex = 0;
because the list resolutions stays emty; cam_.getMediaTypes() does not work properly I think
2. All other examples
- when I press Start button- cannot init camera is shown
I use VS2005 with windows mobile sdk - standard and professional (both)
Any help would be appreciated!