[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
Filed under: Programming
June 18th, 2009 at 8:30 pm
Tested DirectShowNETCF.dll enumerating and setting resolution feature - works great. Started to test the sample grabber (AMCamera) by first using your C# example…however your example does not appear to work with the current version of the DLL…am I missing something?
June 18th, 2009 at 11:37 pm
Oops
Sorry that was debug version
will update soon
June 19th, 2009 at 12:15 am
Updated
June 19th, 2009 at 10:10 am
AMCamera dont work
¿why?
June 19th, 2009 at 11:19 am
What do you mean by “does not work”? did you put DirectShowNETCF.Native.dll to the folder where executable?
June 19th, 2009 at 11:41 am
The camera does not display when I press button Start
Nice work
June 19th, 2009 at 11:49 am
does init and start return true?
June 19th, 2009 at 11:55 am
The panel is in black, do not worry it will resolve
When made the video capture?
Thanks for reply
Greetings
June 19th, 2009 at 12:31 pm
Color of panel says nothing. methods init and start returns boolean if it false it means that its impossible for some reasons init or start graph
June 19th, 2009 at 1:13 pm
The method init return false
June 19th, 2009 at 1:47 pm
I made minor changes, now example says where exaclty problem, new version uploaded, can you check it?
June 19th, 2009 at 1:59 pm
Now see that, you’re the best.
I look forward to your next update;)
June 19th, 2009 at 2:46 pm
Does it work or you can see reason why it failed? if reason please tell me it
June 19th, 2009 at 3:02 pm
I think it’s because at some point in the execution method init () returns false and can not be displayed then the method run () does not start.
It’s what I think, remember I’m newbie on directshow XD
June 19th, 2009 at 3:10 pm
Man i uploaded new version and new Demo of AMCamera if it fail on init method it return why, please check it on your device, because it works on mine
June 19th, 2009 at 3:20 pm
Ah sorry I had not seen, if it works now, you’re the boss
Thanks!!!!
June 19th, 2009 at 10:23 pm
Tested AMCamera example and everything works fine on Motorola MC55. I tried to save the raw frame data to a bmp and/or jpg file assuming the default resolution for my device (W=352, H=288). However, I am apparently not doing something correctly. Below is the code added to AMCamera example. Not sure if you had planned on adding functionality to DLL to do this.
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
private void button1_Click(object sender, EventArgs e)
{
long size = 0;
IntPtr data = cam_.grabFrame(ref size);
byte[] array = new byte[(int)size];
System.Runtime.InteropServices.Marshal.Copy(data, array, 0, (int)size);
DirectShowNETCF.PInvoke.LocalFree(data);
try
{
Bitmap bmp = CopyDataToBitmap(array);
bmp.Save(textBox1.Text, System.Drawing.Imaging.ImageFormat.Bmp);
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
//System.IO.FileStream fs = new System.IO.FileStream(textBox1.Text, System.IO.FileMode.Create);
//fs.Write(array, 0, (int)size);
//fs.Flush();
//fs.Close();
array = null;
}
private Bitmap CopyDataToBitmap(byte[] data)
{
//Create the Bitmap to the know height, width and format
Bitmap bmp = new Bitmap(352, 288, PixelFormat.Format24bppRgb);
//Create a BitmapData and Lock all pixels to be written
BitmapData bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.WriteOnly,
PixelFormat.Format24bppRgb);
//Copy the data from the byte array into BitmapData.Scan0
Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
//Unlock the pixels
bmp.UnlockBits(bmpData);
//Return the bitmap
return bmp;
}
June 20th, 2009 at 1:36 am
Hi KenG,
the problem is that i`m almost sure that camera returns raw frames in YUY12 format or something from YUV, and to receive bitmat you will need to convert it to rgb and than copy to bitmap (dont forget about stride), but if we talk about YUV you should notify that first part of memory (width * height) this is grayscale image, very useful because most morfology algorithms use grayscale images
July 3rd, 2009 at 12:59 pm
Hi, I downloaded the Directshownetcf.dll from ur website and also the examples written in C#.
Camera project is working fine on Windows Mobile Emulator 6.
But when I started the AMCamera project, it is giving error on init-
Can’t find PInvoke DLL ‘DirectShowNETCF.Native.dll’.
Am i missing somthing ?
Thanks.
July 3rd, 2009 at 1:28 pm
Hello,
Yes you forgot to load DirectShowNETCF.Native.dll on device (to the same folder where exacutable placed)
July 6th, 2009 at 7:43 am
Hi, thanks a lot.
Copying the DLLs to the same folder in which exe exists solved my problem.
Thanks a lot.
July 14th, 2009 at 11:49 am
Hi,
I thought that grabFrame() returns the bitmap inverted, but as it turns out the image is FLIPPED horizontally. Am I doing something wrong??
IntPtr buff = cam_.grabFrame(ref size);
// copy raw data to an array
byte[] array = new byte[(int)size];
Marshal.Copy(buff, array, 0, (int)size);
Bitmap bmp = new Bitmap(width, height);
BitmapData data =
bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format16bppRgb565);
System.Runtime.InteropServices.Marshal.Copy(array, 0, data.Scan0, array.Length);
DirectShowNETCF.PInvoke.LocalFree(buff);
array = null;
bmp.UnlockBits(data);
July 28th, 2009 at 12:57 pm
i pasted the DirectShowNETCF.Native.dll to the folders where amcamera.exe exists but im still having the error of Can’t find PInvoke DLL ‘DirectShowNETCF.Native.dll’. Am i missing something? thanks all.
August 3rd, 2009 at 3:00 pm
I am trying to capture image as a stream or byte array.
But the only method I see is cam_.stillImage.
Below there is I cam_.grabFrame(ref size);
Can you explain me how I can implement this ?
Regards
August 3rd, 2009 at 5:17 pm
I was using the wrong example.
Now it is o.k. with frame garbing.
August 25th, 2009 at 1:52 pm
hello:)
i tested the AMCamera example [i had to add a reference to DirectShowNETCF.dll], i copied both DirectShowNETCF.dll and DirectShowNETCF.Native.dll to both \AMCamera\bin\Debug and \AMCamera\bin\Release and i keep receive MissingMethodException was unhandled: Can’t find PInvoke DLL ‘DirectShowNETCF.Native.dll’ in the Init method. I did had to convert the project before opening it in Visual Studio 2008. Any ideas on how to solve this problem?:)
thank you
August 25th, 2009 at 3:29 pm
i answered for tgis question like 5 or more times. you should put directshownetcf.native.dll to folder where executable placed
August 27th, 2009 at 11:42 am
hi, i got an error:
System.ArgumentNullException was unhandled for
private IBaseFilter grabber = (IBaseFilter)Marshal.GetTypedObjectForIUnknown(grabber_, typeof(IBaseFilter));
i assumed grabber is the samplegrabber itself? i added grabber to the graph and nullrenderer after it. it should grab the frames n send it to the nullrenderer when the graph is started right? how can i use the grabFrame method? thanks lots!
August 31st, 2009 at 9:03 am
IBaseFilter grabber = (IBaseFilter)Marshal.GetTypedObjectForIUnknown(grabber_, typeof(IBaseFilter));
The above line of code should give me the ibasefilter object right? However i got a null exception error, I am not exactly sure how to implement the samplegrabber, must i pinoke it? thanks
August 31st, 2009 at 2:17 pm
If AMCamera worws correct on your device then reason of your exception can be only that you doing something worng
September 7th, 2009 at 11:19 am
I declared private static IntPtr grabber_ = new intPtr(); and private IBaseFilter grabber = null;
in the init() method, i used the above code > IntPtr grabber_ = GetBaseFilter();
IBaseFilter grabber = (IBaseFilter)Marshal.GetTypedObjectForIUnknown(grabber_, typeof(IBaseFilter)); the rest of the code is same as the sample above.
but i kept getting nullargument exception, when i checked the intrptr, it has a value = intptr.zero. any ideas? thank you very much.
September 14th, 2009 at 4:47 pm
Hi , I have problem when running grabFrame(ref size) method, nullreference exception . Please help??
September 14th, 2009 at 5:10 pm
i dont know when and how you call this method, so its dificult to help you…
September 18th, 2009 at 10:23 am
Hi,
Can you put a source code example to use the samplegrabber with a custom filter graph like MPEG1?
Thanx.
November 11th, 2009 at 4:18 pm
Hi,
Thanks for sharing such a good info with us.
I get an error msg that says “Cannot init camera! Result: ConnectGrabberError_2″ when i click start button on device.
Why do you think that I get this error message ?
Thanks in advance.
Yasin
November 11th, 2009 at 9:29 pm
ConnectGrabberError_2 means that there something wrong when we trying to connect samplegrabber and video renderer. What exactly class example you got this message on?
November 12th, 2009 at 2:21 pm
I’m getting ConnectGrabberError_2 on init(), when using DirectShowNETCF.Camera.AMCameraEx.AMCameraEx or DirectShowNETCF.Camera.AMCamera.AMCamera. But DirectShowNETCF.Camera.Camera works fine.
Any ideas?
November 12th, 2009 at 9:28 pm
strange, what OS and what Device you got this problem on?
November 13th, 2009 at 9:58 am
Mine is HTC 2125 and WM 5.0
November 17th, 2009 at 12:34 pm
Is there any way to draw images on the stream and make them interactable?
November 17th, 2009 at 9:19 pm
2vinay: its not implemented yet, but if you want you can buy samplegrabber sources and draw image you need on raw frame
November 20th, 2009 at 11:49 pm
Same here: “Cannot init camera! Result: ConnectGrabberError_2 ”
Also DirectShowNETCF.Camera.Camera works fine, but not the others.
It’s a HTC-8900 - Win 6.0
Any ideas?
November 26th, 2009 at 9:12 am
seems like HTC cant render rgb24, i`m working on custom renderer now
December 15th, 2009 at 9:37 pm
Sorry to bother you again with this issue… I copied both DirectShowNETCF.dll and DirectShowNETCF.Native.dll to \AMCamera\bin\Debug, the folder where the executable is placed and I still receive MissingMethodException was unhandled: Can’t find PInvoke DLL ‘DirectShowNETCF.Native.dll’ in the Init method.
Am I missing something?
In the Output window in VS 2008 all references are loaded except for this one.
Sorry and thanks for your help.
December 15th, 2009 at 11:05 pm
you should put DirectShowNETCF.dll on device where executable deployed
December 16th, 2009 at 2:40 pm
Hey thanks, that worked on the device. It doesn’t work on the simulator however, but solved my problem
April 30th, 2010 at 6:31 pm
hi!, where is DirectShowNETCF.Native.dll located? I downloaded the DirectShowNetCF libraries, but I have:
-DirectShowNETCF.dll
-AMCameraEx.Native.dll
-AMCamera.Native.dll
-NullRenderer.dll
I don’t have DirectShowNETCF.Native.dll. thanks
April 30th, 2010 at 7:03 pm
Hi Alex, sorry for all my questions. your blog helps me a lot. I can’t understand how to use the next code you developed.
//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(0×40, (int)size);
frmGrabber.getFrame(res_);
return res_;
}
can you show me a mothod calling it?
thanks!
August 31st, 2010 at 10:23 am
Hey alex..thanks for the post..i have ru into a problem though..the camera never captures any frames…says “cannot init camera” when i press start..whats going wrong?please help!
thanks!