Chromium Code Reviews| 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 68fe68e7108764e391730c86c88ec841569866b1..55bc4efae4c45c15dc638c18982ce404fdc84062 100644 |
| --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h |
| +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h |
| @@ -28,6 +28,7 @@ |
| #include "webrtc/base/checks.h" |
| #include "webrtc/base/file.h" |
| +#include "webrtc/base/logging.h" |
| #include "webrtc/media/engine/webrtcvideodecoderfactory.h" |
| #include "webrtc/media/engine/webrtcvideoencoderfactory.h" |
| #include "webrtc/modules/video_coding/codecs/h264/include/h264.h" |
| @@ -84,6 +85,12 @@ struct CodecParams { |
| std::string filename; |
| bool verbose_logging; |
| + |
| + // In batch mode, the VideoProcessor is fed all the frames for processing |
| + // before any metrics are calculated. This is useful for pipelining HW codecs, |
| + // for which some calculated metrics otherwise would be incorrect. The |
| + // downside with batch mode is that mid-test rate allocation is not supported. |
| + bool batch_mode; |
| }; |
| // Thresholds for the quality metrics. |
| @@ -342,7 +349,7 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| // Reset quantities after each encoder update, update the target |
| // per-frame bandwidth. |
| - void ResetRateControlMetrics(int num_frames) { |
| + void ResetRateControlMetrics(int num_frames_to_hit_target) { |
| for (int i = 0; i < num_temporal_layers_; i++) { |
| num_frames_per_update_[i] = 0; |
| sum_frame_size_mismatch_[i] = 0.0f; |
| @@ -364,35 +371,40 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| sum_encoded_frame_size_total_ = 0.0f; |
| encoding_bitrate_total_ = 0.0f; |
| perc_encoding_rate_mismatch_ = 0.0f; |
| - num_frames_to_hit_target_ = num_frames; |
| + num_frames_to_hit_target_ = num_frames_to_hit_target; |
| encoding_rate_within_target_ = false; |
| sum_key_frame_size_mismatch_ = 0.0; |
| num_key_frames_ = 0; |
| } |
| // For every encoded frame, update the rate control metrics. |
| - void UpdateRateControlMetrics(int frame_num, FrameType frame_type) { |
| - float encoded_size_kbits = processor_->EncodedFrameSize() * 8.0f / 1000.0f; |
| + void UpdateRateControlMetrics(int frame_number, |
| + FrameType frame_type, |
| + size_t encoded_frame_size) { |
| + RTC_CHECK_GE(frame_number, 0); |
| + int layer = LayerIndexForFrame(frame_number); |
|
sprang_webrtc
2017/03/08 16:20:21
Not obvious to me which layer this refers to?
brandtr
2017/03/09 15:18:27
This function returns what TL this frame belongs t
|
| + 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. |
| if (frame_type == kVideoFrameDelta) { |
| // TODO(marpan): Should we count dropped (zero size) frames in mismatch? |
| - sum_frame_size_mismatch_[layer_] += |
| - fabs(encoded_size_kbits - per_frame_bandwidth_[layer_]) / |
| - per_frame_bandwidth_[layer_]; |
| + sum_frame_size_mismatch_[layer] += |
| + fabs(encoded_size_kbits - per_frame_bandwidth_[layer]) / |
| + per_frame_bandwidth_[layer]; |
| } else { |
| - float target_size = (frame_num == 1) ? target_size_key_frame_initial_ |
| - : target_size_key_frame_; |
| + float target_size = (frame_number == 0) ? target_size_key_frame_initial_ |
| + : target_size_key_frame_; |
| sum_key_frame_size_mismatch_ += |
| fabs(encoded_size_kbits - target_size) / target_size; |
| num_key_frames_ += 1; |
| } |
| - sum_encoded_frame_size_[layer_] += encoded_size_kbits; |
| - // Encoding bitrate per layer: from the start of the update/run to the |
| + sum_encoded_frame_size_[layer] += encoded_size_kbits; |
| + // Encoding bit rate per layer: from the start of the update/run to the |
| // current frame. |
| - encoding_bitrate_[layer_] = sum_encoded_frame_size_[layer_] * |
| - frame_rate_layer_[layer_] / |
| - num_frames_per_update_[layer_]; |
| + encoding_bitrate_[layer] = sum_encoded_frame_size_[layer] * |
| + frame_rate_layer_[layer] / |
| + num_frames_per_update_[layer]; |
| // Total encoding rate: from the start of the update/run to current frame. |
| sum_encoded_frame_size_total_ += encoded_size_kbits; |
| encoding_bitrate_total_ = |
| @@ -408,9 +420,9 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| // Verify expected behavior of rate control and print out data. |
| void VerifyRateControlMetrics(int update_index, |
| + int num_dropped_frames, |
| + int num_resize_actions, |
| const RateControlThresholds& rc_expected) { |
| - int num_dropped_frames = processor_->NumberDroppedFrames(); |
| - int num_resize_actions = processor_->NumberSpatialResizes(); |
| printf( |
| "For update #: %d,\n" |
| " Target Bitrate: %d,\n" |
| @@ -503,11 +515,10 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| RTC_NOTREACHED(); |
| break; |
| } |
| - |
| return layer; |
| } |
| - // Set the bitrate and frame rate per layer, for up to 3 layers. |
| + // Set the bit rate and frame rate per layer, for up to 3 layers. |
| void SetLayerRates() { |
| RTC_DCHECK_LE(num_temporal_layers_, kMaxNumTemporalLayers); |
| for (int i = 0; i < num_temporal_layers_; i++) { |
| @@ -551,47 +562,88 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| processor_->SetRates(bit_rate_, frame_rate_); |
| // Process each frame, up to |num_frames|. |
| - int num_frames = rate_profile.num_frames; |
| + int frame_number = 0; |
| int update_index = 0; |
| + int num_frames = rate_profile.num_frames; |
| ResetRateControlMetrics( |
| rate_profile.frame_index_rate_update[update_index + 1]); |
| - int frame_number = 0; |
| - FrameType frame_type = kVideoFrameDelta; |
| - while (processor_->ProcessFrame(frame_number) && |
| - frame_number < num_frames) { |
| - // Get the layer index for the frame |frame_number|. |
| - layer_ = LayerIndexForFrame(frame_number); |
| - // Get the frame_type. |
| - frame_type = processor_->EncodedFrameType(); |
| - // Counter for whole sequence run. |
| - ++frame_number; |
| - // Counters for each rate update. |
| - ++num_frames_per_update_[layer_]; |
| - ++num_frames_total_; |
| - UpdateRateControlMetrics(frame_number, frame_type); |
| - // If we hit another/next update, verify stats for current state and |
| - // update layers and codec with new rates. |
| - if (frame_number == |
| - rate_profile.frame_index_rate_update[update_index + 1]) { |
| - VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); |
| - // Update layer rates and the codec with new rates. |
| - ++update_index; |
| - bit_rate_ = rate_profile.target_bit_rate[update_index]; |
| - frame_rate_ = rate_profile.input_frame_rate[update_index]; |
| - SetLayerRates(); |
| - ResetRateControlMetrics( |
| - rate_profile.frame_index_rate_update[update_index + 1]); |
| - processor_->SetRates(bit_rate_, frame_rate_); |
| + |
| + if (process.batch_mode) { |
| + // In batch mode, we calculate the metrics for all frames after all frames |
| + // have been sent for encoding. |
| + |
| + for (frame_number = 0; frame_number < num_frames; ++frame_number) { |
|
åsapersson
2017/03/08 15:26:46
use frame_number <= num_frames and remove the Proc
sprang_webrtc
2017/03/08 16:20:21
Then the expect becomes a little more complicated
brandtr
2017/03/09 15:18:27
asapersson: Done.
sprang: The last call to Proces
sprang_webrtc
2017/03/10 09:09:37
Acknowledged.
|
| + EXPECT_TRUE(processor_->ProcessFrame(frame_number)); |
| + } |
| + processor_->ProcessFrame(frame_number); |
| + |
| + // 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()); |
| + |
| + for (frame_number = 0; frame_number < num_frames; ++frame_number) { |
| + ++num_frames_per_update_[LayerIndexForFrame(frame_number)]; |
| + ++num_frames_total_; |
| + FrameType frame_type = processor_->EncodedFrameType(frame_number); |
| + size_t encoded_frame_size = processor_->EncodedFrameSize(frame_number); |
| + UpdateRateControlMetrics(frame_number, frame_type, encoded_frame_size); |
| } |
| + } else { |
| + // In online mode, we calculate the metrics for a given frame right after |
| + // it has been sent for encoding. |
| + |
| + if (process.hw_codec) { |
| + LOG(LS_WARNING) << "HW codecs should mostly be run in batch mode, " |
| + "since they may be pipelining."; |
| + } |
| + |
| + while (frame_number < num_frames) { |
| + EXPECT_TRUE(processor_->ProcessFrame(frame_number)); |
| + |
| + ++num_frames_per_update_[LayerIndexForFrame(frame_number)]; |
| + ++num_frames_total_; |
| + FrameType frame_type = processor_->EncodedFrameType(frame_number); |
| + size_t encoded_frame_size = processor_->EncodedFrameSize(frame_number); |
|
åsapersson
2017/03/08 15:26:46
maybe get frame_type and encoded_frame_size in Upd
brandtr
2017/03/09 15:18:27
Done.
|
| + UpdateRateControlMetrics(frame_number, frame_type, encoded_frame_size); |
| + |
| + ++frame_number; |
| + |
| + // If we hit another/next update, verify stats for current state and |
| + // update layers and codec with new rates. |
| + if (frame_number == |
| + rate_profile.frame_index_rate_update[update_index + 1]) { |
| + int num_dropped_frames = processor_->NumberDroppedFrames(); |
| + int num_resize_actions = processor_->NumberSpatialResizes(); |
|
åsapersson
2017/03/08 15:26:46
ditto
brandtr
2017/03/09 15:18:27
Done.
åsapersson
2017/03/10 08:43:27
Perhaps same here.
brandtr
2017/03/10 08:48:40
Sorry for missing that.. :/
|
| + VerifyRateControlMetrics(update_index, num_dropped_frames, |
| + num_resize_actions, |
| + rc_thresholds[update_index]); |
| + |
| + // Update layer rates and the codec with new rates. |
| + ++update_index; |
| + bit_rate_ = rate_profile.target_bit_rate[update_index]; |
| + frame_rate_ = rate_profile.input_frame_rate[update_index]; |
| + SetLayerRates(); |
| + ResetRateControlMetrics( |
| + rate_profile.frame_index_rate_update[update_index + 1]); |
| + processor_->SetRates(bit_rate_, frame_rate_); |
| + } |
| + } |
| + processor_->ProcessFrame(frame_number); |
| + |
| + // 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()); |
| } |
| - VerifyRateControlMetrics(update_index, rc_thresholds[update_index]); |
| + |
| + // 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). |
| + int num_dropped_frames = processor_->NumberDroppedFrames(); |
| + int num_resize_actions = processor_->NumberSpatialResizes(); |
| + VerifyRateControlMetrics(update_index, num_dropped_frames, |
| + num_resize_actions, 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()); |
|
åsapersson
2017/03/08 15:26:46
maybe make this change if needed in upcoming cl
brandtr
2017/03/09 15:18:27
Done.
|
| - |
| // Close the analysis files before we use them for SSIM/PSNR calculations. |
| analysis_frame_reader_->Close(); |
| analysis_frame_writer_->Close(); |
| @@ -601,7 +653,7 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| source_frame_writer_->Close(); |
| } |
| if (encoded_frame_writer_) { |
| - encoded_frame_writer_->Close(); |
| + EXPECT_TRUE(encoded_frame_writer_->Close()); |
| } |
| if (decoded_frame_writer_) { |
| decoded_frame_writer_->Close(); |
| @@ -640,7 +692,8 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| int width, |
| int height, |
| const std::string& filename, |
| - bool verbose_logging) { |
| + bool verbose_logging, |
| + bool batch_mode) { |
| process_settings->codec_type = codec_type; |
| process_settings->hw_codec = hw_codec; |
| process_settings->use_single_core = use_single_core; |
| @@ -655,6 +708,7 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| process_settings->height = height; |
| process_settings->filename = filename; |
| process_settings->verbose_logging = verbose_logging; |
| + process_settings->batch_mode = batch_mode; |
| } |
| static void SetCodecParams(CodecParams* process_settings, |
| @@ -672,7 +726,8 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| packet_loss_probability, key_frame_interval, |
| num_temporal_layers, error_concealment_on, denoising_on, |
| frame_dropper_on, spatial_resize_on, kCifWidth, kCifHeight, |
| - kFilenameForemanCif, false /* verbose_logging */); |
| + kFilenameForemanCif, false /* verbose_logging */, |
| + false /* batch_mode */); |
| } |
| static void SetQualityThresholds(QualityThresholds* quality_thresholds, |
| @@ -756,7 +811,6 @@ class VideoProcessorIntegrationTest : public testing::Test { |
| bool encoding_rate_within_target_; |
| int bit_rate_; |
| int frame_rate_; |
| - int layer_; |
| float target_size_key_frame_initial_; |
| float target_size_key_frame_; |
| float sum_key_frame_size_mismatch_; |