blob: c8eec90a774d6366ab486320ef0c688ebe280a56 [file] [log] [blame]
// Copyright 2014 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.
//
// This file defines the V4L2Device interface which is used by the
// V4L2DecodeAccelerator class to delegate/pass the device specific
// handling of any of the functionalities.
#ifndef MEDIA_GPU_V4L2_V4L2_DEVICE_H_
#define MEDIA_GPU_V4L2_V4L2_DEVICE_H_
#include <stddef.h>
#include <stdint.h>
#include <queue>
#include <vector>
#include <linux/videodev2.h>
#include "base/containers/flat_map.h"
#include "base/containers/small_map.h"
#include "base/files/scoped_file.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "media/base/video_codecs.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "media/base/video_frame_layout.h"
#include "media/gpu/chromeos/fourcc.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/v4l2/buffer_affinity_tracker.h"
#include "media/gpu/v4l2/v4l2_device_poller.h"
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_pixmap_handle.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_image.h"
// TODO(mojahsu): remove this once V4L2 headers are updated.
#ifndef V4L2_PIX_FMT_JPEG_RAW
#define V4L2_PIX_FMT_JPEG_RAW v4l2_fourcc('J', 'P', 'G', 'R')
#endif
#ifndef V4L2_CID_JPEG_LUMA_QUANTIZATION
#define V4L2_CID_JPEG_LUMA_QUANTIZATION (V4L2_CID_JPEG_CLASS_BASE + 5)
#endif
#ifndef V4L2_CID_JPEG_CHROMA_QUANTIZATION
#define V4L2_CID_JPEG_CHROMA_QUANTIZATION (V4L2_CID_JPEG_CLASS_BASE + 6)
#endif
// TODO(b/132589320): remove this once V4L2 header is updated.
#ifndef V4L2_PIX_FMT_MM21
// MTK 8-bit block mode, two non-contiguous planes.
#define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1')
#endif
namespace gfx {
struct NativePixmapPlane;
} // namespace gfx
namespace media {
class V4L2Queue;
class V4L2BufferRefBase;
class V4L2BuffersList;
class V4L2DecodeSurface;
class V4L2RequestRef;
// Wrapper for the 'v4l2_ext_control' structure.
struct V4L2ExtCtrl {
V4L2ExtCtrl(uint32_t id);
V4L2ExtCtrl(uint32_t id, int32_t val);
struct v4l2_ext_control ctrl;
};
// A unique reference to a buffer for clients to prepare and submit.
//
// Clients can prepare a buffer for queuing using the methods of this class, and
// then either queue it using the Queue() method corresponding to the memory
// type of the buffer, or drop the reference to make the buffer available again.
class MEDIA_GPU_EXPORT V4L2WritableBufferRef {
public:
V4L2WritableBufferRef(V4L2WritableBufferRef&& other);
V4L2WritableBufferRef() = delete;
V4L2WritableBufferRef& operator=(V4L2WritableBufferRef&& other);
// Return the memory type of the buffer. Useful to e.g. decide which Queue()
// method to use.
enum v4l2_memory Memory() const;
// Queue a MMAP buffer.
// When requests are supported, a |request_ref| can be passed along this
// the buffer to be submitted.
// If successful, true is returned and the reference to the buffer is dropped
// so this reference becomes invalid.
// In case of error, false is returned and the buffer is returned to the free
// list.
bool QueueMMap(V4L2RequestRef* request_ref = nullptr) &&;
// Queue a USERPTR buffer, assigning |ptrs| as pointer for each plane.
// The size of |ptrs| must be equal to the number of planes of this buffer.
// When requests are supported, a |request_ref| can be passed along this
// the buffer to be submitted.
// If successful, true is returned and the reference to the buffer is dropped
// so this reference becomes invalid.
// In case of error, false is returned and the buffer is returned to the free
// list.
bool QueueUserPtr(const std::vector<void*>& ptrs,
V4L2RequestRef* request_ref = nullptr) &&;
// Queue a DMABUF buffer, assigning |fds| as file descriptors for each plane.
// It is allowed the number of |fds| might be greater than the number of
// planes of this buffer. It happens when the v4l2 pixel format is single
// planar. The fd of the first plane is only used in that case.
// When requests are supported, a |request_ref| can be passed along this
// the buffer to be submitted.
// If successful, true is returned and the reference to the buffer is dropped
// so this reference becomes invalid.
// In case of error, false is returned and the buffer is returned to the free
// list.
bool QueueDMABuf(const std::vector<base::ScopedFD>& fds,
V4L2RequestRef* request_ref = nullptr) &&;
// Queue a DMABUF buffer, assigning file descriptors of |planes| for planes.
// It is allowed the number of |planes| might be greater than the number of
// planes of this buffer. It happens when the v4l2 pixel format is single
// planar. The fd of the first plane of |planes| is only used in that case.
// When requests are supported, a |request_ref| can be passed along this
// the buffer to be submitted.
// If successful, true is returned and the reference to the buffer is dropped
// so this reference becomes invalid.
// In case of error, false is returned and the buffer is returned to the free
// list.
bool QueueDMABuf(const std::vector<gfx::NativePixmapPlane>& planes,
V4L2RequestRef* request_ref = nullptr) &&;
// Queue a |video_frame| using its file descriptors as DMABUFs. The VideoFrame
// must have been constructed from its file descriptors.
// The particularity of this method is that a reference to |video_frame| is
// kept and made available again when the buffer is dequeued through
// |V4L2ReadableBufferRef::GetVideoFrame()|. |video_frame| is thus guaranteed
// to be alive until either all the |V4L2ReadableBufferRef| from the dequeued
// buffer get out of scope, or |V4L2Queue::Streamoff()| is called.
bool QueueDMABuf(scoped_refptr<VideoFrame> video_frame,
V4L2RequestRef* request_ref = nullptr) &&;
// Returns the number of planes in this buffer.
size_t PlanesCount() const;
// Returns the size of the requested |plane|, in bytes.
size_t GetPlaneSize(const size_t plane) const;
// Set the size of the requested |plane|, in bytes. It is only valid for
// USERPTR and DMABUF buffers. When using MMAP buffer, this method triggers a
// DCHECK and is a no-op for release builds.
void SetPlaneSize(const size_t plane, const size_t size);
// This method can only be used with MMAP buffers.
// It will return a pointer to the data of the |plane|th plane.
// In case of error (invalid plane index or mapping failed), a nullptr is
// returned.
void* GetPlaneMapping(const size_t plane);
// Set the timestamp field for this buffer.
void SetTimeStamp(const struct timeval& timestamp);
// Return the previously-set timestamp field for this buffer.
const struct timeval& GetTimeStamp() const;
// Set the number of bytes used for |plane|.
void SetPlaneBytesUsed(const size_t plane, const size_t bytes_used);
// Returns the previously-set number of bytes used for |plane|.
size_t GetPlaneBytesUsed(const size_t plane) const;
// Set the data offset for |plane|, in bytes.
void SetPlaneDataOffset(const size_t plane, const size_t data_offset);
// Return the VideoFrame underlying this buffer. The VideoFrame's layout
// will match that of the V4L2 format. This method will *always* return the
// same VideoFrame instance for a given V4L2 buffer. Moreover, the VideoFrame
// instance will also be the same across V4L2WritableBufferRef and
// V4L2ReadableBufferRef if both references point to the same V4L2 buffer.
// Note: at the moment, this method is valid for MMAP buffers only. It will
// return nullptr for any other buffer type.
scoped_refptr<VideoFrame> GetVideoFrame() WARN_UNUSED_RESULT;
// Return the V4L2 buffer ID of the underlying buffer.
// TODO(acourbot) This is used for legacy clients but should be ultimately
// removed. See crbug/879971
size_t BufferId() const;
// Set the passed config store to this buffer.
// This method is only used for backward compatibility until the config
// store is deprecated and should not be called by new code.
void SetConfigStore(uint32_t config_store);
V4L2WritableBufferRef(const V4L2WritableBufferRef&) = delete;
V4L2WritableBufferRef& operator=(const V4L2WritableBufferRef&) = delete;
~V4L2WritableBufferRef();
private:
// Do the actual queue operation once the v4l2_buffer structure is properly
// filled.
// When requests are supported, a |request_ref| can be passed along this
// the buffer to be submitted.
bool DoQueue(V4L2RequestRef* request_ref,
scoped_refptr<VideoFrame> video_frame) &&;
V4L2WritableBufferRef(const struct v4l2_buffer& v4l2_buffer,
base::WeakPtr<V4L2Queue> queue);
friend class V4L2BufferRefFactory;
std::unique_ptr<V4L2BufferRefBase> buffer_data_;
SEQUENCE_CHECKER(sequence_checker_);
};
// A reference to a read-only, dequeued buffer.
//
// Clients use this class to query the buffer state and content, and are
// guaranteed that the buffer will not be reused until all references are
// destroyed.
// All methods of this class must be called from the same sequence, but
// instances of V4L2ReadableBuffer objects can be destroyed from any sequence.
// They can even outlive the V4L2 buffers they originate from. This flexibility
// is required because V4L2ReadableBufferRefs can be embedded into VideoFrames,
// which are then passed to other threads and not necessarily destroyed before
// the V4L2Queue buffers are freed.
class MEDIA_GPU_EXPORT V4L2ReadableBuffer
: public base::RefCountedThreadSafe<V4L2ReadableBuffer> {
public:
// Returns whether the V4L2_BUF_FLAG_LAST flag is set for this buffer.
bool IsLast() const;
// Returns whether the V4L2_BUF_FLAG_KEYFRAME flag is set for this buffer.
bool IsKeyframe() const;
// Return the timestamp set by the driver on this buffer.
struct timeval GetTimeStamp() const;
// Returns the number of planes in this buffer.
size_t PlanesCount() const;
// Returns the number of bytes used for |plane|.
size_t GetPlaneBytesUsed(size_t plane) const;
// Returns the data offset for |plane|.
size_t GetPlaneDataOffset(size_t plane) const;
// This method can only be used with MMAP buffers.
// It will return a pointer to the data of the |plane|th plane.
// In case of error (invalid plane index or mapping failed), a nullptr is
// returned.
const void* GetPlaneMapping(const size_t plane) const;
// Return the V4L2 buffer ID of the underlying buffer.
// TODO(acourbot) This is used for legacy clients but should be ultimately
// removed. See crbug/879971
size_t BufferId() const;
// Return the VideoFrame underlying this buffer. The VideoFrame's layout
// will match that of the V4L2 format. This method will *always* return the
// same VideoFrame instance for a given V4L2 buffer. Moreover, the VideoFrame
// instance will also be the same across V4L2WritableBufferRef and
// V4L2ReadableBufferRef if both references point to the same V4L2 buffer.
// Note: at the moment, this method is valid for MMAP buffers only. It will
// return nullptr for any other buffer type.
scoped_refptr<VideoFrame> GetVideoFrame() WARN_UNUSED_RESULT;
private:
friend class V4L2BufferRefFactory;
friend class base::RefCountedThreadSafe<V4L2ReadableBuffer>;
~V4L2ReadableBuffer();
V4L2ReadableBuffer(const struct v4l2_buffer& v4l2_buffer,
base::WeakPtr<V4L2Queue> queue,
scoped_refptr<VideoFrame> video_frame);
std::unique_ptr<V4L2BufferRefBase> buffer_data_;
// If this buffer was a DMABUF buffer queued with
// QueueDMABuf(scoped_refptr<VideoFrame>), then this will hold the VideoFrame
// that has been passed at the time of queueing.
scoped_refptr<VideoFrame> video_frame_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(V4L2ReadableBuffer);
};
// Shortcut for naming consistency.
using V4L2ReadableBufferRef = scoped_refptr<V4L2ReadableBuffer>;
class V4L2Device;
class V4L2Buffer;
// Interface representing a specific queue of a |V4L2Device|. It provides free
// and queued buffer management that is commonly required by clients.
//
// Buffers managed by this class undergo the following cycle:
// 1) Allocated buffers are put into a free buffers pool, indicating that they
// are used neither by the client nor the hardware.
// 2) The client obtains a unique, writable reference to one of the free
// buffers in order to set its content and other parameters.
// 3) The client then queues the buffer obtained in 2), which invalidates its
// reference. The buffer is now prepared to be processed by the hardware.
// 4) Once the hardware is done with the buffer, it is ready to be dequeued by
// the client. The client obtains a read-only, counted reference to the
// buffer and can read its content and metadata, as well as making other
// references to it. The buffer will not be reused until all the references
// are dropped. Once this happens, the buffer goes back to the free list
// described in 1).
class MEDIA_GPU_EXPORT V4L2Queue
: public base::RefCountedThreadSafe<V4L2Queue> {
public:
// Set |fourcc| as the current format on this queue. |size| corresponds to the
// desired buffer's dimensions (i.e. width and height members of
// v4l2_pix_format_mplane (if not applicable, pass gfx::Size()).
// |buffer_size| is the desired size in bytes of the buffer for single-planar
// formats (i.e. sizeimage of the first plane). It can be set to 0 if not
// relevant for the desired format.
// If the format could be set, then the |v4l2_format| reflecting the actual
// format is returned. It is guaranteed to feature the specified |fourcc|,
// but any other parameter (including |size| and |buffer_size| may have been
// adjusted by the driver, so the caller must check their values.
absl::optional<struct v4l2_format> SetFormat(uint32_t fourcc,
const gfx::Size& size,
size_t buffer_size)
WARN_UNUSED_RESULT;
// Identical to |SetFormat|, but does not actually apply the format, and can
// be called anytime.
// Returns an adjusted V4L2 format if |fourcc| is supported by the queue, or
// |nullopt| if |fourcc| is not supported or an ioctl error happened.
absl::optional<struct v4l2_format> TryFormat(uint32_t fourcc,
const gfx::Size& size,
size_t buffer_size)
WARN_UNUSED_RESULT;
// Returns the currently set format on the queue. The result is returned as
// a std::pair where the first member is the format, or absl::nullopt if the
// format could not be obtained due to an ioctl error. The second member is
// only used in case of an error and contains the |errno| set by the failing
// ioctl. If the first member is not absl::nullopt, the second member will
// always be zero.
//
// If the second member is 0, then the first member is guaranteed to have
// a valid value. So clients that are not interested in the precise error
// message can just check that the first member is valid and go on.
//
// This pair is used because not all failures to get the format are
// necessarily errors, so we need to way to let the use decide whether it
// is one or not.
std::pair<absl::optional<struct v4l2_format>, int> GetFormat();
// Codec-specific method to get the visible rectangle of the queue, using the
// VIDIOC_G_SELECTION ioctl if available, or VIDIOC_G_CROP as a fallback.
absl::optional<gfx::Rect> GetVisibleRect();
// Allocate |count| buffers for the current format of this queue, with a
// specific |memory| allocation, and returns the number of buffers allocated
// or zero if an error occurred, or if references to any previously allocated
// buffers are still held by any clients.
//
// The number of allocated buffers may be larger than the number requested, so
// callers must always check the return value.
//
// Calling this method while buffers are still allocated results in an error.
size_t AllocateBuffers(size_t count,
enum v4l2_memory memory) WARN_UNUSED_RESULT;
// Deallocate all buffers previously allocated by |AllocateBuffers|. Any
// references to buffers previously allocated held by the client must be
// released, or this call will fail.
bool DeallocateBuffers();
// Returns the memory usage of v4l2 buffers owned by this V4L2Queue which are
// mapped in user space memory.
size_t GetMemoryUsage() const;
// Returns |memory_|, memory type of last buffers allocated by this V4L2Queue.
v4l2_memory GetMemoryType() const;
// Return a reference to a free buffer for the caller to prepare and submit,
// or nullopt if no buffer is currently free.
//
// If the caller discards the returned reference, the underlying buffer is
// made available to clients again.
absl::optional<V4L2WritableBufferRef> GetFreeBuffer();
// Return the buffer at index |requested_buffer_id|, if it is available at
// this time.
//
// If the buffer is currently in use or the provided index is invalid,
// return |absl::nullopt|.
absl::optional<V4L2WritableBufferRef> GetFreeBuffer(
size_t requested_buffer_id);
// Return a V4L2 buffer suitable for the passed VideoFrame.
//
// This method will try as much as possible to always return the same V4L2
// buffer when the same frame is passed again, to avoid memory unmap
// operations in the kernel driver.
//
// The operating mode of the queue must be DMABUF, and the VideoFrame must
// be backed either by a GpuMemoryBuffer, or by DMABUFs. In the case of
// DMABUFs, this method will only work correctly if the same DMABUFs are
// passed with each call, i.e. no dup shall be performed.
//
// This should be the preferred way to obtain buffers when using DMABUF mode,
// since it will maximize performance in that case provided the number of
// different VideoFrames passed to this method does not exceed the number of
// V4L2 buffers allocated on the queue.
absl::optional<V4L2WritableBufferRef> GetFreeBufferForFrame(
const VideoFrame& frame);
// Attempt to dequeue a buffer, and return a reference to it if one was
// available.
//
// The first element of the returned pair will be false if an error occurred,
// in which case the second element will be nullptr. If no error occurred,
// then the first element will be true and the second element will contain a
// reference to the dequeued buffer if one was available, or nullptr
// otherwise.
// Dequeued buffers will not be reused by the driver until all references to
// them are dropped.
std::pair<bool, V4L2ReadableBufferRef> DequeueBuffer();
// Returns true if this queue is currently streaming.
bool IsStreaming() const;
// If not currently streaming, starts streaming. Returns true if we started
// streaming, or were already streaming, or false if we were not streaming
// and an error occurred when attempting to start the stream. On failure, any
// previously-queued buffers will be dequeued without processing and made
// available to the client, while any buffers held by the client will remain
// unchanged and their ownership will remain with the client.
bool Streamon();
// If currently streaming, stops streaming. Also make all queued buffers
// available to the client again regardless of the streaming state.
// If an error occurred while attempting to stop streaming, then false is
// returned and queued buffers are left untouched since the V4L2 queue may
// still be using them.
bool Streamoff();
// Returns the number of buffers currently allocated for this queue.
size_t AllocatedBuffersCount() const;
// Returns the number of currently free buffers on this queue.
size_t FreeBuffersCount() const;
// Returns the number of buffers currently queued on this queue.
size_t QueuedBuffersCount() const;
// Returns true if requests are supported by this queue.
bool SupportsRequests();
// TODO (b/166275274) : Remove this once V4L2 properly supports modifiers.
// Out of band method to configure V4L2 for modifier use.
absl::optional<struct v4l2_format> SetModifierFormat(uint64_t modifier,
const gfx::Size& size);
private:
~V4L2Queue();
// Called when clients request a buffer to be queued.
bool QueueBuffer(struct v4l2_buffer* v4l2_buffer,
scoped_refptr<VideoFrame> video_frame);
const enum v4l2_buf_type type_;
enum v4l2_memory memory_ = V4L2_MEMORY_MMAP;
bool is_streaming_ = false;
// Set to true if the queue supports requests.
bool supports_requests_ = false;
size_t planes_count_ = 0;
// Current format as set by SetFormat.
absl::optional<struct v4l2_format> current_format_;
std::vector<std::unique_ptr<V4L2Buffer>> buffers_;
// Buffers that are available for client to get and submit.
// Buffers in this list are not referenced by anyone else than ourselves.
scoped_refptr<V4L2BuffersList> free_buffers_;
// Buffers that have been queued by the client, and not dequeued yet, indexed
// by the v4l2_buffer queue ID. The value will be set to the VideoFrame that
// has been passed when we queued the buffer, if any.
base::small_map<std::map<size_t, scoped_refptr<VideoFrame>>> queued_buffers_;
// Keep track of which buffer was assigned to which frame by
// |GetFreeBufferForFrame()| so we reuse the same buffer in subsequent calls.
BufferAffinityTracker affinity_tracker_;
scoped_refptr<V4L2Device> device_;
// Callback to call in this queue's destructor.
base::OnceClosure destroy_cb_;
V4L2Queue(scoped_refptr<V4L2Device> dev,
enum v4l2_buf_type type,
base::OnceClosure destroy_cb);
friend class V4L2QueueFactory;
friend class V4L2BufferRefBase;
friend class base::RefCountedThreadSafe<V4L2Queue>;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<V4L2Queue> weak_this_factory_;
DISALLOW_COPY_AND_ASSIGN(V4L2Queue);
};
class V4L2Request;
// Base class for all request related classes.
//
// This class is used to manage requests and not intended to be used
// directly.
class MEDIA_GPU_EXPORT V4L2RequestRefBase {
protected:
V4L2RequestRefBase(V4L2RequestRefBase&& req_base);
V4L2RequestRefBase(V4L2Request* request);
~V4L2RequestRefBase();
V4L2Request* request_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(V4L2RequestRefBase);
};
class V4L2SubmittedRequestRef;
// Interface representing a request reference.
//
// The request reference allows the client to set the controls and buffer to
// the request. It also allows to submit the request to the driver.
// Once the request as been submitted, the request reference cannot be used
// any longer.
// Instead, when a request is submitted, an object denoting a submitted request
// is returned.
class MEDIA_GPU_EXPORT V4L2RequestRef : public V4L2RequestRefBase {
public:
V4L2RequestRef(V4L2RequestRef&& req_ref) :
V4L2RequestRefBase(std::move(req_ref)) {}
// Apply controls to the request.
bool ApplyCtrls(struct v4l2_ext_controls* ctrls) const;
// Apply buffer to the request.
bool ApplyQueueBuffer(struct v4l2_buffer* buffer) const;
// Submits the request to the driver.
absl::optional<V4L2SubmittedRequestRef> Submit() &&;
private:
friend class V4L2RequestsQueue;
V4L2RequestRef(V4L2Request* request) : V4L2RequestRefBase(request) {}
DISALLOW_COPY_AND_ASSIGN(V4L2RequestRef);
};
// Interface representing a submitted request.
//
// After a request is submitted, a request reference cannot be used anymore.
// Instead, an object representing a submitted request is returned.
// Through this object, it is possible to check whether the request
// completed or not.
class MEDIA_GPU_EXPORT V4L2SubmittedRequestRef : public V4L2RequestRefBase {
public:
V4L2SubmittedRequestRef(V4L2SubmittedRequestRef&& req_ref) :
V4L2RequestRefBase(std::move(req_ref)) {}
// Indicates if the request has completed.
bool IsCompleted();
private:
friend class V4L2RequestRef;
V4L2SubmittedRequestRef(V4L2Request* request) : V4L2RequestRefBase(request) {}
DISALLOW_COPY_AND_ASSIGN(V4L2SubmittedRequestRef);
};
// Interface representing a queue of requests. The requests queue manages and
// recycles requests.
//
// Requests undergo the following cycle:
// 1) Allocated requests are put into a free request pool, indicating that they
// are not used by the client and free to be used.
// 2) The client obtains a unique request reference to one of the free
// requests in order to set its controls and buffer.
// 3) The client then submit the request obtained in 2), which invalidates its
// reference and returns a reference to a submitted request.
// 4) Once client releases the submitted request reference, the request goes
// back to the free request pool described in 1).
class MEDIA_GPU_EXPORT V4L2RequestsQueue {
public:
// Gets a free request. If no request is available, a non-valid request
// reference will be returned.
absl::optional<V4L2RequestRef> GetFreeRequest();
private:
// File descriptor of the media device (/dev/mediaX) from which requests
// are created.
base::ScopedFD media_fd_;
// Stores all available requests.
std::vector<std::unique_ptr<V4L2Request>> requests_;
std::queue<V4L2Request*> free_requests_;
// Returns a new request file descriptor.
absl::optional<base::ScopedFD> CreateRequestFD();
friend class V4L2Request;
// Returns a request to the queue after being used.
void ReturnRequest(V4L2Request* request);
friend class V4L2Device;
friend std::unique_ptr<V4L2RequestsQueue>::deleter_type;
V4L2RequestsQueue(base::ScopedFD&& media_fd);
~V4L2RequestsQueue();
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(V4L2RequestsQueue);
};
class MEDIA_GPU_EXPORT V4L2Device
: public base::RefCountedThreadSafe<V4L2Device> {
public:
// Utility format conversion functions
// If there is no corresponding single- or multi-planar format, returns 0.
static uint32_t VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
bool slice_based);
std::vector<VideoCodecProfile> V4L2PixFmtToVideoCodecProfiles(
uint32_t pix_fmt);
// Calculates the largest plane's allocation size requested by a V4L2 device.
static gfx::Size AllocatedSizeFromV4L2Format(
const struct v4l2_format& format);
// Convert required H264 profile and level to V4L2 enums.
static int32_t VideoCodecProfileToV4L2H264Profile(VideoCodecProfile profile);
static int32_t H264LevelIdcToV4L2H264Level(uint8_t level_idc);
// Composes VideoFrameLayout based on v4l2_format.
// If error occurs, it returns absl::nullopt.
static absl::optional<VideoFrameLayout> V4L2FormatToVideoFrameLayout(
const struct v4l2_format& format);
// Returns number of planes of |pix_fmt|.
static size_t GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt);
enum class Type {
kDecoder,
kEncoder,
kImageProcessor,
kJpegDecoder,
kJpegEncoder,
};
// Create and initialize an appropriate V4L2Device instance for the current
// platform, or return nullptr if not available.
static scoped_refptr<V4L2Device> Create();
// Open a V4L2 device of |type| for use with |v4l2_pixfmt|.
// Return true on success.
// The device will be closed in the destructor.
virtual bool Open(Type type, uint32_t v4l2_pixfmt) = 0;
// Returns the V4L2Queue corresponding to the requested |type|, or nullptr
// if the requested queue type is not supported.
scoped_refptr<V4L2Queue> GetQueue(enum v4l2_buf_type type);
// Parameters and return value are the same as for the standard ioctl() system
// call.
virtual int Ioctl(int request, void* arg) = 0;
// This method sleeps until either:
// - SetDevicePollInterrupt() is called (on another thread),
// - |poll_device| is true, and there is new data to be read from the device,
// or an event from the device has arrived; in the latter case
// |*event_pending| will be set to true.
// Returns false on error, true otherwise.
// This method should be called from a separate thread.
virtual bool Poll(bool poll_device, bool* event_pending) = 0;
// These methods are used to interrupt the thread sleeping on Poll() and force
// it to return regardless of device state, which is usually when the client
// is no longer interested in what happens with the device (on cleanup,
// client state change, etc.). When SetDevicePollInterrupt() is called, Poll()
// will return immediately, and any subsequent calls to it will also do so
// until ClearDevicePollInterrupt() is called.
virtual bool SetDevicePollInterrupt() = 0;
virtual bool ClearDevicePollInterrupt() = 0;
// Wrappers for standard mmap/munmap system calls.
virtual void* Mmap(void* addr,
unsigned int len,
int prot,
int flags,
unsigned int offset) = 0;
virtual void Munmap(void* addr, unsigned int len) = 0;
// Return a vector of dmabuf file descriptors, exported for V4L2 buffer with
// |index|, assuming the buffer contains |num_planes| V4L2 planes and is of
// |type|. Return an empty vector on failure.
// The caller is responsible for closing the file descriptors after use.
virtual std::vector<base::ScopedFD> GetDmabufsForV4L2Buffer(
int index,
size_t num_planes,
enum v4l2_buf_type type) = 0;
// Return true if the given V4L2 pixfmt can be used in CreateEGLImage()
// for the current platform.
virtual bool CanCreateEGLImageFrom(const Fourcc fourcc) const = 0;
// Create an EGLImage from provided |handle|, taking full ownership of it.
// Some implementations may also require the V4L2 |buffer_index| of the buffer
// for which |handle| has been exported.
// Return EGL_NO_IMAGE_KHR on failure.
virtual EGLImageKHR CreateEGLImage(EGLDisplay egl_display,
EGLContext egl_context,
GLuint texture_id,
const gfx::Size& size,
unsigned int buffer_index,
const Fourcc fourcc,
gfx::NativePixmapHandle handle) const = 0;
// Create a GLImage from provided |handle|, taking full ownership of it.
virtual scoped_refptr<gl::GLImage> CreateGLImage(
const gfx::Size& size,
const Fourcc fourcc,
gfx::NativePixmapHandle handle) const = 0;
// Destroys the EGLImageKHR.
virtual EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
EGLImageKHR egl_image) const = 0;
// Returns the supported texture target for the V4L2Device.
virtual GLenum GetTextureTarget() const = 0;
// Returns the preferred V4L2 input formats for |type| or empty if none.
virtual std::vector<uint32_t> PreferredInputFormat(Type type) const = 0;
// Get minimum and maximum resolution for fourcc |pixelformat| and store to
// |min_resolution| and |max_resolution|.
void GetSupportedResolution(uint32_t pixelformat,
gfx::Size* min_resolution,
gfx::Size* max_resolution);
std::vector<uint32_t> EnumerateSupportedPixelformats(v4l2_buf_type buf_type);
// NOTE: The below methods to query capabilities have a side effect of
// closing the previously-open device, if any, and should not be called after
// Open().
// TODO(b/150431552): fix this.
// Return V4L2 pixelformats supported by the available image processor
// devices for |buf_type|.
virtual std::vector<uint32_t> GetSupportedImageProcessorPixelformats(
v4l2_buf_type buf_type) = 0;
// Return supported profiles for decoder, including only profiles for given
// fourcc |pixelformats|.
virtual VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles(
const size_t num_formats,
const uint32_t pixelformats[]) = 0;
// Return supported profiles for encoder.
virtual VideoEncodeAccelerator::SupportedProfiles
GetSupportedEncodeProfiles() = 0;
// Return true if image processing is supported, false otherwise.
virtual bool IsImageProcessingSupported() = 0;
// Return true if JPEG codec is supported, false otherwise.
virtual bool IsJpegDecodingSupported() = 0;
virtual bool IsJpegEncodingSupported() = 0;
// Start polling on this V4L2Device. |event_callback| will be posted to
// the caller's sequence if a buffer is ready to be dequeued and/or a V4L2
// event has been posted. |error_callback| will be posted to the client's
// sequence if a polling error has occurred.
bool StartPolling(V4L2DevicePoller::EventCallback event_callback,
base::RepeatingClosure error_callback);
// Stop polling this V4L2Device if polling was active. No new events will
// be posted after this method has returned.
bool StopPolling();
// Schedule a polling event if polling is enabled. This method is intended
// to be called from V4L2Queue, clients should not need to call it directly.
void SchedulePoll();
// Attempt to dequeue a V4L2 event and return it.
absl::optional<struct v4l2_event> DequeueEvent();
// Returns requests queue to get free requests. A null pointer is returned if
// the queue creation failed or if requests are not supported.
V4L2RequestsQueue* GetRequestsQueue();
// Check whether the V4L2 control with specified |ctrl_id| is supported.
bool IsCtrlExposed(uint32_t ctrl_id);
// Set the specified list of |ctrls| for the specified |ctrl_class|, returns
// whether the operation succeeded. If |request_ref| is not nullptr, the
// controls are applied to the request instead of globally for the device.
bool SetExtCtrls(uint32_t ctrl_class,
std::vector<V4L2ExtCtrl> ctrls,
V4L2RequestRef* request_ref = nullptr);
// Get the value of a single control, or absl::nullopt of the control is not
// exposed by the device.
absl::optional<struct v4l2_ext_control> GetCtrl(uint32_t ctrl_id);
// Set periodic keyframe placement (group of pictures length)
bool SetGOPLength(uint32_t gop_length);
protected:
friend class base::RefCountedThreadSafe<V4L2Device>;
V4L2Device();
virtual ~V4L2Device();
VideoDecodeAccelerator::SupportedProfiles EnumerateSupportedDecodeProfiles(
const size_t num_formats,
const uint32_t pixelformats[]);
VideoEncodeAccelerator::SupportedProfiles EnumerateSupportedEncodeProfiles();
private:
// Perform platform-specific initialization of the device instance.
// Return true on success, false on error or if the particular implementation
// is not available.
virtual bool Initialize() = 0;
// Associates a v4l2_buf_type to its queue.
base::flat_map<enum v4l2_buf_type, V4L2Queue*> queues_;
// Callback that is called upon a queue's destruction, to cleanup its pointer
// in queues_.
void OnQueueDestroyed(v4l2_buf_type buf_type);
// Used if EnablePolling() is called to signal the user that an event
// happened or a buffer is ready to be dequeued.
std::unique_ptr<V4L2DevicePoller> device_poller_;
// Indicates whether the request queue creation has been tried once.
bool requests_queue_creation_called_ = false;
// The request queue stores all requests allocated to be used.
std::unique_ptr<V4L2RequestsQueue> requests_queue_;
SEQUENCE_CHECKER(client_sequence_checker_);
};
} // namespace media
#endif // MEDIA_GPU_V4L2_V4L2_DEVICE_H_