#ifndef MEDIA_GPU_V4L2_V4L2_JPEG_ENCODE_ACCELERATOR_H_
#define MEDIA_GPU_V4L2_V4L2_JPEG_ENCODE_ACCELERATOR_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/containers/queue.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/threading/thread.h"
#include "components/chromeos_camera/jpeg_encode_accelerator.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/video_frame.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/v4l2/v4l2_device.h"
#include "media/parsers/jpeg_parser.h"
#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
namespace {
constexpr size_t kMaxI420Plane = 3;
constexpr size_t kMaxNV12Plane = 2;
constexpr size_t kMaxJpegPlane = 1;
static_assert(kMaxI420Plane == 3,
"kMaxI420Plane must be 3 as input may be V4L2_PIX_FMT_YUV420M");
static_assert(
kMaxJpegPlane == 1,
"kMaxJpegPlane must be 1 as output must be V4L2_PIX_FMT_JPEG(_RAW)");
}
namespace base {
class WaitableEvent;
class SequencedTaskRunner;
class SingleThreadTaskRunner;
}
namespace media {
class MEDIA_GPU_EXPORT V4L2JpegEncodeAccelerator
: public chromeos_camera::JpegEncodeAccelerator {
public:
V4L2JpegEncodeAccelerator(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
V4L2JpegEncodeAccelerator(const V4L2JpegEncodeAccelerator&) = delete;
V4L2JpegEncodeAccelerator& operator=(const V4L2JpegEncodeAccelerator&) =
delete;
~V4L2JpegEncodeAccelerator() override;
void InitializeAsync(
chromeos_camera::JpegEncodeAccelerator::Client* client,
chromeos_camera::JpegEncodeAccelerator::InitCB init_cb) override;
size_t GetMaxCodedBufferSize(const gfx::Size& picture_size) override;
void Encode(scoped_refptr<media::VideoFrame> video_frame,
int quality,
BitstreamBuffer* exif_buffer,
BitstreamBuffer output_buffer) override;
void EncodeWithDmaBuf(scoped_refptr<VideoFrame> input_frame,
scoped_refptr<VideoFrame> output_frame,
int quality,
int32_t task_id,
BitstreamBuffer* exif_buffer) override;
private:
void InitializeTask(chromeos_camera::JpegEncodeAccelerator::Client* client,
InitCB init_cb);
struct I420BufferRecord {
I420BufferRecord();
~I420BufferRecord();
void* address[kMaxI420Plane];
size_t length[kMaxI420Plane];
bool at_device;
};
struct JpegBufferRecord {
JpegBufferRecord();
~JpegBufferRecord();
void* address[kMaxJpegPlane];
size_t length[kMaxJpegPlane];
bool at_device;
};
struct JobRecord {
JobRecord(scoped_refptr<VideoFrame> input_frame,
scoped_refptr<VideoFrame> output_frame,
int32_t task_id,
int quality,
base::WritableSharedMemoryMapping exif_mapping);
JobRecord(scoped_refptr<VideoFrame> input_frame,
int quality,
int32_t task_id,
base::WritableSharedMemoryMapping exif_mapping,
base::WritableSharedMemoryMapping output_mapping);
~JobRecord();
scoped_refptr<VideoFrame> input_frame;
scoped_refptr<VideoFrame> output_frame;
int quality;
int32_t task_id;
base::WritableSharedMemoryMapping output_mapping;
base::WritableSharedMemoryMapping exif_mapping;
};
class EncodedInstanceDmaBuf {
public:
EncodedInstanceDmaBuf(V4L2JpegEncodeAccelerator* parent);
~EncodedInstanceDmaBuf();
bool Initialize();
bool CreateBuffers(gfx::Size input_coded_size,
const VideoFrameLayout& input_layout,
size_t output_buffer_size);
bool SetUpJpegParameters(int quality, gfx::Size coded_size);
void ServiceDevice();
void DestroyTask();
base::queue<std::unique_ptr<JobRecord>> input_job_queue_;
base::queue<std::unique_ptr<JobRecord>> running_job_queue_;
private:
size_t FinalizeJpegImage(scoped_refptr<VideoFrame> output_frame,
size_t buffer_size,
base::WritableSharedMemoryMapping exif_mapping);
bool SetInputBufferFormat(gfx::Size coded_size,
const VideoFrameLayout& input_layout);
bool SetOutputBufferFormat(gfx::Size coded_size, size_t buffer_size);
bool RequestInputBuffers();
bool RequestOutputBuffers();
void EnqueueInput();
void EnqueueOutput();
void Dequeue();
bool EnqueueInputRecord();
bool EnqueueOutputRecord();
void DestroyInputBuffers();
void DestroyOutputBuffers();
size_t InputBufferQueuedCount();
size_t OutputBufferQueuedCount();
void NotifyError(int32_t task_id, Status status);
const size_t kBufferCount = 2;
raw_ptr<V4L2JpegEncodeAccelerator> parent_;
std::optional<VideoFrameLayout> device_input_layout_;
scoped_refptr<V4L2Device> device_;
std::unique_ptr<gfx::ClientNativePixmapFactory>
client_native_pixmap_factory_;
bool input_streamon_;
std::vector<int> free_input_buffers_;
bool output_streamon_;
std::vector<int> free_output_buffers_;
uint32_t input_buffer_pixelformat_;
size_t input_buffer_num_planes_;
uint32_t output_buffer_pixelformat_;
uint32_t output_buffer_sizeimage_;
};
void VideoFrameReady(int32_t task_id, size_t encoded_picture_size);
void NotifyError(int32_t task_id, Status status);
void EncodeTask(std::unique_ptr<JobRecord> job_record);
void ServiceDeviceTask();
void DestroyTask(base::WaitableEvent* waiter);
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
raw_ptr<chromeos_camera::JpegEncodeAccelerator::Client> client_;
scoped_refptr<base::SequencedTaskRunner> encoder_task_runner_;
gfx::Size latest_input_buffer_coded_size_
GUARDED_BY_CONTEXT(encoder_sequence_);
int latest_quality_ GUARDED_BY_CONTEXT(encoder_sequence_);
std::queue<std::unique_ptr<EncodedInstanceDmaBuf>> encoded_instances_dma_buf_
GUARDED_BY_CONTEXT(encoder_sequence_);
SEQUENCE_CHECKER(encoder_sequence_);
base::WeakPtr<V4L2JpegEncodeAccelerator> weak_ptr_for_encoder_;
base::WeakPtr<V4L2JpegEncodeAccelerator> weak_ptr_;
base::WeakPtrFactory<V4L2JpegEncodeAccelerator> weak_factory_for_encoder_;
base::WeakPtrFactory<V4L2JpegEncodeAccelerator> weak_factory_;
};
}
#endif