[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
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 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.
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
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 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 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: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 2:46 pm
Does it work or you can see reason why it failed? if reason please tell me 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 1:47 pm
I made minor changes, now example says where exaclty problem, new version uploaded, can you check it?