~ubuntu-branches/ubuntu/trusty/psychtoolbox-3/trusty-proposed

« back to all changes in this revision

Viewing changes to PsychSourceGL/Source/Common/Screen/PsychVideoCaptureSupportLibARVideo.c

  • Committer: Package Import Robot
  • Author(s): Yaroslav Halchenko
  • Date: 2013-11-19 23:34:50 UTC
  • mfrom: (3.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20131119233450-f7nf92vb8qavjmk8
Tags: 3.0.11.20131017.dfsg1-3
Upload to unsable since fresh glew has arrived to sid!

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
        PsychSourceGL/Source/Common/Screen/PsychVideoCaptureSupportLibARVideo.c
3
 
 
4
 
        PLATFORMS:      
5
 
        
6
 
        GNU/Linux, Apple MacOS/X and MS-Windows
7
 
 
8
 
        AUTHORS:
9
 
        
10
 
        Mario Kleiner           mk              mario.kleiner@tuebingen.mpg.de
11
 
 
12
 
        HISTORY:
13
 
        
14
 
        18.04.2009                              Created initial version.
15
 
        27.03.2011                              Disabled. It was not ever implemented on Linux and useless
16
 
                                                        on OS/X. Its limited functionality (on Windows) is replaced by
17
 
                                                        the much more capable GStreamer based video capture engine.
18
 
                                                        Removing this component from the build also allows us the
19
 
                                                        planned change of software license.
20
 
 
21
 
        TODO:
22
 
        
23
 
        We should probably remove the implementation files as there aren't any plans
24
 
        to ever resurrect this now entirely obsolete component.
25
 
 
26
 
        DESCRIPTION:
27
 
        
28
 
         This is the videocapture engine based on the free, open-source (GPL'ed)
29
 
         LibARVideo library, part of the ARToolkit. It only supports video capture,
30
 
         no sound capture and no recording of video or sound.
31
 
         
32
 
         On MacOS/X it is implemented via the Quicktime Sequencegrabber-API, ie., it
33
 
         uses the same engine as our original Quicktime video capture engine. Therefore
34
 
         it doesn't provide any additional functionality or advantages over our default
35
 
         engine. It is only implemented here as a reference to compare against our own
36
 
         engine and for simpler cross-platform development. Maybe we can learn something
37
 
         here?
38
 
         
39
 
         On GNU/Linux it is implemented via the free LGPL'ed GStreamer-Multimedia plugin
40
 
         framework. As such, it should be able to support any video source and video
41
 
         preprocessing operation provided by GStreamers plugins: We have at least support
42
 
         for video4linux and video4linux2 video devices (webcams, DVB, TV tuners, analog
43
 
                                                                                                         cameras and framegrabbers and whatnot), DV firewire consumer cameras, IIDC machine
44
 
         vision cameras, network video (GigE etc in the future), decoded video from video
45
 
         files...
46
 
         
47
 
         On MS-Windows, it is implemented as a DirectShow filtergraph and should therefore
48
 
         be able to access any device supported by a DirectShow Videofilter, ie., pretty
49
 
         much any device on MS-Windows.
50
 
 
51
 
        NOTES:
52
 
 
53
 
        TODO:
54
 
 
55
 
 */
56
 
 
57
 
 
58
 
#include "Screen.h"
59
 
#include <float.h>
60
 
 
61
 
#ifdef PTBVIDEOCAPTURE_ARVIDEO
62
 
 
63
 
// These are the includes for ARToolkit and ARVideo:
64
 
#include <AR/video.h>
65
 
 
66
 
#ifndef DC1394_SUCCESS
67
 
#define DC1394_SUCCESS 0
68
 
#endif
69
 
 
70
 
// Record which defines all state for a capture device:
71
 
typedef struct {
72
 
        int valid;                        // Is this a valid device record? zero == Invalid.
73
 
        AR2VideoParamT  *camera;                // Ptr to a ARVideo camera object that holds the internal state for such cams.
74
 
        ARUint8                 *frame;                 // Ptr to a psych_uint8 matrix which contains the most recently captured/dequeued frame.
75
 
        int dropframes;                                 // 1 == Always deliver most recent frame in FIFO, even if dropping of frames is neccessary.
76
 
        unsigned char* scratchbuffer;     // Scratch buffer for YUV->RGB conversion.
77
 
        int reqpixeldepth;                // Requested depth of single pixel in output texture.
78
 
        int pixeldepth;                   // Depth of single pixel from grabber in bits.
79
 
        int num_dmabuffers;               // Number of DMA ringbuffers to use in DMA capture.
80
 
        int nrframes;                     // Total count of decompressed images.
81
 
        double fps;                       // Acquisition framerate of capture device.
82
 
        int width;                        // Width x height of captured images.
83
 
        int height;
84
 
        double last_pts;                  // Capture timestamp of previous frame.
85
 
        double current_pts;               // Capture timestamp of current frame.
86
 
        int current_dropped;              // Dropped count for this fetch cycle...
87
 
        int nr_droppedframes;             // Counter for dropped frames.
88
 
        int frame_ready;                  // Signals availability of new frames for conversion into GL-Texture.
89
 
        int grabber_active;               // Grabber running?
90
 
        PsychRectType roirect;            // Region of interest rectangle - denotes subarea of full video capture area.
91
 
        double avg_decompresstime;        // Average time spent in Quicktime/Sequence Grabber decompressor.
92
 
        double avg_gfxtime;               // Average time spent in GWorld --> OpenGL texture conversion and statistics.
93
 
        int nrgfxframes;                  // Count of fetched textures.
94
 
} PsychVidcapRecordType;
95
 
 
96
 
static PsychVidcapRecordType vidcapRecordBANK[PSYCH_MAX_CAPTUREDEVICES];
97
 
static int numCaptureRecords = 0;
98
 
static psych_bool firsttime = TRUE;
99
 
 
100
 
// Forward declaration of internal helper function:
101
 
void PsychARDeleteAllCaptureDevices(void);
102
 
 
103
 
 
104
 
/*    PsychGetARVidcapRecord() -- Given a handle, return ptr to video capture record.
105
 
*    --> Internal helper function of PsychVideoCaptureSupport.
106
 
*/
107
 
PsychVidcapRecordType* PsychGetARVidcapRecord(int deviceIndex)
108
 
{
109
 
        // Sanity checks:
110
 
        if (deviceIndex < 0) {
111
 
                PsychErrorExitMsg(PsychError_user, "Invalid (negative) deviceIndex for video capture device passed!");
112
 
        }
113
 
        
114
 
        if (numCaptureRecords >= PSYCH_MAX_CAPTUREDEVICES) {
115
 
                PsychErrorExitMsg(PsychError_user, "Invalid deviceIndex for video capture device passed. Index exceeds number of registered devices!");
116
 
        }
117
 
        
118
 
        if (!vidcapRecordBANK[deviceIndex].valid) {
119
 
                PsychErrorExitMsg(PsychError_user, "Invalid deviceIndex for video capture device passed. No such device open!");
120
 
        }
121
 
        
122
 
        // Ok, we have a valid device record, return a ptr to it:
123
 
        return(&vidcapRecordBANK[deviceIndex]);
124
 
}
125
 
 
126
 
/* CHECKED
127
 
*     PsychARVideoCaptureInit() -- Initialize video capture subsystem.
128
 
*     This routine is called by Screen's RegisterProject.c PsychModuleInit()
129
 
*     routine at Screen load-time. It clears out the vidcapRecordBANK to
130
 
*     bring the subsystem into a clean initial state.
131
 
*/
132
 
void PsychARVideoCaptureInit(void)
133
 
{
134
 
        // Initialize vidcapRecordBANK with NULL-entries:
135
 
        int i;
136
 
        for (i=0; i < PSYCH_MAX_CAPTUREDEVICES; i++) {
137
 
                vidcapRecordBANK[i].valid = 0;
138
 
        }    
139
 
        numCaptureRecords = 0;
140
 
        
141
 
        return;
142
 
}
143
 
 
144
 
/* CHECKED
145
 
*  void PsychARExitVideoCapture() - Shutdown handler.
146
 
*
147
 
*  This routine is called by Screen('CloseAll') and on clear Screen time to
148
 
*  do final cleanup. It deletes all capture objects
149
 
*
150
 
*/
151
 
void PsychARExitVideoCapture(void)
152
 
{
153
 
        // Release all capture devices
154
 
        PsychARDeleteAllCaptureDevices();
155
 
        
156
 
        // Reset firsttime flag to get a cold restart on next invocation of Screen:
157
 
        firsttime = TRUE;
158
 
        return;
159
 
}
160
 
 
161
 
/*  CHECKED
162
 
*  PsychARDeleteAllCaptureDevices() -- Delete all capture objects and release all associated ressources.
163
 
*/
164
 
void PsychARDeleteAllCaptureDevices(void)
165
 
{
166
 
        int i;
167
 
        for (i=0; i<PSYCH_MAX_CAPTUREDEVICES; i++) {
168
 
                if (vidcapRecordBANK[i].valid) PsychARCloseVideoCaptureDevice(i);
169
 
        }
170
 
        return;
171
 
}
172
 
 
173
 
/* CHECKED
174
 
*  PsychARCloseVideoCaptureDevice() -- Close a capture device and release all associated ressources.
175
 
*/
176
 
void PsychARCloseVideoCaptureDevice(int capturehandle)
177
 
{
178
 
        // Retrieve device record for handle:
179
 
        PsychVidcapRecordType* capdev = PsychGetARVidcapRecord(capturehandle);
180
 
        
181
 
        // Stop capture immediately if it is still running:
182
 
        PsychARVideoCaptureRate(capturehandle, 0, 0, NULL);
183
 
        
184
 
        // Close & Shutdown camera, release ressources:
185
 
        ar2VideoClose(capdev->camera);  
186
 
        capdev->camera = NULL;
187
 
        
188
 
        // Invalidate device record to free up this slot in the array:
189
 
        capdev->valid = 0;
190
 
    
191
 
        // Decrease counter of open capture devices:
192
 
        if (numCaptureRecords>0) numCaptureRecords--;
193
 
        
194
 
        // Done.
195
 
        return;
196
 
}
197
 
 
198
 
/* CHECKED TODO
199
 
*      PsychAROpenVideoCaptureDevice() -- Create a video capture object.
200
 
*
201
 
*      This function tries to open and initialize a connection to a camera
202
 
*      and returns the associated captureHandle for it.
203
 
*
204
 
*          slotid = Number of slot in vidcapRecordBANK[] array to use for this camera.
205
 
*      win = Pointer to window record of associated onscreen window.
206
 
*      deviceIndex = Index of the grabber device. (Currently ignored)
207
 
*      capturehandle = handle to the new capture object.
208
 
*      capturerectangle = If non-NULL a ptr to a PsychRectangle which contains the ROI for capture.
209
 
*      reqdepth = Number of layers for captured output textures. (0=Don't care, 1=LUMINANCE8, 2=LUMINANCE8_ALPHA8, 3=RGB8, 4=RGBA8)
210
 
*      num_dmabuffers = Number of buffers in the ringbuffer queue (e.g., DMA buffers) - This is OS specific. Zero = Don't care.
211
 
*      allow_lowperf_fallback = If set to 1 then PTB can use a slower, low-performance fallback path to get nasty devices working.
212
 
*          targetmoviefilename and recordingflags are currently ignored, they would refer to video harddics recording capabilities.
213
 
*/
214
 
psych_bool PsychAROpenVideoCaptureDevice(int slotid, PsychWindowRecordType *win, int deviceIndex, int* capturehandle, double* capturerectangle,
215
 
                                                                   int reqdepth, int num_dmabuffers, int allow_lowperf_fallback, char* targetmoviefilename, unsigned int recordingflags)
216
 
{
217
 
    PsychVidcapRecordType       *capdev = NULL;
218
 
        int                                             w, h;
219
 
    char                                        msgerr[10000];
220
 
        char                                    config[1000];
221
 
        char                                    tmpstr[1000];
222
 
 
223
 
        config[0] = 0;
224
 
        tmpstr[0] = 0;
225
 
        
226
 
        // Default camera config:
227
 
        #if PSYCH_SYSTEM == PSYCH_WINDOWS
228
 
    //strcat(config, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dsvl_input><camera show_format_dialog=\"false\" friendly_name=\"\"><pixel_format><RGB32 flip_h=\"false\" flip_v=\"true\"/></pixel_format></camera></dsvl_input>");
229
 
 
230
 
        // Prefix:
231
 
    strcat(config, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dsvl_input><camera show_format_dialog=\"false\" ");
232
 
 
233
 
        // Specific deviceIndex requested, instead of auto-select?
234
 
    if (deviceIndex >= 1 && deviceIndex <= 3) {
235
 
                // Fetch optional moviename parameter as name spec string:
236
 
                if (targetmoviefilename == NULL) PsychErrorExitMsg(PsychError_user, "You set 'deviceIndex' to a value of 1, 2 or 3, but didn't provide the required device name string in the 'moviename' argument! Aborted.");
237
 
                switch(deviceIndex) {
238
 
                        case 1:
239
 
                                sprintf(tmpstr, "friendly_name=\"%s\" ", targetmoviefilename);
240
 
                                break;
241
 
                                
242
 
                        case 2:
243
 
                                sprintf(tmpstr, "device_name=\"%s\" ", targetmoviefilename);
244
 
                                break;
245
 
                                
246
 
                        case 3:
247
 
                                sprintf(tmpstr, "ieee1394id=\"%s\" ", targetmoviefilename);
248
 
                                break;
249
 
                }
250
 
                
251
 
                strcat(config, tmpstr);
252
 
        }
253
 
        else {
254
 
                // Default device index: Just pass through as default device:
255
 
                strcat(config, "friendly_name=\"\" ");
256
 
        }       
257
 
        #endif
258
 
 
259
 
 
260
 
        #if PSYCH_SYSTEM == PSYCH_OSX
261
 
        char *defaultcamconfig = "";
262
 
        #endif
263
 
 
264
 
        #if PSYCH_SYSTEM == PSYCH_LINUX
265
 
        char *defaultcamconfig = "-dev=/dev/video0 -channel=0 -palette=YUV420P -width=320 -height=240";
266
 
        #endif
267
 
 
268
 
        // Init capturehandle to none:
269
 
    *capturehandle = -1;
270
 
    
271
 
    if (firsttime) {
272
 
                // First time invocation:
273
 
        
274
 
        #if PSYCH_SYSTEM == PSYCH_WINDOWS
275
 
        // On Windows, we need to delay-load the libARvideo.dll DLL. This loading
276
 
        // and linking will automatically happen downstream. However, if delay loading
277
 
        // would fail, we would end up with a crash! For that reason, we try here to
278
 
        // load the DLL, just to probe if the real load/link/bind op later on will
279
 
        // likely succeed. If the following LoadLibrary() call fails and returns NULL,
280
 
        // then we know we would end up crashing. Therefore we'll output some helpful
281
 
        // error-message instead:
282
 
        if (NULL == LoadLibrary("libARvideo.dll")) {
283
 
            // Failed:
284
 
            printf("\n\nPTB-ERROR: Tried to startup video capture engine type 2 (ARVideo). This didn't work,\n");
285
 
            printf("PTB-ERROR: because one of the required helper DLL libraries failed to load. Probably because they\n");
286
 
            printf("PTB-ERROR: could not be found or could not be accessed (e.g., due to permission problems).\n\n");
287
 
            printf("PTB-ERROR: Please read the online help by typing 'help ARVideoCapture' for troubleshooting instructions.\n\n");
288
 
                        PsychErrorExitMsg(PsychError_user, "Unable to start Videocapture engine ARVideo due to DLL loading problems. Aborted.");
289
 
        }
290
 
        #endif
291
 
        
292
 
                firsttime = FALSE;
293
 
    }
294
 
 
295
 
    // Slot 'slotid' will contain the record for our new capture object:
296
 
 
297
 
    // Initialize new record:
298
 
    vidcapRecordBANK[slotid].valid = 1;
299
 
    
300
 
    // Retrieve device record for slotid:
301
 
    capdev = PsychGetARVidcapRecord(slotid);
302
 
        
303
 
    capdev->camera = NULL;
304
 
    capdev->grabber_active = 0;
305
 
    capdev->scratchbuffer = NULL;        
306
 
 
307
 
    // ROI rectangle specified?
308
 
    if (capturerectangle) {
309
 
                // Extract wanted width and height:
310
 
                w = (int) PsychGetWidthFromRect(capturerectangle);
311
 
                h = (int) PsychGetHeightFromRect(capturerectangle);
312
 
 
313
 
                #if PSYCH_SYSTEM == PSYCH_OSX
314
 
                sprintf(tmpstr, " -width=%i -height=%i", w, h);
315
 
                #endif
316
 
                
317
 
                #if PSYCH_SYSTEM == PSYCH_WINDOWS               
318
 
                sprintf(tmpstr, " frame_width=\"%i\" frame_height=\"%i\" ", w, h);
319
 
                #endif
320
 
 
321
 
                #if PSYCH_SYSTEM == PSYCH_LINUX
322
 
                // TODO
323
 
                #endif          
324
 
 
325
 
                strcat(config, tmpstr);
326
 
    }
327
 
 
328
 
        if (num_dmabuffers > 0) {
329
 
                #if PSYCH_SYSTEM == PSYCH_WINDOWS
330
 
                // Get framerate from num_dmabuffers argument:
331
 
                sprintf(tmpstr, " frame_rate=\"%i\" ", num_dmabuffers);
332
 
                strcat(config, tmpstr);
333
 
                #endif
334
 
        }
335
 
 
336
 
#if PSYCH_SYSTEM == PSYCH_OSX
337
 
        // Disable setup dialog:
338
 
        strcat(config, " -nodialog");
339
 
 
340
 
        // Specific deviceIndex requested, instead of auto-select?
341
 
    if (deviceIndex > 0) {
342
 
                sprintf(tmpstr, " -grabber=%i", deviceIndex + 1);
343
 
                strcat(config, tmpstr);
344
 
        }
345
 
        else {
346
 
                deviceIndex = 0;
347
 
        }
348
 
 
349
 
        switch (reqdepth) {
350
 
                case 2:
351
 
                        // A no-go: Instead we use 1 channel luminance8:
352
 
                        if (PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Video capture engine doesn't support requested Luminance+Alpha format. Will revert to pure Luminance instead...\n");
353
 
                case 1:
354
 
                        reqdepth = 1;
355
 
                        sprintf(tmpstr, " -pixelformat=40");
356
 
                        break;
357
 
                        
358
 
                case 3:
359
 
                        reqdepth = 3;
360
 
                        sprintf(tmpstr, " -pixelformat=24");
361
 
                        break;
362
 
 
363
 
                case 5:
364
 
                        reqdepth = 4;
365
 
                        sprintf(tmpstr, "");
366
 
                        break;
367
 
                case 4:
368
 
                case 0:
369
 
                        reqdepth = 4;
370
 
                        sprintf(tmpstr, " -pixelformat=ARGB");
371
 
                        break;
372
 
                        
373
 
                default:
374
 
                        // Unknown format:
375
 
                        PsychErrorExitMsg(PsychError_user, "You requested an invalid image depths (not one of 0, 1, 2, 3 or 4). Aborted.");
376
 
        }
377
 
 
378
 
        strcat(config, tmpstr);
379
 
#endif
380
 
 
381
 
#if PSYCH_SYSTEM == PSYCH_WINDOWS
382
 
        if (reqdepth == 4 || reqdepth == 0) {
383
 
                // Default is RGB32 bit:
384
 
                reqdepth = 4;
385
 
                sprintf(tmpstr, "><pixel_format><RGB32 flip_h=\"false\" flip_v=\"true\"/></pixel_format></camera></dsvl_input>");       
386
 
        }
387
 
        else {
388
 
                // Only other supported format is RGB24 bit:
389
 
                switch (reqdepth) {
390
 
                        case 1:
391
 
                                if (PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Video capture engine doesn't support requested Luminance format. Will revert to RGB color instead...\n");
392
 
                        break;
393
 
                        
394
 
                        case 2:
395
 
                                // A no-go: Instead we use 1 channel luminance8:
396
 
                                if (PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Video capture engine doesn't support requested Luminance+Alpha format. Will revert to RGB color instead...\n");
397
 
                        break;
398
 
                        
399
 
                        case 3:
400
 
                        break;
401
 
                                
402
 
                        default:
403
 
                                // Unknown format:
404
 
                                PsychErrorExitMsg(PsychError_user, "You requested an invalid image depths (not one of 0, 1, 2, 3 or 4). Aborted.");
405
 
                }
406
 
                
407
 
                reqdepth = 3;
408
 
                sprintf(tmpstr, "><pixel_format><RGB24 flip_h=\"false\" flip_v=\"true\"/></pixel_format></camera></dsvl_input>");       
409
 
        }
410
 
 
411
 
        strcat(config, tmpstr);
412
 
        
413
 
    if (deviceIndex == 4) {
414
 
                // Fetch optional moviename parameter as override configuration string:
415
 
                if (targetmoviefilename == NULL) PsychErrorExitMsg(PsychError_user, "You set 'deviceIndex' to a value of 4, but didn't provide the required override configuration string in the 'moviename' argument! Aborted.");
416
 
 
417
 
                // Reset config string:
418
 
                config[0] = 0;
419
 
 
420
 
                // And load the moviename argument as override string:
421
 
                strcat(config, targetmoviefilename);
422
 
        }
423
 
        
424
 
        // End of MS-Windows specific setup.
425
 
#endif
426
 
 
427
 
#if PSYCH_SYSTEM == PSYCH_LINUX
428
 
        // Specific deviceIndex requested, instead of auto-select?
429
 
    if (deviceIndex!=-1) {
430
 
                sprintf(tmpstr, " -dev=/dev/video%i", deviceIndex);
431
 
                strcat(config, tmpstr);
432
 
        }
433
 
        else {
434
 
                deviceIndex = 0;
435
 
        }
436
 
 
437
 
        reqdepth = 3;
438
 
#endif          
439
 
 
440
 
    // Requested output texture pixel depth in layers:
441
 
    capdev->reqpixeldepth = reqdepth;
442
 
        capdev->pixeldepth = reqdepth * 8;
443
 
        
444
 
    // Number of DMA ringbuffers to use in DMA capture mode: If no number provided (==0), set it to 8 buffers...
445
 
#if PSYCH_SYSTEM == PSYCH_OSX
446
 
        if (num_dmabuffers == 1) {
447
 
                // Use single-buffering instead of triple buffering:
448
 
                strcat(config, " -singlebuffer");
449
 
        }
450
 
        else {
451
 
                num_dmabuffers = 3;
452
 
        }
453
 
 
454
 
    capdev->num_dmabuffers = num_dmabuffers;
455
 
#else
456
 
    capdev->num_dmabuffers = num_dmabuffers;
457
 
#endif
458
 
        
459
 
        if (PsychPrefStateGet_Verbosity()>4) printf("PTB-INFO: Final configuration string passed to ARVideo library is:\n%s\n", config);
460
 
 
461
 
        // Prepare error message in case its needed below:
462
 
        sprintf(msgerr, "PTB-ERROR: Opening the %i. camera (deviceIndex=%i) failed!\n", deviceIndex + 1, deviceIndex);
463
 
 
464
 
        // Try to open and initialize camera according to given settings:
465
 
    capdev->camera = ar2VideoOpen(config);
466
 
 
467
 
        // Error abort if camera init failed:
468
 
        if(capdev->camera == NULL) {
469
 
                // Error abort here:
470
 
                capdev->valid = 0;
471
 
                PsychErrorExitMsg(PsychError_user, msgerr);
472
 
    }
473
 
 
474
 
    // Our camera should be ready: Assign final handle.
475
 
    *capturehandle = slotid;
476
 
        
477
 
    // Increase counter of open capture devices:
478
 
    numCaptureRecords++;
479
 
    
480
 
    // Set zero framerate:
481
 
    capdev->fps = 0;
482
 
    
483
 
    // Set image size:
484
 
        ar2VideoInqSize(capdev->camera, &(capdev->width), &(capdev->height));
485
 
    
486
 
        // Create capture ROI corresponding to width and height of video image:
487
 
        PsychMakeRect(capdev->roirect, 0, 0, capdev->width, capdev->height);
488
 
 
489
 
    // Reset framecounter:
490
 
    capdev->nrframes = 0;
491
 
    capdev->grabber_active = 0;
492
 
    
493
 
    printf("PTB-INFO: Camera successfully opened...\n");
494
 
 
495
 
    return(TRUE);
496
 
}
497
 
 
498
 
/* CHECKED
499
 
*  PsychARVideoCaptureRate() - Start- and stop video capture.
500
 
*
501
 
*  capturehandle = Grabber to start-/stop.
502
 
*  playbackrate = zero == Stop capture, non-zero == Capture
503
 
*  dropframes = 0 - Always deliver oldest frame in DMA ringbuffer. 1 - Always deliver newest frame.
504
 
*               --> 1 == drop frames in ringbuffer if behind -- low-latency capture.
505
 
*  startattime = Deadline (in system time) for which to wait before real start of capture.
506
 
*  Returns Number of dropped frames during capture.
507
 
*/
508
 
int PsychARVideoCaptureRate(int capturehandle, double capturerate, int dropframes, double* startattime)
509
 
{
510
 
        int dropped = 0;
511
 
        float framerate = 0;
512
 
        
513
 
        // Retrieve device record for handle:
514
 
        PsychVidcapRecordType* capdev = PsychGetARVidcapRecord(capturehandle);
515
 
        
516
 
        // Start- or stop capture?
517
 
        if (capturerate > 0) {
518
 
                // Start capture:
519
 
                if (capdev->grabber_active) PsychErrorExitMsg(PsychError_user, "You tried to start video capture, but capture is already started!");
520
 
                
521
 
                // Reset statistics:
522
 
                capdev->last_pts = -1.0;
523
 
                capdev->nr_droppedframes = 0;
524
 
                capdev->frame_ready = 0;
525
 
                
526
 
                // Framedropping is not supported by libARVideo, so we implement it ourselves.
527
 
                // Store the 'dropframes' flag in our capdev struct, so the PsychARGetTextureFromCapture()
528
 
                // knows how to handle this:
529
 
                capdev->dropframes = (dropframes > 0) ? 1 : 0;
530
 
 
531
 
                // Ready to go! Now we just need to tell the camera to start its capture cycle:
532
 
                
533
 
                // Wait until start deadline reached:
534
 
                if (*startattime != 0) PsychWaitUntilSeconds(*startattime);
535
 
                
536
 
                // Start DMA driven isochronous data transfer:
537
 
                if(PsychPrefStateGet_Verbosity()>5) printf("PTB-DEBUG: Starting capture...\n"); fflush(NULL);
538
 
 
539
 
                // Start the video capture for this camera.
540
 
                if (ar2VideoCapStart(capdev->camera) !=DC1394_SUCCESS) {
541
 
                        // Failed!
542
 
                        PsychErrorExitMsg(PsychError_user, "Unable to start capture on camera via ar2VideoCapStart() - Start of video capture failed!");
543
 
                }
544
 
                
545
 
                // Record real start time:
546
 
                PsychGetAdjustedPrecisionTimerSeconds(startattime);
547
 
                
548
 
                if(PsychPrefStateGet_Verbosity()>5) printf("PTB-DEBUG: Capture engine fully running...\n"); fflush(NULL);
549
 
                
550
 
                // Query framerate and convert to floating point value and assign it:
551
 
                #if PSYCH_SYSTEM == PSYCH_WINDOWS
552
 
                ar2VideoInqFreq(capdev->camera, &framerate);
553
 
                #else
554
 
                // TODO: Implement for non-Win32:
555
 
                framerate = (float) capturerate;
556
 
                #endif
557
 
 
558
 
                capdev->fps = (double) framerate;
559
 
 
560
 
                // Ok, capture is now started:
561
 
                capdev->grabber_active = 1;
562
 
                
563
 
                // Allocate conversion buffer if needed for YUV->RGB conversions.
564
 
                if (capdev->pixeldepth == -1) {
565
 
                        // Not used at the moment!!
566
 
                        // Software conversion of YUV -> RGB needed. Allocate a proper scratch-buffer:
567
 
                        capdev->scratchbuffer = malloc(capdev->width * capdev->height * 3);
568
 
                }
569
 
                
570
 
                if(PsychPrefStateGet_Verbosity()>1) {
571
 
                        printf("PTB-INFO: Capture started on device %i - Width x Height = %i x %i - Framerate: %f fps.\n", capturehandle, capdev->width, capdev->height, capdev->fps);
572
 
                }
573
 
        }
574
 
        else {
575
 
                // Stop capture:
576
 
                if (capdev->grabber_active) {
577
 
                        // Stop isochronous data transfer from camera:
578
 
                        if (ar2VideoCapStop(capdev->camera) !=DC1394_SUCCESS) {
579
 
                                PsychErrorExitMsg(PsychError_user, "Unable to stop video transfer on camera! (ar2VideoCapStop() failed)!");
580
 
                        }
581
 
                        
582
 
                        // Ok, capture is now stopped.
583
 
                        capdev->frame_ready = 0;
584
 
                        capdev->grabber_active = 0;
585
 
                        
586
 
                        if (capdev->scratchbuffer) {
587
 
                                // Release scratch-buffer:
588
 
                                free(capdev->scratchbuffer);
589
 
                                capdev->scratchbuffer = NULL;
590
 
                        }
591
 
 
592
 
                        if(PsychPrefStateGet_Verbosity()>1){
593
 
                                // Output count of dropped frames:
594
 
                                if ((dropped=capdev->nr_droppedframes) > 0) {
595
 
                                        printf("PTB-INFO: Video capture dropped %i frames on device %i to keep capture running in sync with realtime.\n", dropped, capturehandle); 
596
 
                                }
597
 
                                
598
 
                                if (capdev->nrframes>0) capdev->avg_decompresstime/= (double) capdev->nrframes;
599
 
                                printf("PTB-INFO: Average time spent in video decompressor (waiting/polling for new frames) was %f milliseconds.\n", (float) capdev->avg_decompresstime * 1000.0f);
600
 
                                if (capdev->nrgfxframes>0) capdev->avg_gfxtime/= (double) capdev->nrgfxframes;
601
 
                                printf("PTB-INFO: Average time spent in GetCapturedImage (intensity calculation Video->OpenGL texture conversion) was %f milliseconds.\n",  (float) capdev->avg_gfxtime * 1000.0f);
602
 
                        }
603
 
                }
604
 
        }
605
 
        
606
 
        fflush(NULL);
607
 
    
608
 
        // Reset framecounters and statistics:
609
 
        capdev->nrframes = 0;
610
 
        capdev->avg_decompresstime = 0;
611
 
        capdev->nrgfxframes = 0;
612
 
        capdev->avg_gfxtime = 0;
613
 
        
614
 
        // Return either the real capture framerate (at start of capture) or count of dropped frames - at end of capture.
615
 
        return((capturerate!=0) ? (int) (capdev->fps + 0.5) : dropped);
616
 
}
617
 
 
618
 
 
619
 
/* CHECKED TODO
620
 
*  PsychARGetTextureFromCapture() -- Create an OpenGL texturemap from a specific videoframe from given capture object.
621
 
*
622
 
*  win = Window pointer of onscreen window for which a OpenGL texture should be created.
623
 
*  capturehandle = Handle to the capture object.
624
 
*  checkForImage = >0 == Just check if new image available, 0 == really retrieve the image, blocking if necessary.
625
 
*                   2 == Check for new image, block inside this function (if possible) if no image available.
626
 
*
627
 
*  timeindex = This parameter is currently ignored and reserved for future use.
628
 
*  out_texture = Pointer to the Psychtoolbox texture-record where the new texture should be stored.
629
 
*  presentation_timestamp = A ptr to a double variable, where the presentation timestamp of the returned frame should be stored.
630
 
*  summed_intensity = An optional ptr to a double variable. If non-NULL, then sum of intensities over all channels is calculated and returned.
631
 
*  outrawbuffer = An optional ptr to a memory buffer of sufficient size. If non-NULL, the buffer will be filled with the captured raw image data, e.g., for use inside Matlab or whatever...
632
 
*  Returns Number of pending or dropped frames after fetch on success (>=0), -1 if no new image available yet, -2 if no new image available and there won't be any in future.
633
 
*/
634
 
int PsychARGetTextureFromCapture(PsychWindowRecordType *win, int capturehandle, int checkForImage, double timeindex,
635
 
                                                                 PsychWindowRecordType *out_texture, double *presentation_timestamp, double* summed_intensity, rawcapimgdata* outrawbuffer)
636
 
{
637
 
    GLuint texid;
638
 
    int w, h;
639
 
    double targetdelta, realdelta, frames;
640
 
    unsigned int intensity = 0;
641
 
    unsigned int count, i, bpp;
642
 
    unsigned char* pixptr;
643
 
    psych_bool newframe = FALSE;
644
 
    double tstart, tend;
645
 
    unsigned int pixval, alphacount;
646
 
    int error;
647
 
    int nrdropped = 0;
648
 
    unsigned char* input_image = NULL;
649
 
        
650
 
    // Retrieve device record for handle:
651
 
    PsychVidcapRecordType* capdev = PsychGetARVidcapRecord(capturehandle);
652
 
        
653
 
        // Compute width and height for later creation of textures etc. Need to do this here,
654
 
        // so we can return the values for raw data retrieval:
655
 
        w=capdev->width;
656
 
    h=capdev->height;
657
 
 
658
 
        // Size of a single pixel in bytes:
659
 
        bpp = capdev->reqpixeldepth;
660
 
        
661
 
        // If a outrawbuffer struct is provided, we fill it with info needed to allocate a
662
 
        // sufficient memory buffer for returned raw image data later on:
663
 
        if (outrawbuffer) {
664
 
                outrawbuffer->w = w;
665
 
                outrawbuffer->h = h;
666
 
                outrawbuffer->depth = bpp;
667
 
        }
668
 
        
669
 
    // int waitforframe = (checkForImage > 1) ? 1:0; // Blocking wait for new image requested?
670
 
        
671
 
        // A checkForImage 4 means "no op" with the ARVideo capture engine: This is meant to drive
672
 
        // a movie recording engine, ie., grant processing time to it. Our ARVideo engine doesn't
673
 
        // support movie recording, so this is a no-op:
674
 
        if (checkForImage == 4) return(0);
675
 
 
676
 
    // Take start timestamp for timing stats:
677
 
    PsychGetAdjustedPrecisionTimerSeconds(&tstart);
678
 
        
679
 
    // Should we just check for new image?
680
 
    if (checkForImage) {
681
 
                // Reset current dropped count to zero:
682
 
                capdev->current_dropped = 0;
683
 
        
684
 
                if (capdev->grabber_active == 0) {
685
 
                        // Grabber stopped. We'll never get a new image:
686
 
                        return(-2);
687
 
                }
688
 
                
689
 
                // Check for image in polling mode: We capture in non-blocking mode:                    
690
 
                capdev->frame = ar2VideoGetImage(capdev->camera);
691
 
 
692
 
                // Ok, call succeeded. If the 'frame' pointer is non-NULL then there's a new frame ready and dequeued from DMA
693
 
                // ringbuffer. We'll return it on next non-poll invocation. Otherwise no new video data ready yet:
694
 
                capdev->frame_ready = (capdev->frame != NULL) ? 1 : 0;
695
 
 
696
 
                
697
 
                if (capdev->frame_ready) {
698
 
                        // Store count of currently queued frames (in addition to the one just fetched).
699
 
                        // This is an indication of how well the users script is keeping up with the video stream,
700
 
                        // technically the number of frames that would need to be dropped to keep in sync with the
701
 
                        // stream.
702
 
                        // TODO: Think about this. ARVideo doesn't support a query for pending/dropped frames, so
703
 
                        // we either need to live without this feature or think up something clever...
704
 
                        capdev->current_dropped = (int) 0;
705
 
                        
706
 
                        // Ok, at least one new frame ready. If more than one frame has queued up and
707
 
                        // we are in 'dropframes' mode, ie. we should always deliver the most recent available
708
 
                        // frame, then we quickly fetch & discard all queued frames except the last one.
709
 
                        while((capdev->dropframes) && ((int) capdev->current_dropped > 0)) {
710
 
                                // We just poll - fetch the frames. As we know there are some queued frames, it
711
 
                                // doesn't matter if we poll or block, but polling sounds like a bit less overhead
712
 
                                // at the OS level:
713
 
                                
714
 
                                // First enqueue the recently dequeued buffer...
715
 
                                if (ar2VideoCapNext(capdev->camera) != DC1394_SUCCESS) {
716
 
                                        PsychErrorExitMsg(PsychError_system, "Requeuing of discarded video frame failed while dropping frames (dropframes=1)!!!");
717
 
                                }
718
 
                                
719
 
                                // Then fetch the next one:
720
 
                                if ((capdev->frame = ar2VideoGetImage(capdev->camera)) == NULL) {
721
 
                                        // Polling failed for some reason...
722
 
                                        PsychErrorExitMsg(PsychError_system, "Polling for new video frame failed while dropping frames (dropframes=1)!!!");
723
 
                                }
724
 
                                
725
 
                        }
726
 
                        
727
 
                        // Update stats for decompression:
728
 
                        PsychGetAdjustedPrecisionTimerSeconds(&tend);
729
 
                        
730
 
                        // Increase counter of decompressed frames:
731
 
                        capdev->nrframes++;
732
 
                        
733
 
                        // Update avg. decompress time:
734
 
                        capdev->avg_decompresstime+=(tend - tstart);
735
 
                        
736
 
                        // Query capture timestamp in seconds:
737
 
                        // TODO: ARVideo doesn't provide such a timestamp. For now we just return the current
738
 
                        // system time as a lame replacement...
739
 
                        // On Windows there would be uint64 capdev->camera->g_Timestamp
740
 
                        PsychGetAdjustedPrecisionTimerSeconds(&(capdev->current_pts));
741
 
                }
742
 
 
743
 
                // Return availability status: 0 = new frame ready for retrieval. -1 = No new frame ready yet.
744
 
                return((capdev->frame_ready) ? 0 : -1);
745
 
    }
746
 
    
747
 
    // This point is only reached if checkForImage == FALSE, which only happens
748
 
    // if a new frame is available in our buffer:
749
 
    
750
 
    // Presentation timestamp requested?
751
 
    if (presentation_timestamp) {
752
 
                // Return it:
753
 
                *presentation_timestamp = capdev->current_pts;
754
 
    }
755
 
        
756
 
    // Synchronous texture fetch: Copy content of capture buffer into a texture:
757
 
    // =========================================================================
758
 
        
759
 
    // input_image points to the image buffer in our cam:
760
 
    input_image = (unsigned char*) (capdev->frame);
761
 
        
762
 
    // Do we want to do something with the image data and have a
763
 
    // scratch buffer for color conversion alloc'ed?
764
 
    if ((capdev->scratchbuffer) && ((out_texture) || (summed_intensity) || (outrawbuffer))) {
765
 
                // Yes. Perform color-conversion YUV->RGB from cameras DMA buffer
766
 
                // into the scratch buffer and set scratch buffer as source for
767
 
                // all further operations:
768
 
 
769
 
                memcpy(capdev->scratchbuffer, input_image, capdev->width * capdev->height * bpp);
770
 
                
771
 
                // Ok, at this point we should have a RGB8 texture image ready in scratch_buffer.
772
 
                // Set scratch buffer as our new image source for all further processing:
773
 
                input_image = (unsigned char*) capdev->scratchbuffer;
774
 
    }
775
 
        
776
 
    // Only setup if really a texture is requested (non-benchmarking mode):
777
 
    if (out_texture) {
778
 
                PsychMakeRect(out_texture->rect, 0, 0, w, h);    
779
 
                
780
 
                // Set NULL - special texture object as part of the PTB texture record:
781
 
                out_texture->targetSpecific.QuickTimeGLTexture = NULL;
782
 
                
783
 
                // Set texture orientation as if it were an inverted Offscreen window: Upside-down.
784
 
                out_texture->textureOrientation = 3;
785
 
                
786
 
                #if PSYCH_SYSTEM == PSYCH_WINDOWS
787
 
                // On Windows in non RGB32 bit modes, set orientation to Upright:
788
 
                out_texture->textureOrientation = (capdev->reqpixeldepth == 4) ? 3 : 2;
789
 
                #endif
790
 
 
791
 
                // Setup a pointer to our buffer as texture data pointer: Setting memsize to zero
792
 
                // prevents unwanted free() operation in PsychDeleteTexture...
793
 
                out_texture->textureMemorySizeBytes = 0;
794
 
                
795
 
                // Set texture depth: Could be 8, 16, 24 or 32 bpp.
796
 
                out_texture->depth = capdev->reqpixeldepth * 8;
797
 
                
798
 
                // This will retrieve an OpenGL compatible pointer to the pixel data and assign it to our texmemptr:
799
 
                out_texture->textureMemory = (GLuint*) input_image;
800
 
                
801
 
                // Let PsychCreateTexture() do the rest of the job of creating, setting up and
802
 
                // filling an OpenGL texture with content:
803
 
                PsychCreateTexture(out_texture);
804
 
                
805
 
                // Ready to use the texture...
806
 
    }
807
 
    
808
 
    // Sum of pixel intensities requested?
809
 
    if(summed_intensity) {
810
 
                pixptr = (unsigned char*) input_image;
811
 
                count  = w * h * bpp;
812
 
                for (i=0; i<count; i++) intensity+=(unsigned int) pixptr[i];
813
 
                *summed_intensity = ((double) intensity) / w / h / bpp;
814
 
    }
815
 
        
816
 
        // Raw data requested?
817
 
        if (outrawbuffer) {
818
 
                // Copy it out:
819
 
                outrawbuffer->w = w;
820
 
                outrawbuffer->h = h;
821
 
                outrawbuffer->depth = bpp;
822
 
                count = (w * h * outrawbuffer->depth);
823
 
                memcpy(outrawbuffer->data, (const void *) input_image, count);
824
 
        }
825
 
        
826
 
    // Release the capture buffer. Return it to the DMA ringbuffer pool:
827
 
        if (ar2VideoCapNext(capdev->camera) != DC1394_SUCCESS) {
828
 
                PsychErrorExitMsg(PsychError_system, "Re-Enqueuing processed video frame failed.");
829
 
        }
830
 
 
831
 
    // Update total count of dropped (or pending) frames:
832
 
    capdev->nr_droppedframes += capdev->current_dropped;
833
 
    nrdropped = capdev->current_dropped;
834
 
    capdev->current_dropped = 0;
835
 
        
836
 
    // Timestamping:
837
 
    PsychGetAdjustedPrecisionTimerSeconds(&tend);
838
 
        
839
 
    // Increase counter of retrieved textures:
840
 
    capdev->nrgfxframes++;
841
 
        
842
 
    // Update average time spent in texture conversion:
843
 
    capdev->avg_gfxtime+=(tend - tstart);
844
 
    
845
 
    // We're successfully done! Return number of dropped (or pending in DMA ringbuffer) frames:
846
 
    return(nrdropped);
847
 
}
848
 
 
849
 
// CHECKED
850
 
/* Set capture device specific parameters:
851
 
* Currently, the named parameters are a subset of the parameters supported by the
852
 
* IIDC specification, mapped to more convenient names.
853
 
*
854
 
* Input: pname = Name string to specify the parameter.
855
 
*        value = Either DBL_MAX to not set but only query the parameter, or some other
856
 
*                value, that we try to set in the Firewire camera.
857
 
*
858
 
* Returns: Old value of the setting
859
 
*/
860
 
double PsychARVideoCaptureSetParameter(int capturehandle, const char* pname, double value)
861
 
{
862
 
        unsigned int minval, maxval, intval, oldintval;
863
 
        int triggercount;
864
 
        
865
 
        double oldvalue = DBL_MAX; // Initialize return value to the "unknown/unsupported" default.
866
 
        psych_bool assigned = false;
867
 
        psych_bool present  = false;
868
 
        
869
 
        // Retrieve device record for handle:
870
 
        PsychVidcapRecordType* capdev = PsychGetARVidcapRecord(capturehandle);
871
 
        
872
 
        oldintval = 0xFFFFFFFF;
873
 
        
874
 
        // Round value to integer:
875
 
        intval = (int) (value + 0.5);
876
 
        
877
 
        // Check parameter name pname and call the appropriate subroutine:
878
 
        if (strcmp(pname, "TriggerCount")==0 || strcmp(pname, "WaitTriggerCount")==0) {
879
 
                // Query of cameras internal trigger counter or waiting for a specific
880
 
                // value in the counter requested. Trigger counters are special features,
881
 
                // (so called "Smart Features" or "Advanced Features" in the IIDC spec)
882
 
                // which are only available on selected cameras.
883
 
                // We currently only know how to do this on Basler cameras.
884
 
                return(-2);
885
 
        }
886
 
        
887
 
        if (strcmp(pname, "PrintParameters")==0) {
888
 
                // Special command: List and print all features...
889
 
                printf("PTB-INFO: The camera provides the following information and featureset:\n");
890
 
                ar2VideoDispOption();
891
 
                return(0);
892
 
        }
893
 
 
894
 
        // Return current framerate:
895
 
        if (strcmp(pname, "GetFramerate")==0) {
896
 
                PsychCopyOutDoubleArg(1, FALSE, capdev->fps);
897
 
                return(0);
898
 
        }
899
 
        
900
 
        // Return current ROI of camera, as requested (and potentially modified during
901
 
        // PsychOpenCaptureDevice(). This is a read-only parameter, as the ROI can
902
 
        // only be set during Screen('OpenVideoCapture').
903
 
        if (strcmp(pname, "GetROI")==0) {
904
 
                PsychCopyOutRectArg(1, FALSE, capdev->roirect);
905
 
                return(0);
906
 
        }
907
 
        
908
 
        // Return vendor name string:
909
 
        if (strcmp(pname, "GetVendorname")==0) {
910
 
                PsychCopyOutCharArg(1, FALSE, "Unknown Vendor");
911
 
                return(0);
912
 
        }
913
 
        
914
 
        // Return model name string:
915
 
        if (strcmp(pname, "GetModelname")==0) {
916
 
                PsychCopyOutCharArg(1, FALSE, "Unknown Model");
917
 
                return(0);
918
 
        }
919
 
        
920
 
//      if (strstr(pname, "Brightness")!=0) {
921
 
//              assigned = true;
922
 
//              feature = DC1394_FEATURE_BRIGHTNESS;    
923
 
//      }
924
 
//      
925
 
//      if (strstr(pname, "Gain")!=0) {
926
 
//              assigned = true;
927
 
//              feature = DC1394_FEATURE_GAIN;    
928
 
//      }
929
 
//      
930
 
//      if (strstr(pname, "Exposure")!=0) {
931
 
//              assigned = true;
932
 
//              feature = DC1394_FEATURE_EXPOSURE;    
933
 
//      }
934
 
//      
935
 
//      if (strstr(pname, "Shutter")!=0) {
936
 
//              assigned = true;
937
 
//              feature = DC1394_FEATURE_SHUTTER;    
938
 
//      }
939
 
//      
940
 
//      if (strstr(pname, "Sharpness")!=0) {
941
 
//              assigned = true;
942
 
//              feature = DC1394_FEATURE_SHARPNESS;    
943
 
//      }
944
 
//      
945
 
//      if (strstr(pname, "Saturation")!=0) {
946
 
//              assigned = true;
947
 
//              feature = DC1394_FEATURE_SATURATION;    
948
 
//      }
949
 
//      
950
 
//      if (strstr(pname, "Gamma")!=0) {
951
 
//              assigned = true;
952
 
//              feature = DC1394_FEATURE_GAMMA;    
953
 
//      }
954
 
        
955
 
        // Check if feature is present on this camera:
956
 
        // Not supported yet:
957
 
        present = FALSE;
958
 
        
959
 
//      if (dc1394_feature_is_present(capdev->camera, feature, &present)!=DC1394_SUCCESS) {
960
 
//              if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to query presence of feature %s on camera %i! Ignored.\n", pname, capturehandle);
961
 
//              fflush(NULL);
962
 
//      }
963
 
//      else
964
 
        
965
 
        if (present) {
966
 
                // Feature is available:
967
 
/*              
968
 
                // Retrieve current value:
969
 
                if (dc1394_feature_get_value(capdev->camera, feature, &oldintval)!=DC1394_SUCCESS) {
970
 
                        if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to query value of feature %s on camera %i! Ignored.\n", pname, capturehandle);
971
 
                        fflush(NULL);
972
 
                }
973
 
                else {      
974
 
                        // Do we want to set the value?
975
 
                        if (value != DBL_MAX) {
976
 
                                // Query allowed bounds for its value:
977
 
                                if (dc1394_feature_get_boundaries(capdev->camera, feature, &minval, &maxval)!=DC1394_SUCCESS) {
978
 
                                        if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to query valid value range for feature %s on camera %i! Ignored.\n", pname, capturehandle);
979
 
                                        fflush(NULL);
980
 
                                }
981
 
                                else {
982
 
                                        // Sanity check against range:
983
 
                                        if (intval < minval || intval > maxval) {
984
 
                                                if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Requested setting %i for parameter %s not in allowed range (%i - %i) for camera %i. Ignored.\n",
985
 
                                                                                                                                   intval, pname, minval, maxval, capturehandle);
986
 
                                                fflush(NULL);      
987
 
                                        }
988
 
                                        else {
989
 
                                                // Ok intval is valid for this feature: Can we manually set this feature?
990
 
                                                // Switch feature to manual control mode:
991
 
                                                if (dc1394_feature_set_mode(capdev->camera, feature, DC1394_FEATURE_MODE_MANUAL)!=DC1394_SUCCESS) {
992
 
                                                        if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to set feature %s on camera %i to manual control! Ignored.\n", pname, capturehandle);
993
 
                                                        fflush(NULL);
994
 
                                                }
995
 
                                                else {
996
 
                                                        // Ok, try to set the features new value:
997
 
                                                        if (dc1394_feature_set_value(capdev->camera, feature, intval)!=DC1394_SUCCESS) {
998
 
                                                                if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to set value of feature %s on camera %i to %i! Ignored.\n", pname, capturehandle,
999
 
                                                                                                                                                   intval);
1000
 
                                                                fflush(NULL);
1001
 
                                                        }
1002
 
                                                }
1003
 
                                        }
1004
 
                                }
1005
 
                        }
1006
 
                        else {
1007
 
                                // Don't want to set new value. Do we want to reset feature into auto-mode?
1008
 
                                // Prefixing a parameter name with "Auto"
1009
 
                                // does not switch the parameter into manual
1010
 
                                // control mode + set its value, as normal,
1011
 
                                // but it switches the parameter into automatic
1012
 
                                // mode, if automatic mode is supported by the
1013
 
                                // device.
1014
 
                                if (strstr(pname, "Auto")!=0) {
1015
 
                                        // Switch to automatic control requested - Try it:
1016
 
                                        if (dc1394_feature_set_mode(capdev->camera, feature, DC1394_FEATURE_MODE_AUTO)!=DC1394_SUCCESS) {
1017
 
                                                if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to set feature %s on camera %i to automatic control! Ignored.\n", pname, capturehandle);
1018
 
                                                fflush(NULL);
1019
 
                                        }
1020
 
                                }
1021
 
                        }
1022
 
                }
1023
 
*/
1024
 
        }
1025
 
        else {
1026
 
                if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Requested capture device setting %s not available on cam %i. Ignored.\n", pname, capturehandle);
1027
 
                fflush(NULL);
1028
 
        }
1029
 
        
1030
 
        // Output a warning on unknown parameters:
1031
 
        if (!assigned) {
1032
 
                if(PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Screen('SetVideoCaptureParameter', ...) called with unknown parameter %s. Ignored...\n",
1033
 
                                                                                                   pname);
1034
 
                fflush(NULL);
1035
 
        }
1036
 
        
1037
 
        if (assigned && oldintval!=0xFFFFFFFF) oldvalue = (double) oldintval;
1038
 
        
1039
 
        // Return the old value. Could be DBL_MAX if parameter was unknown or not accepted for some reason.
1040
 
        return(oldvalue);
1041
 
}
1042
 
 
1043
 
#endif