~jocave/checkbox/hybrid-amd-gpu-mods

« back to all changes in this revision

Viewing changes to providers/plainbox-provider-checkbox/bin/camera_test_legacy

  • Committer: Sylvain Pineau
  • Author(s): Taihsiang Ho
  • Date: 2016-05-13 10:02:14 UTC
  • mfrom: (4337.2.2 checkbox)
  • Revision ID: sylvain_pineau-20160513100214-k1bq7iwk9lcdhtfa
"automatic merge of lp:~taihsiangho/checkbox/fix1578136-camera-test-failed-resurrect-for-precise/ by tarmac [r=sylvain-pineau][bug=1578136][author=taihsiangho]"

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python3
 
2
#
 
3
# This file is part of Checkbox.
 
4
#
 
5
# Copyright 2008-2012 Canonical Ltd.
 
6
#
 
7
# The v4l2 ioctl code comes from the Python bindings for the v4l2
 
8
# userspace api (http://pypi.python.org/pypi/v4l2):
 
9
# Copyright (C) 1999-2009 the contributors
 
10
#
 
11
# The JPEG metadata parser is a part of bfg-pages:
 
12
# http://code.google.com/p/bfg-pages/source/browse/trunk/pages/getimageinfo.py
 
13
# Copyright (C) Tim Hoffman
 
14
#
 
15
# Checkbox is free software: you can redistribute it and/or modify
 
16
# it under the terms of the GNU General Public License version 3,
 
17
# as published by the Free Software Foundation.
 
18
 
 
19
#
 
20
# Checkbox is distributed in the hope that it will be useful,
 
21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
23
# GNU General Public License for more details.
 
24
#
 
25
# You should have received a copy of the GNU General Public License
 
26
# along with Checkbox.  If not, see <http://www.gnu.org/licenses/>.
 
27
#
 
28
 
 
29
import argparse
 
30
import ctypes
 
31
import errno
 
32
import fcntl
 
33
import imghdr
 
34
import logging
 
35
import os
 
36
import re
 
37
import struct
 
38
import sys
 
39
import time
 
40
 
 
41
from gi.repository import GObject
 
42
from glob import glob
 
43
from subprocess import check_call, CalledProcessError, STDOUT
 
44
from tempfile import NamedTemporaryFile
 
45
 
 
46
 
 
47
_IOC_NRBITS = 8
 
48
_IOC_TYPEBITS = 8
 
49
_IOC_SIZEBITS = 14
 
50
 
 
51
_IOC_NRSHIFT = 0
 
52
_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
 
53
_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
 
54
_IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
 
55
 
 
56
_IOC_WRITE = 1
 
57
_IOC_READ = 2
 
58
 
 
59
 
 
60
def _IOC(dir_, type_, nr, size):
 
61
    return (
 
62
        ctypes.c_int32(dir_ << _IOC_DIRSHIFT).value |
 
63
        ctypes.c_int32(ord(type_) << _IOC_TYPESHIFT).value |
 
64
        ctypes.c_int32(nr << _IOC_NRSHIFT).value |
 
65
        ctypes.c_int32(size << _IOC_SIZESHIFT).value)
 
66
 
 
67
 
 
68
def _IOC_TYPECHECK(t):
 
69
    return ctypes.sizeof(t)
 
70
 
 
71
 
 
72
def _IOR(type_, nr, size):
 
73
    return _IOC(_IOC_READ, type_, nr, ctypes.sizeof(size))
 
74
 
 
75
 
 
76
def _IOWR(type_, nr, size):
 
77
    return _IOC(_IOC_READ | _IOC_WRITE, type_, nr, _IOC_TYPECHECK(size))
 
78
 
 
79
 
 
80
class v4l2_capability(ctypes.Structure):
 
81
    """
 
82
    Driver capabilities
 
83
    """
 
84
    _fields_ = [
 
85
        ('driver', ctypes.c_char * 16),
 
86
        ('card', ctypes.c_char * 32),
 
87
        ('bus_info', ctypes.c_char * 32),
 
88
        ('version', ctypes.c_uint32),
 
89
        ('capabilities', ctypes.c_uint32),
 
90
        ('reserved', ctypes.c_uint32 * 4),
 
91
    ]
 
92
 
 
93
 
 
94
# Values for 'capabilities' field
 
95
V4L2_CAP_VIDEO_CAPTURE = 0x00000001
 
96
V4L2_CAP_VIDEO_OVERLAY = 0x00000004
 
97
V4L2_CAP_READWRITE = 0x01000000
 
98
V4L2_CAP_STREAMING = 0x04000000
 
99
 
 
100
v4l2_frmsizetypes = ctypes.c_uint
 
101
(
 
102
    V4L2_FRMSIZE_TYPE_DISCRETE,
 
103
    V4L2_FRMSIZE_TYPE_CONTINUOUS,
 
104
    V4L2_FRMSIZE_TYPE_STEPWISE,
 
105
) = range(1, 4)
 
106
 
 
107
 
 
108
class v4l2_frmsize_discrete(ctypes.Structure):
 
109
    _fields_ = [
 
110
        ('width', ctypes.c_uint32),
 
111
        ('height', ctypes.c_uint32),
 
112
    ]
 
113
 
 
114
 
 
115
class v4l2_frmsize_stepwise(ctypes.Structure):
 
116
    _fields_ = [
 
117
        ('min_width', ctypes.c_uint32),
 
118
        ('min_height', ctypes.c_uint32),
 
119
        ('step_width', ctypes.c_uint32),
 
120
        ('min_height', ctypes.c_uint32),
 
121
        ('max_height', ctypes.c_uint32),
 
122
        ('step_height', ctypes.c_uint32),
 
123
    ]
 
124
 
 
125
 
 
126
class v4l2_frmsizeenum(ctypes.Structure):
 
127
    class _u(ctypes.Union):
 
128
        _fields_ = [
 
129
            ('discrete', v4l2_frmsize_discrete),
 
130
            ('stepwise', v4l2_frmsize_stepwise),
 
131
        ]
 
132
 
 
133
    _fields_ = [
 
134
        ('index', ctypes.c_uint32),
 
135
        ('pixel_format', ctypes.c_uint32),
 
136
        ('type', ctypes.c_uint32),
 
137
        ('_u', _u),
 
138
        ('reserved', ctypes.c_uint32 * 2)
 
139
    ]
 
140
 
 
141
    _anonymous_ = ('_u',)
 
142
 
 
143
 
 
144
class v4l2_fmtdesc(ctypes.Structure):
 
145
    _fields_ = [
 
146
        ('index', ctypes.c_uint32),
 
147
        ('type', ctypes.c_int),
 
148
        ('flags', ctypes.c_uint32),
 
149
        ('description', ctypes.c_char * 32),
 
150
        ('pixelformat', ctypes.c_uint32),
 
151
        ('reserved', ctypes.c_uint32 * 4),
 
152
    ]
 
153
 
 
154
V4L2_FMT_FLAG_COMPRESSED = 0x0001
 
155
V4L2_FMT_FLAG_EMULATED = 0x0002
 
156
 
 
157
# ioctl code for video devices
 
158
VIDIOC_QUERYCAP = _IOR('V', 0, v4l2_capability)
 
159
VIDIOC_ENUM_FRAMESIZES = _IOWR('V', 74, v4l2_frmsizeenum)
 
160
VIDIOC_ENUM_FMT = _IOWR('V', 2, v4l2_fmtdesc)
 
161
 
 
162
 
 
163
class CameraTest:
 
164
    """
 
165
    A simple class that displays a test image via GStreamer.
 
166
    """
 
167
    def __init__(self, args, gst_plugin=None, gst_video_type=None):
 
168
        self.args = args
 
169
        self._mainloop = GObject.MainLoop()
 
170
        self._width = 640
 
171
        self._height = 480
 
172
        self._gst_plugin = gst_plugin
 
173
        self._gst_video_type = gst_video_type
 
174
 
 
175
    def detect(self):
 
176
        """
 
177
        Display information regarding webcam hardware
 
178
        """
 
179
        cap_status = dev_status = 1
 
180
        for i in range(10):
 
181
            cp = v4l2_capability()
 
182
            device = '/dev/video%d' % i
 
183
            try:
 
184
                with open(device, 'r') as vd:
 
185
                    fcntl.ioctl(vd, VIDIOC_QUERYCAP, cp)
 
186
            except IOError:
 
187
                continue
 
188
            dev_status = 0
 
189
            print("%s: OK" % device)
 
190
            print("    name   : %s" % cp.card.decode('UTF-8'))
 
191
            print("    driver : %s" % cp.driver.decode('UTF-8'))
 
192
            print("    version: %s.%s.%s"
 
193
                  % (cp.version >> 16,
 
194
                    (cp.version >> 8) & 0xff,
 
195
                     cp.version & 0xff))
 
196
            print("    flags  : 0x%x [" % cp.capabilities,
 
197
                  ' CAPTURE' if cp.capabilities & V4L2_CAP_VIDEO_CAPTURE
 
198
                  else '',
 
199
                  ' OVERLAY' if cp.capabilities & V4L2_CAP_VIDEO_OVERLAY
 
200
                  else '',
 
201
                  ' READWRITE' if cp.capabilities & V4L2_CAP_READWRITE
 
202
                  else '',
 
203
                  ' STREAMING' if cp.capabilities & V4L2_CAP_STREAMING
 
204
                  else '',
 
205
                  ' ]', sep="")
 
206
 
 
207
            resolutions = self._get_supported_resolutions(device)
 
208
            print('    ',
 
209
                  self._supported_resolutions_to_string(resolutions).replace(
 
210
                      "\n", " "),
 
211
                  sep="")
 
212
 
 
213
            if cp.capabilities & V4L2_CAP_VIDEO_CAPTURE:
 
214
                cap_status = 0
 
215
        return dev_status | cap_status
 
216
 
 
217
    def led(self):
 
218
        """
 
219
        Activate camera (switch on led), but don't display any output
 
220
        """
 
221
        pipespec = ("v4l2src device=%(device)s "
 
222
                    "! %(type)s "
 
223
                    "! %(plugin)s "
 
224
                    "! testsink"
 
225
                    % {'device': self.args.device,
 
226
                       'type': self._gst_video_type,
 
227
                       'plugin': self._gst_plugin})
 
228
        logging.debug("LED test with pipeline %s", pipespec)
 
229
        self._pipeline = Gst.parse_launch(pipespec)
 
230
        self._pipeline.set_state(Gst.State.PLAYING)
 
231
        time.sleep(3)
 
232
        self._pipeline.set_state(Gst.State.NULL)
 
233
 
 
234
    def display(self):
 
235
        """
 
236
        Displays the preview window
 
237
        """
 
238
        pipespec = ("v4l2src device=%(device)s "
 
239
                    "! %(type)s,width=%(width)d,height=%(height)d "
 
240
                    "! %(plugin)s "
 
241
                    "! autovideosink"
 
242
                    % {'device': self.args.device,
 
243
                       'type': self._gst_video_type,
 
244
                       'width': self._width,
 
245
                       'height': self._height,
 
246
                       'plugin': self._gst_plugin})
 
247
        logging.debug("display test with pipeline %s", pipespec)
 
248
        self._pipeline = Gst.parse_launch(pipespec)
 
249
        self._pipeline.set_state(Gst.State.PLAYING)
 
250
        time.sleep(10)
 
251
        self._pipeline.set_state(Gst.State.NULL)
 
252
 
 
253
    def still(self):
 
254
        """
 
255
        Captures an image to a file
 
256
        """
 
257
        if self.args.filename:
 
258
            self._still_helper(self.args.filename, self._width, self._height,
 
259
                               self.args.quiet)
 
260
        else:
 
261
            with NamedTemporaryFile(prefix='camera_test_', suffix='.jpg') as f:
 
262
                self._still_helper(f.name, self._width, self._height,
 
263
                                   self.args.quiet)
 
264
 
 
265
    def _still_helper(self, filename, width, height, quiet, pixelformat=None):
 
266
        """
 
267
        Captures an image to a given filename.  width and height specify the
 
268
        image size and quiet controls whether the image is displayed to the
 
269
        user (quiet = True means do not display image).
 
270
        """
 
271
        command = ["fswebcam", "-D 1", "-S 50", "--no-banner",
 
272
                   "-d", self.args.device,
 
273
                   "-r", "%dx%d"
 
274
                   % (width, height), filename]
 
275
        use_gstreamer = False
 
276
        if pixelformat:
 
277
            if 'MJPG' == pixelformat:  # special tweak for fswebcam
 
278
                pixelformat = 'MJPEG'
 
279
            command.extend(["-p", pixelformat])
 
280
 
 
281
        try:
 
282
            check_call(command, stdout=open(os.devnull, 'w'), stderr=STDOUT)
 
283
        except (CalledProcessError, OSError):
 
284
            use_gstreamer = True
 
285
 
 
286
        if use_gstreamer:
 
287
            pipespec = ("v4l2src device=%(device)s "
 
288
                        "! %(type)s,width=%(width)d,height=%(height)d "
 
289
                        "! %(plugin)s "
 
290
                        "! jpegenc "
 
291
                        "! filesink location=%(filename)s"
 
292
                        % {'device': self.args.device,
 
293
                           'type': self._gst_video_type,
 
294
                           'width': width,
 
295
                           'height': height,
 
296
                           'plugin': self._gst_plugin,
 
297
                           'filename': filename})
 
298
            logging.debug("still test with gstreamer and "
 
299
                          "pipeline %s", pipespec)
 
300
            self._pipeline = Gst.parse_launch(pipespec)
 
301
            self._pipeline.set_state(Gst.State.PLAYING)
 
302
            time.sleep(3)
 
303
            self._pipeline.set_state(Gst.State.NULL)
 
304
 
 
305
        if not quiet:
 
306
            import imghdr
 
307
            image_type = imghdr.what(filename)
 
308
            pipespec = ("filesrc location=%(filename)s ! "
 
309
                        "%(type)sdec ! "
 
310
                        "videoscale ! "
 
311
                        "imagefreeze ! autovideosink"
 
312
                        % {'filename': filename,
 
313
                           'type': image_type})
 
314
            self._pipeline = Gst.parse_launch(pipespec)
 
315
            self._pipeline.set_state(Gst.State.PLAYING)
 
316
            time.sleep(10)
 
317
            self._pipeline.set_state(Gst.State.NULL)
 
318
 
 
319
    def _supported_resolutions_to_string(self, supported_resolutions):
 
320
        """
 
321
        Return a printable string representing a list of supported resolutions
 
322
        """
 
323
        ret = ""
 
324
        for resolution in supported_resolutions:
 
325
            ret += "Format: %s (%s)\n" % (resolution['pixelformat'],
 
326
                   resolution['description'])
 
327
            ret += "Resolutions: "
 
328
            for res in resolution['resolutions']:
 
329
                ret += "%sx%s," % (res[0], res[1])
 
330
            # truncate the extra comma with :-1
 
331
            ret = ret[:-1] + "\n"
 
332
        return ret
 
333
 
 
334
    def resolutions(self):
 
335
        """
 
336
        After querying the webcam for supported formats and resolutions,
 
337
        take multiple images using the first format returned by the driver,
 
338
        and see if they are valid
 
339
        """
 
340
        resolutions = self._get_supported_resolutions(self.args.device)
 
341
        # print supported formats and resolutions for the logs
 
342
        print(self._supported_resolutions_to_string(resolutions))
 
343
 
 
344
        # pick the first format, which seems to be what the driver wants for a
 
345
        # default.  This also matches the logic that fswebcam uses to select
 
346
        # a default format.
 
347
        resolution = resolutions[0]
 
348
        if resolution:
 
349
            print("Taking multiple images using the %s format"
 
350
                  % resolution['pixelformat'])
 
351
            for res in resolution['resolutions']:
 
352
                w = res[0]
 
353
                h = res[1]
 
354
                f = NamedTemporaryFile(prefix='camera_test_%s%sx%s' %
 
355
                                       (resolution['pixelformat'], w, h),
 
356
                                       suffix='.jpg', delete=False)
 
357
                print("Taking a picture at %sx%s" % (w, h))
 
358
                self._still_helper(f.name, w, h, True,
 
359
                                   pixelformat=resolution['pixelformat'])
 
360
                if self._validate_image(f.name, w, h):
 
361
                    print("Validated image %s" % f.name)
 
362
                    os.remove(f.name)
 
363
                else:
 
364
                    print("Failed to validate image %s" % f.name,
 
365
                          file=sys.stderr)
 
366
                    os.remove(f.name)
 
367
                    return 1
 
368
            return 0
 
369
 
 
370
    def _get_pixel_formats(self, device, maxformats=5):
 
371
        """
 
372
        Query the camera to see what pixel formats it supports.  A list of
 
373
        dicts is returned consisting of format and description.  The caller
 
374
        should check whether this camera supports VIDEO_CAPTURE before
 
375
        calling this function.
 
376
        """
 
377
        supported_formats = []
 
378
        fmt = v4l2_fmtdesc()
 
379
        fmt.index = 0
 
380
        fmt.type = V4L2_CAP_VIDEO_CAPTURE
 
381
        try:
 
382
            while fmt.index < maxformats:
 
383
                with open(device, 'r') as vd:
 
384
                    if fcntl.ioctl(vd, VIDIOC_ENUM_FMT, fmt) == 0:
 
385
                        pixelformat = {}
 
386
                        # save the int type for re-use later
 
387
                        pixelformat['pixelformat_int'] = fmt.pixelformat
 
388
                        pixelformat['pixelformat'] = "%s%s%s%s" % \
 
389
                            (chr(fmt.pixelformat & 0xFF),
 
390
                             chr((fmt.pixelformat >> 8) & 0xFF),
 
391
                             chr((fmt.pixelformat >> 16) & 0xFF),
 
392
                             chr((fmt.pixelformat >> 24) & 0xFF))
 
393
                        pixelformat['description'] = fmt.description.decode()
 
394
                        supported_formats.append(pixelformat)
 
395
                fmt.index = fmt.index + 1
 
396
        except IOError as e:
 
397
            # EINVAL is the ioctl's way of telling us that there are no
 
398
            # more formats, so we ignore it
 
399
            if e.errno != errno.EINVAL:
 
400
                print("Unable to determine Pixel Formats, this may be a "
 
401
                      "driver issue.")
 
402
            return supported_formats
 
403
        return supported_formats
 
404
 
 
405
    def _get_supported_resolutions(self, device):
 
406
        """
 
407
        Query the camera for supported resolutions for a given pixel_format.
 
408
        Data is returned in a list of dictionaries with supported pixel
 
409
        formats as the following example shows:
 
410
        resolution['pixelformat'] = "YUYV"
 
411
        resolution['description'] = "(YUV 4:2:2 (YUYV))"
 
412
        resolution['resolutions'] = [[width, height], [640, 480], [1280, 720] ]
 
413
 
 
414
        If we are unable to gather any information from the driver, then we
 
415
        return YUYV and 640x480 which seems to be a safe default.
 
416
        Per the v4l2 spec the ioctl used here is experimental
 
417
        but seems to be well supported.
 
418
        """
 
419
        supported_formats = self._get_pixel_formats(device)
 
420
        if not supported_formats:
 
421
            resolution = {}
 
422
            resolution['description'] = "YUYV"
 
423
            resolution['pixelformat'] = "YUYV"
 
424
            resolution['resolutions'] = [[640, 480]]
 
425
            supported_formats.append(resolution)
 
426
            return supported_formats
 
427
 
 
428
        for supported_format in supported_formats:
 
429
            resolutions = []
 
430
            framesize = v4l2_frmsizeenum()
 
431
            framesize.index = 0
 
432
            framesize.pixel_format = supported_format['pixelformat_int']
 
433
            with open(device, 'r') as vd:
 
434
                try:
 
435
                    while fcntl.ioctl(vd,
 
436
                                      VIDIOC_ENUM_FRAMESIZES,
 
437
                                      framesize) == 0:
 
438
                        if framesize.type == V4L2_FRMSIZE_TYPE_DISCRETE:
 
439
                            resolutions.append([framesize.discrete.width,
 
440
                                               framesize.discrete.height])
 
441
                        # for continuous and stepwise, let's just use min and
 
442
                        # max they use the same structure and only return
 
443
                        # one result
 
444
                        elif (framesize.type in (V4L2_FRMSIZE_TYPE_CONTINUOUS,
 
445
                              V4L2_FRMSIZE_TYPE_STEPWISE)):
 
446
                            resolutions.append([framesize.stepwise.min_width,
 
447
                                                framesize.stepwise.min_height]
 
448
                                               )
 
449
                            resolutions.append([framesize.stepwise.max_width,
 
450
                                                framesize.stepwise.max_height]
 
451
                                               )
 
452
                            break
 
453
                        framesize.index = framesize.index + 1
 
454
                except IOError as e:
 
455
                    # EINVAL is the ioctl's way of telling us that there are no
 
456
                    # more formats, so we ignore it
 
457
                    if e.errno != errno.EINVAL:
 
458
                        print("Unable to determine supported framesizes "
 
459
                              "(resolutions), this may be a driver issue.")
 
460
            supported_format['resolutions'] = resolutions
 
461
        return supported_formats
 
462
 
 
463
    def _validate_image(self, filename, width, height):
 
464
        """
 
465
        Given a filename, ensure that the image is the width and height
 
466
        specified and is a valid image file.
 
467
        """
 
468
        if imghdr.what(filename) != 'jpeg':
 
469
            return False
 
470
 
 
471
        outw = outh = 0
 
472
        with open(filename, mode='rb') as jpeg:
 
473
            jpeg.seek(2)
 
474
            b = jpeg.read(1)
 
475
            try:
 
476
                while (b and ord(b) != 0xDA):
 
477
                    while (ord(b) != 0xFF):
 
478
                        b = jpeg.read(1)
 
479
                    while (ord(b) == 0xFF):
 
480
                        b = jpeg.read(1)
 
481
                    if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
 
482
                        jpeg.seek(3, 1)
 
483
                        h, w = struct.unpack(">HH", jpeg.read(4))
 
484
                        break
 
485
                    b = jpeg.read(1)
 
486
                outw, outh = int(w), int(h)
 
487
            except (struct.error, ValueError):
 
488
                pass
 
489
 
 
490
            if outw != width:
 
491
                print("Image width does not match, was %s should be %s" %
 
492
                      (outw, width), file=sys.stderr)
 
493
                return False
 
494
            if outh != height:
 
495
                print("Image width does not match, was %s should be %s" %
 
496
                      (outh, height), file=sys.stderr)
 
497
                return False
 
498
 
 
499
            return True
 
500
 
 
501
        return True
 
502
 
 
503
 
 
504
def parse_arguments(argv):
 
505
    """
 
506
    Parse command line arguments
 
507
    """
 
508
    parser = argparse.ArgumentParser(description="Run a camera-related test")
 
509
    subparsers = parser.add_subparsers(dest='test',
 
510
                                       title='test',
 
511
                                       description='Available camera tests')
 
512
 
 
513
    parser.add_argument('--debug', dest='log_level',
 
514
                        action="store_const", const=logging.DEBUG,
 
515
                        default=logging.INFO, help="Show debugging messages")
 
516
 
 
517
    def add_device_parameter(parser):
 
518
        group = parser.add_mutually_exclusive_group()
 
519
        group.add_argument("-d", "--device", default="/dev/video0",
 
520
                           help="Device for the webcam to use")
 
521
        group.add_argument("--highest-device", action="store_true",
 
522
                           help=("Use the /dev/videoN "
 
523
                                 "where N is the highest value available"))
 
524
        group.add_argument("--lowest-device", action="store_true",
 
525
                           help=("Use the /dev/videoN "
 
526
                                 "where N is the lowest value available"))
 
527
    subparsers.add_parser('detect')
 
528
    led_parser = subparsers.add_parser('led')
 
529
    add_device_parameter(led_parser)
 
530
    display_parser = subparsers.add_parser('display')
 
531
    add_device_parameter(display_parser)
 
532
    still_parser = subparsers.add_parser('still')
 
533
    add_device_parameter(still_parser)
 
534
    still_parser.add_argument("-f", "--filename",
 
535
                              help="Filename to store the picture")
 
536
    still_parser.add_argument("-q", "--quiet", action="store_true",
 
537
                              help=("Don't display picture, "
 
538
                                    "just write the picture to a file"))
 
539
    resolutions_parser = subparsers.add_parser('resolutions')
 
540
    add_device_parameter(resolutions_parser)
 
541
    args = parser.parse_args(argv)
 
542
 
 
543
    def get_video_devices():
 
544
        devices = sorted(glob('/dev/video[0-9]'),
 
545
                         key=lambda d: re.search(r'\d', d).group(0))
 
546
        assert len(devices) > 0, "No video devices found"
 
547
        return devices
 
548
 
 
549
    if hasattr(args, 'highest_device') and args.highest_device:
 
550
        args.device = get_video_devices()[-1]
 
551
    elif hasattr(args, 'lowest_device') and args.lowest_device:
 
552
        args.device = get_video_devices()[0]
 
553
    return args
 
554
 
 
555
 
 
556
if __name__ == "__main__":
 
557
    args = parse_arguments(sys.argv[1:])
 
558
 
 
559
    if not args.test:
 
560
        args.test = 'detect'
 
561
 
 
562
    logging.basicConfig(level=args.log_level)
 
563
 
 
564
    # Import Gst only for the test cases that will need it
 
565
    if args.test in ['display', 'still', 'led', 'resolutions']:
 
566
        from gi.repository import Gst
 
567
        if Gst.version()[0] > 0:
 
568
            gst_plugin = 'videoconvert'
 
569
            gst_video_type = 'video/x-raw'
 
570
        else:
 
571
            gst_plugin = 'ffmpegcolorspace'
 
572
            gst_video_type = 'video/x-raw-yuv'
 
573
        Gst.init(None)
 
574
        camera = CameraTest(args, gst_plugin, gst_video_type)
 
575
    else:
 
576
        camera = CameraTest(args)
 
577
 
 
578
    sys.exit(getattr(camera, args.test)())