#ifndef MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODE_ACCELERATOR_H_
#define MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODE_ACCELERATOR_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include "base/containers/queue.h"
#include "base/containers/small_map.h"
#include "base/memory/ref_counted_memory.h"
#include "base/sequence_checker.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/memory_dump_provider.h"
#include "media/base/bitrate.h"
#include "media/base/encoder_status.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/vaapi/vaapi_utils.h"
#include "media/gpu/vaapi/vaapi_video_encoder_delegate.h"
#include "media/gpu/vaapi/vaapi_wrapper.h"
#include "media/video/video_encode_accelerator.h"
namespace base {
class SequencedTaskRunner;
class SingleThreadTaskRunner;
}
namespace media {
class MEDIA_GPU_EXPORT VaapiVideoEncodeAccelerator
: public VideoEncodeAccelerator,
public base::trace_event::MemoryDumpProvider {
public:
VaapiVideoEncodeAccelerator();
VaapiVideoEncodeAccelerator(const VaapiVideoEncodeAccelerator&) = delete;
VaapiVideoEncodeAccelerator& operator=(const VaapiVideoEncodeAccelerator&) =
delete;
~VaapiVideoEncodeAccelerator() override;
SupportedProfiles GetSupportedProfiles() override;
EncoderStatus Initialize(const Config& config,
Client* client,
std::unique_ptr<MediaLog> media_log) override;
void Encode(scoped_refptr<VideoFrame> frame, bool force_keyframe) override;
void UseOutputBitstreamBuffer(BitstreamBuffer buffer) override;
void RequestEncodingParametersChange(
const Bitrate& bitrate,
uint32_t framerate,
const std::optional<gfx::Size>& size) override;
void RequestEncodingParametersChange(
const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate,
const std::optional<gfx::Size>& size) override;
void Destroy() override;
void Flush(FlushCallback flush_callback) override;
bool IsFlushSupported() override;
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
private:
friend class VaapiVideoEncodeAcceleratorTest;
using EncodeJob = VaapiVideoEncoderDelegate::EncodeJob;
using EncodeResult = VaapiVideoEncoderDelegate::EncodeResult;
enum State {
kUninitialized,
kEncoding,
kError,
};
struct SizeComparator {
constexpr bool operator()(const gfx::Size& lhs,
const gfx::Size& rhs) const {
return std::forward_as_tuple(lhs.width(), lhs.height()) <
std::forward_as_tuple(rhs.width(), rhs.height());
}
};
static constexpr size_t kMaxNumSpatialLayersPlusOne = 3 + 1;
using InputSurfaceMap = base::small_map<
std::map<gfx::Size, std::unique_ptr<ScopedVASurface>, SizeComparator>,
kMaxNumSpatialLayersPlusOne>;
using EncodeSurfacesMap =
base::small_map<std::map<gfx::Size,
std::vector<std::unique_ptr<ScopedVASurface>>,
SizeComparator>,
kMaxNumSpatialLayersPlusOne>;
using EncodeSurfacesCountMap =
base::small_map<std::map<gfx::Size, size_t, SizeComparator>,
kMaxNumSpatialLayersPlusOne>;
struct InputFrameRef;
class ScopedVASurfaceWrapper;
void InitializeTask(const Config& config);
bool AttemptedInitialization() const { return !!client_ptr_factory_; }
void EncodeTask(scoped_refptr<VideoFrame> frame, bool force_keyframe);
void UseOutputBitstreamBufferTask(BitstreamBuffer buffer);
void RequestEncodingParametersChangeTask(
VideoBitrateAllocation bitrate_allocation,
uint32_t framerate,
const std::optional<gfx::Size>& size);
void DestroyTask();
void FlushTask(FlushCallback flush_callback);
bool CreateSurfacesForGpuMemoryBufferEncoding(
const VideoFrame& frame,
const std::vector<gfx::Size>& spatial_layer_resolutions,
std::vector<std::unique_ptr<ScopedVASurfaceWrapper>>* input_surfaces,
std::vector<std::unique_ptr<ScopedVASurfaceWrapper>>*
reconstructed_surfaces);
bool CreateSurfacesForShmemEncoding(
const VideoFrame& frame,
std::unique_ptr<ScopedVASurfaceWrapper>* input_surface,
std::unique_ptr<ScopedVASurfaceWrapper>* reconstructed_surface);
std::unique_ptr<ScopedVASurfaceWrapper> GetOrCreateReconstructedSurface(
const gfx::Size& encode_size);
std::unique_ptr<ScopedVASurfaceWrapper> GetOrCreateInputSurface(
VaapiWrapper& vaapi_wrapper,
const gfx::Size& encode_size,
const std::vector<VaapiWrapper::SurfaceUsageHint>& surface_usage_hints);
scoped_refptr<VaapiWrapper> CreateVppVaapiWrapper();
std::unique_ptr<ScopedVASurfaceWrapper> ExecuteBlitSurface(
const ScopedVASurface* source_surface,
const gfx::Rect source_visible_rect,
const gfx::Size& encode_size);
std::unique_ptr<EncodeJob> CreateEncodeJob(
bool force_keyframe,
base::TimeDelta frame_timestamp,
uint8_t spatial_index,
bool end_of_picture,
VASurfaceID input_surface_id,
std::unique_ptr<ScopedVASurfaceWrapper> reconstructed_surface);
void EncodePendingInputs();
void RecycleInputScopedVASurface(const gfx::Size& encode_size,
std::unique_ptr<ScopedVASurface> va_surface);
void RecycleEncodeScopedVASurface(
const gfx::Size& encode_size,
std::unique_ptr<ScopedVASurface> va_surface);
void TryToReturnBitstreamBuffers();
void ReturnBitstreamBuffer(const EncodeResult& encode_result,
const BitstreamBuffer& buffer);
void NotifyError(EncoderStatus status);
void SetState(State state);
bool IsConfiguredForTesting() const {
return !supported_profiles_for_testing_.empty();
}
static constexpr int kMaxNumOfInstances = 10;
static base::AtomicRefCount num_instances_;
const bool can_use_encoder_ GUARDED_BY_CONTEXT(child_sequence_checker_);
VideoEncoderInfo encoder_info_ GUARDED_BY_CONTEXT(encoder_sequence_checker_);
scoped_refptr<VaapiWrapper> vaapi_wrapper_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
gfx::Size expected_input_coded_size_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
VideoCodec output_codec_ GUARDED_BY_CONTEXT(encoder_sequence_checker_) =
VideoCodec::kUnknown;
gfx::Rect visible_rect_ GUARDED_BY_CONTEXT(encoder_sequence_checker_);
size_t output_buffer_byte_size_
GUARDED_BY_CONTEXT(encoder_sequence_checker_) = 0;
size_t max_pending_results_size_
GUARDED_BY_CONTEXT(encoder_sequence_checker_) = 0;
bool native_input_mode_ GUARDED_BY_CONTEXT(encoder_sequence_checker_) = false;
size_t num_frames_in_flight_ GUARDED_BY_CONTEXT(encoder_sequence_checker_) =
0;
State state_ GUARDED_BY_CONTEXT(encoder_sequence_checker_) =
State::kUninitialized;
std::unique_ptr<VaapiVideoEncoderDelegate> encoder_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
InputSurfaceMap input_surfaces_ GUARDED_BY_CONTEXT(encoder_sequence_checker_);
EncodeSurfacesMap available_encode_surfaces_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
EncodeSurfacesCountMap encode_surfaces_count_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
base::queue<InputFrameRef> input_queue_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
base::queue<BitstreamBuffer> available_bitstream_buffers_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
base::queue<std::optional<EncodeResult>> pending_encode_results_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
const scoped_refptr<base::SequencedTaskRunner> child_task_runner_;
SEQUENCE_CHECKER(child_sequence_checker_);
const scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
SEQUENCE_CHECKER(encoder_sequence_checker_);
std::unique_ptr<base::WeakPtrFactory<Client>> client_ptr_factory_;
base::WeakPtr<Client> client_;
scoped_refptr<VaapiWrapper> vpp_vaapi_wrapper_
GUARDED_BY_CONTEXT(encoder_sequence_checker_);
FlushCallback flush_callback_ GUARDED_BY_CONTEXT(encoder_sequence_checker_);
SupportedProfiles supported_profiles_for_testing_;
base::WeakPtr<VaapiVideoEncodeAccelerator> child_weak_this_;
base::WeakPtr<VaapiVideoEncodeAccelerator> encoder_weak_this_;
base::WeakPtrFactory<VaapiVideoEncodeAccelerator> child_weak_this_factory_{
this};
base::WeakPtrFactory<VaapiVideoEncodeAccelerator> encoder_weak_this_factory_{
this};
};
}
#endif