Various updates to vp8.
Change-Id: Icc7a816491897107764e4c936288e9000e6319b8
diff --git a/test/error_resilience_test.cc b/test/error_resilience_test.cc
index 28cda2f..182547b 100644
--- a/test/error_resilience_test.cc
+++ b/test/error_resilience_test.cc
@@ -316,7 +316,205 @@
Reset();
}
-VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
-VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
+class ErrorResilienceTestLargeCodecControls : public ::libvpx_test::EncoderTest,
+ public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
+ protected:
+ ErrorResilienceTestLargeCodecControls()
+ : EncoderTest(GET_PARAM(0)),
+ encoding_mode_(GET_PARAM(1)) {
+ Reset();
+ }
+ virtual ~ErrorResilienceTestLargeCodecControls() {}
+
+ void Reset() {
+ last_pts_ = 0;
+ tot_frame_number_ = 0;
+ // For testing up to 3 layers.
+ for (int i = 0; i < 3; ++i) {
+ bits_total_[i] = 0;
+ }
+ duration_ = 0.0;
+ }
+
+ virtual void SetUp() {
+ InitializeConfig();
+ SetMode(encoding_mode_);
+ }
+
+ //
+ // Frame flags and layer id for temporal layers.
+ //
+
+ // For two layers, test pattern is:
+ // 1 3
+ // 0 2 .....
+ // For three layers, test pattern is:
+ // 1 3 5 7
+ // 2 6
+ // 0 4 ....
+ // LAST is always update on base/layer 0, GOLDEN is updated on layer 1,
+ // and ALTREF is updated on top layer for 3 layer pattern.
+ int SetFrameFlags(int frame_num, int num_temp_layers) {
+ int frame_flags = 0;
+ if (num_temp_layers == 2) {
+ if (frame_num % 2 == 0) {
+ // Layer 0: predict from L and ARF, update L.
+ frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
+ VP8_EFLAG_NO_UPD_ARF;
+ } else {
+ // Layer 1: predict from L, G and ARF, and update G.
+ frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_UPD_ENTROPY;
+ }
+ } else if (num_temp_layers == 3) {
+ if (frame_num % 4 == 0) {
+ // Layer 0: predict from L, update L.
+ frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
+ VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
+ } else if ((frame_num - 2) % 4 == 0) {
+ // Layer 1: predict from L, G, update G.
+ frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
+ VP8_EFLAG_NO_REF_ARF;
+ } else if ((frame_num - 1) % 2 == 0) {
+ // Layer 2: predict from L, G, ARF; update ARG.
+ frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
+ }
+ }
+ return frame_flags;
+ }
+
+ int SetLayerId(int frame_num, int num_temp_layers) {
+ int layer_id = 0;
+ if (num_temp_layers == 2) {
+ if (frame_num % 2 == 0) {
+ layer_id = 0;
+ } else {
+ layer_id = 1;
+ }
+ } else if (num_temp_layers == 3) {
+ if (frame_num % 4 == 0) {
+ layer_id = 0;
+ } else if ((frame_num - 2) % 4 == 0) {
+ layer_id = 1;
+ } else if ((frame_num - 1) % 2 == 0) {
+ layer_id = 2;
+ }
+ }
+ return layer_id;
+ }
+
+ virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
+ libvpx_test::Encoder *encoder) {
+ if (cfg_.ts_number_layers > 1) {
+ int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers);
+ int frame_flags = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
+ if (video->frame() > 0) {
+ encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
+ encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags);
+ }
+ const vpx_rational_t tb = video->timebase();
+ timebase_ = static_cast<double>(tb.num) / tb.den;
+ duration_ = 0;
+ return;
+ }
+ }
+
+ virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
+ // Time since last timestamp = duration.
+ vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
+ if (duration > 1) {
+ // Update counter for total number of frames (#frames input to encoder).
+ // Needed for setting the proper layer_id below.
+ tot_frame_number_ += static_cast<int>(duration - 1);
+ }
+ int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers);
+ const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
+ // Update the total encoded bits. For temporal layers, update the cumulative
+ // encoded bits per layer.
+ for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) {
+ bits_total_[i] += frame_size_in_bits;
+ }
+ // Update the most recent pts.
+ last_pts_ = pkt->data.frame.pts;
+ ++tot_frame_number_;
+ }
+
+ virtual void EndPassHook(void) {
+ duration_ = (last_pts_ + 1) * timebase_;
+ if (cfg_.ts_number_layers > 1) {
+ for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
+ ++layer) {
+ if (bits_total_[layer]) {
+ // Effective file datarate:
+ effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
+ }
+ }
+ }
+ }
+
+ double effective_datarate_[3];
+ private:
+ libvpx_test::TestMode encoding_mode_;
+ vpx_codec_pts_t last_pts_;
+ double timebase_;
+ int64_t bits_total_[3];
+ double duration_;
+ int tot_frame_number_;
+ };
+
+// Check two codec controls used for:
+// (1) for setting temporal layer id, and (2) for settings encoder flags.
+// This test invokes those controls for each frame, and verifies encoder/decoder
+// mismatch and basic rate control response.
+// TODO(marpan): Maybe move this test to datarate_test.cc.
+TEST_P(ErrorResilienceTestLargeCodecControls, CodecControl3TemporalLayers) {
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_dropframe_thresh = 1;
+ cfg_.rc_min_quantizer = 2;
+ cfg_.rc_max_quantizer = 56;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.rc_dropframe_thresh = 1;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.kf_mode = VPX_KF_DISABLED;
+ cfg_.g_error_resilient = 1;
+
+ // 3 Temporal layers. Framerate decimation (4, 2, 1).
+ cfg_.ts_number_layers = 3;
+ cfg_.ts_rate_decimator[0] = 4;
+ cfg_.ts_rate_decimator[1] = 2;
+ cfg_.ts_rate_decimator[2] = 1;
+ cfg_.ts_periodicity = 4;
+ cfg_.ts_layer_id[0] = 0;
+ cfg_.ts_layer_id[1] = 2;
+ cfg_.ts_layer_id[2] = 1;
+ cfg_.ts_layer_id[3] = 2;
+
+ ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+ 30, 1, 0, 200);
+ for (int i = 200; i <= 800; i += 200) {
+ cfg_.rc_target_bitrate = i;
+ Reset();
+ // 40-20-40 bitrate allocation for 3 temporal layers.
+ cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
+ cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
+ cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
+ ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75)
+ << " The datarate for the file is lower than target by too much, "
+ "for layer: " << j;
+ ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25)
+ << " The datarate for the file is greater than target by too much, "
+ "for layer: " << j;
+ }
+ }
+}
+
+VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
+VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLargeCodecControls,
+ ONE_PASS_TEST_MODES);
+VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
} // namespace