| Index: extensions/browser/api/webcam_private/v4l2_webcam.cc
|
| diff --git a/extensions/browser/api/webcam_private/v4l2_webcam.cc b/extensions/browser/api/webcam_private/v4l2_webcam.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f6d53c50c0dbb60bc5328b89a2965587c6c9e258
|
| --- /dev/null
|
| +++ b/extensions/browser/api/webcam_private/v4l2_webcam.cc
|
| @@ -0,0 +1,172 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "extensions/browser/api/webcam_private/v4l2_webcam.h"
|
| +
|
| +#include <fcntl.h>
|
| +#include <linux/uvcvideo.h>
|
| +#include <linux/videodev2.h>
|
| +#include <stdio.h>
|
| +#include <sys/ioctl.h>
|
| +#include <unistd.h>
|
| +
|
| +#include "base/posix/eintr_wrapper.h"
|
| +
|
| +#define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32)
|
| +#define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33)
|
| +#define V4L2_CID_PANTILT_CMD (V4L2_CID_CAMERA_CLASS_BASE+34)
|
| +
|
| +// GUID of the Extension Unit for Logitech CC3300e motor control:
|
| +// {212de5ff-3080-2c4e-82d9-f587d00540bd}
|
| +#define UVC_GUID_LOGITECH_CC3000E_MOTORS \
|
| + {0x21, 0x2d, 0xe5, 0xff, 0x30, 0x80, 0x2c, 0x4e, \
|
| + 0x82, 0xd9, 0xf5, 0x87, 0xd0, 0x05, 0x40, 0xbd}
|
| +
|
| +#define LOGITECH_MOTORCONTROL_PANTILT_CMD 2
|
| +
|
| +namespace {
|
| +const int kLogitechMenuIndexGoHome = 2;
|
| +
|
| +const uvc_menu_info kLogitechCmdMenu[] = {
|
| + {1, "Set Preset"}, {2, "Get Preset"}, {3, "Go Home"}
|
| +};
|
| +
|
| +const uvc_xu_control_mapping kLogitechCmdMapping = {
|
| + V4L2_CID_PANTILT_CMD,
|
| + "Pan/Tilt Go",
|
| + UVC_GUID_LOGITECH_CC3000E_MOTORS,
|
| + LOGITECH_MOTORCONTROL_PANTILT_CMD,
|
| + 8,
|
| + 0,
|
| + V4L2_CTRL_TYPE_MENU,
|
| + UVC_CTRL_DATA_TYPE_ENUM,
|
| + const_cast<uvc_menu_info*>(&kLogitechCmdMenu[0]),
|
| + arraysize(kLogitechCmdMenu),
|
| +};
|
| +} // namespace
|
| +
|
| +namespace extensions {
|
| +
|
| +V4L2Webcam::V4L2Webcam(const std::string& device_id) : device_id_(device_id) {
|
| +}
|
| +
|
| +V4L2Webcam::~V4L2Webcam() {
|
| +}
|
| +
|
| +bool V4L2Webcam::Open() {
|
| + fd_.reset(HANDLE_EINTR(open(device_id_.c_str(), 0)));
|
| + return fd_.is_valid();
|
| +}
|
| +
|
| +bool V4L2Webcam::EnsureLogitechCommandsMapped() {
|
| + int res =
|
| + HANDLE_EINTR(ioctl(fd_.get(), UVCIOC_CTRL_MAP, &kLogitechCmdMapping));
|
| + // If mapping is successful or it's already mapped, this is a Logitech
|
| + // camera.
|
| + // NOTE: On success, occasionally EFAULT is returned. On a real error,
|
| + // ENOMEM, EPERM, EINVAL, or EOVERFLOW should be returned.
|
| + return res >= 0 || errno == EEXIST || errno == EFAULT;
|
| +}
|
| +
|
| +bool V4L2Webcam::SetWebcamParameter(int fd, uint32_t control_id, int value) {
|
| + struct v4l2_control v4l2_ctrl = {control_id, value};
|
| + int res = HANDLE_EINTR(ioctl(fd, VIDIOC_S_CTRL, &v4l2_ctrl)) >= 0;
|
| + return res >= 0;
|
| +}
|
| +
|
| +bool V4L2Webcam::GetWebcamParameter(int fd, uint32_t control_id, int* value) {
|
| + struct v4l2_control v4l2_ctrl = {control_id};
|
| +
|
| + if (HANDLE_EINTR(ioctl(fd, VIDIOC_G_CTRL, &v4l2_ctrl)))
|
| + return false;
|
| +
|
| + *value = v4l2_ctrl.value;
|
| + return true;
|
| +}
|
| +
|
| +void V4L2Webcam::Reset(bool pan, bool tilt, bool zoom) {
|
| + if (pan || tilt) {
|
| + if (EnsureLogitechCommandsMapped()) {
|
| + SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD,
|
| + kLogitechMenuIndexGoHome);
|
| + } else {
|
| + if (pan) {
|
| + struct v4l2_control v4l2_ctrl = {V4L2_CID_PAN_RESET};
|
| + HANDLE_EINTR(ioctl(fd_.get(), VIDIOC_S_CTRL, &v4l2_ctrl));
|
| + }
|
| +
|
| + if (tilt) {
|
| + struct v4l2_control v4l2_ctrl = {V4L2_CID_TILT_RESET};
|
| + HANDLE_EINTR(ioctl(fd_.get(), VIDIOC_S_CTRL, &v4l2_ctrl));
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (zoom) {
|
| + const int kDefaultZoom = 100;
|
| + SetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, kDefaultZoom);
|
| + }
|
| +}
|
| +
|
| +bool V4L2Webcam::GetPan(int* value) {
|
| + return GetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, value);
|
| +}
|
| +
|
| +bool V4L2Webcam::GetTilt(int* value) {
|
| + return GetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, value);
|
| +}
|
| +
|
| +bool V4L2Webcam::GetZoom(int* value) {
|
| + return GetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, value);
|
| +}
|
| +
|
| +bool V4L2Webcam::SetPan(int value) {
|
| + return SetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, value);
|
| +}
|
| +
|
| +bool V4L2Webcam::SetTilt(int value) {
|
| + return SetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, value);
|
| +}
|
| +
|
| +bool V4L2Webcam::SetZoom(int value) {
|
| + return SetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, value);
|
| +}
|
| +
|
| +bool V4L2Webcam::SetPanDirection(PanDirection direction) {
|
| + int direction_value = 0;
|
| + switch (direction) {
|
| + case PAN_STOP:
|
| + direction_value = 0;
|
| + break;
|
| +
|
| + case PAN_RIGHT:
|
| + direction_value = 1;
|
| + break;
|
| +
|
| + case PAN_LEFT:
|
| + direction_value = -1;
|
| + break;
|
| + }
|
| + return SetWebcamParameter(fd_.get(), V4L2_CID_PAN_SPEED, direction_value);
|
| +}
|
| +
|
| +bool V4L2Webcam::SetTiltDirection(TiltDirection direction) {
|
| + int direction_value = 0;
|
| + switch (direction) {
|
| + case TILT_STOP:
|
| + direction_value = 0;
|
| + break;
|
| +
|
| + case TILT_UP:
|
| + direction_value = 1;
|
| + break;
|
| +
|
| + case TILT_DOWN:
|
| + direction_value = -1;
|
| + break;
|
| + }
|
| + return SetWebcamParameter(fd_.get(), V4L2_CID_TILT_SPEED, direction_value);
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|