Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / extensions / browser / api / webcam_private / v4l2_webcam.cc
blobe99cc0ca199d47bbeded40dfd37edbc52b125dd3
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/webcam_private/v4l2_webcam.h"
7 #include <fcntl.h>
8 #include <linux/uvcvideo.h>
9 #include <linux/videodev2.h>
10 #include <stdio.h>
11 #include <sys/ioctl.h>
12 #include <unistd.h>
14 #include "base/posix/eintr_wrapper.h"
16 #define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32)
17 #define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33)
18 #define V4L2_CID_PANTILT_CMD (V4L2_CID_CAMERA_CLASS_BASE+34)
20 // GUID of the Extension Unit for Logitech CC3300e motor control:
21 // {212de5ff-3080-2c4e-82d9-f587d00540bd}
22 #define UVC_GUID_LOGITECH_CC3000E_MOTORS \
23 {0x21, 0x2d, 0xe5, 0xff, 0x30, 0x80, 0x2c, 0x4e, \
24 0x82, 0xd9, 0xf5, 0x87, 0xd0, 0x05, 0x40, 0xbd}
26 #define LOGITECH_MOTORCONTROL_PANTILT_CMD 2
28 namespace {
29 const int kLogitechMenuIndexGoHome = 2;
31 const uvc_menu_info kLogitechCmdMenu[] = {
32 {1, "Set Preset"}, {2, "Get Preset"}, {3, "Go Home"}
35 const uvc_xu_control_mapping kLogitechCmdMapping = {
36 V4L2_CID_PANTILT_CMD,
37 "Pan/Tilt Go",
38 UVC_GUID_LOGITECH_CC3000E_MOTORS,
39 LOGITECH_MOTORCONTROL_PANTILT_CMD,
42 V4L2_CTRL_TYPE_MENU,
43 UVC_CTRL_DATA_TYPE_ENUM,
44 const_cast<uvc_menu_info*>(&kLogitechCmdMenu[0]),
45 arraysize(kLogitechCmdMenu),
47 } // namespace
49 namespace extensions {
51 V4L2Webcam::V4L2Webcam(const std::string& device_id) : device_id_(device_id) {
54 V4L2Webcam::~V4L2Webcam() {
57 bool V4L2Webcam::Open() {
58 fd_.reset(HANDLE_EINTR(open(device_id_.c_str(), 0)));
59 return fd_.is_valid();
62 bool V4L2Webcam::EnsureLogitechCommandsMapped() {
63 int res =
64 HANDLE_EINTR(ioctl(fd_.get(), UVCIOC_CTRL_MAP, &kLogitechCmdMapping));
65 // If mapping is successful or it's already mapped, this is a Logitech
66 // camera.
67 // NOTE: On success, occasionally EFAULT is returned. On a real error,
68 // ENOMEM, EPERM, EINVAL, or EOVERFLOW should be returned.
69 return res >= 0 || errno == EEXIST || errno == EFAULT;
72 bool V4L2Webcam::SetWebcamParameter(int fd, uint32_t control_id, int value) {
73 struct v4l2_control v4l2_ctrl = {control_id, value};
74 int res = HANDLE_EINTR(ioctl(fd, VIDIOC_S_CTRL, &v4l2_ctrl)) >= 0;
75 return res >= 0;
78 bool V4L2Webcam::GetWebcamParameter(int fd, uint32_t control_id, int* value) {
79 struct v4l2_control v4l2_ctrl = {control_id};
81 if (HANDLE_EINTR(ioctl(fd, VIDIOC_G_CTRL, &v4l2_ctrl)))
82 return false;
84 *value = v4l2_ctrl.value;
85 return true;
88 void V4L2Webcam::GetPan(const GetPTZCompleteCallback& callback) {
89 int value = 0;
90 bool success = GetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, &value);
91 callback.Run(success, value);
94 void V4L2Webcam::GetTilt(const GetPTZCompleteCallback& callback) {
95 int value = 0;
96 bool success = GetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, &value);
97 callback.Run(success, value);
100 void V4L2Webcam::GetZoom(const GetPTZCompleteCallback& callback) {
101 int value = 0;
102 bool success = GetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, &value);
103 callback.Run(success, value);
106 void V4L2Webcam::SetPan(int value,
107 int pan_speed,
108 const SetPTZCompleteCallback& callback) {
109 callback.Run(SetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, value));
112 void V4L2Webcam::SetTilt(int value,
113 int tilt_speed,
114 const SetPTZCompleteCallback& callback) {
115 callback.Run(SetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, value));
118 void V4L2Webcam::SetZoom(int value, const SetPTZCompleteCallback& callback) {
119 callback.Run(SetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, value));
122 void V4L2Webcam::SetPanDirection(PanDirection direction,
123 int pan_speed,
124 const SetPTZCompleteCallback& callback) {
125 int direction_value = 0;
126 switch (direction) {
127 case PAN_STOP:
128 direction_value = 0;
129 break;
131 case PAN_RIGHT:
132 direction_value = 1;
133 break;
135 case PAN_LEFT:
136 direction_value = -1;
137 break;
139 callback.Run(
140 SetWebcamParameter(fd_.get(), V4L2_CID_PAN_SPEED, direction_value));
143 void V4L2Webcam::SetTiltDirection(TiltDirection direction,
144 int tilt_speed,
145 const SetPTZCompleteCallback& callback) {
146 int direction_value = 0;
147 switch (direction) {
148 case TILT_STOP:
149 direction_value = 0;
150 break;
152 case TILT_UP:
153 direction_value = 1;
154 break;
156 case TILT_DOWN:
157 direction_value = -1;
158 break;
160 callback.Run(
161 SetWebcamParameter(fd_.get(), V4L2_CID_TILT_SPEED, direction_value));
164 void V4L2Webcam::Reset(bool pan,
165 bool tilt,
166 bool zoom,
167 const SetPTZCompleteCallback& callback) {
168 if (pan || tilt) {
169 if (EnsureLogitechCommandsMapped()) {
170 if (!SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD,
171 kLogitechMenuIndexGoHome)) {
172 callback.Run(false);
173 return;
175 } else {
176 if (pan) {
177 struct v4l2_control v4l2_ctrl = {V4L2_CID_PAN_RESET};
178 if (!HANDLE_EINTR(ioctl(fd_.get(), VIDIOC_S_CTRL, &v4l2_ctrl))) {
179 callback.Run(false);
180 return;
184 if (tilt) {
185 struct v4l2_control v4l2_ctrl = {V4L2_CID_TILT_RESET};
186 if (!HANDLE_EINTR(ioctl(fd_.get(), VIDIOC_S_CTRL, &v4l2_ctrl))) {
187 callback.Run(false);
188 return;
194 if (zoom) {
195 const int kDefaultZoom = 100;
196 if (!SetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, kDefaultZoom)) {
197 callback.Run(false);
198 return;
202 callback.Run(true);
205 } // namespace extensions