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"
8 #include <linux/uvcvideo.h>
9 #include <linux/videodev2.h>
11 #include <sys/ioctl.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
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
= {
38 UVC_GUID_LOGITECH_CC3000E_MOTORS
,
39 LOGITECH_MOTORCONTROL_PANTILT_CMD
,
43 UVC_CTRL_DATA_TYPE_ENUM
,
44 const_cast<uvc_menu_info
*>(&kLogitechCmdMenu
[0]),
45 arraysize(kLogitechCmdMenu
),
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() {
64 HANDLE_EINTR(ioctl(fd_
.get(), UVCIOC_CTRL_MAP
, &kLogitechCmdMapping
));
65 // If mapping is successful or it's already mapped, this is a Logitech
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;
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
)))
84 *value
= v4l2_ctrl
.value
;
88 void V4L2Webcam::GetPan(const GetPTZCompleteCallback
& callback
) {
90 bool success
= GetWebcamParameter(fd_
.get(), V4L2_CID_PAN_ABSOLUTE
, &value
);
91 callback
.Run(success
, value
);
94 void V4L2Webcam::GetTilt(const GetPTZCompleteCallback
& callback
) {
96 bool success
= GetWebcamParameter(fd_
.get(), V4L2_CID_TILT_ABSOLUTE
, &value
);
97 callback
.Run(success
, value
);
100 void V4L2Webcam::GetZoom(const GetPTZCompleteCallback
& callback
) {
102 bool success
= GetWebcamParameter(fd_
.get(), V4L2_CID_ZOOM_ABSOLUTE
, &value
);
103 callback
.Run(success
, value
);
106 void V4L2Webcam::SetPan(int value
,
108 const SetPTZCompleteCallback
& callback
) {
109 callback
.Run(SetWebcamParameter(fd_
.get(), V4L2_CID_PAN_ABSOLUTE
, value
));
112 void V4L2Webcam::SetTilt(int value
,
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
,
124 const SetPTZCompleteCallback
& callback
) {
125 int direction_value
= 0;
136 direction_value
= -1;
140 SetWebcamParameter(fd_
.get(), V4L2_CID_PAN_SPEED
, direction_value
));
143 void V4L2Webcam::SetTiltDirection(TiltDirection direction
,
145 const SetPTZCompleteCallback
& callback
) {
146 int direction_value
= 0;
157 direction_value
= -1;
161 SetWebcamParameter(fd_
.get(), V4L2_CID_TILT_SPEED
, direction_value
));
164 void V4L2Webcam::Reset(bool pan
,
167 const SetPTZCompleteCallback
& callback
) {
169 if (EnsureLogitechCommandsMapped()) {
170 if (!SetWebcamParameter(fd_
.get(), V4L2_CID_PANTILT_CMD
,
171 kLogitechMenuIndexGoHome
)) {
177 struct v4l2_control v4l2_ctrl
= {V4L2_CID_PAN_RESET
};
178 if (!HANDLE_EINTR(ioctl(fd_
.get(), VIDIOC_S_CTRL
, &v4l2_ctrl
))) {
185 struct v4l2_control v4l2_ctrl
= {V4L2_CID_TILT_RESET
};
186 if (!HANDLE_EINTR(ioctl(fd_
.get(), VIDIOC_S_CTRL
, &v4l2_ctrl
))) {
195 const int kDefaultZoom
= 100;
196 if (!SetWebcamParameter(fd_
.get(), V4L2_CID_ZOOM_ABSOLUTE
, kDefaultZoom
)) {
205 } // namespace extensions