blob: a7b66cb0122c9ebe605e84cad87da0a5b41b985d [file] [log] [blame]
# 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)