commit 74e41428503d16ff365bbfa93ca23332ce04215a Author: Ilya Nikolaevskiy Date: Wed Apr 5 16:16:22 2023 +0000 Revert "V4L2: media/capture: Use VIDIOC_S_EXT_CTRLS API correctly" This reverts commit 4301563bdea1766779b5e032d2eb2ff19959fce3. Reason for revert: Breaks test bot: crbug.com/1430699 Original change's description: > V4L2: media/capture: Use VIDIOC_S_EXT_CTRLS API correctly > > This CL: > - Uses the `which` struct v4l2_ext_controls field instead of > the deprecated `ctrl_class` alias field. > - Prefers the new style value of `V4L2_CTRL_WHICH_CUR_VAL` for that > field instead of the old style value of the control class ID as long > as the device supports the new style (detected on run-time). > - Sets special controls only if they are supported. Trying to set > an unsupported special control as part of a VIDIOC_S_EXT_CTRLS call > causes the whole VIDIOC_S_EXT_CTRLS call to fail. > - Fixes control iteration not to skip over the brightness control. > - Skips permanently disabled and read-only controls. > - Enables the corresponding test case. > > This fixes VIDIOC_S_EXT_CTRLS to work on new device drivers, too. > > API: https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-g-ext-ctrls.html#c.V4L.v4l2_ext_controls > > Bug: 1421739, 732355 > Change-Id: I13593bb647fe664d70a3d8ed8d2789f77397aa40 > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4324021 > Commit-Queue: Eero Hakkinen > Reviewed-by: Tomas Gunnarsson > Reviewed-by: Ilya Nikolaevskiy > Cr-Commit-Position: refs/heads/main@{#1116416} Bug: 1421739, 732355 Change-Id: I291b80009550f0c890b5203060d9283a4074af97 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4401592 Commit-Queue: Tomas Gunnarsson Auto-Submit: Ilya Nikolaevskiy Reviewed-by: Tomas Gunnarsson Cr-Commit-Position: refs/heads/main@{#1126615} diff --git a/media/capture/video/linux/v4l2_capture_delegate.cc b/media/capture/video/linux/v4l2_capture_delegate.cc index 7efa2b1c2252c..864111f5c255e 100644 --- a/media/capture/video/linux/v4l2_capture_delegate.cc +++ b/media/capture/video/linux/v4l2_capture_delegate.cc @@ -138,6 +138,47 @@ int GetControllingSpecialControl(int control_id) { return 0; } +// Determines if |control_id| is special, i.e. controls another one's state. +bool IsSpecialControl(int control_id) { + switch (control_id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + case V4L2_CID_EXPOSURE_AUTO: + case V4L2_CID_EXPOSURE_AUTO_PRIORITY: + case V4L2_CID_FOCUS_AUTO: + return true; + } + return false; +} + +// Determines if |control_id| should be skipped, https://crbug.com/697885. +#if !defined(V4L2_CID_PAN_SPEED) +#define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE + 32) +#endif +#if !defined(V4L2_CID_TILT_SPEED) +#define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE + 33) +#endif +#if !defined(V4L2_CID_PANTILT_CMD) +#define V4L2_CID_PANTILT_CMD (V4L2_CID_CAMERA_CLASS_BASE + 34) +#endif +bool IsBlockedControl(int control_id) { + switch (control_id) { + case V4L2_CID_PAN_RELATIVE: + case V4L2_CID_TILT_RELATIVE: + case V4L2_CID_PAN_RESET: + case V4L2_CID_TILT_RESET: + case V4L2_CID_PAN_ABSOLUTE: + case V4L2_CID_TILT_ABSOLUTE: + case V4L2_CID_ZOOM_ABSOLUTE: + case V4L2_CID_ZOOM_RELATIVE: + case V4L2_CID_ZOOM_CONTINUOUS: + case V4L2_CID_PAN_SPEED: + case V4L2_CID_TILT_SPEED: + case V4L2_CID_PANTILT_CMD: + return true; + } + return false; +} + bool IsNonEmptyRange(const mojom::RangePtr& range) { return range->min < range->max; } @@ -211,49 +252,6 @@ std::vector V4L2CaptureDelegate::GetListOfUsableFourCcs( return supported_formats; } -// Determines if |control_id| is special, i.e. controls another one's state. -// static -bool V4L2CaptureDelegate::IsSpecialControl(int control_id) { - switch (control_id) { - case V4L2_CID_AUTO_WHITE_BALANCE: - case V4L2_CID_EXPOSURE_AUTO: - case V4L2_CID_EXPOSURE_AUTO_PRIORITY: - case V4L2_CID_FOCUS_AUTO: - return true; - } - return false; -} - -// Determines if |control_id| should be skipped, https://crbug.com/697885. -#if !defined(V4L2_CID_PAN_SPEED) -#define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE + 32) -#endif -#if !defined(V4L2_CID_TILT_SPEED) -#define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE + 33) -#endif -#if !defined(V4L2_CID_PANTILT_CMD) -#define V4L2_CID_PANTILT_CMD (V4L2_CID_CAMERA_CLASS_BASE + 34) -#endif -// static -bool V4L2CaptureDelegate::IsBlockedControl(int control_id) { - switch (control_id) { - case V4L2_CID_PAN_RELATIVE: - case V4L2_CID_TILT_RELATIVE: - case V4L2_CID_PAN_RESET: - case V4L2_CID_TILT_RESET: - case V4L2_CID_PAN_ABSOLUTE: - case V4L2_CID_TILT_ABSOLUTE: - case V4L2_CID_ZOOM_ABSOLUTE: - case V4L2_CID_ZOOM_RELATIVE: - case V4L2_CID_ZOOM_CONTINUOUS: - case V4L2_CID_PAN_SPEED: - case V4L2_CID_TILT_SPEED: - case V4L2_CID_PANTILT_CMD: - return true; - } - return false; -} - V4L2CaptureDelegate::V4L2CaptureDelegate( V4L2CaptureDevice* v4l2, const VideoCaptureDeviceDescriptor& device_descriptor, @@ -830,89 +828,100 @@ mojom::RangePtr V4L2CaptureDelegate::RetrieveUserControlRange(int control_id) { } void V4L2CaptureDelegate::ResetUserAndCameraControlsToDefault() { + // Set V4L2_CID_AUTO_WHITE_BALANCE to false first. + v4l2_control auto_white_balance = {}; + auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE; + auto_white_balance.value = false; + if (!RunIoctl(VIDIOC_S_CTRL, &auto_white_balance)) + return; + + std::vector special_camera_controls; + // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL. + v4l2_ext_control auto_exposure = {}; + auto_exposure.id = V4L2_CID_EXPOSURE_AUTO; + auto_exposure.value = V4L2_EXPOSURE_MANUAL; + special_camera_controls.push_back(auto_exposure); + // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false. + v4l2_ext_control priority_auto_exposure = {}; + priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY; + priority_auto_exposure.value = false; + special_camera_controls.push_back(priority_auto_exposure); + // Set V4L2_CID_FOCUS_AUTO to false. + v4l2_ext_control auto_focus = {}; + auto_focus.id = V4L2_CID_FOCUS_AUTO; + auto_focus.value = false; + special_camera_controls.push_back(auto_focus); + struct v4l2_ext_controls ext_controls = {}; - ext_controls.which = V4L2_CTRL_WHICH_CUR_VAL; - ext_controls.count = 0; - const bool use_modern_s_ext_ctrls = - DoIoctl(VIDIOC_S_EXT_CTRLS, &ext_controls) == 0; + ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS; + ext_controls.count = special_camera_controls.size(); + ext_controls.controls = special_camera_controls.data(); + if (DoIoctl(VIDIOC_S_EXT_CTRLS, &ext_controls) < 0) + DPLOG(INFO) << "VIDIOC_S_EXT_CTRLS"; for (const auto& control : kControls) { std::vector camera_controls; - std::vector manual_special_camera_controls; - std::vector special_camera_controls; v4l2_queryctrl range = {}; - // Start right below the base so that the first next retrieved control ID - // is always the first available control ID within the class even if that - // control ID is equal to the base (V4L2_CID_BRIGHTNESS equals to - // V4L2_CID_USER_BASE). - range.id = (control.control_base - 1) | V4L2_CTRL_FLAG_NEXT_CTRL; + range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL; while (0 == DoIoctl(VIDIOC_QUERYCTRL, &range)) { if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id)) break; - - v4l2_ext_control ext_control = {}; - ext_control.id = range.id; - ext_control.value = range.default_value; - - // Prepare to query for the next control as `range` is an in-out - // parameter. range.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - if (range.flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_READ_ONLY)) { - // Permanently disabled or permanently read-only. + if (IsSpecialControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) continue; - } - if (IsBlockedControl(ext_control.id)) { + if (IsBlockedControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) continue; - } - if (IsSpecialControl(ext_control.id)) { - special_camera_controls.push_back(ext_control); - if (ext_control.id == V4L2_CID_EXPOSURE_AUTO) { - ext_control.value = V4L2_EXPOSURE_MANUAL; - } else { - ext_control.value = false; // Not automatic but manual. - } - manual_special_camera_controls.push_back(ext_control); - } else { - camera_controls.push_back(ext_control); - } + struct v4l2_ext_control ext_control = {}; + ext_control.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL; + ext_control.value = range.default_value; + camera_controls.push_back(ext_control); } if (!camera_controls.empty()) { - // Set special controls to manual modes first. - if (!manual_special_camera_controls.empty()) { - ext_controls.which = - use_modern_s_ext_ctrls ? V4L2_CTRL_WHICH_CUR_VAL : control.class_id; - ext_controls.count = manual_special_camera_controls.size(); - ext_controls.controls = manual_special_camera_controls.data(); - if (DoIoctl(VIDIOC_S_EXT_CTRLS, &ext_controls) < 0) { - DPLOG(INFO) << "VIDIOC_S_EXT_CTRLS"; - } - } - - // Set non-special controls to the default values. - ext_controls.which = - use_modern_s_ext_ctrls ? V4L2_CTRL_WHICH_CUR_VAL : control.class_id; - ext_controls.count = camera_controls.size(); - ext_controls.controls = camera_controls.data(); - if (DoIoctl(VIDIOC_S_EXT_CTRLS, &ext_controls) < 0) { - DPLOG(INFO) << "VIDIOC_S_EXT_CTRLS"; - } - } - - // Set special controls to the default values. - if (!special_camera_controls.empty()) { - ext_controls.which = - use_modern_s_ext_ctrls ? V4L2_CTRL_WHICH_CUR_VAL : control.class_id; - ext_controls.count = special_camera_controls.size(); - ext_controls.controls = special_camera_controls.data(); - if (DoIoctl(VIDIOC_S_EXT_CTRLS, &ext_controls) < 0) { + struct v4l2_ext_controls ext_controls2 = {}; + ext_controls2.ctrl_class = control.class_id; + ext_controls2.count = camera_controls.size(); + ext_controls2.controls = camera_controls.data(); + if (DoIoctl(VIDIOC_S_EXT_CTRLS, &ext_controls2) < 0) DPLOG(INFO) << "VIDIOC_S_EXT_CTRLS"; - } } } + + // Now set the special flags to the default values + v4l2_queryctrl range = {}; + range.id = V4L2_CID_AUTO_WHITE_BALANCE; + DoIoctl(VIDIOC_QUERYCTRL, &range); + auto_white_balance.value = range.default_value; + DoIoctl(VIDIOC_S_CTRL, &auto_white_balance); + + special_camera_controls.clear(); + memset(&range, 0, sizeof(range)); + range.id = V4L2_CID_EXPOSURE_AUTO; + DoIoctl(VIDIOC_QUERYCTRL, &range); + auto_exposure.value = range.default_value; + special_camera_controls.push_back(auto_exposure); + + memset(&range, 0, sizeof(range)); + range.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY; + DoIoctl(VIDIOC_QUERYCTRL, &range); + priority_auto_exposure.value = range.default_value; + special_camera_controls.push_back(priority_auto_exposure); + + memset(&range, 0, sizeof(range)); + range.id = V4L2_CID_FOCUS_AUTO; + DoIoctl(VIDIOC_QUERYCTRL, &range); + auto_focus.value = range.default_value; + special_camera_controls.push_back(auto_focus); + + memset(&ext_controls, 0, sizeof(ext_controls)); + ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS; + ext_controls.count = special_camera_controls.size(); + ext_controls.controls = special_camera_controls.data(); + if (DoIoctl(VIDIOC_S_EXT_CTRLS, &ext_controls) < 0) + DPLOG(INFO) << "VIDIOC_S_EXT_CTRLS"; } bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) { diff --git a/media/capture/video/linux/v4l2_capture_delegate.h b/media/capture/video/linux/v4l2_capture_delegate.h index 5eaa0cd004b81..c9be3d02f9344 100644 --- a/media/capture/video/linux/v4l2_capture_delegate.h +++ b/media/capture/video/linux/v4l2_capture_delegate.h @@ -78,9 +78,6 @@ class CAPTURE_EXPORT V4L2CaptureDelegate final { base::WeakPtr GetWeakPtr(); - static bool IsBlockedControl(int control_id); - static bool IsSpecialControl(int control_id); - private: friend class V4L2CaptureDelegateTest; diff --git a/media/capture/video/linux/v4l2_capture_delegate_unittest.cc b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc index 06046ca45d634..4e6e38bbd5c72 100644 --- a/media/capture/video/linux/v4l2_capture_delegate_unittest.cc +++ b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc @@ -35,110 +35,119 @@ static struct { } const kControls[] = {{V4L2_CID_USER_BASE, V4L2_CID_USER_CLASS}, {V4L2_CID_CAMERA_CLASS_BASE, V4L2_CID_CAMERA_CLASS}}; +// Determines if |control_id| is special, i.e. controls another one's state, or +// if it should be denied (see https://crbug.com/697885). +#if !defined(V4L2_CID_PAN_SPEED) +#define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE + 32) +#endif +#if !defined(V4L2_CID_TILT_SPEED) +#define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE + 33) +#endif +#if !defined(V4L2_CID_PANTILT_CMD) +#define V4L2_CID_PANTILT_CMD (V4L2_CID_CAMERA_CLASS_BASE + 34) +#endif +static bool IsSpecialOrBlockedControl(int control_id) { + switch (control_id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + case V4L2_CID_EXPOSURE_AUTO: + case V4L2_CID_EXPOSURE_AUTO_PRIORITY: + case V4L2_CID_FOCUS_AUTO: + case V4L2_CID_PAN_RELATIVE: + case V4L2_CID_TILT_RELATIVE: + case V4L2_CID_PAN_RESET: + case V4L2_CID_TILT_RESET: + case V4L2_CID_PAN_ABSOLUTE: + case V4L2_CID_TILT_ABSOLUTE: + case V4L2_CID_ZOOM_ABSOLUTE: + case V4L2_CID_ZOOM_RELATIVE: + case V4L2_CID_ZOOM_CONTINUOUS: + case V4L2_CID_PAN_SPEED: + case V4L2_CID_TILT_SPEED: + case V4L2_CID_PANTILT_CMD: + return true; + } + return false; +} + static void SetControlsToMaxValues(int device_fd) { - v4l2_ext_controls ext_controls; - memset(&ext_controls, 0, sizeof(ext_controls)); - ext_controls.which = V4L2_CTRL_WHICH_CUR_VAL; - ext_controls.count = 0; - const bool use_modern_s_ext_ctrls = - HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) == 0; + // Set V4L2_CID_AUTO_WHITE_BALANCE to false first. + v4l2_control auto_white_balance = {}; + auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE; + auto_white_balance.value = false; + if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) < 0) + DPLOG(ERROR) << "VIDIOC_S_CTRL"; + + std::vector special_camera_controls; + // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL. + v4l2_ext_control auto_exposure = {}; + auto_exposure.id = V4L2_CID_EXPOSURE_AUTO; + auto_exposure.value = V4L2_EXPOSURE_MANUAL; + special_camera_controls.push_back(auto_exposure); + // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false. + v4l2_ext_control priority_auto_exposure = {}; + priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY; + priority_auto_exposure.value = false; + special_camera_controls.push_back(priority_auto_exposure); + // Set V4L2_CID_FOCUS_AUTO to false. + v4l2_ext_control auto_focus = {}; + auto_focus.id = V4L2_CID_FOCUS_AUTO; + auto_focus.value = false; + special_camera_controls.push_back(auto_focus); + + struct v4l2_ext_controls camera_ext_controls = {}; + camera_ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS; + camera_ext_controls.count = special_camera_controls.size(); + camera_ext_controls.controls = special_camera_controls.data(); + if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &camera_ext_controls)) < + 0) { + DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; + } for (const auto& control : kControls) { std::vector camera_controls; - std::vector manual_special_camera_controls; v4l2_queryctrl range = {}; - // Start right below the base so that the first next retrieved control ID - // is always the first available control ID within the class even if that - // control ID is equal to the base (V4L2_CID_BRIGHTNESS equals to - // V4L2_CID_USER_BASE). - range.id = (control.control_base - 1) | V4L2_CTRL_FLAG_NEXT_CTRL; + range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL; while (0 == HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) { if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id)) break; - - v4l2_ext_control ext_control = {}; - ext_control.id = range.id; - - // Prepare to query for the next control as `range` is an in-out - // parameter. range.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - if (range.flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_READ_ONLY)) { - // Permanently disabled or permanently read-only. - continue; - } - if (V4L2CaptureDelegate::IsBlockedControl(ext_control.id)) { + if (IsSpecialOrBlockedControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) continue; - } - - if (V4L2CaptureDelegate::IsSpecialControl(ext_control.id)) { - if (ext_control.id == V4L2_CID_EXPOSURE_AUTO) { - ext_control.value = V4L2_EXPOSURE_MANUAL; - } else { - ext_control.value = false; // Not automatic but manual. - } - manual_special_camera_controls.push_back(ext_control); - DVLOG(1) << __func__ << " " << range.name << " set to manual"; - } else { - ext_control.value = range.maximum; - camera_controls.push_back(ext_control); - DVLOG(1) << __func__ << " " << range.name << " set to " - << range.maximum; - } - } + DVLOG(1) << __func__ << " " << range.name << " set to " << range.maximum; - // Set special controls to manual modes. - if (!manual_special_camera_controls.empty()) { - ext_controls.which = - use_modern_s_ext_ctrls ? V4L2_CTRL_WHICH_CUR_VAL : control.class_id; - ext_controls.count = manual_special_camera_controls.size(); - ext_controls.controls = manual_special_camera_controls.data(); - if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < - 0) { - DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; - } + struct v4l2_ext_control ext_control = {}; + ext_control.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL; + ext_control.value = range.maximum; + camera_controls.push_back(ext_control); } - // Set non-special controls to maximum values. if (!camera_controls.empty()) { - ext_controls.which = - use_modern_s_ext_ctrls ? V4L2_CTRL_WHICH_CUR_VAL : control.class_id; + struct v4l2_ext_controls ext_controls = {}; + ext_controls.ctrl_class = control.class_id; ext_controls.count = camera_controls.size(); ext_controls.controls = camera_controls.data(); if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0) DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; } - // Start right below the base so that the first next retrieved control ID - // is always the first available control ID within the class even if that - // control ID is equal to the base (V4L2_CID_BRIGHTNESS equals to - // V4L2_CID_USER_BASE). - range.id = (control.control_base - 1) | V4L2_CTRL_FLAG_NEXT_CTRL; + range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL; while (0 == HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) { if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id)) break; - - v4l2_control readback = {}; - readback.id = range.id; - - // Prepare to query for the next control as `range` is an in-out - // parameter. range.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - if (range.flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_READ_ONLY)) { - // Permanently disabled or permanently read-only. + if (IsSpecialOrBlockedControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) continue; - } - if (V4L2CaptureDelegate::IsBlockedControl(readback.id) || - V4L2CaptureDelegate::IsSpecialControl(readback.id)) { - continue; - } + DVLOG(1) << __func__ << " " << range.name << " set to " << range.maximum; + v4l2_control readback = {}; + readback.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL; if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &readback)) < 0) DPLOG(ERROR) << range.name << ", failed to be read."; - EXPECT_EQ(range.maximum, readback.value) - << " control " << range.name << " didn't set correctly"; + EXPECT_EQ(range.maximum, readback.value) << " control " << range.name + << " didnt set correctly"; } } } @@ -186,7 +195,15 @@ class V4L2CaptureDelegateTest : public ::testing::Test { } // anonymous namespace -TEST_F(V4L2CaptureDelegateTest, CreateAndDestroyAndVerifyControls) { +// Fails on Linux, see crbug/732355 +#if BUILDFLAG(IS_LINUX) +#define MAYBE_CreateAndDestroyAndVerifyControls \ + DISABLED_CreateAndDestroyAndVerifyControls +#else +#define MAYBE_CreateAndDestroyAndVerifyControls \ + CreateAndDestroyAndVerifyControls +#endif +TEST_F(V4L2CaptureDelegateTest, MAYBE_CreateAndDestroyAndVerifyControls) { // Check that there is at least a video device, otherwise bail. const base::FilePath path("/dev/"); base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES,