#ifndef MEDIA_GPU_V4L2_TEST_V4L2_IOCTL_SHIM_H_
#define MEDIA_GPU_V4L2_TEST_V4L2_IOCTL_SHIM_H_
#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include <linux/videodev2.h>
#include <string.h>
#include <set>
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "ui/gfx/geometry/size.h"
namespace media {
namespace v4l2_test {
class MmappedBuffer : public base::RefCounted<MmappedBuffer> {
public:
REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
MmappedBuffer(const base::PlatformFile decode_fd,
const struct v4l2_buffer& v4l2_buffer);
class MmappedPlane {
public:
raw_ptr<void> start_addr;
const size_t length;
size_t bytes_used = 0;
MmappedPlane(void* start, size_t len) : start_addr(start), length(len) {}
void CopyInSlice(const uint8_t* frame_data,
size_t frame_size,
bool is_first_slice) {
if (is_first_slice) {
bytes_used = 0;
}
LOG_ASSERT((bytes_used + frame_size) < length)
<< "Not enough memory allocated to copy into.";
memcpy(static_cast<uint8_t*>(start_addr) + bytes_used, frame_data,
frame_size);
bytes_used += frame_size;
}
void CopyIn(const uint8_t* frame_data, size_t frame_size) {
CopyInSlice(frame_data, frame_size, true);
}
};
using MmappedPlanes = std::vector<MmappedPlane>;
MmappedPlanes& mmapped_planes() { return mmapped_planes_; }
uint32_t buffer_id() const { return buffer_id_; }
void set_buffer_id(uint32_t buffer_id) { buffer_id_ = buffer_id; }
uint32_t frame_number() const { return frame_number_; }
void set_frame_number(uint32_t frame_number) { frame_number_ = frame_number; }
private:
friend class base::RefCounted<MmappedBuffer>;
~MmappedBuffer();
MmappedBuffer(const MmappedBuffer&) = delete;
MmappedBuffer& operator=(const MmappedBuffer&) = delete;
MmappedPlanes mmapped_planes_;
const uint32_t num_planes_;
uint32_t buffer_id_;
uint32_t frame_number_;
};
using MmappedBuffers = std::vector<scoped_refptr<MmappedBuffer>>;
class V4L2Queue {
public:
V4L2Queue(enum v4l2_buf_type type,
const gfx::Size& resolution,
enum v4l2_memory memory);
V4L2Queue(const V4L2Queue&) = delete;
V4L2Queue& operator=(const V4L2Queue&) = delete;
~V4L2Queue();
scoped_refptr<MmappedBuffer> GetBuffer(const size_t buffer_id) const;
enum v4l2_buf_type type() const { return type_; }
uint32_t fourcc() const { return fourcc_; }
void set_fourcc(uint32_t fourcc) { fourcc_ = fourcc; }
gfx::Size resolution() const { return resolution_; }
void set_resolution(gfx::Size resolution) { resolution_ = resolution; }
enum v4l2_memory memory() const { return memory_; }
void set_buffers(MmappedBuffers& buffers) { buffers_ = buffers; }
uint32_t num_buffers() const { return num_buffers_; }
void set_num_buffers(uint32_t num_buffers) { num_buffers_ = num_buffers; }
uint32_t num_planes() const { return num_planes_; }
void set_num_planes(uint32_t num_planes) { num_planes_ = num_planes; }
uint32_t last_queued_buffer_id() const { return last_queued_buffer_id_; }
void set_last_queued_buffer_id(uint32_t last_queued_buffer_id) {
last_queued_buffer_id_ = last_queued_buffer_id;
}
int media_request_fd() const { return media_request_fd_; }
void set_media_request_fd(int media_request_fd) {
media_request_fd_ = media_request_fd;
}
std::set<uint32_t> queued_buffer_ids() const { return queued_buffer_ids_; }
void QueueBufferId(uint32_t last_queued_buffer_id) {
queued_buffer_ids_.insert(last_queued_buffer_id);
}
void DequeueBufferId(uint32_t buffer_id) {
queued_buffer_ids_.erase(buffer_id);
}
void DequeueAllBufferIds() { queued_buffer_ids_.clear(); }
private:
const enum v4l2_buf_type type_;
uint32_t fourcc_;
MmappedBuffers buffers_;
uint32_t num_buffers_;
gfx::Size resolution_;
uint32_t num_planes_;
const enum v4l2_memory memory_;
int media_request_fd_;
uint32_t last_queued_buffer_id_;
std::set<uint32_t> queued_buffer_ids_;
};
class V4L2IoctlShim {
public:
V4L2IoctlShim(uint32_t coded_fourcc);
V4L2IoctlShim(const V4L2IoctlShim&) = delete;
V4L2IoctlShim& operator=(const V4L2IoctlShim&) = delete;
~V4L2IoctlShim();
[[nodiscard]] bool QueryCtrl(const uint32_t ctrl_id) const;
[[nodiscard]] bool EnumFrameSizes(uint32_t fourcc) const;
void SetFmt(const std::unique_ptr<V4L2Queue>& queue) const;
void GetFmt(struct v4l2_format* fmt) const;
void TryFmt(struct v4l2_format* fmt) const;
void ReqBufs(std::unique_ptr<V4L2Queue>& queue, uint32_t count) const;
[[nodiscard]] bool QBuf(const std::unique_ptr<V4L2Queue>& queue,
const uint32_t buffer_id) const;
void DQBuf(const std::unique_ptr<V4L2Queue>& queue,
uint32_t* buffer_id) const;
void StreamOn(const enum v4l2_buf_type type) const;
void StreamOff(const enum v4l2_buf_type type) const;
void SetExtCtrls(const std::unique_ptr<V4L2Queue>& queue,
v4l2_ext_controls* ext_ctrls,
bool immediate = false) const;
void MediaIocRequestAlloc(int* req_fd) const;
void MediaRequestIocQueue(const std::unique_ptr<V4L2Queue>& queue) const;
void MediaRequestIocReinit(const std::unique_ptr<V4L2Queue>& queue) const;
void WaitForRequestCompletion(const std::unique_ptr<V4L2Queue>& queue) const;
[[nodiscard]] bool FindMediaDevice(struct v4l2_capability* cap);
void QueryAndMmapQueueBuffers(std::unique_ptr<V4L2Queue>& queue) const;
enum class DeviceType {
kDecoder,
kMedia,
};
private:
[[nodiscard]] bool QueryFormat(enum v4l2_buf_type type,
uint32_t fourcc) const;
template <typename T>
[[nodiscard]] bool Ioctl(int request_code, T arg) const;
base::File decode_fd_;
base::File media_fd_;
bool cur_val_is_supported_ = true;
};
}
}
#endif