This URL has Read-Only access.

Statistics
| Branch: | Tag: | Revision:

root / src / gst / dc1394.cpp @ 1891a153

History | View | Annotate | Download (15.3 kB)

1
// dc1394.cpp
2
// Copyright (C) 2008-2009 Société des arts technologiques (SAT)
3
// http://www.sat.qc.ca
4
// All rights reserved.
5
//
6
// This file is part of [propulse]ART.
7
//
8
// [propulse]ART is free software: you can redistribute it and/or modify
9
// it under the terms of the GNU General Public License as published by
10
// the Free Software Foundation, either version 3 of the License, or
11
// (at your option) any later version.
12
//
13
// [propulse]ART is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
// GNU General Public License for more details.
17
//
18
// You should have received a copy of the GNU General Public License
19
// along with [propulse]ART.  If not, see <http://www.gnu.org/licenses/>.
20
//
21

    
22
#include "util.h"
23
#include "dc1394.h"
24
#include "noncopyable.h"
25

    
26
#include <boost/filesystem/operations.hpp>
27
#include <fstream>
28
#include <dc1394/control.h>
29
#include <libraw1394/raw1394.h>
30
#include <iomanip>
31

    
32
class Dc1394Handle : boost::noncopyable {
33
    public:
34
        // camera-less version
35
        Dc1394Handle() : cameraId_(0), dc1394_(0), cameras_(0), camera_(0)
36
        {
37
            // override log handler to catch library errors
38
            dc1394log_t type = DC1394_LOG_ERROR;
39
            dc1394_log_register_handler(type, log_handler, 0);
40

    
41
            dc1394_ = dc1394_new();
42
            if (dc1394_ == 0)
43
                LOG_ERROR("Could not get handle to dc1394, are /dev/raw1394 and /dev/video1394 present?");
44
            dc1394error_t camerr = dc1394_camera_enumerate(dc1394_, &cameras_);
45
            if (camerr != DC1394_SUCCESS or cameras_ == 0)
46
                LOG_ERROR("Can't find cameras error : " << camerr);
47
        }
48

    
49
        explicit Dc1394Handle(int id) : cameraId_(id), dc1394_(0), cameras_(0), camera_(0)
50
        {
51
            // override log handler to catch library errors
52
            dc1394log_t type = DC1394_LOG_ERROR;
53
            dc1394_log_register_handler(type, log_handler, 0);
54

    
55
            if (cameraId_ < 0)
56
                LOG_ERROR("Invalid camera id " << cameraId_);
57
            dc1394_ = dc1394_new();
58
            if (dc1394_ == 0)
59
                LOG_ERROR("Could not get handle to dc1394, are /dev/raw1394 and /dev/video1394 present?");
60
            dc1394error_t camerr = dc1394_camera_enumerate(dc1394_, &cameras_);
61
            if (camerr != DC1394_SUCCESS or cameras_ == 0)
62
                LOG_ERROR("Can't find cameras error : " << camerr);
63

    
64
            if (cameras_->num > 0)
65
            {
66
                camera_ = dc1394_camera_new_unit(dc1394_, cameras_->ids[cameraId_].guid, cameras_->ids[cameraId_].unit);
67
                if (camera_ == 0)
68
                    LOG_ERROR("Could not get handle to dc1394 camera");
69
            }
70
        }
71

    
72
        ~Dc1394Handle() 
73
        {
74
            LOG_DEBUG("Destroying dc1394handle");
75
            if (camera_ != 0) 
76
                dc1394_camera_free(camera_);
77
            if (cameras_ != 0)
78
                dc1394_camera_free_list(cameras_);
79
            if (dc1394_ != 0)
80
                dc1394_free(dc1394_);
81
        }
82

    
83
        unsigned long long guid() const
84
        {
85
            if (cameraId_ >= 0)
86
                return cameras_->ids[cameraId_].guid;
87
            else
88
            {
89
                LOG_ERROR("Cannot get guid for invalid camera id " << cameraId_);
90
                return 0;
91
            }
92
        }
93

    
94
        int nCameras() const
95
        {
96
            if (cameras_ == 0)
97
                LOG_ERROR("Cannot query number of cameras");
98
            return cameras_->num;
99
        }
100

    
101
        void printInfo() const;
102

    
103
        int capsToMode(int width, int height, 
104
                const std::string &colourspace, int framerate) const;
105

    
106
    private:
107
        static void log_handler(dc1394log_t /*type*/, const char *message, void * /*user*/)
108
        {
109
            LOG_DEBUG(message);
110
        }
111

    
112
        int cameraId_;
113
        dc1394_t * dc1394_; 
114
        dc1394camera_list_t * cameras_;
115
        dc1394camera_t * camera_; 
116
};
117

    
118

    
119
int dc1394_caps_print_format_vmode_caps(int mode)
120
{
121
    int retval = 0;
122

    
123
    switch (mode) 
124
    {
125
#define PRINT_CASE(x) \
126
        case (DC1394_VIDEO_MODE_ ##x): \
127
                                       LOG_PRINT("    " << # x << " (vmode " << mode << ")" << std::endl); \
128
        break
129

    
130
        PRINT_CASE(160x120_YUV444);
131
        PRINT_CASE(320x240_YUV422);
132
        PRINT_CASE(640x480_YUV411);
133
        PRINT_CASE(640x480_YUV422);
134
        PRINT_CASE(640x480_RGB8);
135
        PRINT_CASE(640x480_MONO8);
136
        PRINT_CASE(640x480_MONO16);
137
        PRINT_CASE(800x600_YUV422);
138
        PRINT_CASE(800x600_RGB8);
139
        PRINT_CASE(800x600_MONO8);
140
        PRINT_CASE(1024x768_YUV422);
141
        PRINT_CASE(1024x768_RGB8);
142
        PRINT_CASE(1024x768_MONO8);
143
        PRINT_CASE(800x600_MONO16);
144
        PRINT_CASE(1024x768_MONO16);
145
        PRINT_CASE(1280x960_YUV422);
146
        PRINT_CASE(1280x960_RGB8);
147
        PRINT_CASE(1280x960_MONO8);
148
        PRINT_CASE(1600x1200_YUV422);
149
        PRINT_CASE(1600x1200_RGB8);
150
        PRINT_CASE(1600x1200_MONO8);
151
        PRINT_CASE(1280x960_MONO16);
152
        PRINT_CASE(1600x1200_MONO16);
153

    
154
        default:
155
        LOG_WARNING("Unknown vmode " << mode);
156
        retval = -1;
157
    }
158
    return retval;
159
#undef PRINT_CASE
160
}
161

    
162

    
163
/// FIXME: add checks for other framerates
164
bool modeIsSupported(int mode, const dc1394video_modes_t &supportedModes, 
165
        int framerate, dc1394camera_t *camera)
166
{
167
    bool frameratesMatch = false;
168
    for (int i = supportedModes.num - 1; i >= 0; --i)
169
    {
170
        int m = supportedModes.modes[i];
171
        if (m < DC1394_VIDEO_MODE_EXIF) 
172
        {
173
            if (m == mode)
174
            {
175
                dc1394framerates_t framerates;
176
                dc1394_video_get_supported_framerates(camera,
177
                        (dc1394video_mode_t) m, &framerates);
178
                for (unsigned framerateIdx = 0; 
179
                        not frameratesMatch and framerateIdx < framerates.num;
180
                        ++framerateIdx)
181
                {
182
                    switch (framerates.framerates[framerateIdx])
183
                    {
184
                        case DC1394_FRAMERATE_30:
185
                            frameratesMatch = (framerate == 30);
186
                            break;
187
                        case DC1394_FRAMERATE_15:
188
                            frameratesMatch = (framerate == 15);
189
                            break;
190
                        default:
191
                            break;
192
                    }
193
                }
194
            }
195
        }
196
    }
197
    if (not frameratesMatch)
198
        LOG_WARNING("So far only 15 fps and 30 fps are supported");
199
    return frameratesMatch;
200
}
201

    
202

    
203
/// FIXME: have all the modes here and this will also depend on framerate
204
bool Dc1394::requiresMoreISOSpeed(int mode)
205
{
206
    switch (mode)
207
    {
208
        // using fall through instead of logical or
209
        case DC1394_VIDEO_MODE_1280x960_MONO16:
210
        case DC1394_VIDEO_MODE_1280x960_MONO8:
211
        case DC1394_VIDEO_MODE_1280x960_RGB8:
212
        case DC1394_VIDEO_MODE_1280x960_YUV422:
213
        case DC1394_VIDEO_MODE_1024x768_MONO16:
214
        case DC1394_VIDEO_MODE_1024x768_MONO8:
215
        case DC1394_VIDEO_MODE_1024x768_RGB8:
216
        case DC1394_VIDEO_MODE_1024x768_YUV422:
217
        case DC1394_VIDEO_MODE_800x600_RGB8:
218
            return true;
219
        default:
220
            return false;
221
    }
222
}
223

    
224
int Dc1394::capsToMode(int cameraId, int width, int height, 
225
        const std::string &colourspace, int framerate)
226
{
227
    Dc1394Handle dc(cameraId);
228
    return dc.capsToMode(width, height, colourspace, framerate);
229
}
230

    
231
/// FIXME: replace with table-driven method
232
int Dc1394Handle::capsToMode(int width, int height, 
233
        const std::string &colourspace, int framerate) const
234
{
235
    int mode = 0;
236
    dc1394video_modes_t modes;
237
    dc1394error_t camerr;
238

    
239
    camerr = dc1394_video_get_supported_modes(camera_, &modes);
240
    if (camerr != DC1394_SUCCESS) 
241
        LOG_ERROR("Error getting supported modes\n");
242

    
243
#define RETURN_MODE_FROM_CAPS(WIDTH, HEIGHT, COLOURSPACE)  \
244
    (width == (WIDTH) and height == (HEIGHT))  \
245
    {                                             \
246
        int testMode = DC1394_VIDEO_MODE_ ## WIDTH ##x ## HEIGHT ##_ ## COLOURSPACE; \
247
        if (modeIsSupported(testMode, modes, framerate, camera_))    \
248
        {                                       \
249
            mode = testMode;                    \
250
            LOG_DEBUG("Using mode " << mode);   \
251
            return mode;        \
252
        }   \
253
    } 
254

    
255
    if (colourspace == "yuv")
256
    {
257
        // 640x480 first because it's the nominal case)
258
        // FIXME: should be else ifs unless resolutions match
259
        if RETURN_MODE_FROM_CAPS(640, 480, YUV422);
260
        if RETURN_MODE_FROM_CAPS(640, 480, YUV411);
261
        if RETURN_MODE_FROM_CAPS(160, 120, YUV444);
262
        if RETURN_MODE_FROM_CAPS(320, 240, YUV422);
263
        if RETURN_MODE_FROM_CAPS(800, 600, YUV422);
264
        if RETURN_MODE_FROM_CAPS(1024, 768, YUV422);
265
        if RETURN_MODE_FROM_CAPS(1280, 960, YUV422);
266
        if RETURN_MODE_FROM_CAPS(1600, 1200, YUV422);
267
        LOG_DEBUG("Colourspace " << colourspace << " and resolution "
268
                << width << "x" << height << " are not supported by this camera");
269
    }
270
    else if (colourspace == "gray")
271
    {
272
        // not else if because resolutions are the same
273
        if RETURN_MODE_FROM_CAPS(640, 480, MONO8);
274
        if RETURN_MODE_FROM_CAPS(640, 480, MONO16);
275
        if RETURN_MODE_FROM_CAPS(800, 600, MONO8);
276
        if RETURN_MODE_FROM_CAPS(800, 600, MONO16);
277
        if RETURN_MODE_FROM_CAPS(1024, 768, MONO8);
278
        if RETURN_MODE_FROM_CAPS(1024, 768, MONO16);
279
        if RETURN_MODE_FROM_CAPS(1280, 960, MONO8);
280
        if RETURN_MODE_FROM_CAPS(1600, 1200, MONO8);
281
        if RETURN_MODE_FROM_CAPS(1280, 960, MONO16);
282
        // FIXME:
283
        // This could be supported but won't work unless you use
284
        // dc1394_video_set_operation_mode(camera->camera_info, DC1394_OPERATION_MODE_1394B);
285
        // and then increase the ISO speed to 800
286
        // dc1394_video_set_iso_speed(camera->camera_info,DC1394_ISO_SPEED_800);
287
        if RETURN_MODE_FROM_CAPS(1600, 1200, MONO16);
288
        LOG_WARNING("Colourspace " << colourspace << " and resolution " <<
289
                width << "x" << height << " are not supported by this camera");
290
    }
291
    else if (colourspace == "rgb")
292
    {
293
        if RETURN_MODE_FROM_CAPS(640, 480, RGB8);
294
        if RETURN_MODE_FROM_CAPS(800, 600, RGB8);
295
        if RETURN_MODE_FROM_CAPS(1024, 768, RGB8);
296
        if RETURN_MODE_FROM_CAPS(1280, 960, RGB8);
297
        if RETURN_MODE_FROM_CAPS(1600, 1200, RGB8);
298
        LOG_WARNING("Colourspace " << colourspace << " and resolution " << 
299
                width << "x" << height << " are not supported by this camera");
300
    }
301
    else
302
        THROW_ERROR("Invalid colourspace " << colourspace);
303

    
304
#undef RETURN_MODE_FROM_CAPS
305
    return 0;   /// never gets called
306
}
307

    
308

    
309
void printSupportedFramerates(dc1394framerates_t framerates)
310
{
311
    LOG_PRINT("    Framerates: ");
312
    std::string delimiter;
313

    
314
#define PRINT_CASE_FRACTION(whole, fraction) \
315
    case (DC1394_FRAMERATE_ ## whole ## _ ## fraction): \
316
        LOG_PRINT(# whole  << "." << # fraction); \
317
    break
318

    
319
#define PRINT_CASE(whole) \
320
    case (DC1394_FRAMERATE_ ## whole): \
321
       LOG_PRINT(# whole); \
322
    break
323

    
324
    for (unsigned framerateIdx = 0; framerateIdx < framerates.num; ++framerateIdx)
325
    {
326
        LOG_PRINT(delimiter);
327
        switch (framerates.framerates[framerateIdx])
328
        {
329

    
330
            PRINT_CASE_FRACTION(1, 875);
331
            PRINT_CASE_FRACTION(3, 75);
332
            PRINT_CASE_FRACTION(7, 5);
333
            PRINT_CASE(15);
334
            PRINT_CASE(30);
335
            PRINT_CASE(60);
336
            PRINT_CASE(120);
337
            PRINT_CASE(240);
338
        }
339
        delimiter = ",";
340
    }
341
    LOG_PRINT("\n");
342
#undef PRINT_CASE
343
#undef PRINT_CASE_FRACTION
344
}
345

    
346
bool isModuleReadable(const std::string &module)
347
{
348
    std::string path("/dev/" + module);
349
    std::ifstream input(path.c_str());
350
    bool readable = input.good();
351
    input.close();
352
    return readable;
353
}
354

    
355

    
356
bool isModuleWriteable(const std::string &module)
357
{
358
    std::string path("/dev/" + module);
359
    std::ofstream output(path.c_str());
360
    bool writeable = output.good();
361
    output.close();
362
    return writeable;
363
}
364

    
365

    
366
/// Returns true if cameras were found
367
bool Dc1394::listCameras()
368
{
369
    LOG_DEBUG("listing cameras");
370

    
371
    // make sure raw1394 is loaded and read/writeable
372
    raw1394handle_t tmpHandle = raw1394_new_handle();
373
    if (tmpHandle == NULL) 
374
    {
375
        // if module is present but permissions aren't good, print a warning
376
        // otherwise don't do anything
377
        if (boost::filesystem::exists("/dev/raw1394"))
378
        {
379
            if (boost::filesystem::exists("/dev/video1394"))
380
            {
381
                if (not isModuleReadable("raw1394"))
382
                    LOG_WARNING("Module raw1394 is not readable");
383
                if (not isModuleWriteable("raw1394"))
384
                    LOG_WARNING("Module raw1394 is not writeable");
385
                if (not isModuleReadable("video1394"))
386
                    LOG_WARNING("Module video1394 is not readable");
387
            }
388
            else
389
                LOG_WARNING("Module video1394 is not loaded.");
390
        }
391
        else if (boost::filesystem::exists("/dev/video1394"))
392
            LOG_WARNING("Module raw1394 is not loaded.");
393
        else
394
            LOG_DEBUG("Neither raw1394 nor video1394 modules are loaded");
395
        // do nothing, neither module is loaded, we can assume no firewire utilization
396
        return false;
397
    }
398
    else
399
        raw1394_destroy_handle(tmpHandle);
400
    
401
    int nCameras = Dc1394::nCameras();
402

    
403
    for (int i = 0; i != nCameras; ++i)
404
    {
405
        Dc1394Handle dc(i);
406
        dc.printInfo();
407
    }
408
    return nCameras > 0;
409
}
410

    
411
void Dc1394Handle::printInfo() const
412
{
413
    if (camera_ != 0)
414
    {
415
        dc1394video_modes_t modes;
416
        dc1394framerates_t framerates;
417
        LOG_PRINT("\nDC1394 Camera " << cameraId_ << ": " 
418
                << camera_->vendor << " " << camera_->model << std::endl);
419
        LOG_PRINT("GUID = " << std::hex << guid() << std::endl);
420
        dc1394error_t camerr = dc1394_video_get_supported_modes(camera_, &modes);
421

    
422
        if (camerr != DC1394_SUCCESS) 
423
            LOG_ERROR("Error getting supported modes\n");
424

    
425
        LOG_PRINT("Supported modes :\n");
426
        for (int i = modes.num - 1; i >= 0; --i)
427
        {
428
            int m = modes.modes[i];
429

    
430
            if (m < DC1394_VIDEO_MODE_EXIF) 
431
            {
432
                if (dc1394_caps_print_format_vmode_caps(m) < 0)
433
                    LOG_ERROR("attempt to query mode " << m << " failed");
434

    
435
                camerr = dc1394_video_get_supported_framerates(camera_,
436
                        (dc1394video_mode_t) m, &framerates);
437
                if (camerr != DC1394_SUCCESS)
438
                    LOG_ERROR("dc1394 error : " << camerr);
439
                printSupportedFramerates(framerates);
440
            }
441
        }
442
    }
443
}
444

    
445
int Dc1394::nCameras()
446
{
447
    Dc1394Handle dc;
448
    return dc.nCameras();
449
}
450

    
451
bool Dc1394::areCamerasConnected()
452
{
453
    return nCameras() != 0;
454
}
455

    
456

    
457
int Dc1394::GUIDToCameraNumber(unsigned long long GUID)
458
{
459
    int result = -1;
460
    bool found = false;
461
    int nCameras = Dc1394::nCameras();
462

    
463
    for (int i = 0; not found && i != nCameras; ++i)
464
    {
465
        Dc1394Handle dc(i);
466
        LOG_DEBUG("GUID = " << std::hex << dc.guid());
467

    
468
        if (GUID == dc.guid())
469
        {
470
            result = i;
471
            found = true;
472
        }
473
    }
474

    
475
    if (result == -1)
476
        THROW_ERROR("Could not find camera with guid " << std::hex << GUID);
477

    
478
    return result;
479
}