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) {
return "Flushing";
case VideoEncoder::EncoderEvent::kFlushDone:
return "FlushDone";
case VideoEncoder::EncoderEvent::kKeyFrame:
return "KeyFrame";
default:
return "Unknown";
}
......@@ -43,6 +45,8 @@ constexpr base::TimeDelta kDefaultEventWaitTimeout =
// Default initial size used for |video_encoder_events_|.
constexpr size_t kDefaultEventListSize = 512;
constexpr std::pair<VideoEncoder::EncoderEvent, size_t> kInvalidEncodeUntil{
VideoEncoder::kNumEvents, std::numeric_limits<size_t>::max()};
} // namespace
// static
......@@ -61,7 +65,8 @@ std::unique_ptr<VideoEncoder> VideoEncoder::Create(
VideoEncoder::VideoEncoder()
: event_timeout_(kDefaultEventWaitTimeout),
video_encoder_event_counts_{},
next_unprocessed_event_(0) {
next_unprocessed_event_(0),
encode_until_(kInvalidEncodeUntil) {
video_encoder_events_.reserve(kDefaultEventListSize);
}
......@@ -137,6 +142,7 @@ void VideoEncoder::Encode() {
void VideoEncoder::EncodeUntil(EncoderEvent event, size_t event_count) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(video_encoder_state_.load(), EncoderState::kIdle);
DCHECK(encode_until_ == kInvalidEncodeUntil);
DCHECK(video_);
DVLOGF(4);
......@@ -162,6 +168,13 @@ void VideoEncoder::UpdateBitrate(uint32_t bitrate, uint32_t 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 {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
......@@ -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() {
return WaitForEvent(EncoderEvent::kFlushDone);
}
......@@ -244,16 +276,17 @@ bool VideoEncoder::NotifyEvent(EncoderEvent event) {
video_encoder_events_.push_back(event);
video_encoder_event_counts_[event]++;
event_cv_.Signal();
bool should_continue_encoding = true;
// Check whether video encoding should be paused after this event.
if (encode_until_.first == event &&
encode_until_.second == video_encoder_event_counts_[event]) {
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 media
......@@ -46,6 +46,7 @@ class VideoEncoder {
kBitstreamReady,
kFlushing,
kFlushDone,
kKeyFrame,
kNumEvents,
};
......@@ -90,6 +91,8 @@ class VideoEncoder {
void Flush();
// Updates bitrate based on the specified |bitrate| and |framerate|.
void UpdateBitrate(uint32_t bitrate, uint32_t framerate);
// Force key frame.
void ForceKeyFrame();
// Get the current state of the video encoder.
EncoderState GetState() const;
......@@ -99,6 +102,8 @@ class VideoEncoder {
// events with different types will be consumed. Will return false if the
// specified timeout is exceeded while waiting for the events.
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.
bool WaitForFlushDone();
// Helper function to wait for the specified number of FrameReleased events.
......@@ -146,8 +151,7 @@ class VideoEncoder {
// Automatically pause encoding once the video encoder has seen the specified
// number of events occur.
std::pair<EncoderEvent, size_t> encode_until_{
kNumEvents, std::numeric_limits<size_t>::max()};
std::pair<EncoderEvent, size_t> encode_until_;
SEQUENCE_CHECKER(sequence_checker_);
};
......
......@@ -239,6 +239,14 @@ void VideoEncoderClient::UpdateBitrate(const VideoBitrateAllocation& bitrate,
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 success = true;
for (auto& bitstream_processor : bitstream_processors_)
......@@ -357,6 +365,8 @@ void VideoEncoderClient::BitstreamBufferReady(
auto it = bitstream_buffers_.find(bitstream_buffer_id);
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
// this after scheduling the bitstream to be processed, so calling
......@@ -494,10 +504,9 @@ void VideoEncoderClient::EncodeNextFrameTask() {
weak_this_, encoder_client_task_runner_,
&VideoEncoderClient::EncodeDoneTask, video_frame->timestamp()));
// TODO(dstaessens): Add support for forcing key frames.
bool force_keyframe = false;
encoder_->Encode(video_frame, force_keyframe);
encoder_->Encode(video_frame, force_keyframe_);
force_keyframe_ = false;
num_encodes_requested_++;
num_outstanding_encode_requests_++;
if (encoder_client_config_.encode_interval) {
......@@ -542,6 +551,13 @@ void VideoEncoderClient::UpdateBitrateTask(
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) {
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_client_sequence_checker_);
DCHECK_NE(VideoEncoderClientState::kIdle, encoder_client_state_);
......
......@@ -129,6 +129,9 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client {
// 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();
......@@ -179,6 +182,8 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client {
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);
......@@ -244,6 +249,10 @@ class VideoEncoderClient : public VideoEncodeAccelerator::Client {
// BitstreamBufferReady().
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_);
mutable base::Lock stats_lock_;
......
......@@ -279,9 +279,6 @@ base::Optional<std::string> SupportsNV12DmaBufInput() {
}
} // 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
// the stream, that notifies us all frames have been encoded.
TEST_F(VideoEncoderTest, FlushAtEndOfStream) {
......@@ -316,6 +313,40 @@ TEST_F(VideoEncoderTest, DestroyBeforeInitialize) {
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
// encoder, without waiting for the result of the previous encode requests.
TEST_F(VideoEncoderTest, FlushAtEndOfStream_MultipleOutstandingEncodes) {
......@@ -387,8 +418,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicBitrate) {
const uint32_t first_bitrate = config.bitrate;
encoder->EncodeUntil(VideoEncoder::kFrameReleased,
kNumFramesToEncodeForBitrateCheck);
encoder->WaitForEvent(VideoEncoder::kFrameReleased,
kNumFramesToEncodeForBitrateCheck);
EXPECT_TRUE(encoder->WaitUntilIdle());
EXPECT_NEAR(encoder->GetStats().Bitrate(), first_bitrate,
kBitrateTolerance * first_bitrate);
......@@ -421,8 +451,7 @@ TEST_F(VideoEncoderTest, BitrateCheck_DynamicFramerate) {
encoder->EncodeUntil(VideoEncoder::kFrameReleased,
kNumFramesToEncodeForBitrateCheck);
encoder->WaitForEvent(VideoEncoder::kFrameReleased,
kNumFramesToEncodeForBitrateCheck);
EXPECT_TRUE(encoder->WaitUntilIdle());
EXPECT_NEAR(encoder->GetStats().Bitrate(), 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