blob: e2f66a539dfe3cbea92954c224e1dbd7e0116c79 [file] [log] [blame]
/*
* Copyright (C) 2013-2017 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CROS_CAMERA_V4L2_DEVICE_H_
#define INCLUDE_CROS_CAMERA_V4L2_DEVICE_H_
#include <linux/v4l2-subdev.h>
#include <linux/videodev2.h>
#include <poll.h>
#include <atomic>
#include <string>
#include <vector>
#include <base/synchronization/lock.h>
#include "cros-camera/export.h"
namespace cros {
/*
* Wrapper for v4l2_buffer to provide compatible
* interfaces for multi-plane buffers.
*/
class CROS_CAMERA_EXPORT V4L2Buffer {
public:
V4L2Buffer();
explicit V4L2Buffer(const V4L2Buffer& buf);
uint32_t Index() const { return v4l2_buf_.index; }
void SetIndex(uint32_t index) { v4l2_buf_.index = index; }
uint32_t Type() const { return v4l2_buf_.type; }
void SetType(uint32_t type);
uint32_t Flags() const { return v4l2_buf_.flags; }
void SetFlags(uint32_t flags) { v4l2_buf_.flags = flags; }
uint32_t Field() const { return v4l2_buf_.field; }
void SetField(uint32_t field) { v4l2_buf_.field = field; }
struct timeval Timestamp() const {
return v4l2_buf_.timestamp;
}
void SetTimestamp(struct timeval timestamp) {
v4l2_buf_.timestamp = timestamp;
}
struct v4l2_timecode Timecode() const {
return v4l2_buf_.timecode;
}
void SetTimecode(struct v4l2_timecode timecode) {
v4l2_buf_.timecode = timecode;
}
uint32_t Sequence() const { return v4l2_buf_.sequence; }
void SetSequence(uint32_t sequence) { v4l2_buf_.sequence = sequence; }
uint32_t Memory() const { return v4l2_buf_.memory; }
void SetMemory(uint32_t memory) { v4l2_buf_.memory = memory; }
uint32_t Offset(uint32_t plane) const;
void SetOffset(uint32_t offset, uint32_t plane);
uintptr_t Userptr(uint32_t plane) const;
void SetUserptr(uintptr_t userptr, uint32_t plane);
int Fd(uint32_t plane) const;
void SetFd(int fd, uint32_t plane);
uint32_t BytesUsed(uint32_t plane) const;
void SetBytesUsed(uint32_t bytesused, uint32_t plane);
uint32_t Length(uint32_t plane) const;
void SetLength(uint32_t length, uint32_t plane);
const struct v4l2_buffer* Get() const { return &v4l2_buf_; }
const V4L2Buffer& operator=(const V4L2Buffer& buf);
private:
struct v4l2_buffer v4l2_buf_;
std::vector<struct v4l2_plane> planes_; // For multi-planar buffers.
};
/*
* Wrapper for v4l2_format to provide compatible
* interfaces for multi-plane buffers.
*/
class CROS_CAMERA_EXPORT V4L2Format {
public:
V4L2Format() { v4l2_fmt_ = {}; }
explicit V4L2Format(const struct v4l2_format& fmt) { v4l2_fmt_ = fmt; }
const V4L2Format& operator=(const V4L2Format& fmt);
uint32_t Type() const { return v4l2_fmt_.type; }
void SetType(uint32_t type);
uint32_t Width() const;
void SetWidth(uint32_t width);
uint32_t Height() const;
void SetHeight(uint32_t height);
uint32_t PixelFormat() const;
void SetPixelFormat(uint32_t format);
uint32_t Field() const;
void SetField(uint32_t field);
uint32_t BytesPerLine(uint32_t plane) const;
void SetBytesPerLine(uint32_t bytesperline, uint32_t plane);
uint32_t SizeImage(uint32_t plane) const;
void SetSizeImage(uint32_t size, uint32_t plane);
struct v4l2_format* Get() {
return &v4l2_fmt_;
}
private:
struct v4l2_format v4l2_fmt_;
};
/**
* A class encapsulating simple V4L2 device operations.
*
* Base class that contains common V4L2 operations used by video nodes and
* subdevices. It provides a slightly higher interface than IOCTLS to access
* the devices. It also stores:
* - Name
* - File descriptor
*/
class CROS_CAMERA_EXPORT V4L2Device {
public:
friend class V4L2DevicePoller;
explicit V4L2Device(const std::string name);
virtual ~V4L2Device();
// This method opens the V4L2 device.
//
// Args:
// |flags|: open flags, e.g. O_RDWR, O_NONBLOCK.
//
// Returns:
// 0 on success; corresponding error code on failure.
virtual int Open(int flags);
// This method closes the V4L2 device.
//
// Returns:
// 0 on success; corresponding error code on failure.
virtual int Close();
// These methods sets the control of V4L2 device.
//
// Args:
// |id|: control identifier.
// |value|: new value.
//
// Returns:
// 0 on success; corresponding error code on failure.
int SetControl(int id, int32_t value);
int SetControl(int id, int64_t value);
int SetControl(int id, const std::string value);
// These methods gets the control of V4L2 device.
//
// Args:
// |id|: control identifier.
// |value|: current value.
//
// Returns:
// 0 on success; corresponding error code on failure.
int GetControl(int id, int32_t* value);
int GetControl(int id, int64_t* value);
int GetControl(int id, std::string* value);
// This method enumerates the menu control items of V4L2 device.
//
// Args:
// |menu|: menu control.
//
// Returns:
// 0 on success; corresponding error code on failure.
int QueryMenu(v4l2_querymenu* menu);
// This method enumerates the control of V4L2 device.
//
// Args:
// |control|: control.
//
// Returns:
// 0 on success; corresponding error code on failure.
int QueryControl(v4l2_queryctrl* control);
// This method subscribes event of V4L2 device.
//
// Args:
// |event|: event type.
//
// Returns:
// 0 on success; corresponding error code on failure.
int SubscribeEvent(int event);
// This method unsubscribes event of V4L2 device.
//
// Args:
// |event|: event type.
//
// Returns:
// 0 on success; corresponding error code on failure.
int UnsubscribeEvent(int event);
// This method dequeues event of V4L2 device.
//
// Args:
// |event|: V4L2 event.
//
// Returns:
// 0 on success; corresponding error code on failure.
int DequeueEvent(struct v4l2_event* event);
// This method checks whether V4L2 device is opened.
//
// Returns:
// True if it is opened.
bool IsOpened() { return fd_ != -1; }
// This method gets the name of V4L2 device.
//
// Returns:
// Device name.
const std::string Name() { return name_; }
private:
int SetControl(struct v4l2_ext_control* ext_control);
int GetControl(struct v4l2_ext_control* ext_control);
protected:
std::string name_; /*!< path to device in file system, ex: /dev/video0 */
int fd_; /*!< file descriptor obtained when device is open */
};
class CROS_CAMERA_EXPORT V4L2DevicePoller {
public:
// |flush_fd|: file descriptor of the pipe device that will be used to return
// from Poll() in case of flush request, i.e., to abort poll before timeout
explicit V4L2DevicePoller(std::vector<V4L2Device*> devices, int flush_fd);
virtual ~V4L2DevicePoller() {}
// This method polls the V4L2 device.
//
// Args:
// |timeout_ms|: the number of milliseconds that Poll() should block
// waiting for devices to become ready.
// |events|: a bit mask specifying the events the client is
// interested in.
// |ready_devices|: devices that become ready
//
// Returns:
// On success, a positive number is returned; this is the number of
// devices which have the specified events occurred. A value of 0
// indicates that the call timed out and no file descriptors were ready.
// On error, -1 is returned.
int Poll(int timeout_ms, int events, std::vector<V4L2Device*>* ready_devices);
private:
std::vector<V4L2Device*> devices_;
int flush_fd_;
std::vector<struct pollfd> poll_fds_;
};
/**
* A class encapsulating simple V4L2 video device node operations.
*
* This class extends V4L2Device and adds extra internal state
* and more convenience methods to manage an associated buffer pool
* with the device.
* This class introduces new methods specific to control video device nodes.
*/
class CROS_CAMERA_EXPORT V4L2VideoNode final : public V4L2Device {
public:
explicit V4L2VideoNode(const std::string name);
~V4L2VideoNode();
// This method opens the video device.
//
// Args:
// |flags|: open flags, e.g. O_RDWR, O_NONBLOCK.
//
// Returns:
// 0 on success; corresponding error code on failure.
int Open(int flags) final;
// This method closes the video device.
//
// Returns:
// 0 on success; corresponding error code on failure.
int Close() final;
// This method gets the data format of video device.
//
// Args:
// |format|: V4L2 format returned.
//
// Returns:
// 0 on success; corresponding error code on failure.
int GetFormat(V4L2Format* format);
// This method configures the data format of video device.
//
// Args:
// |format|: V4L2 format.
//
// Returns:
// 0 on success; corresponding error code on failure.
int SetFormat(const V4L2Format& format);
// This method configures the selection rectangles of video device.
//
// Args:
// |selection|: V4L2 selection rectangle.
//
// Returns:
// 0 on success; corresponding error code on failure.
int SetSelection(const struct v4l2_selection& selection);
// This method get the memory type of video device.
//
// Returns:
// V4L2 memory type.
enum v4l2_memory GetMemoryType();
// This method maps video device buffers into memory.
//
// Args:
// |index|: number of the buffer.
// |prot|: desired memory protection of the mapping.
// |flags|: mapping flags.
// |mapped|: mapped addresses.
//
// Returns:
// A pointer to the mapped area; MAP_FAILED on failure.
int MapMemory(unsigned int index,
int prot,
int flags,
std::vector<void*>* mapped);
// This method sets up buffers of the video device. If USERPTR memory type is
// specified, the caller may need to fill in the userptr field of returned
// buffers.
//
// Args:
// |num_buffers|: number of buffers to set up
// |is_cached|: whether the buffers are cached or not
// |memory_type_|: memory type of buffers
// |buffers|: buffers returned
//
// Returns:
// 0 on success; corresponding error code on failure.
int SetupBuffers(size_t num_buffers,
bool is_cached,
enum v4l2_memory memory_type,
std::vector<V4L2Buffer>* buffers);
// This method stops streaming of the video device.
//
// Returns:
// 0 on success; corresponding error code on failure.
int Stop();
// This method starts streaming of the video device.
//
// Returns:
// 0 on success; corresponding error code on failure.
int Start();
// This method grabs a buffer from the video device's outgoing queue.
//
// Args:
// |buf|: V4L2 buffer.
//
// Returns:
// 0 on success; corresponding error code on failure.
int GrabFrame(V4L2Buffer* buf);
// This method enqueues a buffer in the video device's outgoing queue.
//
// Args:
// |buf|: V4L2 buffer.
//
// Returns:
// 0 on success; corresponding error code on failure.
int PutFrame(V4L2Buffer* buf);
// This method exports a buffer as DMABUF file descriptors.
//
// Args:
// |index|: number of the buffer.
// |fds|: exported file descriptors.
//
// Returns:
// 0 on success; corresponding error code on failure.
int ExportFrame(unsigned int index, std::vector<int>* fds);
private:
// This method queries the capabilities of the video device.
//
// Args:
// |cap|: V4L2 capabilities
//
// Returns:
// 0 on success; corresponding error code on failure.
int QueryCap(struct v4l2_capability* cap);
int Qbuf(V4L2Buffer* buf);
int Dqbuf(V4L2Buffer* buf);
int QueryBuffer(int index, enum v4l2_memory memory_type, V4L2Buffer* buf);
int RequestBuffers(size_t num_buffers, enum v4l2_memory memory_type);
int StopLocked();
void DestroyBufferPool();
void PrintBufferInfo(const std::string func, const V4L2Buffer& buf);
enum class VideoNodeState {
CLOSED = 0, /*!< kernel device closed */
OPEN, /*!< device node opened */
CONFIGURED, /*!< device format set, IOC_S_FMT */
PREPARED, /*!< device has requested buffers (set_buffer_pool)*/
STARTED, /*!< stream started, IOC_STREAMON */
ERROR /*!< undefined state */
};
// Lock to protect |state_|
base::Lock state_lock_;
VideoNodeState state_;
// Device capture configuration
V4L2Format format_;
bool is_buffer_cached_;
enum v4l2_buf_type buffer_type_;
enum v4l2_memory memory_type_;
};
/**
* A class encapsulating simple V4L2 sub device node operations.
*
* Sub-devices are control points to the new V4L2 media controller
* architecture.
*/
class CROS_CAMERA_EXPORT V4L2Subdevice final : public V4L2Device {
public:
explicit V4L2Subdevice(const std::string name);
~V4L2Subdevice();
// This method opens the sub-device.
//
// Args:
// |flags|: open flags, e.g. O_RDWR, O_NONBLOCK.
//
// Returns:
// 0 on success; corresponding error code on failure.
int Open(int flags) final;
// This method closes the sub-device.
//
// Returns:
// 0 on success; corresponding error code on failure.
int Close() final;
// This method configures format of the sub-device.
//
// Args:
// |format|: V4L2 sub-device format.
//
// Returns:
// 0 on success; corresponding error code on failure.
int SetFormat(const struct v4l2_subdev_format& format);
// This method configures the selection rectangles of sub-device pad.
//
// Args:
// |selection|: V4L2 sub-device selection rectangle.
//
// Returns:
// 0 on success; corresponding error code on failure.
int SetSelection(const struct v4l2_subdev_selection& selection);
// This method gets the format of sub-device pad.
//
// Args:
// |pad_index|: pad number.
// |width|: image width.
// |height|: image height.
// |code|: format code.
//
// Returns:
// 0 on success; corresponding error code on failure.
int GetPadFormat(int pad_index, int* width, int* height, int* code);
private:
int GetFormat(struct v4l2_subdev_format* format);
private:
enum class SubdevState {
CLOSED = 0, /*!< kernel device closed */
OPEN, /*!< device node opened */
CONFIGURED, /*!< device format set, IOC_S_FMT */
ERROR /*!< undefined state */
};
// Lock to protect |state_|
base::Lock state_lock_;
SubdevState state_;
};
} // namespace cros
#endif // INCLUDE_CROS_CAMERA_V4L2_DEVICE_H_