Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to set Height, Width and Video Format in VFP using AVICAP32.DLL

Status
Not open for further replies.

dylim

Programmer
Dec 12, 2001
106
PH
Hi Guys,

I was able to fire up a webcam on a VFP form using this link:


The problem is, every time the form shows, it will always show a Format Dialog (shown below) asking for Resolution, Pixel Depth and Size.

Screenshot_2023-10-26_155714_xnl5oy.png


Anyway I can programmatically set the three parameters?
 
Even if you could prevent this dialog by making these settings programmatically for your webcam, the experience will differ for every webcam. If multiple webcams are detected you typically get a dialog to choose the webcam and what dialog appears is not in your hands. I've not seen such a dialog with my built in webcam.

I assume this dialog comes up if you click on the cmdFormat button. Well, just don't. It calls whatever form the webcam vendor provides for setting the video format and you have no hands in this.

In the StartPreview method you can see how to set the frame rate per THIS.msg(WM_CAP_SET_PREVIEWRATE,30,0), so you could also set this to 60 or 10. And, likewise, the video format can be set using the WM_CAP_SET_VIDEOFORMAT message as described in
It takes digging into the BITMAPINFO struct to know what to pass in there. The GetVideoFormat method gives you a hint where the width and height are in this struct, as it gets such a struct using the WM_CAP_GET_VIDEOFORMAT message.

In short, all communication with the dive works with messages, as are described in especially all the WM_CAP messages.

Chriss
 
Hi Chriss,

Thanks for your reply.

I did see the link you gave. But man, this is gonna be a whole lot of digging! Am just hoping that someone who has done this would generous enough to help out.

One thing I noticed - it remembers the settings when the form is run in our VFP IDE.

Once I chose 640x480, YUY2 and 614400 and click Ok, the next time the form fires, it remember these values.

But when I compile it into an EXE, it will always prompt for that dialog with the defaults.
 
If you are willing to accept the default settings - or, alternatively, if you can manually set the values the first time and then have the dialogue display those same settings after that - then you might be able to use SendKeys() to send an ESC to the dialogue, thus closing it.

Perhaps something like this:

Code:
oWSH = CREATEOBJECT("wscript.shell")

* Do whatever you do that causes the dialogue to appear

oWSH.AppActivate("Video Format")
oWSH.SendKeys("{ESC}")

This is just off the top of my head. You might need to delay a few hundred milliseconds before (or after) the AppActivate(). And you might need to send a different character to close the dialogue. But it might be something to work on.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,

When I ran the form in our VFP IDE, it will remember the settings (640x480, YUY2, 614400) after the first Video Format dialog. We can use your suggestion in this case.

But, when I compiled it into an EXE already, the Video Format dialog kept on reverting back to the default values! Why is this so?
 
Dylim, you ask why it remembers the values when running from the IDE but not from the EXE. Sorry. No idea.

It must clearly have some mechanism for doing saving the values. Can you try to find out where those values are stored? It might be in the registry, or an INI file somewhere, or in some other file. If you could figure out the answer to that, it should be possible to insert your own values before you fire up the camera.

Going further, I assume that if you downloaded this component from GitHub, you will have the source code. If so, you might be able to find the place where it sets the default values, and then amend it as appropriate. (EDIT: I just noticed that Chris has already given you some hints for doing that.)

Third suggestion: If my idea of sending an ESC to close the dialogue works, then it should be possible to extend the idea so that you send keys to select the actual values you want in the three fields.

On balance, I would think that examining the source code should be your next step.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,

Here is the link to the source code:


Have been at this for hours on end. I really thought I was done with this project as it was working like a charm in the IDE, but to my great dismay, it kept on showing the Format Dialog when run as an EXE.

Thanks once again. I appreciate all you guys.
 
Dylim,

I only see this dialog when I press the Format button. But all you need to start is "Preview Video" and then "Save To DIB".

Do you have a problem with the "Preview Video" button? Is it disabled? Then look into Windows camera privacy settings and allow desktop applications to access the camera, that's only possible to do there, not programmatically.

And if you get this going, look into the code of GetVideoFormat, that loads the struct you need into cBuffer. You could save that and send it with the WM_CAP_SET_VIDEOFORMAT message to set the same format again without using the WM_CAP_DLG_VIDEOFORMAT message that starts the dialog to make that setting.

Chriss
 
dylim,

I hate being the bearer of bad news, but Anatoliy Mogylevets's old code is no longer usefull and you are wasting time with it. Most modern webcam software uses Microsoft DirectShow APIs and it is quite complex. A few years ago we were lucky to get the last version of a Datastead ActiveX control that does amazing things with webcams.:

Capture_tqcvyq.png


For example, there are dozens of choices for video formats:

Capture2_woyihk.png


Other webcam settings:

Capture3_yub10m.png


Unfortunately, Datastead no longer offers an ActiveX control that works with VFP. There is one, I think, for VB. You can check here:
 
Chris Miller,

Hi. When you run that Github code the first time, the form shows a black rectangle. You then press the Format button to get the right configuration - in my case it is 640x480 and YUY2 - the webcam then works.

The succeeding times you run the form, it will already remember the last setting (640x480 and YUY2).

I then made a custom class to wrap the Github code. Works like a charm. Since it remembers the last setting, you just need to call that
Format procedure once.

But, when you compile it into an EXE, the form will always show a black rectangle, so each time you need to call the Format procedure.

As you have mentioned, I then proceeded to 'brute force' and do WM_CAP_SET_VIDEOFORMAT messaging. I have no idea about Structs, so I had to go through and study the whole Struct class of the link provided by you:


It is now working even if compiled into an EXE.

Thanks to you and everybody else who helped! Goes without saying, big thanks to the Foxpert Christof!
 
dylim,

If you don't mind my asking, what are you planning to do with this? You cannot record with it. You cannot use it for video conferencing. The only thing you can do is look at yourself with your webcam and create frame snapshots of yourself. Or maybe this was just an intellectual exercise with no real purpose? Am I missing something?
 
vernpace,

Hi. I developed this for a timekeeping app. Employee taps his RFID card into a reader which then locates the guy's employee data on one side of the form, and on the other side the webcam interface shows him on.

It will now record the time log together with his photo.
 
Glad it works now.

You could have had it easier with what I suggested twice already:
myself said:
The GetVideoFormat method gives you a hint where the width and height are in this struct, as it gets such a struct using the WM_CAP_GET_VIDEOFORMAT message.

myself said:
look into the code of GetVideoFormat, that loads the struct you need into cBuffer. You could save that and send it with the WM_CAP_SET_VIDEOFORMAT message to set the same format again without using the WM_CAP_DLG_VIDEOFORMAT

Well, with structs you learned something that comes in handy in many cass, just look through the several examples Christof provides in his project. Structs are all over the place when it comes to the Windows API.

vernspace,

WM_CAP_SEQUENCE can be used to capture video.

Chriss
 
Chriss,

Here is the strange part. I wrapped the GitHub code into a custom class. I made a SetVideoFormat method that first creates a struct then calls SendMessage with the WM_CAP_SET_VIDEOFORMAT and struct.

So in the Init of the form with the webcam, I called the SetVideoFormat of this custom class I called oWebcam. It won't work!

But if I create the struct in the form Init() then called SendMessage from there and also passed WM_CAP_SET_VIDEOFORMAT, it works!

Anybody care to explain?
 
Post the code, I don't see what you exactly do from your description.

I assume it's order of execution, you first have to connect to the device, before you send the videoformat, otherwise you're sending the message to nothing, that could set itself to that format.
You may alsao havce a scope error in your variables. Can't see without knowing your code.

Chriss
 
Chriss,

This is what worked (code in the Init of the Form). Note that I created a oWebCam custom class as wrapper class to the Github code.

[pre]LOCAL loBitMapInfoHeader, lcString, lpString

IF ThisForm.oWebcam.InitCaptureWindow( This.HWnd, This.shpWebcam.Left, This.shpWebcam.Top )

IF ThisForm.oWebcam.capHeight # ThisForm.shpWebcam.Height OR ThisForm.oWebcam.capWidth # ThisForm.shpWebcam.Width

IF ThisForm.oWebcam.UseBitMapInfo

#DEFINE WM_CAP_START 0x0400
#DEFINE WM_CAP_SET_VIDEOFORMAT ( WM_CAP_START + 45 )

loBitMapInfoHeader = NEWOBJECT( "BitMapInfoHeader" )
loBitMapInfoHeader.biSize = 40
loBitMapInfoHeader.biWidth = 640
loBitMapInfoHeader.biHeight = 480
loBitMapInfoHeader.biPlanes = 1
loBitMapInfoHeader.biBitCount = 16
loBitMapInfoHeader.biCompression = 844715353
loBitMapInfoHeader.biSizeImage = 614400
loBitMapInfoHeader.biXPelsPerMeter = 0
loBitMapInfoHeader.biYPelsPerMeter = 0
loBitMapInfoHeader.biClrUsed = 0
loBitMapInfoHeader.biClrImportant = 0

lpString = loBitMapInfoHeader.GetPointer( 40 )

ThisForm.oWebcam.MessageCenter( WM_CAP_SET_VIDEOFORMAT, 40, lpString )

ELSE
ThisForm.oWebcam.ShowFormatDialog()
ENDIF

ENDIF

ThisForm.oWebcam.StartPreview()

ELSE
* MESSAGEBOX( "Webcam connection unsuccessful.", 0+16, ThisForm.Caption )
ENDIF

ThisForm.RefreshControls()
[/pre]

Here is what did not work:

I simply delegated (and rightfully so) the function of SetVideoFormat to the Webcam class as method SetVideoFormat(). So, in the Init() of the Form, the code would simply be:

[pre]IF ThisForm.oWebcam.InitCaptureWindow( This.HWnd, This.shpWebcam.Left, This.shpWebcam.Top )

IF ThisForm.oWebcam.capHeight # ThisForm.shpWebcam.Height OR ThisForm.oWebcam.capWidth # ThisForm.shpWebcam.Width
ThisForm.oWebcam.SetVideoFormat() && -> the code in above is now here
ENDIF

ThisForm.oWebcam.StartPreview()

ELSE
* MESSAGEBOX( "Webcam connection unsuccessful.", 0+16, ThisForm.Caption )
ENDIF

ThisForm.RefreshControls()
[/pre]

Here is the code Webcam.SetVideoFormat():

[pre]LOCAL loBitMapInfoHeader, lcString, lpString

IF This.UseBitMapInfo

loBitMapInfoHeader = NEWOBJECT( This.BitMapInfoHeaderClass, This.BitMapHeaderClassLib )

loBitMapInfoHeader.biSize = loBitMapInfoHeader.SizeOf()
loBitMapInfoHeader.biWidth = This.biWidth
loBitMapInfoHeader.biHeight = This.biHeight
loBitMapInfoHeader.biPlanes = This.biPlanes
loBitMapInfoHeader.biBitCount = This.biBitCount
loBitMapInfoHeader.biCompression = This.biCompression
loBitMapInfoHeader.biSizeImage = This.biSizeImage
loBitMapInfoHeader.biXPelsPerMeter = This.biXPelsPerMeter
loBitMapInfoHeader.biYPelsPerMeter = This.biYPelsPerMeter
loBitMapInfoHeader.biClrUsed = This.biClrUsed
loBitMapInfoHeader.biClrImportant = This.biClrImportant

lpString = loBitMapInfoHeader.GetPointer( loBitMapInfoHeader.SizeOf() )
This.MessageCenter( WM_CAP_SET_VIDEOFORMAT, loBitMapInfoHeader.SizeOf(), lpString )

ELSE
This.ShowFormatDialog()
ENDIF[/pre]

Take note that biHeight, biWidth, biPlane etc... are now properties of class Webcam.
 
I assume you don't like to past all the verbosae code, but I don't see a method "MessageCenter" in the original code and I don't know how exactly you wrapped the code into oWebcam.
But I assume your parameterization of the MessageCenter methd is not working as you use it.

But a struct is just a string in VFP and passing on strings is no problem.

Chriss
 
Chriss,

I just jazzed up the name of the methods. Hahaha

Msg() in the original one, I just made it MessageCenter(), with exactly the same code.

All the methods I kinda changed their names, that's all.
 
Hm,

not sure if lpString = loBitMapInfoHeader.GetPointer( 40 ) gives you what you need.
Also, the struct you define is a BITMAPINFOHEADER, the struct you should pass in a BITMAPINFO, of which the BITMAPINFOHEADER is only one part. But this might be okay, as you likely use 24bit RGB color mode and no palette, so biClrUsed is 0 and no array of palette colors is added.

I also don't see how you define the struct itself. In the original definition there are mostly integers (LONG andd DWORD are essentially the same) but also some 2 byte short WORDs:
Code:
typedef struct tagBITMAPINFOHEADER {
  DWORD biSize;
  LONG  biWidth;
  LONG  biHeight;
[highlight #FCE94F]  WORD  biPlanes;
  WORD  biBitCount;[/highlight]
  DWORD biCompression;
  DWORD biSizeImage;
  LONG  biXPelsPerMeter;
  LONG  biYPelsPerMeter;
  DWORD biClrUsed;
  DWORD biClrImportant;
} BITMAPINFOHEADER, *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

Othwerwise I don't know what didn't work , as you put the code you now have direct into a method SetVideoFormat. Unless you used anopther hwnd value and/or used "Thisform.oWebcam" within the oWebcam class, where it should simple be THIS, I don't know what you did wrong. But likely that?! I don't know, if I don't see what you actually had exactly instead of just assuming.

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top