Unmanaged buffer problem?

P

Pete Davis

I've got an app that plays video using the ActiveMovie COM stuff.

I'm using the FilgraphManagerClass to play the movie and I'm trying to get
an image from the currently displayed scene.

The call to do it is FilgraphManagerClass.GetCurrentImage(ref int
bufferSize, out int dibImage)

Now, I'm aware that my code, as-is, might not free what it's allocating.
That's okay for the moment. I just want to get it working first, then I'll
get it working cleanly.

unsafe private byte[] GetImageData()
{
byte[] buffer = null;
try
{
int buffSize = 0;
int zero = 0;
fmc.GetCurrentImage(ref buffSize, out zero);

IntPtr tempBuffer = Marshal.AllocHGlobal(buffSize);
int tempBufferInt = tempBuffer.ToInt32();
fmc.GetCurrentImage(ref buffSize, out tempBufferInt);
buffer = new byte[buffSize];
Marshal.Copy((IntPtr) tempBufferInt, buffer, 0, buffSize);
Marshal.FreeHGlobal((IntPtr) tempBufferInt);
}
catch(System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
return buffer;
}

Calling GetCurrentImage with zero for the dibImage, should set the buffSize.
This does not happen, however.

If I skip that first call to GetCurrentImage and instead set buffSize to
say, 10*height*width (which should be more than enough room to store the
image), then on the call to GetCurrentImage causes my application to exit.
No exceptions, no messages in the debug output, the app just ends.

Any ideas?

Pete
 
N

Nicholas Paldino [.NET/C# MVP]

Pete,

A few things. First, I don't know why you are using unsafe code,
because everything that you are using is safe. Rather, you could declare
the array in unsafe code, fix the pointer to it, and then pass it to the
GetCurrentImage method.

Doing some research, it seems that GetCurrentImage method on the
IBasicVideo2 interface is not supported, so I don't think it is a good idea
to go about using it.

Rather, what you should do is use the DirectShow.NET library to
construct your filter graph (you can render it from a file, which is what I
think you want). You can find the managed direct show library at:

http://directshownet.sourceforge.net/

On top of that, there is a blog entry that I have found which describes
how to get the bitmap bits in C# (it uses an interop library to DirectX, but
I think the sourceforge project is better, and you can easily convert the
code to use that):

http://www.a2ii.com/DasBlog/CommentView,guid,759832cd-a983-4c32-a75d-4d1c44c7883c.aspx

I do think that the IMediaDet interface is a little out of date though
(as is the ActiveMovie stuff, btw, it's all DirectShow now). You should be
using the ISampleGrabber interface instead.

There is an example out there that shows how to do this. You can see it
at:

http://www.a2ii.com/tech/directx/tutorialDS6.htm

The link for the code for that tutorial is hard to find, so here it is:

http://www.a2ii.com/tech/directx/tutorialDS6.zip

Note, in that project you will have to remove the reference to
DirectShowLib and replace it with a reference to DirectShowLib that you
downloaded (it's not included in the project).

In the ISampleGrabber.BufferCB method, you can create an instance of a
Bitmap class, using the overload that takes the scan0 parameter. You can
pass the pBuffer parameter into that, and use the video header info (which
has the bitmap header info) information to get the dimensions of the video.

If you are going to save the image, or draw on it, you ^might^ have to
rotate it. If you are going to draw on the image before you save it, then
you should apply a Matrix to the Transform property of the Graphics instance
for the bitmap. Once done drawing, you can call the RotateFlip method to
flip the image (if needed).

Of course, you can always just flip the image before you get the
graphics instance and draw on that. I believe the height property in the
bitmap info header is negative if you need to flip the image.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Pete Davis said:
I've got an app that plays video using the ActiveMovie COM stuff.

I'm using the FilgraphManagerClass to play the movie and I'm trying to get
an image from the currently displayed scene.

The call to do it is FilgraphManagerClass.GetCurrentImage(ref int
bufferSize, out int dibImage)

Now, I'm aware that my code, as-is, might not free what it's allocating.
That's okay for the moment. I just want to get it working first, then I'll
get it working cleanly.

unsafe private byte[] GetImageData()
{
byte[] buffer = null;
try
{
int buffSize = 0;
int zero = 0;
fmc.GetCurrentImage(ref buffSize, out zero);

IntPtr tempBuffer = Marshal.AllocHGlobal(buffSize);
int tempBufferInt = tempBuffer.ToInt32();
fmc.GetCurrentImage(ref buffSize, out tempBufferInt);
buffer = new byte[buffSize];
Marshal.Copy((IntPtr) tempBufferInt, buffer, 0, buffSize);
Marshal.FreeHGlobal((IntPtr) tempBufferInt);
}
catch(System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
return buffer;
}

Calling GetCurrentImage with zero for the dibImage, should set the
buffSize. This does not happen, however.

If I skip that first call to GetCurrentImage and instead set buffSize to
say, 10*height*width (which should be more than enough room to store the
image), then on the call to GetCurrentImage causes my application to exit.
No exceptions, no messages in the debug output, the app just ends.

Any ideas?

Pete
 
P

Pete Davis

Nicholas,

GetCurrentImage() is in IBasicVideo, not IBasicVideo2. IBasicVideo2 simply
adds a getter of PrefferedAspectRatio, which I'm not using.

Where do you see that GetCurrentImage is not supported? There's nothing
about it here:
http://tinyurl.com/b46ho

I have DirectShowNet and have used it before. I was just trying to throw
together a quick and easy image capture without wanting to go through all
the hassles that come with DirectShow.

I was just planning on using it for myself, so I don't really care if it's
using out-of-date interfaces.

From what I've seen on the newsgroups, it appears to function (at least for
some people).

But if it's one of those things where it works for some people and not for
others and I'm one of those "others", then I guess I'm stuck with using
DirectShow.

Pete





Nicholas Paldino said:
Pete,

A few things. First, I don't know why you are using unsafe code,
because everything that you are using is safe. Rather, you could declare
the array in unsafe code, fix the pointer to it, and then pass it to the
GetCurrentImage method.

Doing some research, it seems that GetCurrentImage method on the
IBasicVideo2 interface is not supported, so I don't think it is a good
idea to go about using it.

Rather, what you should do is use the DirectShow.NET library to
construct your filter graph (you can render it from a file, which is what
I think you want). You can find the managed direct show library at:

http://directshownet.sourceforge.net/

On top of that, there is a blog entry that I have found which describes
how to get the bitmap bits in C# (it uses an interop library to DirectX,
but I think the sourceforge project is better, and you can easily convert
the code to use that):

http://www.a2ii.com/DasBlog/CommentView,guid,759832cd-a983-4c32-a75d-4d1c44c7883c.aspx

I do think that the IMediaDet interface is a little out of date though
(as is the ActiveMovie stuff, btw, it's all DirectShow now). You should
be using the ISampleGrabber interface instead.

There is an example out there that shows how to do this. You can see
it at:

http://www.a2ii.com/tech/directx/tutorialDS6.htm

The link for the code for that tutorial is hard to find, so here it is:

http://www.a2ii.com/tech/directx/tutorialDS6.zip

Note, in that project you will have to remove the reference to
DirectShowLib and replace it with a reference to DirectShowLib that you
downloaded (it's not included in the project).

In the ISampleGrabber.BufferCB method, you can create an instance of a
Bitmap class, using the overload that takes the scan0 parameter. You can
pass the pBuffer parameter into that, and use the video header info (which
has the bitmap header info) information to get the dimensions of the
video.

If you are going to save the image, or draw on it, you ^might^ have to
rotate it. If you are going to draw on the image before you save it, then
you should apply a Matrix to the Transform property of the Graphics
instance for the bitmap. Once done drawing, you can call the RotateFlip
method to flip the image (if needed).

Of course, you can always just flip the image before you get the
graphics instance and draw on that. I believe the height property in the
bitmap info header is negative if you need to flip the image.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Pete Davis said:
I've got an app that plays video using the ActiveMovie COM stuff.

I'm using the FilgraphManagerClass to play the movie and I'm trying to
get an image from the currently displayed scene.

The call to do it is FilgraphManagerClass.GetCurrentImage(ref int
bufferSize, out int dibImage)

Now, I'm aware that my code, as-is, might not free what it's allocating.
That's okay for the moment. I just want to get it working first, then
I'll get it working cleanly.

unsafe private byte[] GetImageData()
{
byte[] buffer = null;
try
{
int buffSize = 0;
int zero = 0;
fmc.GetCurrentImage(ref buffSize, out zero);

IntPtr tempBuffer = Marshal.AllocHGlobal(buffSize);
int tempBufferInt = tempBuffer.ToInt32();
fmc.GetCurrentImage(ref buffSize, out tempBufferInt);
buffer = new byte[buffSize];
Marshal.Copy((IntPtr) tempBufferInt, buffer, 0, buffSize);
Marshal.FreeHGlobal((IntPtr) tempBufferInt);
}
catch(System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
return buffer;
}

Calling GetCurrentImage with zero for the dibImage, should set the
buffSize. This does not happen, however.

If I skip that first call to GetCurrentImage and instead set buffSize to
say, 10*height*width (which should be more than enough room to store the
image), then on the call to GetCurrentImage causes my application to
exit. No exceptions, no messages in the debug output, the app just ends.

Any ideas?

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top