Commit 2fb0d3f5 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Chromium LUCI CQ

media/gpu/video_encode_accelerator_tests: Add request keyframe test case

Bug: b:174318867
Test: video_encode_accelerator_tests on trogdor
Change-Id: Ic961a7bc411599e6b43feee128ed09ee42b4cfe1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2564927
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarDavid Staessens <dstaessens@chromium.org>
Cr-Commit-Position: refs/heads/master@{#836515}
parent 5e727ecc
...@@ -31,6 +31,8 @@ const char* EventName(VideoEncoder::EncoderEvent event) { ...@@ -31,6 +31,8 @@ const char* EventName(VideoEncoder::EncoderEvent event) {
return "Flushing"; return "Flushing";
case VideoEncoder::EncoderEvent::kFlushDone: case VideoEncoder::EncoderEvent::kFlushDone:
return "FlushDone"; return "FlushDone";
case VideoEncoder::EncoderEvent::kKeyFrame:
return "KeyFrame";
default: default:
return "Unknown"; return "Unknown";
} }
...@@ -43,6 +45,8 @@ constexpr base::TimeDelta kDefaultEventWaitTimeout = ...@@ -43,6 +45,8 @@ constexpr base::TimeDelta kDefaultEventWaitTimeout =
// Default initial size used for |video_encoder_events_|. // Default initial size used for |video_encoder_events_|.
constexpr size_t kDefaultEventListSize = 512; constexpr size_t kDefaultEventListSize = 512;
constexpr std::pair<VideoEncoder::EncoderEvent, size_t> kInvalidEncodeUntil{
VideoEncoder::kNumEvents, std::numeric_limits<size_t>::max()};
} // namespace } // namespace
// static // static
...@@ -61,7 +65,8 @@ std::unique_ptr<VideoEncoder> VideoEncoder::Create( ...@@ -61,7 +65,8 @@ std::unique_ptr<VideoEncoder> VideoEncoder::Create(
VideoEncoder::VideoEncoder() VideoEncoder::VideoEncoder()
: event_timeout_(kDefaultEventWaitTimeout), : event_timeout_(kDefaultEventWaitTimeout),
video_encoder_event_counts_{}, video_encoder_event_counts_{},
next_unprocessed_event_(0) { next_unprocessed_event_(0),
encode_until_(kInvalidEncodeUntil) {
video_encoder_events_.reserve(kDefaultEventListSize); video_encoder_events_.reserve(kDefaultEventListSize);
} }
...@@ -137,6 +142,7 @@ void VideoEncoder::Encode() { ...@@ -137,6 +142,7 @@ void VideoEncoder::Encode() {
void VideoEncoder::EncodeUntil(EncoderEvent event, size_t event_count) { void VideoEncoder::EncodeUntil(EncoderEvent event, size_t event_count) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(video_encoder_state_.load(), EncoderState::kIdle); DCHECK_EQ(video_encoder_state_.load(), EncoderState::kIdle);
DCHECK(encode_until_ == kInvalidEncodeUntil);
DCHECK(video_); DCHECK(video_);
DVLOGF(4); DVLOGF(4);
...@@ -162,6 +168,13 @@ void VideoEncoder::UpdateBitrate(uint32_t bitrate, uint32_t framerate) { ...@@ -162,6 +168,13 @@ void VideoEncoder::UpdateBitrate(uint32_t bitrate, uint32_t framerate) {
encoder_client_->UpdateBitrate(bitrate_allocation, framerate); encoder_client_->UpdateBitrate(bitrate_allocation, framerate);
} }
void VideoEncoder::ForceKeyFrame() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOGF(4);
encoder_client_->ForceKeyFrame();
}
VideoEncoder::EncoderState VideoEncoder::GetState() const { VideoEncoder::EncoderState VideoEncoder::GetState() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -200,6 +213,25 @@ bool VideoEncoder::WaitForEvent(EncoderEvent event, size_t times) { ...@@ -200,6 +213,25 @@ bool VideoEncoder::WaitForEvent(EncoderEvent event, size_t times) {
} }
} }
bool VideoEncoder::WaitUntilIdle() {
base::TimeDelta time_waiting;
base::AutoLock auto_lock(event_lock_);
while (true) {
if (video_encoder_state_.load() == EncoderState::kIdle)
return true;
// Check whether we've exceeded the maximum time we're allowed to wait.
if (time_waiting >= event_timeout_) {
LOG(ERROR) << "Timeout while waiting for EncodeUntil complete";
return false;
}
const base::TimeTicks start_time = base::TimeTicks::Now();
event_cv_.TimedWait(event_timeout_ - time_waiting);
time_waiting += base::TimeTicks::Now() - start_time;
}
}
bool VideoEncoder::WaitForFlushDone() { bool VideoEncoder::WaitForFlushDone() {
return WaitForEvent(EncoderEvent::kFlushDone); return WaitForEvent(EncoderEvent::kFlushDone);
} }
...@@ -244,16 +276,17 @@ bool VideoEncoder::NotifyEvent(EncoderEvent event) { ...@@ -244,16 +276,17 @@ bool VideoEncoder::NotifyEvent(EncoderEvent event) {
video_encoder_events_.push_back(event); video_encoder_events_.push_back(event);
video_encoder_event_counts_[event]++; video_encoder_event_counts_[event]++;
event_cv_.Signal();
bool should_continue_encoding = true;
// Check whether video encoding should be paused after this event. // Check whether video encoding should be paused after this event.
if (encode_until_.first == event && if (encode_until_.first == event &&
encode_until_.second == video_encoder_event_counts_[event]) { encode_until_.second == video_encoder_event_counts_[event]) {
video_encoder_state_ = EncoderState::kIdle; video_encoder_state_ = EncoderState::kIdle;
return false; encode_until_ = kInvalidEncodeUntil;
should_continue_encoding = false;
} }
return true; event_cv_.Signal();
return should_continue_encoding;
} }
} // namespace test } // namespace test
} // namespace media } // namespace media
...@@ -46,6 +46,7 @@ class VideoEncoder { ...@@ -46,6 +46,7 @@ class VideoEncoder {
kBitstreamReady, kBitstreamReady,
kFlushing, kFlushing,
kFlushDone, kFlushDone,
kKeyFrame,
kNumEvents, kNumEvents,
}; };
...@@ -90,6 +91,8 @@ class VideoEncoder { ...@@ -90,6 +91,8 @@ class VideoEncoder {
void Flush(); void Flush();
// Updates bitrate based on the specified |bitrate| and |framerate|. // Updates bitrate based on the specified |bitrate| and |framerate|.
void UpdateBitrate(uint32_t bitrate, uint32_t framerate); void UpdateBitrate(uint32_t bitrate, uint32_t framerate);
// Force key frame.
void ForceKeyFrame();
// Get the current state of the video encoder. // Get the current state of the video encoder.
EncoderState GetState() const; EncoderState GetState() const;
...@@ -99,6 +102,8 @@ class VideoEncoder { ...@@ -99,6 +102,8 @@ class VideoEncoder {
// events with different types will be consumed. Will return false if the // events with different types will be consumed. Will return false if the
// specified timeout is exceeded while waiting for the events. // specified timeout is exceeded while waiting for the events.
bool WaitForEvent(EncoderEvent event, size_t times = 1); bool WaitForEvent(EncoderEvent event, size_t times = 1);
// Wait until the |video_encoder_state_| becomes kIdle.
bool WaitUntilIdle();
// Helper function to wait for a FlushDone event. // Helper function to wait for a FlushDone event.
bool WaitForFlushDone(); bool WaitForFlushDone();
// Helper function to wait for the specified number of FrameReleased events. // Helper function to wait for the specified number of FrameReleased events.
...@@ -146,8 +151,7 @@ class VideoEncoder { ...@@ -146,8 +151,7 @@ class VideoEncoder {
// Automatically pause encoding once the video encoder has seen the specified // Automatically pause encoding once the video encoder has seen the specified
// number of events occur. // number of events occur.
std::pair<EncoderEvent, size_t> encode_until_{ std::pair<EncoderEvent, size_t> encode_until_;
kNumEvents, std::numeric_limits<size_t>::max()};
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
}; };
......
...@@ -239,6 +239,14 @@ void VideoEncoderClient::UpdateBitrate(const VideoBitrateAllocation& bitrate, ...@@ -239,6 +239,14 @@ void VideoEncoderClient::UpdateBitrate(const VideoBitrateAllocation& bitrate,
weak_this_, bitrate, framerate)); weak_this_, bitrate, framerate));
} }
void VideoEncoderClient::ForceKeyFrame() {
DCHECK_CALLED_ON_VALID_SEQUENCE(test_sequence_checker_);
encoder_client_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&VideoEncoderClient::ForceKeyFrameTask, weak_this_));
}
bool VideoEncoderClient::WaitForBitstreamProcessors() { bool VideoEncoderClient::WaitForBitstreamProcessors() {
bool success = true; bool success = true;
for (auto& bitstream_processor : bitstream_processors_) for (auto& bitstream_processor : bitstream_processors_)
...@@ -357,6 +365,8 @@ void VideoEncoderClient::BitstreamBufferReady( ...@@ -357,6 +365,8 @@ void VideoEncoderClient::BitstreamBufferReady(
auto it = bitstream_buffers_.find(bitstream_buffer_id); auto it = bitstream_buffers_.find(bitstream_buffer_id);
ASSERT_NE(it, bitstream_buffers_.end()); ASSERT_NE(it, bitstream_buffers_.end());
if (metadata.key_frame)
FireEvent(VideoEncoder::EncoderEvent::kKeyFrame);
// Notify the test an encoded bitstream buffer is ready. We should only do // Notify the test an encoded bitstream buffer is ready. We should only do
// this after scheduling the bitstream to be processed, so calling // this after scheduling the bitstream to be processed, so calling
...@@ -494,10 +504,9 @@ void VideoEncoderClient::EncodeNextFrameTask() { ...@@ -494,10 +504,9 @@ void VideoEncoderClient::EncodeNextFrameTask() {
weak_this_, encoder_client_task_runner_, weak_this_, encoder_client_task_runner_,
&VideoEncoderClient::EncodeDoneTask, video_frame->timestamp())); &VideoEncoderClient::EncodeDoneTask, video_frame->timestamp()));
// TODO(dstaessens): Add support for forcing key frames. encoder_->Encode(video_frame, force_keyframe_);
bool force_keyframe = false;
encoder_->Encode(video_frame, force_keyframe);
force_keyframe_ = false;
num_encodes_requested_++; num_encodes_requested_++;
num_outstanding_encode_requests_++; num_outstanding_encode_requests_++;
if (encoder_client_config_.encode_interval) { if (encoder_client_config_.encode_interval) {
...@@ -542,6 +551,13 @@ void VideoEncoderClient::UpdateBitrateTask( ...@@ -542,6 +551,13 @@ void VideoEncoderClient::UpdateBitrateTask(
current_stats_.framerate = framerate; current_stats_.framerate = framerate;
} }
void VideoEncoderClient::ForceKeyFrameTask() {
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_client_sequence_checker_);
DVLOGF(4);
force_keyframe_ = true;
}
void VideoEncoderClient::EncodeDoneTask(base::TimeDelta timestamp) { void VideoEncoderClient::EncodeDoneTask(base::TimeDelta timestamp) {
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_client_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_client_sequence_checker_);
DCHECK_NE(VideoEncoderClientState::kIdle, encoder_client_state_); DCHECK_NE(VideoEncoderClientState::kIdle, encoder_client_state_);
......
...@@ -129,6 +129,9 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client { ...@@ -129,6 +129,9 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client {
// Updates bitrate based on the specified |bitrate| and |framerate|. // Updates bitrate based on the specified |bitrate| and |framerate|.
void UpdateBitrate(const VideoBitrateAllocation& bitrate, uint32_t 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 // Wait until all bitstream processors have finished processing. Returns
// whether processing was successful. // whether processing was successful.
bool WaitForBitstreamProcessors(); bool WaitForBitstreamProcessors();
...@@ -179,6 +182,8 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client { ...@@ -179,6 +182,8 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client {
void FlushTask(); void FlushTask();
void UpdateBitrateTask(const VideoBitrateAllocation& bitrate, void UpdateBitrateTask(const VideoBitrateAllocation& bitrate,
uint32_t framerate); 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. // Called by the encoder when a frame has been encoded.
void EncodeDoneTask(base::TimeDelta timestamp); void EncodeDoneTask(base::TimeDelta timestamp);
...@@ -244,6 +249,10 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client { ...@@ -244,6 +249,10 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client {
// BitstreamBufferReady(). // BitstreamBufferReady().
size_t frame_index_ = 0; size_t frame_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_); VideoEncoderStats current_stats_ GUARDED_BY(stats_lock_);
mutable base::Lock stats_lock_; mutable base::Lock stats_lock_;
......
...@@ -279,9 +279,6 @@ base::Optional<std::string> SupportsNV12DmaBufInput() { ...@@ -279,9 +279,6 @@ base::Optional<std::string> SupportsNV12DmaBufInput() {
} }
} // namespace } // namespace
// TODO(dstaessens): Add more test scenarios:
// - Forcing key frames
// Encode video from start to end. Wait for the kFlushDone event at the end of // Encode video from start to end. Wait for the kFlushDone event at the end of
// the stream, that notifies us all frames have been encoded. // the stream, that notifies us all frames have been encoded.
TEST_F(VideoEncoderTest, FlushAtEndOfStream) { TEST_F(VideoEncoderTest, FlushAtEndOfStream) {
...@@ -316,6 +313,40 @@ TEST_F(VideoEncoderTest, DestroyBeforeInitialize) { ...@@ -316,6 +313,40 @@ TEST_F(VideoEncoderTest, DestroyBeforeInitialize) {
EXPECT_NE(video_encoder, nullptr); EXPECT_NE(video_encoder, nullptr);
} }
// Test forcing key frames while encoding a video.
TEST_F(VideoEncoderTest, ForceKeyFrame) {
auto config = GetDefaultConfig();
const size_t middle_frame = config.num_frames_to_encode;
config.num_frames_to_encode *= 2;
auto encoder = CreateVideoEncoder(g_env->Video(), config);
// It is expected that our hw encoders don't produce key frames in a short
// time span like a few hundred frames.
// TODO(hiroh): This might be wrong on some platforms. Needs to update.
// Encode the first frame, this should always be a keyframe.
encoder->EncodeUntil(VideoEncoder::kBitstreamReady, 1u);
EXPECT_TRUE(encoder->WaitUntilIdle());
EXPECT_EQ(encoder->GetEventCount(VideoEncoder::kKeyFrame), 1u);
// Encode until the middle of stream and request force_keyframe.
encoder->EncodeUntil(VideoEncoder::kFrameReleased, middle_frame);
EXPECT_TRUE(encoder->WaitUntilIdle());
// Check if there is no keyframe except the first frame.
EXPECT_EQ(encoder->GetEventCount(VideoEncoder::kKeyFrame), 1u);
encoder->ForceKeyFrame();
// Check if the |middle_frame|+1-th frame is keyframe.
encoder->EncodeUntil(VideoEncoder::kBitstreamReady, middle_frame + 1u);
EXPECT_TRUE(encoder->WaitUntilIdle());
EXPECT_EQ(encoder->GetEventCount(VideoEncoder::kKeyFrame), 2u);
// Encode until the end of stream.
encoder->Encode();
EXPECT_TRUE(encoder->WaitForFlushDone());
EXPECT_EQ(encoder->GetEventCount(VideoEncoder::kKeyFrame), 2u);
EXPECT_EQ(encoder->GetFlushDoneCount(), 1u);
EXPECT_EQ(encoder->GetFrameReleasedCount(), config.num_frames_to_encode);
EXPECT_TRUE(encoder->WaitForBitstreamProcessors());
}
// Encode video from start to end. Multiple buffer encodes will be queued in the // Encode video from start to end. Multiple buffer encodes will be queued in the
// encoder, without waiting for the result of the previous encode requests. // encoder, without waiting for the result of the previous encode requests.
TEST_F(VideoEncoderTest, FlushAtEndOfStream_MultipleOutstandingEncodes) { TEST_F(VideoEncoderTest, FlushAtEndOfStream_MultipleOutstandingEncodes) {
...@@ -387,8 +418,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicBitrate) { ...@@ -387,8 +418,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicBitrate) {
const uint32_t first_bitrate = config.bitrate; const uint32_t first_bitrate = config.bitrate;
encoder->EncodeUntil(VideoEncoder::kFrameReleased, encoder->EncodeUntil(VideoEncoder::kFrameReleased,
kNumFramesToEncodeForBitrateCheck); kNumFramesToEncodeForBitrateCheck);
encoder->WaitForEvent(VideoEncoder::kFrameReleased, EXPECT_TRUE(encoder->WaitUntilIdle());
kNumFramesToEncodeForBitrateCheck);
EXPECT_NEAR(encoder->GetStats().Bitrate(), first_bitrate, EXPECT_NEAR(encoder->GetStats().Bitrate(), first_bitrate,
kBitrateTolerance * first_bitrate); kBitrateTolerance * first_bitrate);
...@@ -421,8 +451,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicFramerate) { ...@@ -421,8 +451,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicFramerate) {
encoder->EncodeUntil(VideoEncoder::kFrameReleased, encoder->EncodeUntil(VideoEncoder::kFrameReleased,
kNumFramesToEncodeForBitrateCheck); kNumFramesToEncodeForBitrateCheck);
encoder->WaitForEvent(VideoEncoder::kFrameReleased, EXPECT_TRUE(encoder->WaitUntilIdle());
kNumFramesToEncodeForBitrateCheck);
EXPECT_NEAR(encoder->GetStats().Bitrate(), config.bitrate, EXPECT_NEAR(encoder->GetStats().Bitrate(), config.bitrate,
kBitrateTolerance * config.bitrate); kBitrateTolerance * config.bitrate);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment