Autor Beitrag
mtin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 177

Win XP SP2
BDS2006 Enterprise
BeitragVerfasst: Di 21.03.06 19:28 
also, ich hab jetzt immernoch Probleme mit meiner Webcam :D
nachdem jetzt normal alles klappt, würde ich das ganze gerne in eine eigene Klasse TWebcam packen...
das funktioniert soweit auch ganz gut, nur müsste ich die Callback-funktion ja mit reinnehmen, da sie auf Variablen der Klasse zugreift!
nochmal zum Verständnis: Die Callback-Funktion sieht so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
function OnFrame(hCapWnd: HWND; lpVHDR: PVideoHdr): DWord; stdcall;
begin
  Result:=1;
  SendMessage(CapHandle, WM_CAP_GET_VIDEOFORMAT, SizeOf(BitmapInfo), Integer(@BitmapInfo));

  src:=lpVHdr^.lpData;
  dest:=Frame.ScanLine[0];

  case bitmapinfo.bmiHeader.biCompression of
    UYVY: UYVYtoARGB(src, dest, w, h);
    YUY2: YUY2toARGB(src, dest, w, h);
    I420: I420toARGB(src, dest, w, h);
  end;

  Frame.Changed;
end;
Und der Webcam sage ich so, wie sie die Callback-Funktion findet:
ausblenden Delphi-Quelltext
1:
SendMessage(CapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, Integer(@OnFrame));					

So funktioniert alles außer, dass ich alle benötigte Variablen nicht in die TWebcam reinschreiben kann sondern Global machen muss. Damit genau das funktioniert, hab ich mir gedacht, ich schreib einfach sowohl vor die Funktion an sich als auch in dieser Zeile ein TWebcam.OnFrame:
ausblenden Delphi-Quelltext
1:
SendMessage(CapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, Integer(@TWebcam.OnFrame));					

(und dann natürlich noch in der Klasse TWebcam die Funktion deklarieren)

allerdings klappt dann irgendwas nicht mehr, bei der Zeile
ausblenden Delphi-Quelltext
1:
2:
src:=lpVHdr^.lpData;
dest:=Frame.ScanLine[0];
kommt irgendeine exception...ich weiß auch nicht genau was da schiefläuft...
sobald ich dann wieder das aus der Klasse rausnehme und einfach global mache klappt wieder alles...

hatt irgendjemand davon ne Ahnung?
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Di 21.03.06 22:20 
Was für eine Exception den? In Messageboxen kann man mit STRG+C den Text kopieren.

Vermutlich greifst du auf Speicher zu der eigentlich nicht dir gehört, kann er denn lpVHdr^ dereferenzieren?
mtin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 177

Win XP SP2
BDS2006 Enterprise
BeitragVerfasst: Di 21.03.06 22:54 
First chance exception at $7C81EB33. Exception class EAccessViolation with message 'Access violation at address 0046DE0C in module 'TWebcam.exe'. Read of address 00DD0944'. Process TWebcam.exe (1568)hm, du hattest Recht, lpVHdr^ zeigt auf nil...also nichts... :cry:

hast du eine Ahnung wieso das immer auftritt wenn ich das in die TWebcam-Klasse mit aufnehme?
Ich mach hier einfach mal meine gesamte Unit rein...
wenn du die Graphics32-Komponenten hast könntest du das ja vielleicht mal ausprobieren?

einfach in einem neuen Projekt die Unit einbinden und dann
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
var cam:TWebcam;

cam:=TWebcam.Create(Form1.Handle);

Image321.Bitmap:=cam.Frame;


hier ist sie:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
unit webcamdriver;

interface

uses GR32, UConvert, Windows, Messages, ExtCtrls, SysUtils;


function capCreateCaptureWindow(lpszWindowName  : LPCSTR;
                                dwStyle         : DWORD;
                                x, y            : Integer;
                                nWidth          : Integer;
                                nHeight         : Integer;
                                hwndParent      : HWND;
                                nID             : Integer ): HWND; stdcall;
                                external 'AVICAP32.DLL' name 'capCreateCaptureWindowA';

 type
  PVIDEOHDR = ^TVIDEOHDR;
  TVIDEOHDR = packed record
    lpData         : PBYTE;                // pointer to locked data buffer
    dwBufferLength : DWORD;                // Length of data buffer
    dwBytesUsed    : DWORD;                // Bytes actually used
    dwTimeCaptured : DWORD;                // Milliseconds from start of stream
    dwUser         : DWORD;                // for client's use
    dwFlags        : DWORD;                // assorted flags (see defines)
    dwReserved     : array[0..3of DWORD; // reserved for driver
  end;




type
  TWebcam = class
  private
  //---------------PRIVATE--------------
    var
      CapHandle:  HWND;
      w,h:        Integer;
    const
      WM_CAP_SET_CALLBACK_FRAME       = (WM_USER +  5);
      WM_CAP_DRIVER_CONNECT           = (WM_USER + 10);
      WM_CAP_DRIVER_DISCONNECT        = (WM_USER + 11);
      WM_CAP_EDIT_COPY                = (WM_USER + 30);
      WM_CAP_DLG_VIDEOFORMAT          = (WM_USER + 41);
      WM_CAP_DLG_VIDEOSOURCE          = (WM_USER + 42);
      WM_CAP_DLG_VIDEODISPLAY         = (WM_USER + 43);
      WM_CAP_GET_VIDEOFORMAT          = (WM_USER + 44);
      WM_CAP_SET_VIDEOFORMAT          = (WM_USER + 45);
      WM_CAP_DLG_VIDEOCOMPRESSION     = (WM_USER + 46);
      WM_CAP_SET_PREVIEW              = (WM_USER + 50);
      WM_CAP_SET_OVERLAY              = (WM_USER + 51);
      WM_CAP_SET_PREVIEWRATE          = (WM_USER + 52);
      WM_CAP_SET_SCALE                = (WM_USER + 53);
    procedure bildgroesse_anpassen;
  public
  //---------------PUBLIC--------------
    var resolution,bit,compression: string;
        Frame:                      TBitmap32;
    constructor create(FormHandle:HWND);
    function OnFrame(hCapWnd: HWND; lpVHDR: PVideoHdr): DWord; stdcall;
    procedure DLG_VideoSource;
    procedure DLG_VideoFormat;
    procedure DLG_VideoCompression;
  end;

implementation

//------------------CALLBACK-FUNCTION--------------------|
//                                                       |
function TWebcam.OnFrame(hCapWnd: HWND; lpVHDR: PVideoHdr): DWord; stdcall;
var BitmapInfo: TBitmapInfo;
    src, dest: Pointer;
begin
  Result:=1;
  FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
  SendMessage(CapHandle, WM_CAP_GET_VIDEOFORMAT, SizeOf(BitmapInfo), Integer(@BitmapInfo));

  src:=lpVHdr^.lpData;
  dest:=Frame.ScanLine[0];

  case bitmapinfo.bmiHeader.biCompression of
    BI_RGB: case bitmapinfo.bmiHeader.biBitCount of
              16: Conv16To32(src, dest, w, h);
              24: Conv24To32(src, dest, w, h);
              32: Move(src^, dest^, w*h*4);
            end;
    UYVY: UYVYtoARGB(src, dest, w, h);
    YUY2: YUY2toARGB(src, dest, w, h);
    I420: I420toARGB(src, dest, w, h);
  end;

  Frame.Changed;
end;
//                                                       |
//------------------/CALLBACK-FUNCTION-------------------|

//------------------CONSTRUCTOR--------------------------|
//                                                       |
constructor TWebcam.create(FormHandle:HWND);
begin
  inherited Create;
  CapHandle:=capCreateCaptureWindow('Video',
                                    ws_child + ws_visible,
                                    00,
                                    11,
                                    FormHandle,
                                    1);

  SendMessage(CapHandle, WM_CAP_DRIVER_CONNECT, 00);
  SendMessage(CapHandle, WM_CAP_SET_PREVIEWRATE,10);  //25
  sendMessage(Caphandle, WM_CAP_SET_OVERLAY, 10);
//  sendMessage(Caphandle, WM_CAP_SET_SCALE, Byte(True), 0);
  SendMessage(CapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, Integer(@TWebcam.OnFrame));

  Frame:=TBitmap32.Create;
  bildgroesse_anpassen;

end;
//                                                       |
//------------------/CONSTRUCTOR-------------------------|

//------------------bildgröße...-------------------------|
//                                                       |
procedure TWebcam.bildgroesse_anpassen;
var BitmapInfo: TBitmapInfo;
begin
  SendMessage(CapHandle, WM_CAP_GET_VIDEOFORMAT, SizeOf(BitmapInfo), Integer(@BitmapInfo));
  w:=bitmapinfo.bmiHeader.biWidth;
  h:=bitmapinfo.bmiHeader.biHeight;
  Frame.SetSize(w, h);
// Video-Daten
  resolution:=IntToStr(w)+'x'+IntToStr(h);
  bit:=IntToStr(bitmapinfo.bmiHeader.biBitCount)+'bit';
  compression:=GETFOURCC(bitmapinfo.bmiHeader.biCompression);
end;
//                                                       |
//------------------/bildgröße...------------------------|

//------------------DIALOGE------------------------------|
//                                                       |
procedure TWebcam.DLG_VideoFormat;
begin
sendMessage(CapHandle, WM_CAP_DLG_VIDEOFORMAT, 10);
bildgroesse_anpassen;
end;
procedure TWebcam.DLG_VideoSource;
begin
sendMessage(CapHandle, WM_CAP_DLG_VIDEOSOURCE, 10);
bildgroesse_anpassen;
end;

procedure TWebcam.DLG_VideoCompression;
begin
sendMessage(CapHandle, WM_CAP_DLG_VIDEOCOMPRESSION, 10);
bildgroesse_anpassen;
end;
//                                                       |
//------------------/DIALOGE-----------------------------|


end.


ich häng mal auch gleich ein Beispielprojekt an...da sind alle jetzigen funktionen der Unit drin...

EDIT: hab vergessen das du auch noch die UConvert.pas brauchst...die ist in der angehängten Datei!
Einloggen, um Attachments anzusehen!
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Mi 22.03.06 09:06 
Sry aber ich bearbeite gerade mein Projekt für meine Prüfung und habe daher recht wenig Zeit. Ich habe auch keine Erfahrung auf dem Gebiet. Ich denke du könntest das der Community veranschaulichen, wenn du mal komplett die Klasse vorher und hinterher postest. Vermutlich hängt das mit dem StdCall oder ähnlichen Dingen zusammen.

Wäre es nicht einfacher die Callback so zu lassen aber darin die eigentliche Verarbeitung durch eine Klassenmethode anzustoßen? IMHO wäre das o.k. und verständlich.
mtin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 177

Win XP SP2
BDS2006 Enterprise
BeitragVerfasst: Mi 22.03.06 17:26 
mhm, gut ich überarbeite die nochma und stell das wichtigste dann rein...aber wie meinst du das?
Wie soll ich die eigentliche Verarbeitung in eine Klassenmethode auslagern?
Die kann ich ja nicht aufrufen...also sowas wie hier im nachfolgenden geht natürlich nicht
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
function OnFrame(hCapWnd: HWND; lpVHDR: PVideoHdr): DWord; stdcall;
begin
  Result:=1;
  TWebcam.AfterFrame(lpVHDR);
end;



gut, hier ist jetzt das wichtigste (wirklich nur das was die Callback-Funktion betrifft, so funktioniert das ganze sicher nicht ;)

Die Deklaration dieses "TVIDEOHDR"
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
unit webcamdriver;

interface

uses GR32, UConvert, Windows, Messages, ExtCtrls, SysUtils;


 type
  PVIDEOHDR = ^TVIDEOHDR;
  TVIDEOHDR = packed record
    lpData         : PBYTE;                // pointer to locked data buffer
    dwBufferLength : DWORD;                // Length of data buffer
    dwBytesUsed    : DWORD;                // Bytes actually used
    dwTimeCaptured : DWORD;                // Milliseconds from start of stream
    dwUser         : DWORD;                // for client's use
    dwFlags        : DWORD;                // assorted flags (see defines)
    dwReserved     : array[0..3of DWORD; // reserved for driver
  end;


und jetzt die beiden Teile, einfach nur die Callback-Funktion mit in die Klasse TWebcam aufgenommen oder eben nicht, wäre aber wegen der Variablen sehr viel schöner!

AUßERHALB der Klasse
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
      var
       CapHandle:  HWND;
      const
       WM_CAP_SET_CALLBACK_FRAME  = (WM_USER +  5);

      var Frame:   TBitmap32;

type
  TWebcam = class
  private

  public
      constructor create(FormHandle:HWND);
  end;

implementation

//------------------CALLBACK-FUNCTION--------------------|
//                                                       |
function OnFrame(hCapWnd: HWND; lpVHDR: PVideoHdr): DWord; stdcall;
begin

----> lpVHDR enthält die Videodaten
                        (alles funktioniert perfekt)
end;

//------------------CONSTRUCTOR--------------------------|
constructor TWebcam.create(FormHandle:HWND);
begin
  inherited Create;
  SendMessage(CapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, Integer(@OnFrame));
end;
INNERHALB der Klasse
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
type
  TWebcam = class
  private
      var
       CapHandle:  HWND;
      const
       WM_CAP_SET_CALLBACK_FRAME  = (WM_USER +  5);
      var 
       Frame:   TBitmap32;

  public
      
      constructor create(FormHandle:HWND);
      function OnFrame(hCapWnd: HWND; lpVHDR: PVideoHdr): DWord; stdcall;

  end;

implementation

//------------------CALLBACK-FUNCTION--------------------|
//                                                       |
function TWebcam.OnFrame(hCapWnd: HWND; lpVHDR: PVideoHdr): DWord; stdcall;
begin

----> lpVHDR ist "NIL"
          (exceptions über exceptions^^)
end;

//------------------CONSTRUCTOR--------------------------|
constructor TWebcam.create(FormHandle:HWND);
begin
  inherited Create;
  SendMessage(CapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, Integer(@TWebcam.OnFrame));
end;
(Veränderungen sind hervorgehoben)

ahja.. :oops: ich hab keine Ahnung was das StdCall überhaupt bedeutet, ich les es jetzt mal nach aber vielleicht kann mir trotzdem jemand helfen :)
mtin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 177

Win XP SP2
BDS2006 Enterprise
BeitragVerfasst: Sa 25.03.06 15:55 
kennt sich da denn keiner aus?
oder beschreib ich das zu schlecht?

brauche H I L F E!!
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Di 28.03.06 15:12 
Callbacks zu machen ohne wissen über DLLs,Speichermanagement,... kann sehr langwierig werden, weil einen Delphi da nichtmehr unterstützen kann da die Daten auch aus anderen Sprachen,Formaten,... kommen können.

STDCll ist eine Aufrufkonvention und gibt An in welcher Reihenfolge Parameter erwartet werden.

Ja so wie du das im ersten Source gemacht hast meinte ich das eine Funktion außerhalb der Klasse, die die Klassenmethode anstößt.

Hast du auch deine Methode als external; gekennzeichnet? Ansonsten sind die von außen nicht verfügbar!

Ich habe wie gesagt leider nicht das Wissen noch die Zeit noch die Möglichkeiten das detailiert nachzutesten, sry :oops: