I am using the Windows API to take a picture with the attached webcam.
All works fine except the picture captured is very dark. If I start the webcam in another application and then I capture with my application, all works fine. What am I doing wrong?
Here is the code I use:
procedure TWebCam.Execute; //different thread
var
hand: THandle;
fname: AnsiString;
const
WM_CAP_START = $0400;
WM_CAP_DRIVER_CONNECT = $0400 + 10;
WM_CAP_DRIVER_DISCONNECT = $0400 + 11;
WM_CAP_SAVEDIB = $0400 + 25;
WM_CAP_GRAB_FRAME = $0400 + 60;
WM_CAP_STOP = $0400 + 68;
WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52;
WM_CAP_SET_SCALE = WM_CAP_START + 53;
begin
FreeOnTerminate := True;
fname := AnsiString(IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) +
'capture.bmp');
if FileExists(String(fname)) then DeleteFile(string(fname));
hand := capCreateCaptureWindowA('CapWindow32', WS_CHILD and WS_VISIBLE, 0, 0,
0, 0, frmMain.Handle, 0);
if hand <> 0 then
begin
if SendMessage(hand, WM_CAP_DRIVER_CONNECT, 0, 0) <> 0 then
begin
SendMessage(hand,WM_CAP_SET_PREVIEWRATE,66,0); //tried some stuff that are not required but without any success
SendMessage(hand, WM_CAP_SET_PREVIEW, 1, 0);
Sleep(5000);
SendMessage(hand, WM_CAP_GRAB_FRAME, 0, 0);
SendMessage(hand, WM_CAP_SAVEDIB, 0, NativeInt(PAnsichar(fname)));
SendMessage(hand, WM_CAP_DRIVER_DISCONNECT, 0, 0);
SendMessage(hand, $0010, 0, 0);
SendMessage(frmMain.Handle,WM_USER + 24,0,0); //notify main thread
end
else
begin
SendMessage(hand, $0010, 0, 0);
Synchronize(NoWebcam);
end;
end
else
Synchronize(NoWebcam);
end;
I hate to give my own questions an answer but maybe someone will find it useful in the future.
The thing is that the webcam adjusts its luminosity progressively when it starts, so you must first capture some dummy frames to get a normal picture… Here is what I use now:
Works like a charm, kind of hacky, I wish a WaitForInputIdle function exist for devices too…