// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_V4L2_V4L2_IMAGE_PROCESSOR_BACKEND_H_
#define MEDIA_GPU_V4L2_V4L2_IMAGE_PROCESSOR_BACKEND_H_
#include <linux/videodev2.h>
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <optional>
#include <vector>
#include "base/containers/queue.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "media/gpu/chromeos/image_processor_backend.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/v4l2/v4l2_device.h"
#include "ui/gfx/geometry/size.h"
namespace base {
class TimeTicks;
}
namespace media {
// Handles image processing accelerators that expose a V4L2 memory-to-memory
// interface. The threading model of this class is the same as for other V4L2
// hardware accelerators (see V4L2VideoDecodeAccelerator) for more details.
class MEDIA_GPU_EXPORT V4L2ImageProcessorBackend
: public ImageProcessorBackend {
public:
// Factory method to create V4L2ImageProcessorBackend to convert from
// input_config to output_config. The number of input buffers and output
// buffers will be |num_buffers|. Provided |error_cb| will be posted to the
// same thread Create() is called if an error occurs after initialization.
// Returns nullptr if V4L2ImageProcessorBackend fails to create.
// Note: output_mode will be removed once all its clients use import mode.
// TODO(crbug.com/917798): remove |device| parameter once
// V4L2VideoDecodeAccelerator no longer creates and uses
// |image_processor_device_| before V4L2ImageProcessorBackend is created.
static std::unique_ptr<ImageProcessorBackend> Create(
scoped_refptr<V4L2Device> device,
size_t num_buffers,
const PortConfig& input_config,
const PortConfig& output_config,
OutputMode output_mode,
ErrorCB error_cb);
V4L2ImageProcessorBackend(const V4L2ImageProcessorBackend&) = delete;
V4L2ImageProcessorBackend& operator=(const V4L2ImageProcessorBackend&) =
delete;
// ImageProcessor implementation.
void ProcessFrame(scoped_refptr<FrameResource> input_frame,
scoped_refptr<FrameResource> output_frame,
FrameResourceReadyCB cb) override;
void ProcessLegacyFrame(scoped_refptr<FrameResource> frame,
LegacyFrameResourceReadyCB cb) override;
void Reset() override;
// Returns true if image processing is supported on this platform.
static bool IsSupported();
// Returns a vector of supported input formats in fourcc.
static std::vector<uint32_t> GetSupportedInputFormats();
// Returns a vector of supported output formats in fourcc.
static std::vector<uint32_t> GetSupportedOutputFormats();
// Gets |output_size| and |num_planes|] required by the device for conversion
// from |input_pixelformat| with |input_size| to |output_pixelformat| with
// expected |output_size|. On success, returns true with adjusted
// |output_size| and |num_planes|. On failure, returns false without touching
// |output_size| and |num_planes|.
// TODO(b/191450183): Remove |output_size| and assert
// DCHECK_EQ(input_size, output_size) inside the body.
static bool TryOutputFormat(uint32_t input_pixelformat,
uint32_t output_pixelformat,
const gfx::Size& input_size,
gfx::Size* output_size,
size_t* num_planes);
std::string type() const override;
private:
friend struct std::default_delete<V4L2ImageProcessorBackend>;
// Callback for initialization.
using InitCB = base::OnceCallback<void(bool)>;
// Job record. Jobs are processed in a FIFO order. |input_frame| will be
// processed and the result written into |output_frame|. Once processing is
// complete, |ready_cb| or |legacy_frame_ready_cb| will be called depending on
// which Process() method has been used to create that JobRecord.
struct JobRecord {
JobRecord();
~JobRecord();
scoped_refptr<FrameResource> input_frame;
FrameResourceReadyCB ready_cb;
LegacyFrameResourceReadyCB legacy_ready_cb;
scoped_refptr<FrameResource> output_frame;
size_t output_buffer_id;
// This is filled only if chrome tracing in "media" category is enabled.
std::optional<base::TimeTicks> start_time;
};
V4L2ImageProcessorBackend(scoped_refptr<V4L2Device> device,
const PortConfig& input_config,
const PortConfig& output_config,
v4l2_memory input_memory_type,
v4l2_memory output_memory_type,
OutputMode output_mode,
ErrorCB error_cb);
~V4L2ImageProcessorBackend() override;
void Destroy() override;
// Stop all processing on |poll_task_runner_|.
void DestroyOnPollSequence();
void EnqueueInput(const JobRecord* job_record, V4L2WritableBufferRef buffer);
void EnqueueOutput(JobRecord* job_record, V4L2WritableBufferRef buffer);
void Dequeue();
bool EnqueueInputRecord(const JobRecord* job_record,
V4L2WritableBufferRef buffer);
bool EnqueueOutputRecord(JobRecord* job_record, V4L2WritableBufferRef buffer);
bool CreateInputBuffers(size_t num_buffers);
bool CreateOutputBuffers(size_t num_buffers);
// Reconfigure the |type| queue for |size|.
bool ReconfigureV4L2Format(const gfx::Size& size, enum v4l2_buf_type type);
// Callback of FrameResource destruction. Since FrameResource destruction
// callback might be executed on any sequence, we use a thunk to post the
// task to |device_task_runner_|.
static void V4L2VFRecycleThunk(
scoped_refptr<base::SequencedTaskRunner> task_runner,
std::optional<base::WeakPtr<V4L2ImageProcessorBackend>> image_processor,
V4L2ReadableBufferRef buf);
void V4L2VFRecycleTask(V4L2ReadableBufferRef buf);
void NotifyError();
// ImageProcessor implementation.
void ProcessJobs();
void ServiceDevice();
void TriggerPoll(bool poll_device);
// Ran on |poll_task_runner_| to wait for device events.
void DevicePollTask(bool poll_device);
const v4l2_memory input_memory_type_;
const v4l2_memory output_memory_type_;
// V4L2 device in use. Accessed from both the main task runner and
// |poll_task_runner_|.
// TODO(mcasas): Unclear whether that's racy.
scoped_refptr<V4L2Device> device_ GUARDED_BY_FIXME(sequence_checker_);
base::queue<std::unique_ptr<JobRecord>> input_job_queue_
GUARDED_BY_CONTEXT(sequence_checker_);
base::queue<std::unique_ptr<JobRecord>> running_jobs_
GUARDED_BY_CONTEXT(sequence_checker_);
scoped_refptr<V4L2Queue> input_queue_ GUARDED_BY_CONTEXT(sequence_checker_);
scoped_refptr<V4L2Queue> output_queue_ GUARDED_BY_CONTEXT(sequence_checker_);
// Sequence and its checker used to poll the V4L2 for events only.
scoped_refptr<base::SingleThreadTaskRunner> poll_task_runner_;
SEQUENCE_CHECKER(poll_sequence_checker_);
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtr<V4L2ImageProcessorBackend> weak_this_;
base::WeakPtr<V4L2ImageProcessorBackend> poll_weak_this_;
base::WeakPtrFactory<V4L2ImageProcessorBackend> weak_this_factory_{this};
base::WeakPtrFactory<V4L2ImageProcessorBackend> poll_weak_this_factory_{this};
};
} // namespace media
namespace std {
template <>
struct default_delete<media::V4L2ImageProcessorBackend>
: public default_delete<media::ImageProcessorBackend> {};
} // namespace std
#endif // MEDIA_GPU_V4L2_V4L2_IMAGE_PROCESSOR_BACKEND_H_