HTCCamera v.1.0

HTC provides the simpliest DirectShow driver, that does not allow to chose resolution of frame that we want to grab… does not allow to control flash or autofocus and other available settings that default application allows…

Here is first version of HTCCamera class that works directly with driver as result we can choose resolution of grabbing frame, we can grab frames to memory without saving to storage. also it allows to control flash and autofocus!

In future it will allow to control brightness, saturation, hue, whiteballance so on…

First vesion you can download here

How to get focused/targeted image?

After i added functionality to draw target/rectangle on preview, i received some emails with question how to grab part that exactly in rectagnle.

Ok you dont need anything special and any lib, for example you draw target with

Rect _rect

then to grab that part you need:

1. Grab full image

Bitmap bmp = new Bitmap(width, height);
System.Drawing.Imaging.BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height),
System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);

bFlag = cam_.getRgb565(data.Scan0);
bmp.UnlockBits(data);

2. Create 2nd bitmap

Bitmap bmp2 = new Bitmap(_rect.Right - _rect.Left, _rect.Bottom - _rect.Top);

3. Using Graphics cut required part

gr.DrawImage(bmp, new Rectangle(0, 0, bmp2.Width, bmp2.Height),
new Rectangle(_rect.Left, _rect.Top, bmp2.Width, bmp2.Height), GraphicsUnit.Pixel);

bmp2 - result bitmap and its exactly what you need

More samplegrabber chages

Made some changes in samplegrabber and IGetFrame interface now you can define target position and target type, so new IGetFrame:

[ComVisible(true), ComImport,
Guid("2B21644A-D405-4E27-A51C-A4812bE0CE4C"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGetFrame
{
[PreserveSig]
int getFrame(IntPtr pBuff);

[PreserveSig]
int getSize([Out] out long size);

[PreserveSig]
int getFrameParams(
[Out] out int width,
[Out] out int height,
[Out] out RawFrameFormat format);

[PreserveSig]
int drawText(
[In] IntPtr ptr,
[In] int height,
[In] int width);

[PreserveSig]
int stopDraw();

[PreserveSig]
int getGrayScale(IntPtr ptr);

[PreserveSig]
int getRgb(IntPtr ptr);

[PreserveSig]
int drawTarget(Rect rect, int type);

[PreserveSig]
int stopDrawTarget();
}

P.S. dont forget that rect depends of frame size, not control size.

Link to new library version

Samplegrabber Changes

I made some changes in native part of library (Samplegrabber) now we can use up to 3 samplegrabbers in the same time and now you can PIvoke for samplegrabber like in bellow code:

[DllImport("DirectShowNETCF.Native.dll")]
private static extern IntPtr GetBaseFilter(int index);

[DllImport("DirectShowNETCF.Native.dll")]
private static extern void DeleteBaseFilter(int index);

also interface IBaseFrame has been changed:

[ComVisible(true), ComImport,
Guid("2B21644A-D405-4E27-A51C-A4812bE0CE4C"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGetFrame
{
[PreserveSig]
int getFrame(IntPtr pBuff);

[PreserveSig]
int getSize([Out] out long size);

[PreserveSig]
int getFrameParams(
[Out] out int width,
[Out] out int height,
[Out] out RawFrameFormat format);

[PreserveSig]
int drawText(
[In] IntPtr ptr,
[In] int height,
[In] int width);

[PreserveSig]
int stopDraw();

[PreserveSig]
int getGrayScale(IntPtr ptr);

[PreserveSig]
int getRgb(IntPtr ptr);

[PreserveSig]
int drawTarget();

[PreserveSig]
int stopDrawTarget();
}

all this changes was made for new functionality (grabbing rgb or grayscale frames for RGB565 or YV12 fromats, drawing target on preview, using more then 1 sample grabber in 1 application)

You can check updated AMCamera example from DirectShowNETCF

DirectShow.NETCF sources

I received a lot of requests for share sources of library…
First of all, sorry guys i`m not going to open sources for free, but if somebody really need em for some reasons (sign library, add changes, learn something so on) i ready to sell it. you will have to sign NDA and then you can use it in any your project as Library or as units/classes.

What do sources include:

a) Sources
b) 1 year support by email/skype/phone
c) 1 year free updates

Price:

  • PlayerControl - $99
  • Camera - $99
  • AMCamera class without native sources - $99
  • AMCamera class + native sources - 199
  • AMCameraExControl/AMCameraEx without native sources - $199
  • AMCameraExControl/AMCameraEx + native sources - $299
  • NullCamera class without native sources - $69
  • NullCamera class + native sources - $149
  • Camera + PlayerControl + AMCamera + AMCameraEx + NullCamera - $599

HTCCamera

  • HTCCamera - remove MessageBoxes - $300
  • HTCCamera - C# sources - $500

contacts you can find on site/blog

[Windows Mobile]Draw Text on preview or SampleGrabber and DirectShow.NETCF

If you ever used DirectShow under windows then you know that if you want draw text on preview you can use VMRRenderer, but windows mobile dont provide any way to draw text on preview :(

I see there only 1 way to solve it - Draw text directly on stream, so we need SampleGrabber to got access to raw stream, also we need to create our own font (thats the main problem). i made small demo that allows draw text on preview.

So IGetFrame was modified:

[ComVisible(true), ComImport,
Guid("2B21644A-D405-4E27-A51C-A4812bE0CE4C"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGetFrame
{
[PreserveSig]
int getFrame(IntPtr pBuff);

[PreserveSig]
int getSize([Out] out long size);

[PreserveSig]
int getFrameParams(
[Out] out int width,
[Out] out int height,
[Out] out RawFrameFormat format);

[PreserveSig]
int drawText(
[In] IntPtr ptr,
[In] int height,
[In] int width);

[PreserveSig]
int stopDraw();
}

As you can see we got new method: drawText([In] IntPtr ptr, [In] int height, [In] int width);
where ptr - is our text in special format…
how to conver text to IntPtr?
there added extra class: CABC, here is example how to draw text:

CABC abc = new CABC("abcd dabc cdab bcda");
frmGrabber.drawText(abc.getText(), abc.Height, abc.Width);
abc.Dispose();
abc = null;

Also you can check AMCamera example from DirectShowNETCF

[Windows Mobile] Capturing Raw Frames or SampleGrabber and DirectShow.NETCF

What is SampleGrabber? this is filter (as a rule Transform or TransInPlace) that goes after filter which samples we are going to grab.

Why do we need SampleGrabber?
1. In windows mobile this is the fastest way to still images, more than that we still uncompressed images (so we dont loose time for encoding/decoding)
2. We can use SampleGrabber to draw text or images on received stream
3. We grab images to memory.

I Think this is enough to say that sample grabber is useful.
The problem is that windows already have sample grabber and we dont need to make any extra moves to use it, but Windows Mobile knows nothing about sample grabber :(

On www.codeproject.com you can find some articles that explain how to implement SampleGrabber. But there tons limits and problems in every case, so i decided to implement my own.

The main question was “Is it possible to implement SampleGrabber that not need to registered?”. I meant that if i programming on C++ i can use unit (class) that contain samplegrabber code, i if i programming on any other language i can use this unit compiled to dll. Yes its possible (!!!!) we dont need resvrCE and anything else, just unit or dll :)

I was going to use developed SampleGrabber for barcode reader, but samples that i receive were too blurred to be recognized even by human (may be this is my cam dieing? O,o). anyway that was reason i decided to stop work on it, so here is what i got for this time:

DirectShowNETCF.Native.dll that contain SampleGrabber. How to use it?

[DllImport("DirectShowNETCF.Native.dll")]
private static extern IntPtr GetBaseFilter();

this is method returns IntPtr that equal to IBaseFilter*

how to get IBaseFilter?

IntPtr grabber_ = GetBaseFilter();
IBaseFilter grabber = (IBaseFilter)Marshal.GetTypedObjectForIUnknown(grabber_, typeof(IBaseFilter));

To grab raw frame you have to call
1. getSize(out long size)
2. alloc memory (use DirectShowNETCF.PInvoke.LocalAlloc(0×40, size))
3. call getFrame(IntPtr pBuff)

[ComVisible(true), ComImport,
Guid("2B21644A-D405-4E27-A51C-A4812bE0CE4C"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGetFrame
{
[PreserveSig]
int getFrame(IntPtr pBuff);

[PreserveSig]
int getSize([Out] out long size);
}

//example of grabbing frame
public IntPtr grabFrame(ref long bufSize)
{
IntPtr res_ = IntPtr.Zero;
long size = 0;
frmGrabber.getSize(out size);
bufSize = size;
res_ = PInvoke.LocalAlloc(0x40, (int)size);
frmGrabber.getFrame(res_);
return res_;
}

last version of DirectShowNETCF you can download here

[Windows Mobile] Changing still image resolution or DirectShow.NETCF part IV

Most of us who was trying to use DirectShowNETCF found that resolution of stilled image smaller that it could be, for example my device (Samsung i710) got default resolution on still pin 320×240, but i know that it supports resolutions up to 2Mpx. So that should be fixed :)

What do we need to change resolution?
1. We need Enum supported:

2. Using IAMStreamConfig set required mediatype to required pin (STILL pin in our case)

here is interfaces:

[ComVisible(true), ComImport,
Guid("89C31040-846B-11CE-97D3-00AA0055595A"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumMediaTypes
{
[PreserveSig]
int Next(
[In] int cMediaTypes,
[Out] out IntPtr ppMediaTypes,
[Out] out int pcFetched
);

[PreserveSig]
int Skip([In] int cMediaTypes);

[PreserveSig]
int Reset();

[PreserveSig]
int Clone([Out] out IEnumMediaTypes ppEnum);
}

[ComVisible(true), ComImport,
Guid("C6E13340-30AC-11D0-A18C-00A0C9118956"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAMStreamConfig
{
[PreserveSig]
int SetFormat([In, MarshalAs(UnmanagedType.LPStruct)] AMMediaType pmt);

[PreserveSig]
int GetFormat([Out] out IntPtr pmt);

[PreserveSig]
int GetNumberOfCapabilities(
[Out] out int piCount,
[Out] out int piSize);

[PreserveSig]
int GetStreamCaps(
[In] int iIndex,
[Out] out IntPtr ppmt,
[In] IntPtr pSCC
);
}

Also was created useful class CEnumMediatypes (as in DSPack)

public class CEnumMediaTypes
{
private List<AMMediaType> FList;
private IEnumMediaTypes EnumMediaTypes;
private IntPtr Mt;
public void Free()
{
Clear();
}

public CEnumMediaTypes()
{
FList = new List<AMMediaType>();
}

private void Clear()
{
for (int i = 0; i < FList.Count; i++)
{
DirectShowEx.FreeMediaType(FList[i]);
FList[0] = null;
FList.RemoveAt(0);
}

FList.Clear();
}

public int Count
{
get
{
return FList.Count;
}
}

public void Assign(ICaptureGraphBuilder2 capGraph, IBaseFilter filter, Guid category)
{
Clear();

IPin pin_ = null;
CGuid guid = new CGuid(category);
CGuid guid2 = new CGuid(CLSID_.MEDIATYPE_Video);
int res = capGraph.FindPin(filter, PinDirection.Output, guid, guid2, true, 0, out pin_);

if (res > -1)
{
pin_.EnumMediaTypes(out EnumMediaTypes);
if (EnumMediaTypes == null)
{
return;
}

int fetched = 0;

int hr = EnumMediaTypes.Next(1, out Mt, out fetched);
while (hr == 0)
{
fetched = 0;
hr = EnumMediaTypes.Next(1, out Mt, out fetced);
AMMediaType mt = (AMMediaType)Marshal.PtrToStructure(Mt, typeof(AMMediaType));
FList.Add(mt);
}

Marshal.ReleaseComObject(EnumMediaTypes);
Marshal.ReleaseComObject(pin_);
}
}

private string getFourCC(int value)
{
IntPtr ptr = Marshal.AllocHGlobal(4);
Marshal.WriteInt32(ptr, value);
byte[] bt = new byte[4];
Marshal.Copy(ptr, bt, 0, 4);
Marshal.FreeHGlobal(ptr);
char[] ch = new char[4];
for (int i = 0; i < 4; i++)
{
ch[i] = (char)bt[i];
}
bt = null;
return new string(ch);
}

public string GetMediaDescription(int index)
{
string result = "";

AMMediaType tempType = FList[index];
if (tempType.formatType == CLSID_.VideoInfo)
{
result += ((VideoInfoHeader)Marshal.PtrToStructure(tempType.formatPtr, typeof(VideoInfoHeader))).BmiHeader.Width.ToString();
result += 'X';
result += ((VideoInfoHeader)Marshal.PtrToStructure(tempType.formatPtr, typeof(VideoInfoHeader))).BmiHeader.Height.ToString();
}
else
{
if (tempType.formatType == CLSID_.VideoInfo2)
{
result += ((VideoInfoHeader2)Marshal.PtrToStructure(tempType.formatPtr, typeof(VideoInfoHeader2))).BmiHeader.Width.ToString();
result += 'X';
result += ((VideoInfoHeader2)Marshal.PtrToStructure(tempType.formatPtr, typeof(VideoInfoHeader2))).BmiHeader.Height.ToString();
}
}

tempType = null;
return result;
}

public AMMediaType this[int index]
{
get
{
return FList[index];
}
}

}

Exaple how to set/change resolution is here

[Windows Mobile]Stilling images from Camera C# or DirectShow .NETCF part III

Ok, most popular question for last week was: “How to still images from windows mobile camera?”
I finished my project little bit earlier that i was planing, so i have free time again and looking for job too :)

So what do we need? tons extra com interfaces (Ipin, IEnumPins, IEnumFilters, IFileSinkFilter, IAMVideoControl and so on).

Also i implemented 2 useful classes (as for me) CPinList and CFilterList (the same as in DSPack).

public class CFilterList
{
private List<IBaseFilter> Filters;
private IEnumFilters enumFilters = null;
public CFilterList()
{
Filters = new List<IBaseFilter>();
}
~CFilterList()
{
Free();
Filters = null;
}
public void Assign(IGraphBuilder fg)
{
Clear();
fg.EnumFilters(out enumFilters);
IBaseFilter Filter;
int fetched = 0;

while (enumFilters.Next(1, out Filter, out fetched) == 0)
{
Filters.Add(Filter);
}

Marshal.ReleaseComObject(enumFilters);
enumFilters = null;
}
public int Count
{
get
{
return Filters.Count;
}
}
public IBaseFilter this[int index]
{
get
{
return Filters[index];
}
}
public void Free()
{
Clear();
}
private void Clear()
{
while (Filters.Count > 0)
{
Marshal.ReleaseComObject(Filters[0]);
Filters[0] = null;
Filters.RemoveAt(0);
}

Filters.Clear();
}
}

public class CPinList
{
private List<IPin> Pins = null;
private IEnumPins enumPins = null;

public CPinList()
{
Pins = new List<IPin>();
}

~CPinList()
{
Free();
Pins = null;
}

public int Count
{
get
{
return Pins.Count;
}
}

public IPin this[int index]
{
get
{
return Pins[index];
}
}

public void Assign(IBaseFilter filter)
{
Clear();
filter.EnumPins(out enumPins);

IPin pin;
int fetched = 0;

while (enumPins.Next(1, out pin, out fetched) == 0)
{
Pins.Add(pin);
}

Marshal.ReleaseComObject(enumPins);
enumPins = null;

}

private void Clear()
{
while (Pins.Count > 0)
{
Marshal.ReleaseComObject(Pins[0]);
Pins[0] = null;
Pins.RemoveAt(0);
}
Pins.Clear();
}

public void Free()
{
Clear();
}
}

so now stilling images works, btw in the same time with preview, but there some bad news (if we can call it so):
a) it takes like 15 seconds to build graph :(
b) when i still image preview hangs for like 2 seconds.

good news:
a) we can implement samplegrabber filter and do not wait when stilling images and building graph
b) filter of video capture device has 3 output pins (on my device), i`m not sure, but seems like: preview, still image and probably still video :) will try to check it soon

And last one perhaps preview and stilling images wont work on some devices in the same time so you will need to choose what exactly you need (but this is only unconfirmed “perhaps”)

Almost forgot

[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