| Index: webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h
|
| diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h
|
| index 5c275aa949015bd3ef63aa340d2283f2258b4488..c784194e958bb530e93f324c9d050d55aec9325d 100644
|
| --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h
|
| +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h
|
| @@ -28,8 +28,11 @@
|
| #endif
|
|
|
| #include "webrtc/base/checks.h"
|
| +#include "webrtc/base/event.h"
|
| #include "webrtc/base/file.h"
|
| #include "webrtc/base/logging.h"
|
| +#include "webrtc/base/task_queue.h"
|
| +#include "webrtc/base/timeutils.h"
|
| #include "webrtc/media/engine/webrtcvideodecoderfactory.h"
|
| #include "webrtc/media/engine/webrtcvideoencoderfactory.h"
|
| #include "webrtc/modules/video_coding/codecs/h264/include/h264.h"
|
| @@ -41,6 +44,7 @@
|
| #include "webrtc/modules/video_coding/include/video_codec_interface.h"
|
| #include "webrtc/modules/video_coding/include/video_coding.h"
|
| #include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
|
| +#include "webrtc/system_wrappers/include/sleep.h"
|
| #include "webrtc/test/gtest.h"
|
| #include "webrtc/test/testsupport/fileutils.h"
|
| #include "webrtc/test/testsupport/frame_reader.h"
|
| @@ -237,6 +241,7 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| }
|
|
|
| void SetUpCodecConfig(const CodecParams& process,
|
| + const RateProfile& rate_profile,
|
| const VisualizationParams* visualization_params) {
|
| CreateEncoderAndDecoder(process.hw_codec, process.codec_type);
|
|
|
| @@ -255,12 +260,13 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| // Key frame interval and packet loss are set for each test.
|
| config_.keyframe_interval = process.key_frame_interval;
|
| config_.networking_config.packet_loss_probability =
|
| - packet_loss_probability_;
|
| + process.packet_loss_probability;
|
|
|
| // Configure codec settings.
|
| VideoCodingModule::Codec(process.codec_type, &codec_settings_);
|
| config_.codec_settings = &codec_settings_;
|
| - config_.codec_settings->startBitrate = start_bitrate_;
|
| + float start_bitrate = rate_profile.target_bit_rate[0];
|
| + config_.codec_settings->startBitrate = start_bitrate;
|
| config_.codec_settings->width = process.width;
|
| config_.codec_settings->height = process.height;
|
|
|
| @@ -318,13 +324,13 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| test::OutputPath() + process.filename +
|
| "_cd-" + CodecTypeToPayloadName(process.codec_type).value_or("") +
|
| "_hw-" + std::to_string(process.hw_codec) +
|
| - "_fr-" + std::to_string(start_frame_rate_) +
|
| - "_br-" + std::to_string(static_cast<int>(start_bitrate_));
|
| + "_br-" + std::to_string(static_cast<int>(start_bitrate));
|
| // clang-format on
|
| + int start_frame_rate = rate_profile.input_frame_rate[0];
|
| if (visualization_params->save_source_y4m) {
|
| source_frame_writer_.reset(new test::Y4mFrameWriterImpl(
|
| output_filename_base + "_source.y4m", config_.codec_settings->width,
|
| - config_.codec_settings->height, start_frame_rate_));
|
| + config_.codec_settings->height, start_frame_rate));
|
| RTC_CHECK(source_frame_writer_->Init());
|
| }
|
| if (visualization_params->save_encoded_ivf) {
|
| @@ -337,7 +343,7 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| decoded_frame_writer_.reset(new test::Y4mFrameWriterImpl(
|
| output_filename_base + "_decoded.y4m",
|
| config_.codec_settings->width, config_.codec_settings->height,
|
| - start_frame_rate_));
|
| + start_frame_rate));
|
| RTC_CHECK(decoded_frame_writer_->Init());
|
| }
|
| }
|
| @@ -349,7 +355,6 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| analysis_frame_writer_.get(), packet_manipulator_.get(), config_,
|
| &stats_, source_frame_writer_.get(), encoded_frame_writer_.get(),
|
| decoded_frame_writer_.get()));
|
| - processor_->Init();
|
| }
|
|
|
| // Reset quantities after each encoder update, update the target
|
| @@ -383,12 +388,12 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| }
|
|
|
| // For every encoded frame, update the rate control metrics.
|
| - void UpdateRateControlMetrics(int frame_number) {
|
| + void UpdateRateControlMetrics(int frame_number,
|
| + FrameType frame_type,
|
| + size_t encoded_frame_size) {
|
| RTC_CHECK_GE(frame_number, 0);
|
| int tl_idx = TemporalLayerIndexForFrame(frame_number);
|
| - FrameType frame_type = processor_->EncodedFrameType(frame_number);
|
| - float encoded_size_kbits =
|
| - processor_->EncodedFrameSize(frame_number) * 8.0f / 1000.0f;
|
| + float encoded_size_kbits = encoded_frame_size * 8.0f / 1000.0f;
|
|
|
| // Update layer data.
|
| // Update rate mismatch relative to per-frame bandwidth for delta frames.
|
| @@ -423,11 +428,36 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| }
|
| }
|
|
|
| + void UpdateRateControlMetrics(int frame_number, rtc::TaskQueue* task_queue) {
|
| + FrameType frame_type;
|
| + size_t encoded_frame_size;
|
| +
|
| + if (task_queue) {
|
| + rtc::Event sync_event(false, false);
|
| + task_queue->PostTask([this, &frame_type, &encoded_frame_size,
|
| + frame_number, &sync_event]() {
|
| + frame_type = processor_->EncodedFrameType(frame_number);
|
| + encoded_frame_size = processor_->EncodedFrameSize(frame_number);
|
| + sync_event.Set();
|
| + });
|
| + ASSERT_TRUE(sync_event.Wait(rtc::Event::kForever));
|
| + } else {
|
| + frame_type = processor_->EncodedFrameType(frame_number);
|
| + encoded_frame_size = processor_->EncodedFrameSize(frame_number);
|
| + }
|
| +
|
| + UpdateRateControlMetrics(frame_number, frame_type, encoded_frame_size);
|
| + }
|
| +
|
| + void UpdateRateControlMetrics(int frame_number) {
|
| + UpdateRateControlMetrics(frame_number, nullptr);
|
| + }
|
| +
|
| // Verify expected behavior of rate control and print out data.
|
| void VerifyRateControlMetrics(int update_index,
|
| - const RateControlThresholds& rc_expected) {
|
| - int num_dropped_frames = processor_->NumberDroppedFrames();
|
| - int num_resize_actions = processor_->NumberSpatialResizes();
|
| + const RateControlThresholds& rc_expected,
|
| + int num_dropped_frames,
|
| + int num_resize_actions) {
|
| printf(
|
| "For update #: %d,\n"
|
| " Target Bitrate: %d,\n"
|
| @@ -489,6 +519,35 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| }
|
| }
|
|
|
| + void VerifyRateControlMetrics(int update_index,
|
| + const RateControlThresholds& rc_expected,
|
| + rtc::TaskQueue* task_queue) {
|
| + int num_dropped_frames;
|
| + int num_resize_actions;
|
| +
|
| + if (task_queue) {
|
| + rtc::Event sync_event(false, false);
|
| + task_queue->PostTask(
|
| + [this, &num_dropped_frames, &num_resize_actions, &sync_event]() {
|
| + num_dropped_frames = processor_->NumberDroppedFrames();
|
| + num_resize_actions = processor_->NumberSpatialResizes();
|
| + sync_event.Set();
|
| + });
|
| + ASSERT_TRUE(sync_event.Wait(rtc::Event::kForever));
|
| + } else {
|
| + num_dropped_frames = processor_->NumberDroppedFrames();
|
| + num_resize_actions = processor_->NumberSpatialResizes();
|
| + }
|
| +
|
| + VerifyRateControlMetrics(update_index, rc_expected, num_dropped_frames,
|
| + num_resize_actions);
|
| + }
|
| +
|
| + void VerifyRateControlMetrics(int update_index,
|
| + const RateControlThresholds& rc_expected) {
|
| + VerifyRateControlMetrics(update_index, rc_expected, nullptr);
|
| + }
|
| +
|
| void VerifyQuality(const test::QualityMetricsResult& psnr_result,
|
| const test::QualityMetricsResult& ssim_result,
|
| const QualityThresholds& quality_thresholds) {
|
| @@ -570,11 +629,9 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| RateControlThresholds* rc_thresholds,
|
| const VisualizationParams* visualization_params) {
|
| // Codec/config settings.
|
| - start_bitrate_ = rate_profile.target_bit_rate[0];
|
| - start_frame_rate_ = rate_profile.input_frame_rate[0];
|
| - packet_loss_probability_ = process.packet_loss_probability;
|
| num_temporal_layers_ = process.num_temporal_layers;
|
| - SetUpCodecConfig(process, visualization_params);
|
| + SetUpCodecConfig(process, rate_profile, visualization_params);
|
| +
|
| // Update the temporal layers and the codec with the initial rates.
|
| bit_rate_ = rate_profile.target_bit_rate[0];
|
| frame_rate_ = rate_profile.input_frame_rate[0];
|
| @@ -582,7 +639,6 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| // Set the initial target size for key frame.
|
| target_size_key_frame_initial_ =
|
| 0.5 * kInitialBufferSize * bit_rate_layer_[0];
|
| - processor_->SetRates(bit_rate_, frame_rate_);
|
|
|
| // Process each frame, up to |num_frames|.
|
| int frame_number = 0;
|
| @@ -595,17 +651,54 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| // In batch mode, we calculate the metrics for all frames after all frames
|
| // have been sent for encoding.
|
|
|
| + // AndroidMediaEncoder must be called on a task queue, so during the batch
|
| + // run we will call |processor_| on a task queue.
|
| + rtc::TaskQueue task_queue("VidProc TQ");
|
| +
|
| + // Initialize |processor_|, which initializes the encoder and decoder.
|
| + rtc::Event sync_event(false, false);
|
| + task_queue.PostTask([this, &sync_event]() {
|
| + processor_->Init();
|
| + processor_->SetRates(bit_rate_, frame_rate_);
|
| + sync_event.Set();
|
| + });
|
| + ASSERT_TRUE(sync_event.Wait(rtc::Event::kForever));
|
| +
|
| + // Post all frames (in order) to encoder.
|
| + int start_frame_rate = rate_profile.input_frame_rate[0];
|
| // TODO(brandtr): Refactor "frame number accounting" so we don't have to
|
| // call ProcessFrame num_frames+1 times here.
|
| for (frame_number = 0; frame_number <= num_frames; ++frame_number) {
|
| - EXPECT_TRUE(processor_->ProcessFrame(frame_number));
|
| + task_queue.PostTask([this, frame_number]() {
|
| + EXPECT_TRUE(processor_->ProcessFrame(frame_number));
|
| + });
|
| +
|
| + // In order to not overwhelm the OpenMAX buffers in the Android
|
| + // MediaCodec API, we roughly pace the frames here. The downside
|
| + // is that the encode run will be done in realtime.
|
| + if (process.hw_codec) {
|
| + SleepMs(rtc::kNumMillisecsPerSec / start_frame_rate);
|
| + }
|
| }
|
|
|
| + // Give the task queue some time to finish processing the posted frames,
|
| + // then shut down processing and synchronize with main thread.
|
| + SleepMs(rtc::kNumMillisecsPerSec);
|
| + sync_event.Reset();
|
| + task_queue.PostTask([this, &sync_event]() {
|
| + processor_->Release();
|
| + sync_event.Set();
|
| + });
|
| + ASSERT_TRUE(sync_event.Wait(rtc::Event::kForever));
|
| +
|
| + // Calculate and print rate control metrics.
|
| for (frame_number = 0; frame_number < num_frames; ++frame_number) {
|
| ++num_frames_per_update_[TemporalLayerIndexForFrame(frame_number)];
|
| ++num_frames_total_;
|
| - UpdateRateControlMetrics(frame_number);
|
| + UpdateRateControlMetrics(frame_number, &task_queue);
|
| }
|
| +
|
| + VerifyRateControlMetrics(update_index, rc_thresholds[0], &task_queue);
|
| } else {
|
| // In online mode, we calculate the metrics for a given frame right after
|
| // it has been sent for encoding.
|
| @@ -615,6 +708,10 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| "since they may be pipelining.";
|
| }
|
|
|
| + // Initialize |processor_| on main thread.
|
| + processor_->Init();
|
| + processor_->SetRates(bit_rate_, frame_rate_);
|
| +
|
| while (frame_number < num_frames) {
|
| EXPECT_TRUE(processor_->ProcessFrame(frame_number));
|
| VerifyQpParser(process, frame_number);
|
| @@ -643,18 +740,16 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| // TODO(brandtr): Refactor "frame number accounting" so we don't have to
|
| // call ProcessFrame one extra time here.
|
| EXPECT_TRUE(processor_->ProcessFrame(frame_number));
|
| - }
|
|
|
| - // Verify rate control metrics for all frames (if in batch mode), or for all
|
| - // frames since the last rate update (if not in batch mode).
|
| - VerifyRateControlMetrics(update_index, rc_thresholds[update_index]);
|
| + // Release codecs to make sure they have finished processing.
|
| + processor_->Release();
|
| +
|
| + // Verify for final rate update.
|
| + VerifyRateControlMetrics(update_index, rc_thresholds[update_index]);
|
| + }
|
| EXPECT_EQ(num_frames, frame_number);
|
| EXPECT_EQ(num_frames + 1, static_cast<int>(stats_.stats_.size()));
|
|
|
| - // Release encoder and decoder to make sure they have finished processing.
|
| - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release());
|
| - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release());
|
| -
|
| // Close the analysis files before we use them for SSIM/PSNR calculations.
|
| analysis_frame_reader_->Close();
|
| analysis_frame_writer_->Close();
|
| @@ -829,11 +924,8 @@ class VideoProcessorIntegrationTest : public testing::Test {
|
| float target_size_key_frame_;
|
| float sum_key_frame_size_mismatch_;
|
| int num_key_frames_;
|
| - float start_bitrate_;
|
| - int start_frame_rate_;
|
|
|
| // Codec and network settings.
|
| - float packet_loss_probability_;
|
| int num_temporal_layers_;
|
| };
|
|
|
|
|