| OLD | NEW |
| (Empty) | |
| 1 /* |
| 2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include "third_party/googletest/src/include/gtest/gtest.h" |
| 12 #include "test/codec_factory.h" |
| 13 #include "test/encode_test_driver.h" |
| 14 #include "test/i420_video_source.h" |
| 15 #include "test/util.h" |
| 16 |
| 17 namespace { |
| 18 |
| 19 const int kMaxErrorFrames = 12; |
| 20 const int kMaxDroppableFrames = 12; |
| 21 |
| 22 class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, |
| 23 public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> { |
| 24 protected: |
| 25 ErrorResilienceTestLarge() |
| 26 : EncoderTest(GET_PARAM(0)), |
| 27 psnr_(0.0), |
| 28 nframes_(0), |
| 29 mismatch_psnr_(0.0), |
| 30 mismatch_nframes_(0), |
| 31 encoding_mode_(GET_PARAM(1)) { |
| 32 Reset(); |
| 33 } |
| 34 |
| 35 virtual ~ErrorResilienceTestLarge() {} |
| 36 |
| 37 void Reset() { |
| 38 error_nframes_ = 0; |
| 39 droppable_nframes_ = 0; |
| 40 pattern_switch_ = 0; |
| 41 } |
| 42 |
| 43 virtual void SetUp() { |
| 44 InitializeConfig(); |
| 45 SetMode(encoding_mode_); |
| 46 } |
| 47 |
| 48 virtual void BeginPassHook(unsigned int /*pass*/) { |
| 49 psnr_ = 0.0; |
| 50 nframes_ = 0; |
| 51 mismatch_psnr_ = 0.0; |
| 52 mismatch_nframes_ = 0; |
| 53 } |
| 54 |
| 55 virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) { |
| 56 psnr_ += pkt->data.psnr.psnr[0]; |
| 57 nframes_++; |
| 58 } |
| 59 |
| 60 // |
| 61 // Frame flags and layer id for temporal layers. |
| 62 // For two layers, test pattern is: |
| 63 // 1 3 |
| 64 // 0 2 ..... |
| 65 // LAST is updated on base/layer 0, GOLDEN updated on layer 1. |
| 66 // Non-zero pattern_switch parameter means pattern will switch to |
| 67 // not using LAST for frame_num >= pattern_switch. |
| 68 int SetFrameFlags(int frame_num, |
| 69 int num_temp_layers, |
| 70 int pattern_switch) { |
| 71 int frame_flags = 0; |
| 72 if (num_temp_layers == 2) { |
| 73 if (frame_num % 2 == 0) { |
| 74 if (frame_num < pattern_switch || pattern_switch == 0) { |
| 75 // Layer 0: predict from LAST and ARF, update LAST. |
| 76 frame_flags = VP8_EFLAG_NO_REF_GF | |
| 77 VP8_EFLAG_NO_UPD_GF | |
| 78 VP8_EFLAG_NO_UPD_ARF; |
| 79 } else { |
| 80 // Layer 0: predict from GF and ARF, update GF. |
| 81 frame_flags = VP8_EFLAG_NO_REF_LAST | |
| 82 VP8_EFLAG_NO_UPD_LAST | |
| 83 VP8_EFLAG_NO_UPD_ARF; |
| 84 } |
| 85 } else { |
| 86 if (frame_num < pattern_switch || pattern_switch == 0) { |
| 87 // Layer 1: predict from L, GF, and ARF, update GF. |
| 88 frame_flags = VP8_EFLAG_NO_UPD_ARF | |
| 89 VP8_EFLAG_NO_UPD_LAST; |
| 90 } else { |
| 91 // Layer 1: predict from GF and ARF, update GF. |
| 92 frame_flags = VP8_EFLAG_NO_REF_LAST | |
| 93 VP8_EFLAG_NO_UPD_LAST | |
| 94 VP8_EFLAG_NO_UPD_ARF; |
| 95 } |
| 96 } |
| 97 } |
| 98 return frame_flags; |
| 99 } |
| 100 |
| 101 virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video, |
| 102 ::libvpx_test::Encoder *encoder) { |
| 103 frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST | |
| 104 VP8_EFLAG_NO_UPD_GF | |
| 105 VP8_EFLAG_NO_UPD_ARF); |
| 106 // For temporal layer case. |
| 107 if (cfg_.ts_number_layers > 1) { |
| 108 frame_flags_ = SetFrameFlags(video->frame(), |
| 109 cfg_.ts_number_layers, |
| 110 pattern_switch_); |
| 111 for (unsigned int i = 0; i < droppable_nframes_; ++i) { |
| 112 if (droppable_frames_[i] == video->frame()) { |
| 113 std::cout << "Encoding droppable frame: " |
| 114 << droppable_frames_[i] << "\n"; |
| 115 } |
| 116 } |
| 117 } else { |
| 118 if (droppable_nframes_ > 0 && |
| 119 (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) { |
| 120 for (unsigned int i = 0; i < droppable_nframes_; ++i) { |
| 121 if (droppable_frames_[i] == video->frame()) { |
| 122 std::cout << "Encoding droppable frame: " |
| 123 << droppable_frames_[i] << "\n"; |
| 124 frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST | |
| 125 VP8_EFLAG_NO_UPD_GF | |
| 126 VP8_EFLAG_NO_UPD_ARF); |
| 127 return; |
| 128 } |
| 129 } |
| 130 } |
| 131 } |
| 132 } |
| 133 |
| 134 double GetAveragePsnr() const { |
| 135 if (nframes_) |
| 136 return psnr_ / nframes_; |
| 137 return 0.0; |
| 138 } |
| 139 |
| 140 double GetAverageMismatchPsnr() const { |
| 141 if (mismatch_nframes_) |
| 142 return mismatch_psnr_ / mismatch_nframes_; |
| 143 return 0.0; |
| 144 } |
| 145 |
| 146 virtual bool DoDecode() const { |
| 147 if (error_nframes_ > 0 && |
| 148 (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) { |
| 149 for (unsigned int i = 0; i < error_nframes_; ++i) { |
| 150 if (error_frames_[i] == nframes_ - 1) { |
| 151 std::cout << " Skipping decoding frame: " |
| 152 << error_frames_[i] << "\n"; |
| 153 return 0; |
| 154 } |
| 155 } |
| 156 } |
| 157 return 1; |
| 158 } |
| 159 |
| 160 virtual void MismatchHook(const vpx_image_t *img1, |
| 161 const vpx_image_t *img2) { |
| 162 double mismatch_psnr = compute_psnr(img1, img2); |
| 163 mismatch_psnr_ += mismatch_psnr; |
| 164 ++mismatch_nframes_; |
| 165 // std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n"; |
| 166 } |
| 167 |
| 168 void SetErrorFrames(int num, unsigned int *list) { |
| 169 if (num > kMaxErrorFrames) |
| 170 num = kMaxErrorFrames; |
| 171 else if (num < 0) |
| 172 num = 0; |
| 173 error_nframes_ = num; |
| 174 for (unsigned int i = 0; i < error_nframes_; ++i) |
| 175 error_frames_[i] = list[i]; |
| 176 } |
| 177 |
| 178 void SetDroppableFrames(int num, unsigned int *list) { |
| 179 if (num > kMaxDroppableFrames) |
| 180 num = kMaxDroppableFrames; |
| 181 else if (num < 0) |
| 182 num = 0; |
| 183 droppable_nframes_ = num; |
| 184 for (unsigned int i = 0; i < droppable_nframes_; ++i) |
| 185 droppable_frames_[i] = list[i]; |
| 186 } |
| 187 |
| 188 unsigned int GetMismatchFrames() { |
| 189 return mismatch_nframes_; |
| 190 } |
| 191 |
| 192 void SetPatternSwitch(int frame_switch) { |
| 193 pattern_switch_ = frame_switch; |
| 194 } |
| 195 |
| 196 private: |
| 197 double psnr_; |
| 198 unsigned int nframes_; |
| 199 unsigned int error_nframes_; |
| 200 unsigned int droppable_nframes_; |
| 201 unsigned int pattern_switch_; |
| 202 double mismatch_psnr_; |
| 203 unsigned int mismatch_nframes_; |
| 204 unsigned int error_frames_[kMaxErrorFrames]; |
| 205 unsigned int droppable_frames_[kMaxDroppableFrames]; |
| 206 libvpx_test::TestMode encoding_mode_; |
| 207 }; |
| 208 |
| 209 TEST_P(ErrorResilienceTestLarge, OnVersusOff) { |
| 210 const vpx_rational timebase = { 33333333, 1000000000 }; |
| 211 cfg_.g_timebase = timebase; |
| 212 cfg_.rc_target_bitrate = 2000; |
| 213 cfg_.g_lag_in_frames = 10; |
| 214 |
| 215 init_flags_ = VPX_CODEC_USE_PSNR; |
| 216 |
| 217 libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, |
| 218 timebase.den, timebase.num, 0, 30); |
| 219 |
| 220 // Error resilient mode OFF. |
| 221 cfg_.g_error_resilient = 0; |
| 222 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); |
| 223 const double psnr_resilience_off = GetAveragePsnr(); |
| 224 EXPECT_GT(psnr_resilience_off, 25.0); |
| 225 |
| 226 // Error resilient mode ON. |
| 227 cfg_.g_error_resilient = 1; |
| 228 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); |
| 229 const double psnr_resilience_on = GetAveragePsnr(); |
| 230 EXPECT_GT(psnr_resilience_on, 25.0); |
| 231 |
| 232 // Test that turning on error resilient mode hurts by 10% at most. |
| 233 if (psnr_resilience_off > 0.0) { |
| 234 const double psnr_ratio = psnr_resilience_on / psnr_resilience_off; |
| 235 EXPECT_GE(psnr_ratio, 0.9); |
| 236 EXPECT_LE(psnr_ratio, 1.1); |
| 237 } |
| 238 } |
| 239 |
| 240 // Check for successful decoding and no encoder/decoder mismatch |
| 241 // if we lose (i.e., drop before decoding) a set of droppable |
| 242 // frames (i.e., frames that don't update any reference buffers). |
| 243 // Check both isolated and consecutive loss. |
| 244 TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) { |
| 245 const vpx_rational timebase = { 33333333, 1000000000 }; |
| 246 cfg_.g_timebase = timebase; |
| 247 cfg_.rc_target_bitrate = 500; |
| 248 // FIXME(debargha): Fix this to work for any lag. |
| 249 // Currently this test only works for lag = 0 |
| 250 cfg_.g_lag_in_frames = 0; |
| 251 |
| 252 init_flags_ = VPX_CODEC_USE_PSNR; |
| 253 |
| 254 libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, |
| 255 timebase.den, timebase.num, 0, 40); |
| 256 |
| 257 // Error resilient mode ON. |
| 258 cfg_.g_error_resilient = 1; |
| 259 cfg_.kf_mode = VPX_KF_DISABLED; |
| 260 |
| 261 // Set an arbitrary set of error frames same as droppable frames. |
| 262 // In addition to isolated loss/drop, add a long consecutive series |
| 263 // (of size 9) of dropped frames. |
| 264 unsigned int num_droppable_frames = 11; |
| 265 unsigned int droppable_frame_list[] = {5, 16, 22, 23, 24, 25, 26, 27, 28, |
| 266 29, 30}; |
| 267 SetDroppableFrames(num_droppable_frames, droppable_frame_list); |
| 268 SetErrorFrames(num_droppable_frames, droppable_frame_list); |
| 269 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); |
| 270 // Test that no mismatches have been found |
| 271 std::cout << " Mismatch frames: " |
| 272 << GetMismatchFrames() << "\n"; |
| 273 EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); |
| 274 |
| 275 // Reset previously set of error/droppable frames. |
| 276 Reset(); |
| 277 |
| 278 #if 0 |
| 279 // TODO(jkoleszar): This test is disabled for the time being as too |
| 280 // sensitive. It's not clear how to set a reasonable threshold for |
| 281 // this behavior. |
| 282 |
| 283 // Now set an arbitrary set of error frames that are non-droppable |
| 284 unsigned int num_error_frames = 3; |
| 285 unsigned int error_frame_list[] = {3, 10, 20}; |
| 286 SetErrorFrames(num_error_frames, error_frame_list); |
| 287 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); |
| 288 |
| 289 // Test that dropping an arbitrary set of inter frames does not hurt too much |
| 290 // Note the Average Mismatch PSNR is the average of the PSNR between |
| 291 // decoded frame and encoder's version of the same frame for all frames |
| 292 // with mismatch. |
| 293 const double psnr_resilience_mismatch = GetAverageMismatchPsnr(); |
| 294 std::cout << " Mismatch PSNR: " |
| 295 << psnr_resilience_mismatch << "\n"; |
| 296 EXPECT_GT(psnr_resilience_mismatch, 20.0); |
| 297 #endif |
| 298 } |
| 299 |
| 300 // Check for successful decoding and no encoder/decoder mismatch |
| 301 // if we lose (i.e., drop before decoding) the enhancement layer frames for a |
| 302 // two layer temporal pattern. The base layer does not predict from the top |
| 303 // layer, so successful decoding is expected. |
| 304 TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) { |
| 305 const vpx_rational timebase = { 33333333, 1000000000 }; |
| 306 cfg_.g_timebase = timebase; |
| 307 cfg_.rc_target_bitrate = 500; |
| 308 cfg_.g_lag_in_frames = 0; |
| 309 |
| 310 cfg_.rc_end_usage = VPX_CBR; |
| 311 // 2 Temporal layers, no spatial layers, CBR mode. |
| 312 cfg_.ss_number_layers = 1; |
| 313 cfg_.ts_number_layers = 2; |
| 314 cfg_.ts_rate_decimator[0] = 2; |
| 315 cfg_.ts_rate_decimator[1] = 1; |
| 316 cfg_.ts_periodicity = 2; |
| 317 cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; |
| 318 cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate; |
| 319 |
| 320 init_flags_ = VPX_CODEC_USE_PSNR; |
| 321 |
| 322 libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, |
| 323 timebase.den, timebase.num, 0, 40); |
| 324 |
| 325 // Error resilient mode ON. |
| 326 cfg_.g_error_resilient = 1; |
| 327 cfg_.kf_mode = VPX_KF_DISABLED; |
| 328 SetPatternSwitch(0); |
| 329 |
| 330 // The odd frames are the enhancement layer for 2 layer pattern, so set |
| 331 // those frames as droppable. Drop the last 7 frames. |
| 332 unsigned int num_droppable_frames = 7; |
| 333 unsigned int droppable_frame_list[] = {27, 29, 31, 33, 35, 37, 39}; |
| 334 SetDroppableFrames(num_droppable_frames, droppable_frame_list); |
| 335 SetErrorFrames(num_droppable_frames, droppable_frame_list); |
| 336 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); |
| 337 // Test that no mismatches have been found |
| 338 std::cout << " Mismatch frames: " |
| 339 << GetMismatchFrames() << "\n"; |
| 340 EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); |
| 341 |
| 342 // Reset previously set of error/droppable frames. |
| 343 Reset(); |
| 344 } |
| 345 |
| 346 // Check for successful decoding and no encoder/decoder mismatch |
| 347 // for a two layer temporal pattern, where at some point in the |
| 348 // sequence, the LAST ref is not used anymore. |
| 349 TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) { |
| 350 const vpx_rational timebase = { 33333333, 1000000000 }; |
| 351 cfg_.g_timebase = timebase; |
| 352 cfg_.rc_target_bitrate = 500; |
| 353 cfg_.g_lag_in_frames = 0; |
| 354 |
| 355 cfg_.rc_end_usage = VPX_CBR; |
| 356 // 2 Temporal layers, no spatial layers, CBR mode. |
| 357 cfg_.ss_number_layers = 1; |
| 358 cfg_.ts_number_layers = 2; |
| 359 cfg_.ts_rate_decimator[0] = 2; |
| 360 cfg_.ts_rate_decimator[1] = 1; |
| 361 cfg_.ts_periodicity = 2; |
| 362 cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; |
| 363 cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate; |
| 364 |
| 365 init_flags_ = VPX_CODEC_USE_PSNR; |
| 366 |
| 367 libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, |
| 368 timebase.den, timebase.num, 0, 100); |
| 369 |
| 370 // Error resilient mode ON. |
| 371 cfg_.g_error_resilient = 1; |
| 372 cfg_.kf_mode = VPX_KF_DISABLED; |
| 373 SetPatternSwitch(60); |
| 374 |
| 375 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); |
| 376 // Test that no mismatches have been found |
| 377 std::cout << " Mismatch frames: " |
| 378 << GetMismatchFrames() << "\n"; |
| 379 EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); |
| 380 |
| 381 // Reset previously set of error/droppable frames. |
| 382 Reset(); |
| 383 } |
| 384 |
| 385 class ErrorResilienceTestLargeCodecControls : public ::libvpx_test::EncoderTest, |
| 386 public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> { |
| 387 protected: |
| 388 ErrorResilienceTestLargeCodecControls() |
| 389 : EncoderTest(GET_PARAM(0)), |
| 390 encoding_mode_(GET_PARAM(1)) { |
| 391 Reset(); |
| 392 } |
| 393 |
| 394 virtual ~ErrorResilienceTestLargeCodecControls() {} |
| 395 |
| 396 void Reset() { |
| 397 last_pts_ = 0; |
| 398 tot_frame_number_ = 0; |
| 399 // For testing up to 3 layers. |
| 400 for (int i = 0; i < 3; ++i) { |
| 401 bits_total_[i] = 0; |
| 402 } |
| 403 duration_ = 0.0; |
| 404 } |
| 405 |
| 406 virtual void SetUp() { |
| 407 InitializeConfig(); |
| 408 SetMode(encoding_mode_); |
| 409 } |
| 410 |
| 411 // |
| 412 // Frame flags and layer id for temporal layers. |
| 413 // |
| 414 |
| 415 // For two layers, test pattern is: |
| 416 // 1 3 |
| 417 // 0 2 ..... |
| 418 // For three layers, test pattern is: |
| 419 // 1 3 5 7 |
| 420 // 2 6 |
| 421 // 0 4 .... |
| 422 // LAST is always update on base/layer 0, GOLDEN is updated on layer 1, |
| 423 // and ALTREF is updated on top layer for 3 layer pattern. |
| 424 int SetFrameFlags(int frame_num, int num_temp_layers) { |
| 425 int frame_flags = 0; |
| 426 if (num_temp_layers == 2) { |
| 427 if (frame_num % 2 == 0) { |
| 428 // Layer 0: predict from L and ARF, update L. |
| 429 frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | |
| 430 VP8_EFLAG_NO_UPD_ARF; |
| 431 } else { |
| 432 // Layer 1: predict from L, G and ARF, and update G. |
| 433 frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | |
| 434 VP8_EFLAG_NO_UPD_ENTROPY; |
| 435 } |
| 436 } else if (num_temp_layers == 3) { |
| 437 if (frame_num % 4 == 0) { |
| 438 // Layer 0: predict from L, update L. |
| 439 frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | |
| 440 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; |
| 441 } else if ((frame_num - 2) % 4 == 0) { |
| 442 // Layer 1: predict from L, G, update G. |
| 443 frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | |
| 444 VP8_EFLAG_NO_REF_ARF; |
| 445 } else if ((frame_num - 1) % 2 == 0) { |
| 446 // Layer 2: predict from L, G, ARF; update ARG. |
| 447 frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; |
| 448 } |
| 449 } |
| 450 return frame_flags; |
| 451 } |
| 452 |
| 453 int SetLayerId(int frame_num, int num_temp_layers) { |
| 454 int layer_id = 0; |
| 455 if (num_temp_layers == 2) { |
| 456 if (frame_num % 2 == 0) { |
| 457 layer_id = 0; |
| 458 } else { |
| 459 layer_id = 1; |
| 460 } |
| 461 } else if (num_temp_layers == 3) { |
| 462 if (frame_num % 4 == 0) { |
| 463 layer_id = 0; |
| 464 } else if ((frame_num - 2) % 4 == 0) { |
| 465 layer_id = 1; |
| 466 } else if ((frame_num - 1) % 2 == 0) { |
| 467 layer_id = 2; |
| 468 } |
| 469 } |
| 470 return layer_id; |
| 471 } |
| 472 |
| 473 virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video, |
| 474 libvpx_test::Encoder *encoder) { |
| 475 if (cfg_.ts_number_layers > 1) { |
| 476 int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers); |
| 477 int frame_flags = SetFrameFlags(video->frame(), cfg_.ts_number_layers); |
| 478 if (video->frame() > 0) { |
| 479 encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id); |
| 480 encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags); |
| 481 } |
| 482 const vpx_rational_t tb = video->timebase(); |
| 483 timebase_ = static_cast<double>(tb.num) / tb.den; |
| 484 duration_ = 0; |
| 485 return; |
| 486 } |
| 487 } |
| 488 |
| 489 virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { |
| 490 // Time since last timestamp = duration. |
| 491 vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; |
| 492 if (duration > 1) { |
| 493 // Update counter for total number of frames (#frames input to encoder). |
| 494 // Needed for setting the proper layer_id below. |
| 495 tot_frame_number_ += static_cast<int>(duration - 1); |
| 496 } |
| 497 int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers); |
| 498 const size_t frame_size_in_bits = pkt->data.frame.sz * 8; |
| 499 // Update the total encoded bits. For temporal layers, update the cumulative |
| 500 // encoded bits per layer. |
| 501 for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) { |
| 502 bits_total_[i] += frame_size_in_bits; |
| 503 } |
| 504 // Update the most recent pts. |
| 505 last_pts_ = pkt->data.frame.pts; |
| 506 ++tot_frame_number_; |
| 507 } |
| 508 |
| 509 virtual void EndPassHook(void) { |
| 510 duration_ = (last_pts_ + 1) * timebase_; |
| 511 if (cfg_.ts_number_layers > 1) { |
| 512 for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers); |
| 513 ++layer) { |
| 514 if (bits_total_[layer]) { |
| 515 // Effective file datarate: |
| 516 effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_
; |
| 517 } |
| 518 } |
| 519 } |
| 520 } |
| 521 |
| 522 double effective_datarate_[3]; |
| 523 private: |
| 524 libvpx_test::TestMode encoding_mode_; |
| 525 vpx_codec_pts_t last_pts_; |
| 526 double timebase_; |
| 527 int64_t bits_total_[3]; |
| 528 double duration_; |
| 529 int tot_frame_number_; |
| 530 }; |
| 531 |
| 532 // Check two codec controls used for: |
| 533 // (1) for setting temporal layer id, and (2) for settings encoder flags. |
| 534 // This test invokes those controls for each frame, and verifies encoder/decoder |
| 535 // mismatch and basic rate control response. |
| 536 // TODO(marpan): Maybe move this test to datarate_test.cc. |
| 537 TEST_P(ErrorResilienceTestLargeCodecControls, CodecControl3TemporalLayers) { |
| 538 cfg_.rc_buf_initial_sz = 500; |
| 539 cfg_.rc_buf_optimal_sz = 500; |
| 540 cfg_.rc_buf_sz = 1000; |
| 541 cfg_.rc_dropframe_thresh = 1; |
| 542 cfg_.rc_min_quantizer = 2; |
| 543 cfg_.rc_max_quantizer = 56; |
| 544 cfg_.rc_end_usage = VPX_CBR; |
| 545 cfg_.rc_dropframe_thresh = 1; |
| 546 cfg_.g_lag_in_frames = 0; |
| 547 cfg_.kf_mode = VPX_KF_DISABLED; |
| 548 cfg_.g_error_resilient = 1; |
| 549 |
| 550 // 3 Temporal layers. Framerate decimation (4, 2, 1). |
| 551 cfg_.ts_number_layers = 3; |
| 552 cfg_.ts_rate_decimator[0] = 4; |
| 553 cfg_.ts_rate_decimator[1] = 2; |
| 554 cfg_.ts_rate_decimator[2] = 1; |
| 555 cfg_.ts_periodicity = 4; |
| 556 cfg_.ts_layer_id[0] = 0; |
| 557 cfg_.ts_layer_id[1] = 2; |
| 558 cfg_.ts_layer_id[2] = 1; |
| 559 cfg_.ts_layer_id[3] = 2; |
| 560 |
| 561 ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, |
| 562 30, 1, 0, 200); |
| 563 for (int i = 200; i <= 800; i += 200) { |
| 564 cfg_.rc_target_bitrate = i; |
| 565 Reset(); |
| 566 // 40-20-40 bitrate allocation for 3 temporal layers. |
| 567 cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; |
| 568 cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; |
| 569 cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate; |
| 570 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); |
| 571 for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) { |
| 572 ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75) |
| 573 << " The datarate for the file is lower than target by too much, " |
| 574 "for layer: " << j; |
| 575 ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25) |
| 576 << " The datarate for the file is greater than target by too much, " |
| 577 "for layer: " << j; |
| 578 } |
| 579 } |
| 580 } |
| 581 |
| 582 VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES); |
| 583 VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLargeCodecControls, |
| 584 ONE_PASS_TEST_MODES); |
| 585 VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES); |
| 586 } // namespace |
| OLD | NEW |