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 <string> 12 #include "third_party/googletest/src/include/gtest/gtest.h" 13 #include "test/codec_factory.h" 14 #include "test/decode_test_driver.h" 15 #include "test/i420_video_source.h" 16 #include "vpx/svc_context.h" 17 #include "vpx/vp8cx.h" 18 #include "vpx/vpx_encoder.h" 19 20 namespace { 21 22 using libvpx_test::CodecFactory; 23 using libvpx_test::Decoder; 24 using libvpx_test::VP9CodecFactory; 25 26 class SvcTest : public ::testing::Test { 27 protected: 28 static const uint32_t kWidth = 352; 29 static const uint32_t kHeight = 288; 30 31 SvcTest() 32 : codec_iface_(0), 33 test_file_name_("hantro_collage_w352h288.yuv"), 34 stats_file_name_("hantro_collage_w352h288.stat"), 35 codec_initialized_(false), 36 decoder_(0) { 37 memset(&svc_, 0, sizeof(svc_)); 38 memset(&codec_, 0, sizeof(codec_)); 39 memset(&codec_enc_, 0, sizeof(codec_enc_)); 40 } 41 42 virtual ~SvcTest() {} 43 44 virtual void SetUp() { 45 svc_.encoding_mode = INTER_LAYER_PREDICTION_IP; 46 svc_.log_level = SVC_LOG_DEBUG; 47 svc_.log_print = 0; 48 49 codec_iface_ = vpx_codec_vp9_cx(); 50 const vpx_codec_err_t res = 51 vpx_codec_enc_config_default(codec_iface_, &codec_enc_, 0); 52 EXPECT_EQ(VPX_CODEC_OK, res); 53 54 codec_enc_.g_w = kWidth; 55 codec_enc_.g_h = kHeight; 56 codec_enc_.g_timebase.num = 1; 57 codec_enc_.g_timebase.den = 60; 58 codec_enc_.kf_min_dist = 100; 59 codec_enc_.kf_max_dist = 100; 60 61 vpx_codec_dec_cfg_t dec_cfg = {0}; 62 VP9CodecFactory codec_factory; 63 decoder_ = codec_factory.CreateDecoder(dec_cfg, 0); 64 } 65 66 virtual void TearDown() { 67 vpx_svc_release(&svc_); 68 delete(decoder_); 69 if (codec_initialized_) vpx_codec_destroy(&codec_); 70 } 71 72 SvcContext svc_; 73 vpx_codec_ctx_t codec_; 74 struct vpx_codec_enc_cfg codec_enc_; 75 vpx_codec_iface_t *codec_iface_; 76 std::string test_file_name_; 77 std::string stats_file_name_; 78 bool codec_initialized_; 79 Decoder *decoder_; 80 }; 81 82 TEST_F(SvcTest, SvcInit) { 83 // test missing parameters 84 vpx_codec_err_t res = vpx_svc_init(NULL, &codec_, codec_iface_, &codec_enc_); 85 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 86 res = vpx_svc_init(&svc_, NULL, codec_iface_, &codec_enc_); 87 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 88 res = vpx_svc_init(&svc_, &codec_, NULL, &codec_enc_); 89 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 90 91 res = vpx_svc_init(&svc_, &codec_, codec_iface_, NULL); 92 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 93 94 svc_.spatial_layers = 6; // too many layers 95 res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_); 96 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 97 98 svc_.spatial_layers = 0; // use default layers 99 res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_); 100 EXPECT_EQ(VPX_CODEC_OK, res); 101 codec_initialized_ = true; 102 EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers); 103 } 104 105 TEST_F(SvcTest, InitTwoLayers) { 106 svc_.spatial_layers = 2; 107 vpx_svc_set_scale_factors(&svc_, "4/16,16*16"); // invalid scale values 108 vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_); 109 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 110 111 vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); // valid scale values 112 res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_); 113 EXPECT_EQ(VPX_CODEC_OK, res); 114 codec_initialized_ = true; 115 } 116 117 TEST_F(SvcTest, InvalidOptions) { 118 vpx_codec_err_t res = vpx_svc_set_options(&svc_, NULL); 119 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 120 121 res = vpx_svc_set_options(&svc_, "not-an-option=1"); 122 EXPECT_EQ(VPX_CODEC_OK, res); 123 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 124 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 125 } 126 127 TEST_F(SvcTest, SetLayersOption) { 128 vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=3"); 129 EXPECT_EQ(VPX_CODEC_OK, res); 130 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 131 EXPECT_EQ(VPX_CODEC_OK, res); 132 codec_initialized_ = true; 133 EXPECT_EQ(3, svc_.spatial_layers); 134 } 135 136 TEST_F(SvcTest, SetEncodingMode) { 137 vpx_codec_err_t res = vpx_svc_set_options(&svc_, "encoding-mode=alt-ip"); 138 EXPECT_EQ(VPX_CODEC_OK, res); 139 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 140 EXPECT_EQ(VPX_CODEC_OK, res); 141 codec_initialized_ = true; 142 EXPECT_EQ(ALT_INTER_LAYER_PREDICTION_IP, svc_.encoding_mode); 143 } 144 145 TEST_F(SvcTest, SetMultipleOptions) { 146 vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=2 encoding-mode=ip"); 147 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 148 EXPECT_EQ(VPX_CODEC_OK, res); 149 codec_initialized_ = true; 150 EXPECT_EQ(2, svc_.spatial_layers); 151 EXPECT_EQ(INTER_LAYER_PREDICTION_IP, svc_.encoding_mode); 152 } 153 154 TEST_F(SvcTest, SetScaleFactorsOption) { 155 svc_.spatial_layers = 2; 156 vpx_codec_err_t res = 157 vpx_svc_set_options(&svc_, "scale-factors=not-scale-factors"); 158 EXPECT_EQ(VPX_CODEC_OK, res); 159 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 160 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 161 162 res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3"); 163 EXPECT_EQ(VPX_CODEC_OK, res); 164 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 165 EXPECT_EQ(VPX_CODEC_OK, res); 166 codec_initialized_ = true; 167 } 168 169 TEST_F(SvcTest, SetQuantizersOption) { 170 svc_.spatial_layers = 2; 171 vpx_codec_err_t res = vpx_svc_set_options(&svc_, "quantizers=not-quantizers"); 172 EXPECT_EQ(VPX_CODEC_OK, res); 173 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 174 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 175 176 vpx_svc_set_options(&svc_, "quantizers=40,45"); 177 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 178 EXPECT_EQ(VPX_CODEC_OK, res); 179 codec_initialized_ = true; 180 } 181 182 TEST_F(SvcTest, SetKeyFrameQuantizersOption) { 183 svc_.spatial_layers = 2; 184 vpx_codec_err_t res = vpx_svc_set_options(&svc_, 185 "quantizers-keyframe=not-quantizers"); 186 EXPECT_EQ(VPX_CODEC_OK, res); 187 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 188 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 189 190 vpx_svc_set_options(&svc_, "quantizers-keyframe=40,45"); 191 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 192 EXPECT_EQ(VPX_CODEC_OK, res); 193 codec_initialized_ = true; 194 } 195 196 TEST_F(SvcTest, SetQuantizers) { 197 vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30", 0); 198 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 199 200 res = vpx_svc_set_quantizers(&svc_, NULL, 0); 201 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 202 203 svc_.spatial_layers = 2; 204 res = vpx_svc_set_quantizers(&svc_, "40", 0); 205 EXPECT_EQ(VPX_CODEC_OK, res); 206 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 207 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 208 209 res = vpx_svc_set_quantizers(&svc_, "40,30", 0); 210 EXPECT_EQ(VPX_CODEC_OK, res); 211 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 212 EXPECT_EQ(VPX_CODEC_OK, res); 213 codec_initialized_ = true; 214 } 215 216 TEST_F(SvcTest, SetKeyFrameQuantizers) { 217 vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,31", 1); 218 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 219 220 res = vpx_svc_set_quantizers(&svc_, NULL, 1); 221 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 222 223 res = vpx_svc_set_quantizers(&svc_, "40,30", 1); 224 EXPECT_EQ(VPX_CODEC_OK, res); 225 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 226 EXPECT_EQ(VPX_CODEC_OK, res); 227 codec_initialized_ = true; 228 } 229 230 TEST_F(SvcTest, SetScaleFactors) { 231 vpx_codec_err_t res = vpx_svc_set_scale_factors(NULL, "4/16,16/16"); 232 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 233 234 res = vpx_svc_set_scale_factors(&svc_, NULL); 235 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 236 237 svc_.spatial_layers = 2; 238 res = vpx_svc_set_scale_factors(&svc_, "4/16"); 239 EXPECT_EQ(VPX_CODEC_OK, res); 240 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 241 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 242 243 res = vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); 244 EXPECT_EQ(VPX_CODEC_OK, res); 245 res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 246 EXPECT_EQ(VPX_CODEC_OK, res); 247 codec_initialized_ = true; 248 } 249 250 // Test that decoder can handle an SVC frame as the first frame in a sequence. 251 TEST_F(SvcTest, FirstFrameHasLayers) { 252 svc_.spatial_layers = 2; 253 vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); 254 vpx_svc_set_quantizers(&svc_, "40,30", 0); 255 256 vpx_codec_err_t res = 257 vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 258 EXPECT_EQ(VPX_CODEC_OK, res); 259 codec_initialized_ = true; 260 261 libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, 262 codec_enc_.g_timebase.den, 263 codec_enc_.g_timebase.num, 0, 30); 264 video.Begin(); 265 266 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 267 video.duration(), VPX_DL_GOOD_QUALITY); 268 EXPECT_EQ(VPX_CODEC_OK, res); 269 270 const vpx_codec_err_t res_dec = decoder_->DecodeFrame( 271 static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), 272 vpx_svc_get_frame_size(&svc_)); 273 274 // this test fails with a decoder error 275 ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); 276 } 277 278 TEST_F(SvcTest, EncodeThreeFrames) { 279 svc_.spatial_layers = 2; 280 vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); 281 vpx_svc_set_quantizers(&svc_, "40,30", 0); 282 283 vpx_codec_err_t res = 284 vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 285 ASSERT_EQ(VPX_CODEC_OK, res); 286 codec_initialized_ = true; 287 288 libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, 289 codec_enc_.g_timebase.den, 290 codec_enc_.g_timebase.num, 0, 30); 291 // FRAME 0 292 video.Begin(); 293 // This frame is a keyframe. 294 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 295 video.duration(), VPX_DL_GOOD_QUALITY); 296 ASSERT_EQ(VPX_CODEC_OK, res); 297 EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_)); 298 299 vpx_codec_err_t res_dec = decoder_->DecodeFrame( 300 static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), 301 vpx_svc_get_frame_size(&svc_)); 302 ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); 303 304 // FRAME 1 305 video.Next(); 306 // This is a P-frame. 307 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 308 video.duration(), VPX_DL_GOOD_QUALITY); 309 ASSERT_EQ(VPX_CODEC_OK, res); 310 EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_)); 311 312 res_dec = decoder_->DecodeFrame( 313 static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), 314 vpx_svc_get_frame_size(&svc_)); 315 ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); 316 317 // FRAME 2 318 video.Next(); 319 // This is a P-frame. 320 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 321 video.duration(), VPX_DL_GOOD_QUALITY); 322 ASSERT_EQ(VPX_CODEC_OK, res); 323 EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_)); 324 325 res_dec = decoder_->DecodeFrame( 326 static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), 327 vpx_svc_get_frame_size(&svc_)); 328 ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); 329 } 330 331 TEST_F(SvcTest, GetLayerResolution) { 332 svc_.spatial_layers = 2; 333 vpx_svc_set_scale_factors(&svc_, "4/16,8/16"); 334 vpx_svc_set_quantizers(&svc_, "40,30", 0); 335 336 vpx_codec_err_t res = 337 vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 338 EXPECT_EQ(VPX_CODEC_OK, res); 339 codec_initialized_ = true; 340 341 // ensure that requested layer is a valid layer 342 uint32_t layer_width, layer_height; 343 res = vpx_svc_get_layer_resolution(&svc_, svc_.spatial_layers, 344 &layer_width, &layer_height); 345 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 346 347 res = vpx_svc_get_layer_resolution(NULL, 0, &layer_width, &layer_height); 348 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 349 350 res = vpx_svc_get_layer_resolution(&svc_, 0, NULL, &layer_height); 351 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 352 353 res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, NULL); 354 EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 355 356 res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, &layer_height); 357 EXPECT_EQ(VPX_CODEC_OK, res); 358 EXPECT_EQ(kWidth * 4 / 16, layer_width); 359 EXPECT_EQ(kHeight * 4 / 16, layer_height); 360 361 res = vpx_svc_get_layer_resolution(&svc_, 1, &layer_width, &layer_height); 362 EXPECT_EQ(VPX_CODEC_OK, res); 363 EXPECT_EQ(kWidth * 8 / 16, layer_width); 364 EXPECT_EQ(kHeight * 8 / 16, layer_height); 365 } 366 367 TEST_F(SvcTest, FirstPassEncode) { 368 svc_.spatial_layers = 2; 369 codec_enc_.g_pass = VPX_RC_FIRST_PASS; 370 vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); 371 vpx_svc_set_quantizers(&svc_, "40,30", 0); 372 373 vpx_codec_err_t res = 374 vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 375 ASSERT_EQ(VPX_CODEC_OK, res); 376 codec_initialized_ = true; 377 378 libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, 379 codec_enc_.g_timebase.den, 380 codec_enc_.g_timebase.num, 0, 30); 381 // FRAME 0 382 video.Begin(); 383 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 384 video.duration(), VPX_DL_GOOD_QUALITY); 385 ASSERT_EQ(VPX_CODEC_OK, res); 386 EXPECT_GT(vpx_svc_get_rc_stats_buffer_size(&svc_), 0U); 387 388 // FRAME 1 389 video.Next(); 390 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 391 video.duration(), VPX_DL_GOOD_QUALITY); 392 ASSERT_EQ(VPX_CODEC_OK, res); 393 EXPECT_GT(vpx_svc_get_rc_stats_buffer_size(&svc_), 0U); 394 395 // Flush encoder and test EOS packet 396 res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(), 397 video.duration(), VPX_DL_GOOD_QUALITY); 398 ASSERT_EQ(VPX_CODEC_OK, res); 399 EXPECT_GT(vpx_svc_get_rc_stats_buffer_size(&svc_), 0U); 400 } 401 402 TEST_F(SvcTest, SecondPassEncode) { 403 svc_.spatial_layers = 2; 404 codec_enc_.g_pass = VPX_RC_LAST_PASS; 405 406 FILE *const stats_file = libvpx_test::OpenTestDataFile(stats_file_name_); 407 ASSERT_TRUE(stats_file != NULL) << "Stats file open failed. Filename: " 408 << stats_file; 409 410 struct vpx_fixed_buf stats_buf; 411 fseek(stats_file, 0, SEEK_END); 412 stats_buf.sz = static_cast<size_t>(ftell(stats_file)); 413 fseek(stats_file, 0, SEEK_SET); 414 415 stats_buf.buf = malloc(stats_buf.sz); 416 ASSERT_TRUE(stats_buf.buf != NULL); 417 const size_t bytes_read = fread(stats_buf.buf, 1, stats_buf.sz, stats_file); 418 ASSERT_EQ(bytes_read, stats_buf.sz); 419 fclose(stats_file); 420 codec_enc_.rc_twopass_stats_in = stats_buf; 421 422 vpx_codec_err_t res = 423 vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); 424 ASSERT_EQ(VPX_CODEC_OK, res); 425 codec_initialized_ = true; 426 427 libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, 428 codec_enc_.g_timebase.den, 429 codec_enc_.g_timebase.num, 0, 30); 430 // FRAME 0 431 video.Begin(); 432 // This frame is a keyframe. 433 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 434 video.duration(), VPX_DL_GOOD_QUALITY); 435 ASSERT_EQ(VPX_CODEC_OK, res); 436 EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_)); 437 438 vpx_codec_err_t res_dec = decoder_->DecodeFrame( 439 static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), 440 vpx_svc_get_frame_size(&svc_)); 441 ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); 442 443 // FRAME 1 444 video.Next(); 445 // This is a P-frame. 446 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 447 video.duration(), VPX_DL_GOOD_QUALITY); 448 ASSERT_EQ(VPX_CODEC_OK, res); 449 EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_)); 450 451 res_dec = decoder_->DecodeFrame( 452 static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), 453 vpx_svc_get_frame_size(&svc_)); 454 ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); 455 456 // FRAME 2 457 video.Next(); 458 // This is a P-frame. 459 res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), 460 video.duration(), VPX_DL_GOOD_QUALITY); 461 ASSERT_EQ(VPX_CODEC_OK, res); 462 EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_)); 463 464 res_dec = decoder_->DecodeFrame( 465 static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), 466 vpx_svc_get_frame_size(&svc_)); 467 ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); 468 469 free(stats_buf.buf); 470 } 471 472 } // namespace 473