Einzelnen Beitrag anzeigen

TStringlist

Registriert seit: 1. Dez 2003
360 Beiträge
 
Turbo Delphi für Win32
 
#1

Rückumwandlung eines gegrabten Frames (Webcam) in Bitmap

  Alt 30. Jul 2005, 11:11
Hi (hoffe das Ganze hier ist nicht zu lang).

>> Wie wandle ich das Rohmaterial eines gegrabten Frames (von einer Webcam) wieder in ein korrektes Bitmap um?

Es geht also wieder mal um das Auslesen einer Webcam, bzw. wie man davon z.B. jede Sekunde ein Bild (Frame) "abzweigt" (etwa um es danach untersuchen zu können) ...und was insgesamt auch dann funktionieren sollte, wenn das Prog. im Hintergrund läuft und man das Clipboard für andere Applications freizuhalten hat.

Code-mäßig aufgebaut habe ich meinen Versuch dabei auf diesen Thread hier bzw. das was Ultimator dort anfangs postete. Im Unterschied zu diesem Verfahren benutze ich jetzt aber nicht das Clipboard, sondern eine (Frame-) Callback-Funktion, welche mittels dieser WM installiert wird:

WM_CAP_SET_CALLBACK_FRAME = WM_User + 5; ..plus nochmal dem Creator mit der dazugehörenden SendMessage-Zeile:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  GrabFrameFlag := false;

  VHandle := capCreateCaptureWindow('Video',ws_child+ws_visible, 0, 0,
  640, 480, Panel1.Handle, 1);
  SendMessage(VHandle, WM_CAP_DRIVER_CONNECT, 0, 0);
  SendMessage(VHandle, WM_CAP_SET_PREVIEWRATE, 15, 0);
  sendMessage(VHandle, WM_CAP_SET_OVERLAY, 1, 0);
  SendMessage(VHandle, wm_cap_set_preview, 1, 0);

  SendMessage(VHandle, WM_CAP_SET_CALLBACK_FRAME, 0, integer(@FrameCallbackFunction));

  SendMessage(VHandle,WM_CAP_DLG_VIDEOFORMAT,1,0);

  VDC := getDC(VHandle);
  hCompatibleBitmap := CreateCompatibleBitmap(VDC,640,480);
end;
Wie man am Ende des Creators sieht, versuche ich dort noch ein zum CaptureWindow kompatibles Bitmap zu erstellen, in welches ich in der Callback-Funktion dann das Rohmaterial des Frames hineinzuladen versuche.


...und schließlich also die Callback-Funktion selbst (plus einem Recordtyp, nötig für den zweiten Parameter der Parameterliste: "lpVHdr: pointer to struct containing captured frame information")

Delphi-Quellcode:
Type
TVIDEOHDR = record
  lpData : Pointer; // address of video buffer
  dwBufferLength : DWord; // size, in bytes, of the Data buffer
  dwBytesUsed : DWord; // see below
  dwTimeCaptured : DWord; // see below
  dwUser : DWord; // user-specific data
  dwFlags : DWord; // see below
  dwReserved1, dwReserved2, dwReserved3 : DWord; // reserved; do not use
end;
TVideoHDRPtr = ^TVideoHDR;

function FrameCallbackFunction(AHandle : hWnd; VIDEOHDR : TVideoHDRPtr): bool; stdcall;
var ACount : integer;
begin
  result := true;

  // da diese Callback-Funktion sonst bei jedem Preview-Frame ganz durchlaufen werden würde:
  // jetzt nur noch mehr dann, wenn draußen GrabFrameFlag auf TRUE gesetzt wurde PLUS, für die
  // Hintergrundlaufbarkeit: SendMessage(VHandle, WM_CAP_GRAB_FRAME_NOSTOP, 1, 0);
  if GrabFrameFlag = false then exit;
  GrabFrameFlag := false;

  windows.beep(1000,10); // nur nochmal zum akustischen Besuchs-Check

  ACount := SetBitmapBits(hCompatibleBitmap,VideoHDR^.dwBufferLength,VideoHDR^.lpData);
  with form2 do begin
    FBitmap.Handle := hCompatibleBitmap;
    PaintBox1.Repaint; // hier wird dann der Inhalt von FBitmap auf form2.PaintBox1 ausgegeben.
  end;
end;

Wie man am Code in der Callback-Funktion sieht, versuche ich dort jetzt mittels der ApiFunktion 'SetBitmapBits' das Rohmaterial des Frames in ein zum CaptureWindow compatibles Bitmap zu laden. Anschließend übertrage ich es dann Handle-mäßig auf ein VCL-Bitmap (FBitmap), welches schließlich in einer Paintbox ausgegeben wird. NUR – kann man das alles überhaupt so machen? (Oder/aber, warum eigentlich auch wieder nicht, bzw. wie sonst?)

Jedenfalls besteht das dabei herauskommende Bild dann aber leider nur aus irgendwelchen Farbschlieren und ist im unteren Drittel völlig schwarz. Besonders auch letzteres legt dann irgendwie die Vermutung nahe, dass das Frame-Rohmaterial vor oder während des Transfers wahrscheinlich wenigstens noch hätte dekomprimiert werden müssen.

In einem aufrufbaren Dialog-Window (bzgl. des einstellbaren (Frame-) Formates) wird ja dann auch zufällig noch mit angezeigt, dass die Komprimierung vom Typ I420 ist und ein Bild 460800 Bytes groß. Das hieße also bei 640*480 Pixels pro Pixel 12 Bits?!?

Frage wäre hier also vor allem auch: Wie kann man für das so vorliegendes Rohmaterial eine Dekomprimierung durchführen??? Oder wo könnten sonst Fehler in der Art sein, wie ich das oben insgesamt versuche? Bzw. gibt es sonst noch irgendwelche einfacheren Alternativen dazu?

Irgendwelche Ideen?
MfG (& Thx ggf.)
  Mit Zitat antworten Zitat