J'avais téléchargé et installé l'xcellent composant JHVideoCap ici: http://www.torry.net/vcl/mmedia/video/jhvideocap.zip
L'auteur est:
Joerg Huebler
Wilhelm-Braun Str. 19
88250 Weingarten
Germany
et son adresse mail est: huebler@fbm.fh-weingarten.de

J'ai créé une fonction DLL qui crée un tel composant dynamiquement et qui le gère pour capter vidéos et photos fixes à partir d'une source vidéo, en général la WebCam du PC. Ca marche très bien.

Il y a un seul problème: lorsqu'on active le composant, il établit le lien avec le driver vidéo. Si ce driver n'est pas spécifié, il affiche une fenêtre de sélection, et la sélection doit être faite manuellement, puis validée. C'est normal. Mais il y a un moyen de spécifier le driver, soit par son nom, soit par son indice (entre 0 et 9) dans la liste des drivers vidéo de Windows (la WebCam intégrée a l'indice 0). On peut le spécifier, il trouve bien le bon driver, mais à l'activation, il efface tout et affiche quand-même la fenêtre de sélection ! Ceci est vraiment gênant !

J'ai longuement cherché sur le web, et je me suis rendu compte que de nombreux programmeurs ont eu le même problème, à partir de Windows Vista, et ce jusqu'à W10. Personne n'a une solution, et même MicroSoft n'a pas de vraie solution. Certains proposent de faire une boucle d'attente, d'autres suggèrent de fermer cette fenêtre purement et simplement. Tout cela est brutal et ne marche pas - le programme plante par la suite.

J'ai conçu une solution pour contourner le problème. La difficulté, c'est que la méthode DriverOpen avec le paramètre True affiche systématiquement la fenêtre de sélection en mode modal, et le process est bloqué. J'ai conc conçu un thread que je lance à l'intéreur de la méthode DriverOpen, juste avant la ligne critique. Puis, ce thread guette m'apparition de cette fenêtre, passe à la ComboBox de sélection, sélectionne le premier driver (la WebCam intégrée), passe sur le bouton de validation "Ok", le clique et ermine le thread. Tout ceci n'empêche pas cette fenêtre d'apparaître, mais c'est très rapide et aucune intervention n'est nécessaire.

Je sais, c'est un hack, mais il m'a rendu de grands services. Alors, je vais partager le code ici. J'ai modifié une seule unité dans la distribution dont le lien est indiqué ci-dessus: l'unité VideoCap.bas. Voici le code modifié:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
unit Videocap;
 
interface
 
 uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,stdctrls, Dialogs, Forms,  
  ExtCtrls,vfw,mmsystem,syncobjs;
 
{
 
  This is derived from TVideo 2.3
  Thanks to huebler@fbm.fh-weingarten.de
 
  Joerg Huebler
  Wilhelm-Braun Str. 19
  88250 Weingarten
  Germany
 
  Downloaded from: http://www.torry.net/vcl/mmedia/video/jhvideocap.zip
  
  modification history
 
  Date         Author    Comment
  ----------------------------------------------------------------------------------
  19/03/2017   Klaus     introuce a thread to hack the damned Vidéo source window
}
 
 ///////////////////////////////////////////////////////////////////////////////
// Video Capturing
 
type
// Types for audio-settings
 TChannel = (Stereo, Mono);
 TFrequency = (f8000Hz, f11025Hz, f22050Hz, f44100Hz);
 TResolution  = (r8Bit, r16Bit);
 
 
// Types for event-procedures
type
  TCapStatusProc = procedure(Sender: TObject) of object;
  TCapStatusCallback = procedure (Sender:TObject;nID:integer;status:string) of object;
  TVideoStream = procedure (sender:TObject;lpVhdr:PVIDEOHDR) of object;
  TAudioStream = procedure (sender:TObject;lpWHdr:PWAVEHDR) of object;
  TError       = procedure (sender:TObject;nID:integer; errorstr:string) of object;
 
 
// Exceptions
type ENoDriverException      = class(Exception);
type ENoCapWindowException   = class(Exception);
type ENotConnectException    = class(Exception);
type ENoOverlayException     = class(Exception);
type EFalseFormat            = class(Exception);
type ENotOpen                = class(Exception);
type EBufferFileError        = class(Exception);
 
 
type
TAudioFormat = class (TPersistent)
   private
    FChannels :TChannel;
    FFrequency:TFrequency;
    FRes      :TResolution;
  private
    procedure SetAudio(handle:Thandle); // Setting Audio Data to Capture Window
 
  public
   constructor create;
 
   published
     property Channels: TChannel read FChannels write Fchannels     default Mono;
     property Frequency: TFrequency read FFrequency write fFrequency default f8000Hz;
     property Resolution : TResolution read FRes write FRes         default r8Bit;
 end;
 
 
{
  Klaus: special thread to hack the Vidéo source window !
}
type TCapThread = class(TThread)
  private
    fOwnerControl: TCustomControl;
  protected
    procedure Execute; override;
  public
    property OwnerControl: TCustomControl read fOwnerControl write fOwnerControl;
end;
{
  Klaus: end of special thread to hack the Vidéo source window !
}
 
 
 
 
 
type
  TVideoCap = class(TCustomControl)
  private
 
   fdriverIndex            : integer;             // Videodriver index
   fVideoDriverName        : string;              // name of videodriver
   fhCapWnd                : THandle;             // handle for CAP-Window
   fpDrivercaps            : PCapDriverCaps;      // propertys of videodriver
   fpDriverStatus          : pCapStatus;          // status of capdriver
   fscale                  : boolean;             // window scaling
   fprop                   : boolean;             // proportional scaling
   fpreviewrate            : word;                // Frames p. sec during preview
   fmicrosecpframe         : cardinal;            // framerate as microsconds
   fCapVideoFileName       : string;              // name of the capture file
   fTempFileName           : String;              // Name of temporary avi-file
   fTempFileSize           : word;                // size of Tmp- File in MB
 
   fCapSingleImageFileName : string;              // name of the file for a single image
   fcapAudio               : boolean;             // Capture also audio stream
   fcapTimeLimit           : word;                // Time limit for captureing
   fIndexSize              : cardinal;            // size of the index in the capture file
   fcapToFile              : boolean;             // Write frames to file druing capturing
   FAudioFormat            : TAudioFormat;        // Audio Format
   fCapStatusProcedure     : TCapStatusProc;      // Event procedure for internal component status
   fcapStatusCallBack      : TCapStatusCallback;  // Event procedure for status of then driver
   fcapVideoStream         : TVideoStream;        // Event procedure for each Video frame during capturing
   fcapAudioStream         : TAudiostream;        // Event procedure for each Audio buffer
   fcapFrameCallback       : TVideoStream;        // Event procedure for each Video frame during preview
   fcapError               : TError;              // Event procedure for Error
 
   fOwnerPanel             : TPanel;              // Klaus: hosting panel used by the DLL
   fOwnerThread            : TCapThread;          // Klaus: thread used to hack the "Vidéo source" window
 
   procedure setsize(var msg:TMessage); message WM_SIZE;  // Changing size of cap window
   function GetDriverCaps:boolean;                        // get driver capitiyties
   procedure DeleteDriverProps;                           // delete driver capitilyites
   procedure CreateTmpFile(drvopn:boolean); // Create or delete a temp avi´-file
 
   function GetDriverStatus(callback:boolean):boolean; // Getting state of driver
   Procedure SetDriverOpen(value:boolean) ;         // Open and Close the driver
   function GetDriverOpen:boolean;                        // is Driver open ?
   function GetPreview:boolean;   // preview mode
   function GetOverlay:Boolean;   // overlay eode;
   procedure SizeCap;             // calc size of the Capture Window
   procedure Setprop(value:Boolean); // Stretch Picture proportional to Window Size
   procedure SetMicroSecPerFrame(value:cardinal);    // micro seconds between two frames
   procedure setFrameRate(value:word);               // Setting Frames p. second
   function  GetFrameRate:word;                      // Getting Frames p. second.
 
 
 
    // Handlers for Propertys
 
   procedure SetDriverIndex(value:integer);// Select Driver by setting driver index
   function CreateCapWindow:boolean;       // Opening driver, create capture window
   procedure DestroyCapwindow;             //  Closing Driver, destrying capture window
    function GetCapWidth:word;              // Width and Heigth of Video-Frame
    function GetCapHeight:word;
    function  GetHasDlgVFormat  : Boolean;  // Driver has a format dialog
    function  GetHasDlgVDisplay : Boolean;  // Driver has a display dialog
    function  GetHasDlgVSource  : Boolean;  // Driver has a source dialog
    function  GetHasVideoOverlay: Boolean;  // Driver has overlay mode
    procedure Setoverlay(value:boolean);  // Driver will use overlay mode
    procedure SetPreview(value:boolean);  // Driver will use preview mode
    procedure SetScale(value:Boolean);   //  Stretching Frame to component size
    procedure SetpreviewRate(value:word); // Setting preview frame rate
    function GetCapInProgress:boolean;    // Capturing  in progress
    procedure SetIndexSize(value:cardinal); // Setting index size in capture file
    function GetBitMapInfoNP:TBITMAPINFO; //  Bitmapinfo Without Palette
    function GetBitmapHeader:TBitmapInfoHeader; //Get only Header;
    procedure SetBitmapHeader(Header:TBitmapInfoHeader); // Set only Header
    procedure SetBufferFileSize(value:word); // Setting of Tmp-File
 
  // Setting callbacks as events
    procedure SetStatCallBack(value:TCapStatusCallback);
    procedure SetCapVideoStream(value:TVideoStream);
    procedure SetCapAudioStream(value:TAudioStream);
    procedure SetCapFrameCallback(value:TVideoStream);
    procedure SetCapError(value:TError);
 
  public
 
   procedure SetDriverName(value:String); // Select Driver by setting driver name
 
    constructor Create(AOwner: TComponent); override;
    destructor destroy; override;
 
    property  HasDlgFormat:Boolean read GetHasDlgVFormat;       // Driver has a format dialog
    property  HasDlgDisplay:Boolean read GetHasDlgVDisplay;     // Driver has a display dialog
    property  HasDlgSource:Boolean read GetHasDlgVSource;       // Driver has a sourve dialog
    property  HasVideoOverlay:boolean read GetHasVideoOverlay;  // Driver has overlay mode
    property  CapWidth: word read GetCapWidth;                  // Width of the captured frames
    property  CapHeight: word read GetCapHeight;                // Hight of the captured frames
    property  CapInProgess: boolean read getCapinProgress;      // capturing is progress
    property  BitMapInfo:TBitmapinfo read GetBitmapInfoNP;      // Get the Bitmapinfo of the frames wiht no legal palette
   //Header of the Bitmapinfo
    function DlgVFormat:Boolean;                         // Shows VideoFormat dialog of the Driver
    function DlgVDisplay:boolean;                        // Shows VideoDisplay dialog of the Driver
    function DlgVSource:boolean;                         // Shows   VideoSource  dialog of the Driver
    function DlgVCompression:Boolean;                    // Shows  VideoCompression dialog from VfW
    function GrabFrame:boolean;                          // Capture one Frame and stops overlay or preview mode
    function GrabFrameNoStop:boolean;                    // Capture one frame without stoppin overlay or preview
    function SaveAsDIB:Boolean;                          // saves actual frame as DIB
    function SaveToClipboard:Boolean;                    // Puts actual fasme to then Clipboard
    function StartCapture:Boolean;                       // Starts Capturing
    function StopCapture:Boolean;                        // Stops capturing
    function GetBitmapInfo(var p:Pointer):integer;       // The whole Bitmap-Info with complete palette
    procedure SetBitmapInfo(p:Pointer;size:integer);     // Setting whole Bitmap-Info with complete palette
    property  BitMapInfoHeader:TBitmapInfoHeader read GetBitmapHeader write SetBitmapHeader;
    function SaveCap:boolean;                            // Saves Avi-File if Bufferfile is used
    function CapSingleFramesOpen:boolean;                // Opens AVI-File for Singe Image Capturing
    function CapSingleFramesClose:boolean;               // Close AVI-File after Singe Image Capturing
    function CapSingleFrame:boolean;                     // Captures a Single frame to File
    property OwnerPanel: TPanel read fOwnerPanel write fOwnerPanel;            // Klaus: owning panel comtrol
 
 published
   property align;
   property color;
   property visible;
   property DriverOpen: boolean read getDriveropen write setDriverOpen;      // Opens the Driver / or is Driver open
   property DriverIndex:integer read fdriverindex write SetDriverIndex;      // Index of driver
   property DriverName: string read fVideoDriverName write SetDrivername;    // Name of the Driver
   property VideoOverlay:boolean read GetOverlay write SetOverlay;           // Overlay - Mode
   property VideoPreview:boolean read GetPreview write SetPreview;           // Preview - Mode
   property PreviewScaleToWindow:boolean read fscale write Setscale;         // Stretching Frame to component size
   property PreviewScaleProportional:boolean read  fprop write Setprop;      // Stretching Frame poportional to original size
   property PreviewRate:word read fpreviewrate write SetpreviewRate;         //Preview frame rate
   property MicroSecPerFrame:cardinal read  fmicrosecpframe write SetMicroSecPerFrame;  //micro seconds between two frames
   property FrameRate:word read  getFramerate write setFrameRate;            //Frames p. second
   Property CapAudio:Boolean read fcapAudio write fcapAudio;                 // Captue audio stream to
   property VideoFileName:string read fCapVideoFileName   write fCapVideoFileName  ; // Name of capture file
   property SingleImageFile:string read FCapSingleImageFileName write FCapSingleImageFileName;  // Name of file for single image
   property CapTimeLimit:word read fCapTimeLimit write fCapTimeLimit; // time limit for Capturing
   property CapIndexSize:cardinal read findexSize write setIndexSize; // Size of the index for capture file
   property CapToFile:boolean read fcaptoFile write fcapToFile;       // Write Frames to capture file
   property CapAudioFormat:TAudioformat read FAudioformat write FAudioFormat; // Format of captuing Audiodata
   property BufferFileSize:word read ftempfilesize write SetBufferFileSize; // Size of Bufferfile in MB
  // Internal Events and Callbacks as Events
   property OnStatus:TCapStatusProc read fCapStatusProcedure write FCapStatusProcedure;
   property OnStatusCallback:TCapStatusCallback read fcapStatuscallback write SetStatCallback;
   property OnVideoStream:TVideoStream read fcapVideoStream write SetCapVideoStream;
   property OnFrameCallback:TVideoStream read FcapFramecallback write SetCapFrameCallback;
   property OnAudioStream:TAudioStream read fcapAudioStream write SetCapAudioStream;
   property OnError:TError read fcapError write SetCapError;
   property OnMouseMove;
   property OnMouseUp;
   property OnMouseDown;
   property OnClick;
   Property OnDblClick;
   property OwnerThread: TCapThread read fOwnerThread write FownerThread;    // Klaus: hack thread
 end;
 
 
Function GetDriverList:TStringList;  // Fill stringlist with names and versioninfo of all installed capture drivers
procedure FrameToBitmap(Bitmap:TBitmap;FrameBuffer:pointer; BitmapInfo:TBitmapInfo);  // Make a TBitmap from a Frame
procedure BitmapToFrame(Bitmap:TBitmap; FrameBuffer:pointer; BitmapInfo:TBitmapInfo); // Make a Frame form a Bitmap
 
procedure Register;
 
implementation
 
{
  Klaus: hack thread used to hack the "Vidéo source" window:
         - wait for window to appear and be stable
         - select the first video source
         - validate the window (which will close than)
         - quit the thread
}
procedure TCapThread.Execute;
 
  // internal procedure for non blocking wait
  procedure Delay(AMSecs: Cardinal);
  var
    iStop : cardinal;
  begin
    iStop := GetTickCount + AMsecs;
    while GetTickCount < iStop do
    begin
      Application.ProcessMessages;
      sleep(1);
    end
  end;
 
  // internal function to get the window class from a handle
  function GetWindowClassName(Window: HWND): string;
  const
    MaxClassNameLength = 257;//256 plus null terminator
  var
    Buffer: array [0..MaxClassNameLength-1] of Char;
    len: Integer;
  begin
    len := GetClassName(Window, Buffer, Length(Buffer));
    if len=0 then RaiseLastOSError;
    SetString(Result, Buffer, len);
  end;
 
var
  VC: TVideoCap;                                    // related TVideoCap control
  hnd, hnd1, hnd0, hndx, hndb: HWND;                // handle for the "Vidéo source" window
  s, s1: string;                                    // receives control class names
  cnt: integer;                                     // loop count used to find the OK button
  ind: integer;                                     // copy of the DriverIndex property
  i: integer;                                       // loop variable
begin
  FreeOnTerminate := true;                          // thread will disappear on exit
  VC := TVideoCap(OwnerControl);                    // recover the related TVideoCap control
  hnd := 0;                                         // just in case...
  cnt := 0;
 
  while VC.fhCapWnd=0 do delay(200);                // wait for the VideoCap window to appear
  hnd1 := 0;
  hnd0 := VC.fhCapWnd;                              // start with the VideoCap window's handle
  while hnd=0 do begin                              // now look for the "Vidéo source" window whitch must be the foreground window
    hnd := GetForegroundWindow();                   // get the foreground windows handle
    s1 := GetWindowClassName(hnd);                  // and its class name
    if s1='TForm' then exit;                        // is it TForm ? so no Vidéo source window present !
    if s1='#32770' then hndx := hnd;                // is it Window's special #32770 window class ? so remember this as start point
    cnt := 0;                                       // reset the counter (used to localize the Ok button)
    while s1='#32770' do begin                      // there might be other child windows of this kind...
       hnd0 := hnd;                                 // use the current child as new start point
       hnd1 := 0;                                   // start at first child
       hnd := FindWindowEx(hnd0,hnd1,nil,nil);      // get next child (will finally be the video source combo box !
       s1 := GetWindowClassName(hnd);               // and its class name
       inc(cnt);                                    // count this one
       if cnt=1 then begin                          // if first child:  it is the class containing the Ok button as second child !
          hndb := FindWindowEx(hnd0,hnd,nil,nil);   // so get the handle of the Ok button
       end;
    end;
 
    delay(100);                                     // wait a bit and try again
  end;
  // now send some keys to the window
  ind := VC.DriverIndex;
  for i:=0 to ind do begin                                                              // loop to select the correct video source
    SendMessage(hnd, WM_KEYDOWN, VK_RIGHT, MakeLong(0, MapVirtualKey(VK_RIGHT, 0)));    // right arrow - selects next video source
    SendMessage(hnd, WM_KEYUP, VK_RIGHT, MakeLong(0, MapVirtualKey(VK_RIGHT, 0)));
  end;
  SendMessage(hndb, WM_LBUTTONDOWN, MK_LBUTTON, 5 or (5 shl 16));                       // left click on the OK button
  SendMessage(hndb, WM_LBUTTONUP, 0, 5 or (5 shl 16));
  VC.OwnerThread := nil;                            // dismiss the thread from the TCapVideo control
  // the thread will now exit and disappear
end;
{
  Klaus: end of special stream Execute procedure
}
 
 // Callback for status of video captures
function StatusCallbackProc(hWnd : HWND; nID : Integer; lpsz : Pchar): LongInt; stdcall;
var Control:TVideoCap;
begin
  control:=TVideoCap(capGetUserData(hwnd));
  if assigned(control) then
   begin
       if assigned(control.fcapStatusCallBack) then
              control.fcapStatusCallBack(control,nId,strPas(lpsz));
   end;
  result:= 1;
end;
 
// Callback for video stream
function VideoStreamCallbackProc(hWnd:Hwnd; lpVHdr:PVIDEOHDR):longint; stdcall;
 var Control:TVideoCap;
begin
   control:= TVideoCap(capGetUserData(hwnd));
  if assigned(control) then
   begin
    if assigned(control.fcapVideoStream ) then
         control.fcapVideoStream(control,lpvHdr);
   end;
 result:= 1;
end;
 
//Callback for Frames during Preview
function FrameCallbackProc(hwnd:Hwnd; lpvhdr:PVideoHdr):longint;stdcall;
var Control:TVideoCap;
 
begin
  control:= TVideoCap(capGetUserData(hwnd));
  if assigned(control) then
   begin
    if assigned(control.fcapFrameCallback ) then
         control.fcapFrameCallback(control,lpvHdr);
   end;
 result:= 1;
end;
 
 
// Callback for audio stream
function AudioStreamCallbackProc(hwnd:HWND;lpWHdr:PWaveHdr):longInt; stdcall;
var control:TVideoCap;
begin
 control:= TVideoCap(capGetUserData(hwnd));
 if assigned(control) then
  if assigned(control.fcapAudioStream) then
    begin
     control.fcapAudioStream(control,lpwhdr);
    end;
 result:= 1;
end;
 
// Callback for Error
function ErrorCallbackProc(hwnd:HWND;nId:integer;lzError:Pchar):longint;stdcall;
 
var Control:TVideoCap;
 
 begin
 control:= TVideoCap(capGetUserData(hwnd));
 if assigned(control) then
  if assigned(control.fcaperror) then
    begin
     control.fcapError(control,nId,StrPas(lzError));
    end;
 result:= 1;
end;
 
 
 
 
 
 
 
// New Window-Procedure for CaputreWindow to post messages like WM_MouseMove to Component
 
function WCapproc(hw:THandle;messa:DWord; w:wParam; l:lParam):integer;stdcall;
 var oldwndProc:Pointer;
     parentWnd:Thandle;
 begin
    oldwndproc:=Pointer(GetWindowLong(hw,GWL_USERDATA));
    case Messa of
     WM_MOUSEMOVE,
     WM_LBUTTONDBLCLK,
     WM_LBUTTONDOWN,WM_RBUTTONDOWN,WM_MBUTTONDOWN ,
     WM_LBUTTONUP,WM_RBUTTONUP,WM_MBUTTONUP:
       begin
        ParentWnd:=Thandle(GetWindowLong(hw,GWL_HWNDPARENT));
        sendMessage(ParentWnd,messa,w,l);
        result := integer(true);
       end
    else
       result:= callWindowProc(oldwndproc,hw,messa,w,l);
   end;
 
 end;
 
(*---------------------------------------------------------------*)
// constructor and Destructor
constructor TVideoCap.Create(aowner:TComponent);
 
begin
 inherited create(aowner);
 height                  := 100;
 width                   := 100;
 Color                   :=clblack;
 fVideoDriverName        := '';
 fdriverindex            := -1 ;
 fhCapWnd                := 0;
 fCapVideoFileName       := 'Video.avi';
 fCapSingleImageFileName := 'Capture.bmp';
 fscale                  := false;
 fprop                   := false;
 fpreviewrate            := 30;
 fmicrosecpframe         := 66667;
 fpDrivercaps            := nil;
 fpDriverStatus          := nil;
 fcapToFile              := true;
 findexSize              := 0;
 ftempFileSize           := 0;
 fCapStatusProcedure     := nil;
 fcapStatusCallBack      := nil;
 fcapVideoStream         := nil;
 fcapAudioStream         := nil;
 
 fOwnerPanel             := TPanel(aowner);      // Klaus: host the TVideoCap inside a Panel
 fOwnerThread            := nil;                 // Klaus: initially no hack thread
 
 FAudioformat:=TAudioFormat.Create;
 
end;
 
 destructor TVideoCap.destroy;
  begin
    DestroyCapWindow;
    deleteDriverProps;
    fAudioformat.free;
    inherited destroy;
  end;
 
 
 
 
(*---------------------------------------------------------------*)
// Messagehandler for sizing the capture window
 procedure TVideoCap.SetSize(var msg:TMessage);
  begin
  if (fhCapWnd <> 0) and (Fscale) then
    begin
     if msg.msg = WM_SIZE then SizeCap;
    end;
  end;
 
 
// Sizing capture window
 procedure TVideoCap.SizeCap;
 var h,w:integer;
     f,cf:single;
 begin
  if not fscale then
      MoveWindow(fhcapWnd,0,0,Capwidth,capheight,true)
    else
      begin
       if fprop then
        begin
        f:= Width/height;
        cf:= CapWidth/CapHeight;
        if f >  cf then
         begin
          h:= height;
          w:= round(h*cf);
         end
        else
          begin
          w:= width;
          h:= round(w*1/cf);
         end
        end
       else
        begin
         h:= height;
         w:= Width;
       end;
       MoveWindow(fhcapWnd,0,0,w, h,true);
     end;
 end;
 
 
  (*---------------------------------------------------------------*)
// Delete driver infos
procedure TVideoCap.DeleteDriverProps;
 begin
   if assigned(fpDrivercaps) then
    begin
      dispose(fpDrivercaps);
      fpDriverCaps:= nil;
    end;
    if assigned(fpDriverStatus) then
     begin
       dispose(fpDriverStatus);
       fpDriverStatus:= nil;
     end;
 
 end;
 
 
(*---------------------------------------------------------------*)
// Buffer File
procedure TVideoCap.CreateTmpFile(drvOpn:boolean);
 var s,f:array [0..MAX_PATH] of char;
    size:word;
    ok:boolean;
    e:Exception;
 
 begin
   if (ftempFileName ='') and (ftempFileSize = 0) then exit;
   if drvOpn then Size := ftempFileSize else size:=0;
   if fTempFileName = '' then
     begin
       GetTempPath(sizeof(s),@s);
       GetTempFileName(s,'cap',0,f);
       ftempfilename := f;
     end;
   if size <> 0 then
    begin
       capFileSetCaptureFile(fhCapWnd,strpCopy(f,ftempfilename));
       ok:=capFileAlloc(fhcapWnd,1024*1024* ftempFileSize);
      if not ok then
       begin
         e:= EBufferFileError.Create('Could not create tmp file');
         raise e;
       end;
    end
   else
    begin
     capFileSetCaptureFile(fhCapWnd,strpCopy(f, fCapVideoFileName));
     DeleteFile(fTempfileName);
     fTempFileName:= '';
    end;
 end;
 
procedure TVideoCap.SetBufferFileSize(Value:word);
 
 begin
   if value = fTempFilesize then exit;
   ftempFileSize:=value;
   if DriverOpen Then CreateTmpFile(true);
 end;
 
 
 
 
(*---------------------------------------------------------------*)
// Capitilies of the Driver
 
 function TVideoCap.GetDriverCaps:boolean;
 var savestat : integer;
 
 begin
   result:= false;
   if assigned(fpDrivercaps) then
     begin
       result:= true;
       exit;
     end;
   if fdriverIndex = -1 then exit;
   savestat := fhCapwnd;  // save state of the window
   if fhCapWnd = 0 then CreateCapWindow;
   if fhCapWnd = 0 then exit;
   new(fpDrivercaps);
   if capDriverGetCaps(fhCapWnd, fpDriverCaps, sizeof(TCapDriverCaps)) then
    begin
     result:= true;
     if savestat = 0 then destroyCapWindow;
     exit;
    end;
   dispose(fpDriverCaps);  // Error can't open then Driver
   fpDriverCaps := nil;
   if savestat = 0 then destroyCapWindow;
 end;
 
(*---------------------------------------------------------------*)
 // BitmapInfo without a Palette
function TVideoCap.GetBitMapInfoNp:TBitmapinfo;
 var  e:Exception;
 begin
  if driveropen then
   begin
     capGetVideoFormat(fhcapWnd, @result,sizeof(TBitmapInfo));
     exit;
   end ;
 
  fillchar(result,sizeof(TBitmapInfo),0);
  e:= ENotOpen.Create('Driver not Open');
  raise e;
 end;
 
// Whole BitmapInfo
function TVideoCap.GetBitMapInfo(var p:Pointer):integer;
var size:integer;
    e:Exception;
 
begin
  p:=nil;
  if driverOpen then
    begin
      size:= capGetVideoFormat(fhcapWnd,p,0);
      getmem(p,size);
      capGetVideoFormat(fhcapwnd,p,size);
      result:=size;
      exit;
    end;
 e:= ENotOpen.Create('Driver not Open');
 raise e;
end;
 
// Setting whole BitmapInfo
procedure TVideoCap.SetBitmapInfo(p:Pointer;size:integer);
var e:Exception;
    supported:boolean;
begin
 if driverOpen then
  begin
    supported:=capSetVideoFormat(fhcapWnd,p,size);
    if not supported then
    begin
     e:=EFalseFormat.Create('Not supported Frame Format' );
     raise e;
    end;
   exit;
  end;
 e:= ENotOpen.Create('Driver not Open');
 raise e;
end;
 
 
 
 
// Only Header of BitmapInfo
 
function TVideoCap.GetBitMapHeader:TBitmapinfoHeader;
 var e:Exception;
 begin
  if driveropen then
   begin
    capGetVideoFormat(fhcapWnd, @result,sizeof(TBitmapInfoHeader));
    exit;
   end ;
 fillchar(result,sizeof(TBitmapInfoHeader),0);
 e:= ENotOpen.Create('Driver not Open');
 raise e;
end;
 
procedure TVideoCap.SetBitMapHeader(header:TBitmapInfoHeader);
 var e:exception;
 
 begin
  if driveropen then
   begin
    if not capSetVideoFormat(fhcapWnd,@header,sizeof(TBitmapInfoHeader)) then
     begin
      e:= EFalseFormat.Create('Not supported Frame Format');
      raise e;
     end;
    exit;
   end
  else
   begin
    e:= ENotOpen.Create('Driver not Open');
    raise e;
   end;
 end;
 
 
 (*---------------------------------------------------------------*)
 
function TVideoCap.getDriverStatus(callback:boolean):boolean;
begin
  result := false;
  if fhCapWnd <> 0 then
  begin
  if not assigned(fpDriverstatus) then new(fpDriverStatus);
  if capGetStatus(fhCapWnd,fpdriverstatus, sizeof(TCapStatus)) then
   begin
     result:= true;
  end;
  end;
 if assigned(fCapStatusProcedure)and callback then fcapStatusProcedure ( self);
end;
 
 
 
(*---------------------------------------------------------------*)
// Setting name of driver
 
procedure TVideoCap.SetDrivername(value:string);
var i:integer;
    name:array[0..80] of char;
    ver :array[0..80] of char;
begin
 if fVideoDrivername = value then exit;
 for i:= 0 to 9 do
  if capGetDriverDescription( i,name,80,ver,80) then
    if strpas(name) = value then
     begin
      fVideoDriverName := value;
      Driverindex:= i;
      exit;
    end;
 fVideoDrivername:= '';
 DriverIndex:= -1;
end;
 
(*---------------------------------------------------------------*)
procedure TVideoCap.SetDriverIndex(value:integer);
var  name:array[0..80] of char;
     ver :array[0..80] of char;
 
begin
  if value = fdriverindex then exit;
  destroyCapWindow;
  deleteDriverProps;  // Alte Treiberfähigkeiten Löschen
  if value > -1 then
    begin
     if capGetDriverDescription(value,name,80,ver,80) then
        fVideoDriverName:= StrPas(name)
     else
       value:= -1;
   end;
 if value = -1 then  fvideoDriverName:= '';
 fdriverindex:= value;
end;
 
(*---------------------------------------------------------------*)
function TVideoCap.CreateCapWindow;
 var Ex:Exception;
     savewndproc:integer;
 begin
    if fhCapWnd <> 0 then
     begin
      result:= true;
      exit;
    end;
 
   if fdriverIndex = -1 then
    begin
     Ex := ENoDriverException.Create('No capture driver selected');
     GetDriverStatus(true);
     raise ex;
     exit;
    end;
   fhCapWnd := capCreateCaptureWindow( PChar(Name),
              WS_CHILD or WS_VISIBLE , 0, 0,
               Width, Height,
              Handle, 5001);
   if fhCapWnd =0 then
     begin
       Ex:= ENoCapWindowException.Create('Can not create capture window');
       GetDriverStatus(true);
       raise ex;
       exit;
      end;
 
  // Set our own Address to the CapWindow
 capSetUserData(fhCapwnd,integer(self));
 // Set our own window procedure to Capture-Window
 savewndproc:=SetWindowLong(fhcapWnd,GWL_WNDPROC,integer(@WCapProc));
 // User Data for old WndProc adress
 SetWindowLong(fhcapWnd,GWL_USERDATA,savewndProc);
 // Setting callbacks as events
if assigned(fcapStatusCallBack ) then
  capSetCallbackOnStatus(fhcapWnd ,StatusCallbackProc);
if assigned(fcapFrameCallback) then
  capSetCallbackOnFrame(fhcapWnd,FrameCallbackProc);
if assigned(fcapError) then
   capSetCallbackOnError(fhcapWnd,ErrorCallBackProc);
 
 
if assigned(fcapVideoStream) then
   capSetCallbackOnVideoStream(fhcapwnd,VideoStreamCallbackProc);
if assigned(fcapAudioStream) then
       capSetCallbackOnWaveStream(fhcapWnd,AudioStreamCallbackProc);
 
 if not capDriverConnect(fhCapWnd, fdriverIndex) then
     begin
       Ex:= ENotConnectException.Create('Can not connect capture driver with capture window');
       Destroycapwindow;
       GetDriverStatus(true);
       raise ex;
       exit;
   end;
 
 
 
 CreateTmpFile(True);
 capPreviewScale(fhCapWnd, fscale);
 capPreviewRate(fhCapWnd, round( 1/fpreviewrate*1000));
 GetDriverStatus(true);
 Sizecap;
 result:= true;
end;
 
(*------------------------------------------------------------------------*)
// Setting callbacks as events
 
procedure TVideoCap.SetStatCallBack(value:TCapStatusCallback);
begin
 fcapStatusCallBack := value;
 if DriverOpen then
   if assigned(fcapStatusCallBack) then
      capSetCallbackOnStatus(fhcapWnd ,StatusCallbackProc)
   else
    capSetCallbackOnStatus(fhcapWnd ,nil);
end;
 
 
procedure TVideoCap.SetCapVideoStream(value:TVideoStream);
 begin
  fcapVideoStream:= value;
  if DriverOpen then
   if assigned(fcapVideoStream) then
     capSetCallbackOnVideoStream(fhcapwnd,VideoStreamCallbackProc)
   else
    capSetCallbackOnVideoStream(fhcapwnd, nil);
 end;
 
procedure TVideoCap.SetCapFrameCallback(value:TVideoStream);
begin
 fcapframeCallback:= value;
 if DriverOpen then
   if assigned(fcapFrameCallback) then
     capSetCallbackOnFrame(fhcapwnd,FrameCallBackProc)
   else
    capSetCallbackOnFrame(fhcapwnd, nil);
 end;
 
 
 
procedure TVideoCap.SetCapAudioStream(value:TAudioStream);
  begin
   fcapAudioStream:= value;
    if DriverOpen then
     if assigned(fcapAudioStream) then
       capSetCallbackOnWaveStream(fhcapWnd,AudioStreamCallbackProc)
     else
      capSetCallbackOnWaveStream(fhcapWnd,nil);
  end;
 
 
 procedure TVideoCap.SetCapError(value:TError);
 begin
  fcapError:= value;
  if DriverOpen then
     if assigned(fcapError) then
       capSetCallbackOnError(fhcapWnd,ErrorCallbackProc)
     else
      capSetCallbackOnError(fhcapWnd,nil);
 end;
 
 
 
(*---------------------------------------------------------------*)
procedure TVideoCap.DestroyCapWindow;
begin
  if fhCapWnd = 0 then exit;
  CreateTmpFile(False);
  CapDriverDisconnect(fhCapWnd);
  SetWindowLong(fhcapWnd,GWL_WNDPROC,GetWindowLong(fhcapwnd,GWL_USERDATA)); // Old windowproc
  DestroyWindow( fhCapWnd ) ;
  fhCapWnd := 0;
end;
 
(*---------------------------------------------------------------*)
function  TVideoCap.GetHasVideoOverlay:Boolean;
 
begin
   if getDriverCaps then
     Result := fpDriverCaps^.fHasOverlay
   else
     result:= false;
 end;
 
(*---------------------------------------------------------------*)
 
function  TVideoCap.GetHasDlgVFormat:Boolean;
begin
  if getDriverCaps then
     Result := fpDriverCaps^.fHasDlgVideoFormat
   else
     result:= false;
end;
 
(*---------------------------------------------------------------*)
function  TVideoCap.GetHasDlgVDisplay : Boolean;
 
begin
  if getDriverCaps then
     Result := fpDriverCaps^.fHasDlgVideoDisplay
   else
     result:= false;
end;
 
(*---------------------------------------------------------------*)
function  TVideoCap.GetHasDlgVSource  : Boolean;
begin
  if getDriverCaps then
     Result := fpDriverCaps^.fHasDlgVideoSource
   else
     result:= false;
end;
 
(*---------------------------------------------------------------*)
function TVideoCap.DlgVFormat:boolean;
var    savestat : integer;
begin
   result:= false;
   if fdriverIndex = -1 then exit;
   savestat := fhCapwnd;
   if fhCapWnd = 0 then
        if not CreateCapWindow then exit;
   result :=capDlgVideoFormat(fhCapWnd);
   if result then GetDriverStatus(true);
   if savestat = 0 then destroyCapWindow;
   if result then
   begin
    Sizecap;
    Repaint;
  end;
 end;
 
(*---------------------------------------------------------------*)
function TVideoCap.DlgVDisplay:boolean;
var savestat : integer;
begin
   result:= false;
   if fdriverIndex = -1 then exit;
   savestat := fhCapwnd;
   if fhCapWnd = 0 then
       if not CreateCapWindow then exit;
   result:=capDlgVideoDisplay(fhCapWnd) ;
   if result then GetDriverStatus(true);
   if savestat = 0 then destroyCapWindow;
   if result then
   begin
    SizeCap;
    Repaint;
  end;
end;
 
(*---------------------------------------------------------------*)
function TVideoCap.DlgVSource:boolean;
var savestat : integer;
 
begin
 result:= false;
 if fdriverIndex = -1 then exit;
  savestat := fhCapwnd;
  if fhCapWnd = 0 then
   if not createCapWindow then exit;
  result:= capDlgVideoSource(fhCapWnd);
  if result then GetDriverStatus(true);
  if savestat = 0 then destroyCapWindow;
  if result then
  begin
   SizeCap;
   Repaint;
 end;
end;
(*---------------------------------------------------------------*)
function TVideoCap.DlgVCompression;
var savestat : integer;
 
begin
 result:= false;
 if fdriverIndex = -1 then exit;
  savestat := fhCapwnd;
  if fhCapWnd = 0 then
   if not createCapWindow then exit;
   result:=capDlgVideoCompression(fhCapWnd);
  if savestat = 0 then destroyCapWindow;
 end;
 
 
(*---------------------------------------------------------------*)
 // Single Frame Grabbling
 function TVideoCap.GrabFrame:boolean;
 begin
  result:= false;
  if not DriverOpen then exit;
  Result:= capGrabFrame(fhcapwnd);
  if result then GetDriverStatus(true);
 end;
 
 function TVideoCap.GrabFrameNoStop:boolean;
 begin
  result:= false;
  if not DriverOpen then exit;
  Result:= capGrabFrameNoStop(fhcapwnd);
  if result then GetDriverStatus(true);
 end;
 
 (*---------------------------------------------------------------*)
// save frame as DIP
function TVideoCap.SaveAsDIB:Boolean;
  var s:array[0..MAX_PATH] of char;
begin
   result:= false;
   if not DriverOpen then exit;
   result := capFileSaveDIB(fhcapwnd,strpCopy(s,fCapSingleImageFileName));
end;
 
function  TVideoCap.SaveToClipboard:boolean;
begin
 result:= false;
 if not Driveropen then exit;
 result:= capeditCopy(fhcapwnd);
end;
 
 
(*---------------------------------------------------------------*)
 
procedure TVideoCap.Setoverlay(value:boolean);
var ex:Exception;
begin
 if value = GetOverlay then exit;
 if gethasVideoOverlay = false then
   begin
    Ex:= ENoOverlayException.Create('Driver has no overlay mode');
    raise ex;
    exit;
   end;
 if value = true then
  begin
   if fhcapWnd = 0 then  CreateCapWindow;
   GrabFrame;
  end;
 
 capOverlay(fhCapWnd,value);
 GetDriverStatus(true);
 invalidate;
 end;
 
function TVideoCap.GetOverlay:boolean;
begin
 if fhcapWnd = 0 then result := false
 else
  result:= fpDriverStatus^.fOverlayWindow;
end;
 
 
 
(*---------------------------------------------------------------*)
 
procedure TVideoCap.SetPreview(value:boolean);
begin
 if value = GetPreview then exit;
 if value = true then
   if fhcapWnd = 0 then  CreateCapWindow;
 capPreview(fhCapWnd,value);
 GetDriverStatus(true);
 invalidate;
end;
 
function TVideoCap.GetPreview:boolean;
begin
 if fhcapWnd = 0 then result := false
 else
  result:= fpDriverStatus^.fLiveWindow;
end;
 
 
 
procedure TVideoCap.SetPreviewRate(value:word);
begin
 if value = fpreviewrate then exit;
 if value < 1 then value := 1;
 if value > 30 then value := 30;
 fpreviewrate:= value;
 if DriverOpen then capPreviewRate(fhCapWnd, round( 1/fpreviewrate*1000));
end;
 
(*---------------------------------------------------------------*)
 
procedure TVideoCap.SetMicroSecPerFrame(value:cardinal);
 begin
  if value =  fmicrosecpframe then exit;
  if value < 33333 then value := 33333;
   fmicrosecpframe := value;
end;
 
 
 
procedure TVideoCap.setFrameRate(value:word);
begin
 if value <> 0 then fmicrosecpframe:= round(1.0/value*1000000.0);
end;
 
function  TVideoCap.GetFrameRate:word;
begin
 if fmicrosecpFrame > 0   then
   result:= round(1./ fmicrosecpframe * 1000000.0)
else
  result:= 0;
end;
 
 
function TVideoCap.StartCapture;
var CapParms:TCAPTUREPARMS;
    name:array[0..MAX_PATH] of char;
 
 begin
   result := false;
   if not DriverOpen then exit;
   capCaptureGetSetup(fhCapWnd, @CapParms, sizeof(TCAPTUREPARMS));
 
  if ftempfilename='' then
   capFileSetCaptureFile(fhCapWnd,strpCopy(name, fCapVideoFileName));
 
 
   CapParms.dwRequestMicroSecPerFrame := fmicrosecpframe;
   CapParms.fLimitEnabled    := BOOL(FCapTimeLimit);
   CapParms.wTimeLimit       := fCapTimeLimit;
   CapParms.fCaptureAudio    := fCapAudio;
   CapParms.fMCIControl      := FALSE;
   CapParms.fYield           := TRUE;
   CapParms.vKeyAbort        := VK_ESCAPE;
   CapParms.fAbortLeftMouse  := FALSE;
   CapParms.fAbortRightMouse := FALSE;
   if CapParms.fLimitEnabled then // Calculate Indexsize
     begin
       CapParms.dwIndexSize:= frameRate*FCapTimeLimit; // For Video Frames
       If fCapAudio then
         CapParms.dwIndexSize := CapParms.dwIndexSize + 5*FCapTimeLimit; // Additional Buffer for Audio
      end
    else
      begin
        If CapParms.dwIndexSize = 0 then     // Default Value
          CapParms.DwIndexSize := 100000 // Value bigger then default for larger Videos
        else
          CapParms.dwIndexSize := findexSize; // IndexSize by user
      end;
   if CapParms.dwIndexSize < 1800 then CapParms.dwIndexSize:= 1800;  // Limit Control
   If CapParms.dwIndexSize > 324000 then CapParms.dwIndexSize:= 324000;
 
   capCaptureSetSetup(fhCapWnd, @CapParms, sizeof(TCAPTUREPARMS));
   if fCapAudio then FAudioformat.SetAudio(fhcapWnd);
   if CapToFile then
    result:= capCaptureSequence(fhCapWnd)
   else
    result := capCaptureSequenceNoFile(fhCapWnd);
   GetDriverStatus(true);
 end;
 
 
function TVideoCap.StopCapture;
begin
 result:=false;
 if not DriverOpen then exit;
 result:=CapCaptureStop(fhcapwnd);
 GetDriverStatus(true);
 
end;
 
function TVideoCap.SaveCap:Boolean;
var name:array[0..MAX_PATH] of char;
 begin
  result := capFileSaveAs(fhcapwnd,strPCopy(name,fCapVideoFileName)); // strpCopy(name, fCapVideoFileName));
end;
 
 
procedure TVideoCap.SetIndexSize(value:cardinal);
  begin
   if value = 0 then
    begin
      findexSize:= 0;
      exit;
    end;
   if value < 1800 then value := 1800;
   if value > 324000 then value := 324000;
  findexsize:= value;
 
 end;
 
 
function TVideoCap.GetCapInProgress:boolean;
  begin
   result:= false;
   if not DriverOpen then exit;
   GetDriverStatus(false);
   result:= fpDriverStatus^.fCapturingNow ;
 end;
 (*---------------------------------------------------------------*)
 
Procedure TVideoCap.SetScale(value:boolean);
 
begin
 if value = fscale then  exit;
 fscale:= value;
 if DriverOpen then
   begin
    capPreviewScale(fhCapWnd, fscale);
    SizeCap;
   end;
 Repaint;
end;
 
Procedure TVideoCap.Setprop(value:Boolean);
begin
 if value = fprop then exit;
 fprop:=value;
 if DriverOpen then Sizecap;
 Repaint;
end;
 
 
(*---------------------------------------------------------------*)
function TVideoCap.GetCapWidth;
 
begin
 if assigned(fpDriverStatus) then
   result:= fpDriverStatus^.uiImageWidth
else
   result:= 0;
end;
 
function TVideoCap.GetCapHeight;
 
begin
 if assigned(fpDriverStatus) then
   result:= fpDriverStatus^.uiImageHeight
else
   result:= 0;
end;
 
 
{
 
    RegOpenKey HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\MediaResources\msvideo\MSVideo.VFWWDM", lngKey
    RegSetValueEx lngKey, "DevicePath", 0, 1, ByVal Strdata, Len(Strdata)
    RegCloseKey lngKey
    capCreateCaptureWindow("CaptureWindow", WS_CHILD Or WS_VISIBLE, 0, 0, 0, 0, Picture4.hwnd, 0)
 
Function GetCurrentWebCam() As String
  Dim WSHShell As Object
  Dim MyRegKey As String
  Set WSHShell = CreateObject("WScript.Shell")
  MyRegKey = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MediaResources\msvideo\MSVideo.VFWWDM\DevicePath"
  GetCurrentWebCam = WSHShell.regread(MyRegKey)
  Set WSHShell = Nothing
End Function
 
Sub SetCurrentWebCam(Camstr As String)
  Dim WSHShell As Object
  Dim MyRegKey As String
  Set WSHShell = CreateObject("WScript.Shell")
  MyRegKey = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MediaResources\msvideo\MSVideo.VFWWDM\DevicePath"
  WSHShell.regwrite MyRegKey, Camstr
  Set WSHShell = Nothing
End Sub
     
}
(*---------------------------------------------------------------*)
 Procedure TVideoCap.SetDriverOpen(value:boolean);
 begin
   if value = GetDriverOpen then exit;
   if value = false then DestroyCapWindow;
   if value = true then begin
 
     OwnerThread := TCapThread.Create(true);           // Klaus: create the hack thread
     OwnerThread.OwnerControl := self;                 // Klaus: set the link to the owning TVideoCap
     OwnerThread.Resume;                               // Klaus: and launch the thread
 
     CreateCapWindow;          // original line
   end;
 end;
 
 
function TVideoCap.GetDriverOpen:boolean;
begin
 result := fhcapWnd <> 0;
end;
 
(*---------------------------------------------------------------*)
// Singele frame Capturing
 
function TVideoCap.CapSingleFramesOpen:boolean;
 var name :array [0..MAX_PATH] of char;
     CapParms:TCAPTUREPARMS;
 
 begin
   result := false;
   if not DriverOpen then exit;
 
   capCaptureGetSetup(fhCapWnd, @CapParms, sizeof(TCAPTUREPARMS));
   if ftempfilename='' then
    capFileSetCaptureFile(fhCapWnd,strpCopy(name, fCapVideoFileName));
 
   CapParms.dwRequestMicroSecPerFrame := fmicrosecpframe;
   CapParms.fLimitEnabled    := BOOL(0);
   CapParms.fCaptureAudio    := false;
   CapParms.fMCIControl      := FALSE;
   CapParms.fYield           := TRUE;
   CapParms.vKeyAbort        := VK_ESCAPE;
   CapParms.dwIndexSize := findexSize; // IndexSize by user
   if CapParms.dwIndexSize < 1800 then CapParms.dwIndexSize:= 1800;  // Limit Control
   If CapParms.dwIndexSize > 324000 then CapParms.dwIndexSize:= 324000;
   capCaptureSetSetup(fhCapWnd, @CapParms, sizeof(TCAPTUREPARMS));
 
   result:= capCaptureSingleFrameOpen(fhcapWnd);
end;
 
function TVideoCap.CapSingleFramesClose:boolean;
 var E:Exception;
 begin
   if not driverOpen then
     begin
        e:= ENotOpen.Create('Driver not Open');
        raise e;
        exit;
      end;
    result:= CapCaptureSingleFrameClose(fhcapWnd);
 end;
 
 
function TVideoCap.CapSingleFrame:boolean;
 var E:Exception;
begin
  if not driverOpen then
     begin
        e:= ENotOpen.Create('Driver not Open');
        raise e;
        exit;
     end;
    result:= CapCaptureSingleFrame(fhcapWnd);
 end;
 
///////////////////////////////////////////////////////////////////////////
 
 
constructor TAudioFormat.create;
begin
     inherited create;
     FChannels:=Mono;
     FFrequency:=f8000Hz;
     Fres:=r8Bit;
end;
 
 
 
procedure TAudioFormat.SetAudio(handle:Thandle);
Var WAVEFORMATEX:TWAVEFORMATEX;
 
begin
     if handle= 0 then exit;  // No CapWindow
     capGetAudioFormat(handle,@WAVEFORMATEX, SizeOf(TWAVEFORMATEX));
     case FFrequency of
          f8000hz  :WAVEFORMATEX.nSamplesPerSec:=8000;
          f11025Hz:WAVEFORMATEX.nSamplesPerSec:=11025;
          f22050Hz:WAVEFORMATEX.nSamplesPerSec:=22050;
          f44100Hz:WAVEFORMATEX.nSamplesPerSec:=44100;
     end;
     WAVEFORMATEX.nAvgBytesPerSec:= WAVEFORMATEX.nSamplesPerSec;
     if FChannels=Mono then
          WAVEFORMATEX.nChannels:=1
     else
          WAVEFORMATEX.nChannels:=2;
     if FRes=r8Bit then
        WAVEFORMATEX.wBitsPerSample:=8
     else
        WAVEFORMATEX.wBitsPerSample:=16;
     capSetAudioFormat(handle,@WAVEFORMATEX, SizeOf(TWAVEFORMATEX));
end;
 
 
///////////////////////////////////////////////////////////////////////////
 
 
// Creating a list with capture drivers
Function GetDriverList:TStringList;
var i:integer;
    name:array[0..80] of char;
    ver :array[0..80] of char;
begin
 result:= TStringList.Create;
 result.Capacity:= 10;
 result.Sorted:= false;
 for i:= 0 to 9 do
   if capGetDriverDescription( i,name,80,ver,80) then
      result.Add(StrPas(name)+ ' '+strpas(ver))
   else
     break;
 end;
 
procedure FrameToBitmap(Bitmap:TBitmap;FrameBuffer:pointer; BitmapInfo:TBitmapInfo);
 var  hdd:Thandle;
 
begin
 
 with Bitmap  do
 begin
  Width:= BitmapInfo.bmiHeader.biWidth;      // New size of Bitmap
  Height:=Bitmapinfo.bmiHeader.biHeight;
  hdd:= DrawDibOpen;
  DrawDibDraw(hdd,canvas.handle,0,0,BitmapInfo.BmiHeader.biwidth,BitmapInfo.bmiheader.biheight,@BitmapInfo.bmiHeader,
                  frameBuffer,0,0,bitmapInfo.bmiHeader.biWidth,bitmapInfo.bmiHeader.biheight,0);
  DrawDibClose(hdd);
  end;
end;
 
 
 
procedure BitmapToFrame(Bitmap:TBitmap; FrameBuffer:pointer; BitmapInfo:TBitmapInfo);
 var ex:Exception;
begin
  if bitmapInfo.bmiHeader.BiCompression <> bi_RGB then
  begin
    ex:=  EFalseFormat.Create('Not Supported DIB format');
    raise ex ;
  end;
  with Bitmap do
   GetDiBits(canvas.handle,handle,0,BitmapInfo.bmiHeader.biheight,FrameBuffer,BitmapInfo,DIB_RGB_COLORS);
 end;
 
 
 
 
 
procedure Register;
begin
  RegisterComponents( 'Video', [TVideoCap]);
end;
 
 
 
end.
Voilà. Ca m'a appris beaucoup de choses, et en particulier la technique du thread a pu être mise au point grâce à l'aide précieuse de Andnotor de ce forum. Il est donc normal que je renvoie l'ascenseur.

EDIT

J'ai modifié légèrement le code ci-dessus pour prendre en compte automatiquement la valeur de la propriété DriverIndex afin de sélectionner la bonne ligne dans la fenêtre de sélection de la source vidéo.