1 /* 2 * Copyright (c) 2013 The WebRTC 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 <vector> 12 13 #include "testing/gtest/include/gtest/gtest.h" 14 #include "webrtc/common.h" 15 #include "webrtc/modules/video_coding/codecs/interface/mock/mock_video_codec_interface.h" 16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" 17 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" 18 #include "webrtc/modules/video_coding/main/interface/mock/mock_vcm_callbacks.h" 19 #include "webrtc/modules/video_coding/main/interface/video_coding.h" 20 #include "webrtc/modules/video_coding/main/source/video_coding_impl.h" 21 #include "webrtc/modules/video_coding/main/test/test_util.h" 22 #include "webrtc/system_wrappers/interface/clock.h" 23 #include "webrtc/system_wrappers/interface/scoped_ptr.h" 24 #include "webrtc/test/frame_generator.h" 25 #include "webrtc/test/testsupport/fileutils.h" 26 #include "webrtc/test/testsupport/gtest_disable.h" 27 28 using ::testing::_; 29 using ::testing::AllOf; 30 using ::testing::ElementsAre; 31 using ::testing::ElementsAreArray; 32 using ::testing::Field; 33 using ::testing::NiceMock; 34 using ::testing::Pointee; 35 using ::testing::Return; 36 using ::testing::FloatEq; 37 using std::vector; 38 using webrtc::test::FrameGenerator; 39 40 namespace webrtc { 41 namespace vcm { 42 namespace { 43 enum { 44 kMaxNumberOfTemporalLayers = 3 45 }; 46 47 struct Vp8StreamInfo { 48 float framerate_fps[kMaxNumberOfTemporalLayers]; 49 int bitrate_kbps[kMaxNumberOfTemporalLayers]; 50 }; 51 52 MATCHER_P(MatchesVp8StreamInfo, expected, "") { 53 bool res = true; 54 for (int tl = 0; tl < kMaxNumberOfTemporalLayers; ++tl) { 55 if (fabs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) { 56 *result_listener << " framerate_fps[" << tl 57 << "] = " << arg.framerate_fps[tl] << " (expected " 58 << expected.framerate_fps[tl] << ") "; 59 res = false; 60 } 61 if (abs(expected.bitrate_kbps[tl] - arg.bitrate_kbps[tl]) > 10) { 62 *result_listener << " bitrate_kbps[" << tl 63 << "] = " << arg.bitrate_kbps[tl] << " (expected " 64 << expected.bitrate_kbps[tl] << ") "; 65 res = false; 66 } 67 } 68 return res; 69 } 70 71 class EmptyFrameGenerator : public FrameGenerator { 72 public: 73 virtual I420VideoFrame* NextFrame() OVERRIDE { 74 frame_.ResetSize(); 75 return &frame_; 76 } 77 78 private: 79 I420VideoFrame frame_; 80 }; 81 82 class PacketizationCallback : public VCMPacketizationCallback { 83 public: 84 PacketizationCallback(Clock* clock) 85 : clock_(clock), start_time_ms_(clock_->TimeInMilliseconds()) {} 86 87 virtual ~PacketizationCallback() {} 88 89 virtual int32_t SendData(FrameType frame_type, 90 uint8_t payload_type, 91 uint32_t timestamp, 92 int64_t capture_time_ms, 93 const uint8_t* payload_data, 94 uint32_t payload_size, 95 const RTPFragmentationHeader& fragmentation_header, 96 const RTPVideoHeader* rtp_video_header) OVERRIDE { 97 assert(rtp_video_header); 98 frame_data_.push_back(FrameData(payload_size, *rtp_video_header)); 99 return 0; 100 } 101 102 void Reset() { 103 frame_data_.clear(); 104 start_time_ms_ = clock_->TimeInMilliseconds(); 105 } 106 107 float FramerateFpsWithinTemporalLayer(int temporal_layer) { 108 return CountFramesWithinTemporalLayer(temporal_layer) * 109 (1000.0 / interval_ms()); 110 } 111 112 float BitrateKbpsWithinTemporalLayer(int temporal_layer) { 113 return SumPayloadBytesWithinTemporalLayer(temporal_layer) * 8.0 / 114 interval_ms(); 115 } 116 117 Vp8StreamInfo CalculateVp8StreamInfo() { 118 Vp8StreamInfo info; 119 for (int tl = 0; tl < 3; ++tl) { 120 info.framerate_fps[tl] = FramerateFpsWithinTemporalLayer(tl); 121 info.bitrate_kbps[tl] = BitrateKbpsWithinTemporalLayer(tl); 122 } 123 return info; 124 } 125 126 private: 127 struct FrameData { 128 FrameData() {} 129 130 FrameData(uint32_t payload_size, const RTPVideoHeader& rtp_video_header) 131 : payload_size(payload_size), rtp_video_header(rtp_video_header) {} 132 133 uint32_t payload_size; 134 RTPVideoHeader rtp_video_header; 135 }; 136 137 int64_t interval_ms() { 138 int64_t diff = (clock_->TimeInMilliseconds() - start_time_ms_); 139 EXPECT_GT(diff, 0); 140 return diff; 141 } 142 143 int CountFramesWithinTemporalLayer(int temporal_layer) { 144 int frames = 0; 145 for (size_t i = 0; i < frame_data_.size(); ++i) { 146 EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec); 147 const uint8_t temporal_idx = 148 frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx; 149 if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx) 150 frames++; 151 } 152 return frames; 153 } 154 155 int SumPayloadBytesWithinTemporalLayer(int temporal_layer) { 156 int payload_size = 0; 157 for (size_t i = 0; i < frame_data_.size(); ++i) { 158 EXPECT_EQ(kRtpVideoVp8, frame_data_[i].rtp_video_header.codec); 159 const uint8_t temporal_idx = 160 frame_data_[i].rtp_video_header.codecHeader.VP8.temporalIdx; 161 if (temporal_idx <= temporal_layer || temporal_idx == kNoTemporalIdx) 162 payload_size += frame_data_[i].payload_size; 163 } 164 return payload_size; 165 } 166 167 Clock* clock_; 168 int64_t start_time_ms_; 169 vector<FrameData> frame_data_; 170 }; 171 172 class TestVideoSender : public ::testing::Test { 173 protected: 174 // Note: simulated clock starts at 1 seconds, since parts of webrtc use 0 as 175 // a special case (e.g. frame rate in media optimization). 176 TestVideoSender() : clock_(1000), packetization_callback_(&clock_) {} 177 178 virtual void SetUp() OVERRIDE { 179 sender_.reset(new VideoSender(&clock_, &post_encode_callback_)); 180 EXPECT_EQ(0, sender_->InitializeSender()); 181 EXPECT_EQ(0, sender_->RegisterTransportCallback(&packetization_callback_)); 182 } 183 184 void AddFrame() { 185 assert(generator_.get()); 186 sender_->AddVideoFrame(*generator_->NextFrame(), NULL, NULL); 187 } 188 189 SimulatedClock clock_; 190 PacketizationCallback packetization_callback_; 191 MockEncodedImageCallback post_encode_callback_; 192 scoped_ptr<VideoSender> sender_; 193 scoped_ptr<FrameGenerator> generator_; 194 }; 195 196 class TestVideoSenderWithMockEncoder : public TestVideoSender { 197 protected: 198 static const int kDefaultWidth = 1280; 199 static const int kDefaultHeight = 720; 200 static const int kNumberOfStreams = 3; 201 static const int kNumberOfLayers = 3; 202 static const int kUnusedPayloadType = 10; 203 204 virtual void SetUp() OVERRIDE { 205 TestVideoSender::SetUp(); 206 generator_.reset(new EmptyFrameGenerator()); 207 EXPECT_EQ( 208 0, 209 sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, false)); 210 memset(&settings_, 0, sizeof(settings_)); 211 EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &settings_)); 212 settings_.numberOfSimulcastStreams = kNumberOfStreams; 213 ConfigureStream(kDefaultWidth / 4, 214 kDefaultHeight / 4, 215 100, 216 &settings_.simulcastStream[0]); 217 ConfigureStream(kDefaultWidth / 2, 218 kDefaultHeight / 2, 219 500, 220 &settings_.simulcastStream[1]); 221 ConfigureStream( 222 kDefaultWidth, kDefaultHeight, 1200, &settings_.simulcastStream[2]); 223 settings_.plType = kUnusedPayloadType; // Use the mocked encoder. 224 EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200)); 225 } 226 227 virtual void TearDown() OVERRIDE { sender_.reset(); } 228 229 void ExpectIntraRequest(int stream) { 230 if (stream == -1) { 231 // No intra request expected. 232 EXPECT_CALL( 233 encoder_, 234 Encode(_, 235 _, 236 Pointee(ElementsAre(kDeltaFrame, kDeltaFrame, kDeltaFrame)))) 237 .Times(1).WillRepeatedly(Return(0)); 238 return; 239 } 240 assert(stream >= 0); 241 assert(stream < kNumberOfStreams); 242 std::vector<VideoFrameType> frame_types(kNumberOfStreams, kDeltaFrame); 243 frame_types[stream] = kKeyFrame; 244 EXPECT_CALL( 245 encoder_, 246 Encode(_, 247 _, 248 Pointee(ElementsAreArray(&frame_types[0], frame_types.size())))) 249 .Times(1).WillRepeatedly(Return(0)); 250 } 251 252 static void ConfigureStream(int width, 253 int height, 254 int max_bitrate, 255 SimulcastStream* stream) { 256 assert(stream); 257 stream->width = width; 258 stream->height = height; 259 stream->maxBitrate = max_bitrate; 260 stream->numberOfTemporalLayers = kNumberOfLayers; 261 stream->qpMax = 45; 262 } 263 264 VideoCodec settings_; 265 NiceMock<MockVideoEncoder> encoder_; 266 }; 267 268 TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequests) { 269 EXPECT_EQ(0, sender_->IntraFrameRequest(0)); 270 ExpectIntraRequest(0); 271 AddFrame(); 272 ExpectIntraRequest(-1); 273 AddFrame(); 274 275 EXPECT_EQ(0, sender_->IntraFrameRequest(1)); 276 ExpectIntraRequest(1); 277 AddFrame(); 278 ExpectIntraRequest(-1); 279 AddFrame(); 280 281 EXPECT_EQ(0, sender_->IntraFrameRequest(2)); 282 ExpectIntraRequest(2); 283 AddFrame(); 284 ExpectIntraRequest(-1); 285 AddFrame(); 286 287 EXPECT_EQ(-1, sender_->IntraFrameRequest(3)); 288 ExpectIntraRequest(-1); 289 AddFrame(); 290 291 EXPECT_EQ(-1, sender_->IntraFrameRequest(-1)); 292 ExpectIntraRequest(-1); 293 AddFrame(); 294 } 295 296 TEST_F(TestVideoSenderWithMockEncoder, TestIntraRequestsInternalCapture) { 297 // De-register current external encoder. 298 EXPECT_EQ(0, 299 sender_->RegisterExternalEncoder(NULL, kUnusedPayloadType, false)); 300 // Register encoder with internal capture. 301 EXPECT_EQ( 302 0, sender_->RegisterExternalEncoder(&encoder_, kUnusedPayloadType, true)); 303 EXPECT_EQ(0, sender_->RegisterSendCodec(&settings_, 1, 1200)); 304 ExpectIntraRequest(0); 305 EXPECT_EQ(0, sender_->IntraFrameRequest(0)); 306 ExpectIntraRequest(1); 307 EXPECT_EQ(0, sender_->IntraFrameRequest(1)); 308 ExpectIntraRequest(2); 309 EXPECT_EQ(0, sender_->IntraFrameRequest(2)); 310 // No requests expected since these indices are out of bounds. 311 EXPECT_EQ(-1, sender_->IntraFrameRequest(3)); 312 EXPECT_EQ(-1, sender_->IntraFrameRequest(-1)); 313 } 314 315 class TestVideoSenderWithVp8 : public TestVideoSender { 316 public: 317 TestVideoSenderWithVp8() 318 : codec_bitrate_kbps_(300), available_bitrate_kbps_(1000) {} 319 320 virtual void SetUp() OVERRIDE { 321 TestVideoSender::SetUp(); 322 323 const char* input_video = "foreman_cif"; 324 const int width = 352; 325 const int height = 288; 326 generator_.reset(FrameGenerator::CreateFromYuvFile( 327 test::ResourcePath(input_video, "yuv").c_str(), width, height)); 328 329 codec_ = MakeVp8VideoCodec(width, height, 3); 330 codec_.minBitrate = 10; 331 codec_.startBitrate = codec_bitrate_kbps_; 332 codec_.maxBitrate = codec_bitrate_kbps_; 333 EXPECT_EQ(0, sender_->RegisterSendCodec(&codec_, 1, 1200)); 334 } 335 336 static VideoCodec MakeVp8VideoCodec(int width, 337 int height, 338 int temporal_layers) { 339 VideoCodec codec; 340 memset(&codec, 0, sizeof(codec)); 341 EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &codec)); 342 codec.width = width; 343 codec.height = height; 344 codec.codecSpecific.VP8.numberOfTemporalLayers = temporal_layers; 345 return codec; 346 } 347 348 void InsertFrames(float framerate, float seconds) { 349 for (int i = 0; i < seconds * framerate; ++i) { 350 clock_.AdvanceTimeMilliseconds(1000.0f / framerate); 351 EXPECT_CALL(post_encode_callback_, Encoded(_, NULL, NULL)) 352 .WillOnce(Return(0)); 353 AddFrame(); 354 355 // SetChannelParameters needs to be called frequently to propagate 356 // framerate from the media optimization into the encoder. 357 // Note: SetChannelParameters fails if less than 2 frames are in the 358 // buffer since it will fail to calculate the framerate. 359 if (i != 0) { 360 EXPECT_EQ(VCM_OK, 361 sender_->SetChannelParameters( 362 available_bitrate_kbps_ * 1000, 0, 200)); 363 } 364 } 365 } 366 367 Vp8StreamInfo SimulateWithFramerate(float framerate) { 368 const float short_simulation_interval = 5.0; 369 const float long_simulation_interval = 10.0; 370 // It appears that this 5 seconds simulation is needed to allow 371 // bitrate and framerate to stabilize. 372 InsertFrames(framerate, short_simulation_interval); 373 packetization_callback_.Reset(); 374 375 InsertFrames(framerate, long_simulation_interval); 376 return packetization_callback_.CalculateVp8StreamInfo(); 377 } 378 379 protected: 380 VideoCodec codec_; 381 int codec_bitrate_kbps_; 382 int available_bitrate_kbps_; 383 }; 384 385 TEST_F(TestVideoSenderWithVp8, 386 DISABLED_ON_ANDROID(FixedTemporalLayersStrategy)) { 387 const int low_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0]; 388 const int mid_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1]; 389 const int high_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2]; 390 { 391 Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}}; 392 EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected)); 393 } 394 { 395 Vp8StreamInfo expected = {{3.75, 7.5, 15.0}, {low_b, mid_b, high_b}}; 396 EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected)); 397 } 398 } 399 400 TEST_F(TestVideoSenderWithVp8, 401 DISABLED_ON_ANDROID(RealTimeTemporalLayersStrategy)) { 402 Config extra_options; 403 extra_options.Set<TemporalLayers::Factory>( 404 new RealTimeTemporalLayersFactory()); 405 VideoCodec codec = MakeVp8VideoCodec(352, 288, 3); 406 codec.extra_options = &extra_options; 407 codec.minBitrate = 10; 408 codec.startBitrate = codec_bitrate_kbps_; 409 codec.maxBitrate = codec_bitrate_kbps_; 410 EXPECT_EQ(0, sender_->RegisterSendCodec(&codec, 1, 1200)); 411 412 const int low_b = codec_bitrate_kbps_ * 0.4; 413 const int mid_b = codec_bitrate_kbps_ * 0.6; 414 const int high_b = codec_bitrate_kbps_; 415 416 { 417 Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}}; 418 EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected)); 419 } 420 { 421 Vp8StreamInfo expected = {{5.0, 10.0, 20.0}, {low_b, mid_b, high_b}}; 422 EXPECT_THAT(SimulateWithFramerate(20.0), MatchesVp8StreamInfo(expected)); 423 } 424 { 425 Vp8StreamInfo expected = {{7.5, 15.0, 15.0}, {mid_b, high_b, high_b}}; 426 EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected)); 427 } 428 { 429 Vp8StreamInfo expected = {{5.0, 10.0, 10.0}, {mid_b, high_b, high_b}}; 430 EXPECT_THAT(SimulateWithFramerate(10.0), MatchesVp8StreamInfo(expected)); 431 } 432 { 433 // TODO(andresp): Find out why this fails with framerate = 7.5 434 Vp8StreamInfo expected = {{7.0, 7.0, 7.0}, {high_b, high_b, high_b}}; 435 EXPECT_THAT(SimulateWithFramerate(7.0), MatchesVp8StreamInfo(expected)); 436 } 437 } 438 } // namespace 439 } // namespace vcm 440 } // namespace webrtc 441