Acessing pointers from capSetCallbackOnFrame (avicap32.dll)

  • Thread starter Thread starter Workgroups
  • Start date Start date
W

Workgroups

I'm writing a piece of video software, sort of like a webcam, that's meant
to show a preview on the screen from any WDM capable cam. I want to give
the user RGB sliders, and process each frame by running it through a color
matrix before it's displayed on the screen.

So far I've succesfully created a preview window and established a
capSetCallbackOnFrame callback function that fires every time a new frame of
video is available from the camera. So now I need to copy the video buffer
(image) I vicariously receive a pointer to in the callback function into an
image, transform the image's color w/ a color matrix and then paint the
colorized image to some control (like a picturebox, probably).

But I'm stumped when it comes to "doing something" with the data that's
coming back from capSetCallbackOnFrame. It's a pointer to a structure, and
one of the elements of the structure contains the pointer to the video
buffer. The documentation for this is really hard to come by, although
there is a popular VB6 example of this floating around that I've been using
for a guide that looks like this:

Function MyFrameCallback(ByVal lwnd As Long, ByVal lpVHdr As Long) As Long

Dim VideoHeader As VIDEOHDR
Dim VideoData() As Byte

RtlMoveMemory VarPtr(VideoHeader), lpVHdr, Len(VideoHeader)
ReDim VideoData(VideoHeader.dwBytesUsed)
RtlMoveMemory VarPtr(VideoData(0)), VideoHeader.lpData,
VideoHeader.dwBytesUsed

End Function

The VIDEOHDR structure looks like this:

Type VIDEOHDR
lpData As Long 'address of video buffer
dwBufferLength As Long 'size, in bytes, of the Data buffer
dwBytesUsed As Long
dwTimeCaptured As Long
dwUser As Long
dwFlags As Long
dwReserved(3) As Long '// reserved; do not use
End Type

I've tried to reporduce this in .NET but I haven't been too successful so
far... I've tried to use Marshal.Copy and Marshal.PtrToStructure, to copy
the data referenced at lpVHdr into it's appropriate structure format on the
managed side, but I don't think I'm doing it right; my structure ends up
with what I'm pretty sure is erroneous data; all the values are 0 except
for dwFlags = 64, so... "something" is getting copied in there but it's not
correct. I am at a loss as to how to get that video buffer turned into an
image object.
 
Hi,

capCreateCaptureWindow will display the incoming video for you. Here
is an link to an example.

http://www.windowsformsdatagridhelp.com/default.aspx?ID=458a6b78-eacc-48b9-9036-e5cf2ebb86b6

Ken
--------------------------
I'm writing a piece of video software, sort of like a webcam, that's meant
to show a preview on the screen from any WDM capable cam. I want to give
the user RGB sliders, and process each frame by running it through a color
matrix before it's displayed on the screen.

So far I've succesfully created a preview window and established a
capSetCallbackOnFrame callback function that fires every time a new frame of
video is available from the camera. So now I need to copy the video buffer
(image) I vicariously receive a pointer to in the callback function into an
image, transform the image's color w/ a color matrix and then paint the
colorized image to some control (like a picturebox, probably).

But I'm stumped when it comes to "doing something" with the data that's
coming back from capSetCallbackOnFrame. It's a pointer to a structure, and
one of the elements of the structure contains the pointer to the video
buffer. The documentation for this is really hard to come by, although
there is a popular VB6 example of this floating around that I've been using
for a guide that looks like this:

Function MyFrameCallback(ByVal lwnd As Long, ByVal lpVHdr As Long) As Long

Dim VideoHeader As VIDEOHDR
Dim VideoData() As Byte

RtlMoveMemory VarPtr(VideoHeader), lpVHdr, Len(VideoHeader)
ReDim VideoData(VideoHeader.dwBytesUsed)
RtlMoveMemory VarPtr(VideoData(0)), VideoHeader.lpData,
VideoHeader.dwBytesUsed

End Function

The VIDEOHDR structure looks like this:

Type VIDEOHDR
lpData As Long 'address of video buffer
dwBufferLength As Long 'size, in bytes, of the Data buffer
dwBytesUsed As Long
dwTimeCaptured As Long
dwUser As Long
dwFlags As Long
dwReserved(3) As Long '// reserved; do not use
End Type

I've tried to reporduce this in .NET but I haven't been too successful so
far... I've tried to use Marshal.Copy and Marshal.PtrToStructure, to copy
the data referenced at lpVHdr into it's appropriate structure format on the
managed side, but I don't think I'm doing it right; my structure ends up
with what I'm pretty sure is erroneous data; all the values are 0 except
for dwFlags = 64, so... "something" is getting copied in there but it's not
correct. I am at a loss as to how to get that video buffer turned into an
image object.
 
Thanks for the reply Ken. I wish my only goal were to show the preview (my
life would be easier). Thanks to that code in the link I could do that
fairly easily.

What I need to add is a way for the user to adjust R, G, B to modify the
color hue of the video preview. I have created a test app that can
successfully change the color of a normal static (non-cam) image using a
color matrix, so my idea for the cam is to capture each frame from at frame
call back, create an image object from the supplied video buffer, perform a
color matrix transformation on the image (just as I had done in my test app)
and then display the new, colorized image to a picturebox. And this would
occur on every frame callback, so essentially I take data from the raw
stream, filter it, and display my own "colorized preview window" (as it
were) in a picturebox.

I got the preview working, I got the callback "working" (well, it gets
called) but I'm hung up on the logistics of accessing the video buffer
pointer that is supposedly sent to me in a structure (VIDEOHDR) in the
callback function. I've defined the structure like this:

Public Structure VIDEOHDR
Dim lpData As IntPtr
Dim dwBufferLength As Integer
Dim dwBytesUsed As Integer
Dim dwTimeCaptured As Integer
Dim dwUser As Integer
Dim dwFlags As Integer
<VBFixedArray(3)> Dim dwReserved() As Integer
End Structure

But my values in the callback are always this:

lpData = 0
dwBufferLength = 0
dwBytesUsed = 0
dwTimeCaptured = 0
dwUser = 0
dwFlags = 64
 
This was a newbie interop problem. The structure passed to my callback
function was not being populated correctly because I was initially
establishing callback by calling a mal-overloaded SendMessage in the first
place:

SendMessage (intPtr, integer, integer, intPtr) as intPtr

with this data:

(PreviewWndHandle, _
WM_CAP_SET_CALLBACK_FRAME, _
0, _
MyDelegate.Method.MethodHandle.GetFunctionPointer)

Someone in the interop ng clued me in that I should create a SendMessage
overload specific for the call:

SendMessage (intPtr, integer, intPtr, MyDelegateType)

Which now I call with similar data,

(PreviewWndHandle, _
WM_CAP_SET_CALLBACK_FRAME, _
IntPtr.Zero, _
MyDelegate)

Passing the delegate itself (instead of using the .GetFunctionPointer method
of the delegate) seems to have made the difference between my callback
function receiving valid and invalid data. Once the callback was setup
properly the structure arrived to my callback populated correctly, and I was
able to create a new managed bitmap from the unmanaged buffer, via the
pointer in the structure:

oBmp = New Bitmap(640, 480, 640 * 3, PixelFormat.Format24bppRgb,
lpVIDEOHDR.lpData)

I draw oBmp onto a 2nd bitmap with an imageAttributes containing a
colorMatrix reflecting user slider values for
r/g/b/brightness/contrast/saturation and essentially create my own
"filtered" preview window. Takes a fair amount of cpu power depending upon
preview rate of the camera, but it's doing it ;-)
 
Back
Top