| # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import glob |
| import logging |
| import ntpath |
| import os |
| import re |
| import stat |
| from autotest_lib.client.bin import test, utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.cros.graphics import graphics_utils |
| |
| |
| class camera_V4L2(test.test): |
| version = 1 |
| preserve_srcdir = True |
| v4l2_major_dev_num = 81 |
| v4l2_minor_dev_num_min = 0 |
| v4l2_minor_dev_num_max = 64 |
| |
| def setup(self): |
| # TODO(jiesun): make binary here when cross compile issue is resolved. |
| os.chdir(self.srcdir) |
| utils.make('clean') |
| utils.make() |
| |
| def run_once(self, run_unit_tests=True, run_capture_tests=True, |
| assert_mandatory_controls=False): |
| |
| self.assert_mandatory_controls = assert_mandatory_controls |
| self.find_video_capture_devices() |
| |
| for device in self.v4l2_devices: |
| self.usb_info = self.get_camera_device_usb_info(device) |
| if run_unit_tests: |
| self.run_v4l2_unittests(device) |
| if run_capture_tests: |
| self.run_v4l2_capture_test(device) |
| |
| def get_camera_device_usb_info(self, device): |
| device_name = ntpath.basename(device) |
| vid_path = "/sys/class/video4linux/%s/device/../idVendor" % device_name |
| pid_path = "/sys/class/video4linux/%s/device/../idProduct" % device_name |
| with open(vid_path, 'r') as f_vid, open(pid_path, 'r') as f_pid: |
| vid = f_vid.read() |
| pid = f_pid.read() |
| return vid.strip() + ":" + pid.strip() |
| |
| def is_v4l2_capture_device(self, device): |
| executable = os.path.join(self.bindir, "media_v4l2_is_capture_device") |
| cmd = "%s %s" % (executable, device) |
| logging.info("Running %s" % cmd) |
| return utils.system(cmd, ignore_status=True) == 0 |
| |
| def find_video_capture_devices(self): |
| self.v4l2_devices = [] |
| for device in glob.glob("/dev/video*"): |
| statinfo = os.stat(device) |
| if (stat.S_ISCHR(statinfo.st_mode) and |
| os.major(statinfo.st_rdev) == self.v4l2_major_dev_num and |
| os.minor(statinfo.st_rdev) >= |
| self.v4l2_minor_dev_num_min and |
| os.minor(statinfo.st_rdev) < self.v4l2_minor_dev_num_max and |
| self.is_v4l2_capture_device(device)): |
| self.v4l2_devices.append(device) |
| logging.info("Detected devices: %s\n" % self.v4l2_devices) |
| if not self.v4l2_devices: |
| raise error.TestFail("No V4L2 devices found!") |
| |
| def unittest_passed(self, testname, stdout): |
| return re.search(r"OK \] V4L2DeviceTest\." + testname, stdout) |
| |
| def run_v4l2_unittests(self, device): |
| self.executable = os.path.join(self.bindir, "media_v4l2_unittest") |
| cmd = "%s --device=%s" % (self.executable, device) |
| logging.info("Running %s" % cmd) |
| stdout = utils.system_output(cmd, retain_output=True) |
| |
| # Check the result of unittests. |
| # We had exercise all the optional ioctls in unittest which maybe |
| # optional by V4L2 Specification. Therefore we need to check those |
| # tests that we thought are mandatory. |
| # 1. Multiple open should be supported for panel application. |
| if not self.unittest_passed("MultipleOpen", stdout): |
| raise error.TestError(device + " does not support multiple open!") |
| |
| # 2. Need to make sure this is really support or just driver error. |
| if not self.unittest_passed("MultipleInit", stdout): |
| raise error.TestError(device + " does support multiple init!") |
| |
| # 3. EnumInput and EnumStandard is optional. |
| |
| # 4. EnumControl is mandatory. |
| if not self.unittest_passed("EnumControl", stdout): |
| raise error.TestError(device + " does support enum controls!") |
| pattern = re.compile(r"Control (\w+) is enabled\((\d+)-(\d+):(\d+)\)") |
| control_info = pattern.findall(stdout) |
| self.supported_controls = [x[0] for x in control_info] |
| logging.info("Supported Controls: %s\n" % self.supported_controls) |
| |
| # TODO(jiesun): what is required? |
| mandatory_controls = [ |
| "Brightness", |
| "Contrast", |
| "Saturation", |
| "Hue", |
| "Gamma"] |
| for control in mandatory_controls: |
| if self.assert_mandatory_controls and \ |
| control not in self.supported_controls: |
| raise error.TestError(device + " does not support " + control) |
| |
| # 5. SetControl is mandatory. |
| if not self.unittest_passed("SetControl", stdout): |
| raise error.TestError(device + " does not support set controls!") |
| |
| # 6. 7. Set/GetCrop are both optional. |
| |
| # 8. ProbeCaps is mandatory. |
| if not self.unittest_passed("ProbeCaps", stdout): |
| raise error.TestError(device + " does not support probe caps!") |
| |
| if not re.search(r"support video capture interface.>>>", stdout): |
| raise error.TestFail(device + " does not support video capture!") |
| |
| # 9. EnumFormats is always mandatory. |
| if not self.unittest_passed("EnumFormats", stdout): |
| raise error.TestError(device + " does not support enum formats!") |
| |
| pattern = re.compile(r"supported format #\d+: .* \((....)\)") |
| format_info = pattern.findall(stdout) |
| # Remove duplicated pixel formats from list. |
| self.supported_formats = list(set(format_info)) |
| logging.info("Supported pixel format: %s\n", self.supported_formats) |
| |
| # 10. Get/SetParam for framerate is optional. |
| # 11. EnumFrameSize is optional. |
| |
| def run_v4l2_capture_test(self, device): |
| options = ["--device=%s" % device] |
| options += ["--usb-info=%s" % self.usb_info] |
| |
| executable = os.path.join(self.bindir, "media_v4l2_test") |
| cmd = "%s %s" % (executable, " ".join(options)) |
| logging.info("Running %s" % cmd) |
| stdout = utils.system_output(cmd, retain_output=True) |