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..672b1d2588f0b06723ac2720ed79c0e70fc02c79 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) { |
+ 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; |
+ |
// 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_[tl_idx] += |
+ fabs(encoded_size_kbits - per_frame_bandwidth_[tl_idx]) / |
+ per_frame_bandwidth_[tl_idx]; |
} 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 |
- // current frame. |
- encoding_bitrate_[layer_] = sum_encoded_frame_size_[layer_] * |
- frame_rate_layer_[layer_] / |
- num_frames_per_update_[layer_]; |
+ sum_encoded_frame_size_[tl_idx] += encoded_size_kbits; |
+ // Encoding bit rate per temporal layer: from the start of the update/run |
+ // to the current frame. |
+ encoding_bitrate_[tl_idx] = sum_encoded_frame_size_[tl_idx] * |
+ frame_rate_layer_[tl_idx] / |
+ num_frames_per_update_[tl_idx]; |
// Total encoding rate: from the start of the update/run to current frame. |
sum_encoded_frame_size_total_ += encoded_size_kbits; |
encoding_bitrate_total_ = |
@@ -475,40 +487,39 @@ class VideoProcessorIntegrationTest : public testing::Test { |
EXPECT_GT(ssim_result.min, quality_thresholds.min_min_ssim); |
} |
- // Layer index corresponding to frame number, for up to 3 layers. |
- int LayerIndexForFrame(int frame_number) { |
- int layer = -1; |
+ // Temporal layer index corresponding to frame number, for up to 3 layers. |
+ int TemporalLayerIndexForFrame(int frame_number) { |
+ int tl_idx = -1; |
switch (num_temporal_layers_) { |
case 1: |
- layer = 0; |
+ tl_idx = 0; |
break; |
case 2: |
- // layer 0: 0 2 4 ... |
- // layer 1: 1 3 |
- layer = (frame_number % 2 == 0) ? 0 : 1; |
+ // temporal layer 0: 0 2 4 ... |
+ // temporal layer 1: 1 3 |
+ tl_idx = (frame_number % 2 == 0) ? 0 : 1; |
break; |
case 3: |
- // layer 0: 0 4 8 ... |
- // layer 1: 2 6 |
- // layer 2: 1 3 5 7 |
+ // temporal layer 0: 0 4 8 ... |
+ // temporal layer 1: 2 6 |
+ // temporal layer 2: 1 3 5 7 |
if (frame_number % 4 == 0) { |
- layer = 0; |
+ tl_idx = 0; |
} else if ((frame_number + 2) % 4 == 0) { |
- layer = 1; |
+ tl_idx = 1; |
} else if ((frame_number + 1) % 2 == 0) { |
- layer = 2; |
+ tl_idx = 2; |
} |
break; |
default: |
RTC_NOTREACHED(); |
break; |
} |
- |
- return layer; |
+ return tl_idx; |
} |
- // Set the bitrate and frame rate per layer, for up to 3 layers. |
- void SetLayerRates() { |
+ // Set the bit rate and frame rate per temporal layer, for up to 3 layers. |
+ void SetTemporalLayerRates() { |
RTC_DCHECK_LE(num_temporal_layers_, kMaxNumTemporalLayers); |
for (int i = 0; i < num_temporal_layers_; i++) { |
float bit_rate_ratio = |
@@ -541,54 +552,83 @@ class VideoProcessorIntegrationTest : public testing::Test { |
packet_loss_probability_ = process.packet_loss_probability; |
num_temporal_layers_ = process.num_temporal_layers; |
SetUpCodecConfig(process, visualization_params); |
- // Update the layers and the codec with the initial rates. |
+ // 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]; |
- SetLayerRates(); |
+ SetTemporalLayerRates(); |
// 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 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. |
+ |
+ // 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)); |
} |
+ |
+ for (frame_number = 0; frame_number < num_frames; ++frame_number) { |
+ ++num_frames_per_update_[TemporalLayerIndexForFrame(frame_number)]; |
+ ++num_frames_total_; |
+ UpdateRateControlMetrics(frame_number); |
+ } |
+ } 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_[TemporalLayerIndexForFrame(frame_number)]; |
+ ++num_frames_total_; |
+ UpdateRateControlMetrics(frame_number); |
+ |
+ ++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]) { |
+ 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]; |
+ SetTemporalLayerRates(); |
+ ResetRateControlMetrics( |
+ rate_profile.frame_index_rate_update[update_index + 1]); |
+ processor_->SetRates(bit_rate_, frame_rate_); |
+ } |
+ } |
+ // 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]); |
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: |
+ // 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()); |
@@ -601,7 +641,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 +680,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 +696,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 +714,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 +799,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_; |