OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "extensions/browser/api/webcam_private/v4l2_webcam.h" |
| 6 |
| 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> |
| 13 |
| 14 #include "base/posix/eintr_wrapper.h" |
| 15 |
| 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) |
| 19 |
| 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} |
| 25 |
| 26 #define LOGITECH_MOTORCONTROL_PANTILT_CMD 2 |
| 27 |
| 28 namespace { |
| 29 const int kLogitechMenuIndexGoHome = 2; |
| 30 |
| 31 const uvc_menu_info kLogitechCmdMenu[] = { |
| 32 {1, "Set Preset"}, {2, "Get Preset"}, {3, "Go Home"} |
| 33 }; |
| 34 |
| 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, |
| 40 8, |
| 41 0, |
| 42 V4L2_CTRL_TYPE_MENU, |
| 43 UVC_CTRL_DATA_TYPE_ENUM, |
| 44 const_cast<uvc_menu_info*>(&kLogitechCmdMenu[0]), |
| 45 arraysize(kLogitechCmdMenu), |
| 46 }; |
| 47 } // namespace |
| 48 |
| 49 namespace extensions { |
| 50 |
| 51 V4L2Webcam::V4L2Webcam(const std::string& device_id) : device_id_(device_id) { |
| 52 } |
| 53 |
| 54 V4L2Webcam::~V4L2Webcam() { |
| 55 } |
| 56 |
| 57 bool V4L2Webcam::Open() { |
| 58 fd_.reset(HANDLE_EINTR(open(device_id_.c_str(), 0))); |
| 59 return fd_.is_valid(); |
| 60 } |
| 61 |
| 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; |
| 70 } |
| 71 |
| 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; |
| 76 } |
| 77 |
| 78 bool V4L2Webcam::GetWebcamParameter(int fd, uint32_t control_id, int* value) { |
| 79 struct v4l2_control v4l2_ctrl = {control_id}; |
| 80 |
| 81 if (HANDLE_EINTR(ioctl(fd, VIDIOC_G_CTRL, &v4l2_ctrl))) |
| 82 return false; |
| 83 |
| 84 *value = v4l2_ctrl.value; |
| 85 return true; |
| 86 } |
| 87 |
| 88 void V4L2Webcam::Reset(bool pan, bool tilt, bool zoom) { |
| 89 if (pan || tilt) { |
| 90 if (EnsureLogitechCommandsMapped()) { |
| 91 SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD, |
| 92 kLogitechMenuIndexGoHome); |
| 93 } else { |
| 94 if (pan) { |
| 95 struct v4l2_control v4l2_ctrl = {V4L2_CID_PAN_RESET}; |
| 96 HANDLE_EINTR(ioctl(fd_.get(), VIDIOC_S_CTRL, &v4l2_ctrl)); |
| 97 } |
| 98 |
| 99 if (tilt) { |
| 100 struct v4l2_control v4l2_ctrl = {V4L2_CID_TILT_RESET}; |
| 101 HANDLE_EINTR(ioctl(fd_.get(), VIDIOC_S_CTRL, &v4l2_ctrl)); |
| 102 } |
| 103 } |
| 104 } |
| 105 |
| 106 if (zoom) { |
| 107 const int kDefaultZoom = 100; |
| 108 SetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, kDefaultZoom); |
| 109 } |
| 110 } |
| 111 |
| 112 bool V4L2Webcam::GetPan(int* value) { |
| 113 return GetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, value); |
| 114 } |
| 115 |
| 116 bool V4L2Webcam::GetTilt(int* value) { |
| 117 return GetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, value); |
| 118 } |
| 119 |
| 120 bool V4L2Webcam::GetZoom(int* value) { |
| 121 return GetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, value); |
| 122 } |
| 123 |
| 124 bool V4L2Webcam::SetPan(int value) { |
| 125 return SetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, value); |
| 126 } |
| 127 |
| 128 bool V4L2Webcam::SetTilt(int value) { |
| 129 return SetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, value); |
| 130 } |
| 131 |
| 132 bool V4L2Webcam::SetZoom(int value) { |
| 133 return SetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, value); |
| 134 } |
| 135 |
| 136 bool V4L2Webcam::SetPanDirection(PanDirection direction) { |
| 137 int direction_value = 0; |
| 138 switch (direction) { |
| 139 case PAN_STOP: |
| 140 direction_value = 0; |
| 141 break; |
| 142 |
| 143 case PAN_RIGHT: |
| 144 direction_value = 1; |
| 145 break; |
| 146 |
| 147 case PAN_LEFT: |
| 148 direction_value = -1; |
| 149 break; |
| 150 } |
| 151 return SetWebcamParameter(fd_.get(), V4L2_CID_PAN_SPEED, direction_value); |
| 152 } |
| 153 |
| 154 bool V4L2Webcam::SetTiltDirection(TiltDirection direction) { |
| 155 int direction_value = 0; |
| 156 switch (direction) { |
| 157 case TILT_STOP: |
| 158 direction_value = 0; |
| 159 break; |
| 160 |
| 161 case TILT_UP: |
| 162 direction_value = 1; |
| 163 break; |
| 164 |
| 165 case TILT_DOWN: |
| 166 direction_value = -1; |
| 167 break; |
| 168 } |
| 169 return SetWebcamParameter(fd_.get(), V4L2_CID_TILT_SPEED, direction_value); |
| 170 } |
| 171 |
| 172 } // namespace extensions |
OLD | NEW |