#ifndef MEDIA_GPU_TEST_VIDEO_ENCODER_VIDEO_ENCODER_CLIENT_H_
#define MEDIA_GPU_TEST_VIDEO_ENCODER_VIDEO_ENCODER_CLIENT_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "gpu/command_buffer/client/test_shared_image_interface.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/video_bitrate_allocation.h"
#include "media/gpu/test/bitstream_helpers.h"
#include "media/gpu/test/video_encoder/video_encoder.h"
#include "media/video/video_encode_accelerator.h"
namespace media {
namespace test {
class AlignedDataHelper;
class RawVideo;
struct VideoEncoderClientConfig {
static constexpr uint32_t kDefaultBitrate = 200000;
VideoEncoderClientConfig(
const RawVideo* video,
VideoCodecProfile output_profile,
const std::vector<VideoEncodeAccelerator::Config::SpatialLayer>&
spatial_layers,
SVCInterLayerPredMode inter_layer_pred_mode,
VideoEncodeAccelerator::Config::ContentType content_type,
const media::VideoBitrateAllocation& bitrate,
bool reverse);
VideoEncoderClientConfig(const VideoEncoderClientConfig&);
~VideoEncoderClientConfig();
VideoCodecProfile output_profile = VideoCodecProfile::H264PROFILE_MAIN;
gfx::Size output_resolution;
std::vector<VideoEncodeAccelerator::Config::SpatialLayer> spatial_layers;
size_t num_temporal_layers = 1u;
size_t num_spatial_layers = 1u;
SVCInterLayerPredMode inter_layer_pred_mode = SVCInterLayerPredMode::kOff;
VideoEncodeAccelerator::Config::ContentType content_type =
VideoEncodeAccelerator::Config::ContentType::kCamera;
size_t max_outstanding_encode_requests = 1;
uint8_t drop_frame_thresh = 0;
media::VideoBitrateAllocation bitrate_allocation;
uint32_t framerate = 30.0;
uint32_t gop_length = 0;
std::optional<base::TimeDelta> encode_interval = std::nullopt;
size_t num_frames_to_encode = 0;
VideoEncodeAccelerator::Config::StorageType input_storage_type =
VideoEncodeAccelerator::Config::StorageType::kShmem;
const bool reverse = false;
};
class VideoEncoderStats {
public:
VideoEncoderStats();
VideoEncoderStats(const VideoEncoderStats&);
~VideoEncoderStats();
VideoEncoderStats(uint32_t framerate,
size_t num_temporal_layers,
size_t num_spatial_layers);
uint32_t Bitrate() const;
uint32_t LayerBitrate(size_t spatial_idx, size_t temporal_idx) const;
void Reset();
uint32_t framerate = 0;
size_t total_num_encoded_frames = 0;
size_t total_encoded_frames_size = 0;
size_t num_dropped_frames = 0;
std::vector<std::vector<size_t>> num_encoded_frames_per_layer;
std::vector<std::vector<size_t>> encoded_frames_size_per_layer;
size_t num_spatial_layers = 0;
size_t num_temporal_layers = 0;
};
class VideoEncoderClient : public VideoEncodeAccelerator::Client {
public:
VideoEncoderClient(const VideoEncoderClient&) = delete;
VideoEncoderClient& operator=(const VideoEncoderClient&) = delete;
~VideoEncoderClient() override;
static std::unique_ptr<VideoEncoderClient> Create(
const VideoEncoder::EventCallback& event_cb,
std::vector<std::unique_ptr<BitstreamProcessor>> bitstream_processors,
const VideoEncoderClientConfig& config);
bool Initialize(const RawVideo* video);
void Encode();
void Flush();
bool IsFlushSupported() { return encoder_->IsFlushSupported(); }
void UpdateBitrate(const VideoBitrateAllocation& bitrate, uint32_t framerate);
void ForceKeyFrame();
bool WaitForBitstreamProcessors();
VideoEncoderStats GetStats() const;
void ResetStats();
bool IsHardwareAccelerated();
void RequireBitstreamBuffers(unsigned int input_count,
const gfx::Size& input_coded_size,
size_t output_buffer_size) override;
void BitstreamBufferReady(int32_t bitstream_buffer_id,
const BitstreamBufferMetadata& metadata) override;
void NotifyErrorStatus(const EncoderStatus& status) override;
void NotifyEncoderInfoChange(const VideoEncoderInfo& info) override;
private:
enum class VideoEncoderClientState {
kUninitialized = 0,
kIdle,
kEncoding,
kFlushing,
};
VideoEncoderClient(
const VideoEncoder::EventCallback& event_cb,
std::vector<std::unique_ptr<BitstreamProcessor>> bitstream_processors,
const VideoEncoderClientConfig& config);
void Destroy();
void CreateEncoderTask(const RawVideo* video,
bool* success,
base::WaitableEvent* done);
void DestroyEncoderTask(base::WaitableEvent* done);
void EncodeTask();
void EncodeNextFrameTask();
void FlushTask();
void UpdateBitrateTask(const VideoBitrateAllocation& bitrate,
uint32_t framerate);
void ForceKeyFrameTask();
void EncodeDoneTask(base::TimeDelta timestamp);
void FlushDoneTask(bool success);
void FlushDoneTaskIfNeeded();
void FireEvent(VideoEncoder::EncoderEvent event);
scoped_refptr<BitstreamProcessor::BitstreamRef> CreateBitstreamRef(
int32_t bitstream_buffer_id,
const BitstreamBufferMetadata& metadata);
void BitstreamBufferProcessed(int32_t bitstream_buffer_id);
int32_t GetNextBitstreamBufferId();
VideoEncoder::EventCallback event_cb_;
std::vector<std::unique_ptr<BitstreamProcessor>> bitstream_processors_;
std::unique_ptr<media::VideoEncodeAccelerator> encoder_;
const VideoEncoderClientConfig encoder_client_config_;
base::Thread encoder_client_thread_;
scoped_refptr<base::SingleThreadTaskRunner> encoder_client_task_runner_;
size_t num_outstanding_encode_requests_ = 0;
VideoEncoderClientState encoder_client_state_;
raw_ptr<const RawVideo> video_ = nullptr;
std::unique_ptr<media::test::AlignedDataHelper> aligned_data_helper_;
size_t output_buffer_size_ = 0u;
std::map<int32_t, base::UnsafeSharedMemoryRegion> bitstream_buffers_;
int32_t next_bitstream_buffer_id_ = 0;
size_t num_encodes_requested_ = 0;
size_t frame_index_ = 0;
std::map<base::TimeDelta, base::TimeTicks> source_timestamps_;
bool force_keyframe_ = false;
VideoEncoderStats current_stats_ GUARDED_BY(stats_lock_);
VideoEncoderInfo encoder_info_ GUARDED_BY(stats_lock_);
mutable base::Lock stats_lock_;
scoped_refptr<gpu::TestSharedImageInterface> test_sii_;
SEQUENCE_CHECKER(test_sequence_checker_);
SEQUENCE_CHECKER(encoder_client_sequence_checker_);
base::WeakPtr<VideoEncoderClient> weak_this_;
base::WeakPtrFactory<VideoEncoderClient> weak_this_factory_{this};
};
}
}
#endif