| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #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/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/sequence_checker.h" |
| #include "base/threading/thread.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 gpu { |
| class GpuMemoryBufferFactory; |
| } |
| |
| namespace media { |
| |
| class Video; |
| |
| namespace test { |
| |
| class AlignedDataHelper; |
| |
| // Video encoder client configuration. |
| // TODO(dstaessens): Add extra parameters (e.g. h264 output level) |
| struct VideoEncoderClientConfig { |
| static constexpr uint32_t kDefaultBitrate = 200000; |
| VideoEncoderClientConfig( |
| const Video* video, |
| VideoCodecProfile output_profile, |
| const std::vector<VideoEncodeAccelerator::Config::SpatialLayer>& |
| spatial_layers, |
| const media::VideoBitrateAllocation& bitrate, |
| bool reverse); |
| VideoEncoderClientConfig(const VideoEncoderClientConfig&); |
| ~VideoEncoderClientConfig(); |
| |
| // The output profile to be used. |
| VideoCodecProfile output_profile = VideoCodecProfile::H264PROFILE_MAIN; |
| // The resolution output by VideoEncoderClient. |
| gfx::Size output_resolution; |
| // The number of temporal/spatial layers of the output stream. |
| size_t num_temporal_layers = 1u; |
| size_t num_spatial_layers = 1u; |
| // The spatial layers for SVC stream, it's empty for simple stream. |
| std::vector<VideoEncodeAccelerator::Config::SpatialLayer> spatial_layers; |
| // The maximum number of bitstream buffer encodes that can be requested |
| // without waiting for the result of the previous encodes requests. |
| size_t max_outstanding_encode_requests = 1; |
| // The desired bitrate in bits/second. |
| media::VideoBitrateAllocation bitrate; |
| // The desired framerate in frames/second. |
| uint32_t framerate = 30.0; |
| // The interval of calling VideoEncodeAccelerator::Encode(). If this is |
| // absl::nullopt, Encode() is called once VideoEncodeAccelerator consumes |
| // the previous VideoFrames. |
| absl::optional<base::TimeDelta> encode_interval = absl::nullopt; |
| // The number of frames to be encoded. This can be more than the number of |
| // frames in the video, and in which case the VideoEncoderClient loops the |
| // video during encoding. |
| size_t num_frames_to_encode = 0; |
| // The storage type of the input VideoFrames. |
| VideoEncodeAccelerator::Config::StorageType input_storage_type = |
| VideoEncodeAccelerator::Config::StorageType::kShmem; |
| // True if the video should play backwards at reaching the end of video. |
| // Otherwise the video loops. See the comment in AlignedDataHelper for detail. |
| const bool reverse = false; |
| }; |
| |
| struct VideoEncoderStats { |
| VideoEncoderStats(); |
| VideoEncoderStats(const VideoEncoderStats&); |
| ~VideoEncoderStats(); |
| VideoEncoderStats(uint32_t framerate, |
| size_t num_temporal_layers, |
| size_t num_spatial_layers); |
| uint32_t Bitrate() const; |
| void Reset(); |
| |
| uint32_t framerate = 0; |
| size_t total_num_encoded_frames = 0; |
| size_t total_encoded_frames_size = 0; |
| // Filled in spatial/temporal layer encoding and codec is vp9. |
| 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; |
| }; |
| |
| // The video encoder client is responsible for the communication between the |
| // test video encoder and the video encoder. It also communicates with the |
| // attached decoder buffer processors. The video encoder client can only have |
| // one active encoder at any time. To encode a different stream the Destroy() |
| // and Initialize() functions have to be called to destroy and re-create the |
| // encoder. |
| // |
| // All communication with the encoder is done on the |encoder_client_thread_|, |
| // so callbacks scheduled by the encoder can be executed asynchronously. This is |
| // necessary in order not to interrupt the test flow. |
| class VideoEncoderClient : public VideoEncodeAccelerator::Client { |
| public: |
| // Disallow copy and assign. |
| VideoEncoderClient(const VideoEncoderClient&) = delete; |
| VideoEncoderClient& operator=(const VideoEncoderClient&) = delete; |
| |
| ~VideoEncoderClient() override; |
| |
| // Return an instance of the VideoEncoderClient. The |
| // |gpu_memory_buffer_factory| will not be owned by the encoder client, the |
| // caller should guarantee it outlives the encoder client. The |event_cb| will |
| // be called whenever an event occurs (e.g. frame encoded) and should be |
| // thread-safe. |
| static std::unique_ptr<VideoEncoderClient> Create( |
| const VideoEncoder::EventCallback& event_cb, |
| std::vector<std::unique_ptr<BitstreamProcessor>> bitstream_processors, |
| gpu::GpuMemoryBufferFactory* const gpu_memory_buffer_factory, |
| const VideoEncoderClientConfig& config); |
| |
| // Initialize the video encode accelerator for the specified |video|. |
| // Initialization is performed asynchronous, upon completion a 'kInitialized' |
| // event will be sent to the test encoder. |
| bool Initialize(const Video* video); |
| |
| // Start encoding the video stream, encoder should be idle when this function |
| // is called. This function is non-blocking, for each frame encoded a |
| // 'kFrameEncoded' event will be sent to the test encoder. |
| void Encode(); |
| // Flush all scheduled encode tasks. This function is non-blocking, a |
| // kFlushing/kFlushDone event is sent upon start/finish. The kFlushDone |
| // event is always sent after all associated kFrameEncoded events. |
| void Flush(); |
| |
| // Updates bitrate based on the specified |bitrate| and |framerate|. |
| void UpdateBitrate(const VideoBitrateAllocation& bitrate, uint32_t framerate); |
| |
| // Force the next frame to be encoded to be a key frame. |
| void ForceKeyFrame(); |
| |
| // Wait until all bitstream processors have finished processing. Returns |
| // whether processing was successful. |
| bool WaitForBitstreamProcessors(); |
| |
| // Get/Reset video encode statistics. |
| VideoEncoderStats GetStats() const; |
| void ResetStats(); |
| |
| // VideoEncodeAccelerator::Client implementation |
| 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 NotifyError(VideoEncodeAccelerator::Error error) 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, |
| gpu::GpuMemoryBufferFactory* const gpu_memory_buffer_factory, |
| const VideoEncoderClientConfig& config); |
| |
| // Destroy the video encoder client. |
| void Destroy(); |
| |
| // Create a new video |encoder_| on the |encoder_client_thread_|. |
| void CreateEncoderTask(const Video* video, |
| bool* success, |
| base::WaitableEvent* done); |
| // Destroy the active video |encoder_| on the |encoder_client_thread_|. |
| void DestroyEncoderTask(base::WaitableEvent* done); |
| |
| // Start encoding video stream buffers on the |encoder_client_thread_|. |
| void EncodeTask(); |
| // Instruct the encoder to encode the next video frame on the |
| // |encoder_client_thread_|. |
| void EncodeNextFrameTask(); |
| // Instruct the encoder to perform a flush on the |encoder_client_thread_|. |
| void FlushTask(); |
| void UpdateBitrateTask(const VideoBitrateAllocation& bitrate, |
| uint32_t framerate); |
| // Instruct the encoder to force a key frame on the |encoder_client_thread_|. |
| void ForceKeyFrameTask(); |
| |
| // Called by the encoder when a frame has been encoded. |
| void EncodeDoneTask(base::TimeDelta timestamp); |
| // Called by the encoder when flushing has completed. |
| void FlushDoneTask(bool success); |
| // Calls FlushDoneTask() if needed. This is necessary if Flush() flow is |
| // simulated because VEA doesn't support Flush(). |
| void FlushDoneTaskIfNeeded(); |
| |
| // Fire the specified event. |
| void FireEvent(VideoEncoder::EncoderEvent event); |
| |
| // Create BitstreamRef from |buffer| and |metadata| passed to |
| // |bitstream_processors_|. |
| scoped_refptr<BitstreamProcessor::BitstreamRef> CreateBitstreamRef( |
| int32_t bitstream_buffer_id, |
| const BitstreamBufferMetadata& metadata); |
| |
| // Invoked when BitstreamBuffer associated with |bitstream_buffer_id| can be |
| // reused by |encoder_|. |
| void BitstreamBufferProcessed(int32_t bitstream_buffer_id); |
| |
| // Get the next bitstream buffer id to be used. |
| int32_t GetNextBitstreamBufferId(); |
| |
| // The callback used to notify the test video encoder of events. |
| VideoEncoder::EventCallback event_cb_; |
| // The list of bitstream processors. All bitstream buffers will be forwarded |
| // to the bitstream processors (e.g. verification of contents). |
| std::vector<std::unique_ptr<BitstreamProcessor>> bitstream_processors_; |
| |
| // The currently active video encode accelerator. |
| std::unique_ptr<media::VideoEncodeAccelerator> encoder_; |
| // The video encoder client configuration. |
| const VideoEncoderClientConfig encoder_client_config_; |
| // The thread used for all communication with the video encode accelerator. |
| base::Thread encoder_client_thread_; |
| // The task runner associated with the |encoder_client_thread_|; |
| scoped_refptr<base::SingleThreadTaskRunner> encoder_client_task_runner_; |
| |
| // The current number of outgoing frame encode requests. |
| size_t num_outstanding_encode_requests_ = 0; |
| // Encoder client state, should only be accessed on the encoder client thread. |
| VideoEncoderClientState encoder_client_state_; |
| |
| // The video being encoded, owned by the video encoder test environment. |
| const Video* video_ = nullptr; |
| // Helper used to align data and create frames from the raw video stream. |
| std::unique_ptr<media::test::AlignedDataHelper> aligned_data_helper_; |
| |
| // Size of the output buffer requested by the encoder. |
| size_t output_buffer_size_ = 0u; |
| // Maps bitstream buffer Id's on the associated memory. |
| std::map<int32_t, base::UnsafeSharedMemoryRegion> bitstream_buffers_; |
| |
| // Id to be used for the the next bitstream buffer. |
| int32_t next_bitstream_buffer_id_ = 0; |
| |
| // A counter to how many VideoEncodeAccelerator::Encode() is called. |
| size_t num_encodes_requested_ = 0; |
| |
| // A counter to track what frame is represented by a bitstream returned on |
| // BitstreamBufferReady(). |
| size_t frame_index_ = 0; |
| |
| // The current top spatial layer index. |
| uint8_t current_top_spatial_index_ = 0; |
| |
| // Force a key frame on next Encode(), only accessed on the |
| // |encoder_client_thread_|. |
| bool force_keyframe_ = false; |
| |
| VideoEncoderStats current_stats_ GUARDED_BY(stats_lock_); |
| mutable base::Lock stats_lock_; |
| |
| gpu::GpuMemoryBufferFactory* const gpu_memory_buffer_factory_; |
| |
| SEQUENCE_CHECKER(test_sequence_checker_); |
| SEQUENCE_CHECKER(encoder_client_sequence_checker_); |
| |
| base::WeakPtr<VideoEncoderClient> weak_this_; |
| base::WeakPtrFactory<VideoEncoderClient> weak_this_factory_{this}; |
| }; |
| |
| } // namespace test |
| } // namespace media |
| |
| #endif // MEDIA_GPU_TEST_VIDEO_ENCODER_VIDEO_ENCODER_CLIENT_H_ |