1 /* 2 * Copyright (c) 2012 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 <assert.h> 12 #include <math.h> 13 14 #include <sstream> 15 #include <string> 16 17 #include "webrtc/modules/video_capture/include/video_capture_factory.h" 18 #include "webrtc/system_wrappers/interface/tick_util.h" 19 #include "webrtc/test/testsupport/fileutils.h" 20 #include "webrtc/test/testsupport/frame_reader.h" 21 #include "webrtc/test/testsupport/frame_writer.h" 22 #include "webrtc/test/testsupport/perf_test.h" 23 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h" 24 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h" 25 #include "webrtc/video_engine/test/auto_test/primitives/framedrop_primitives.h" 26 #include "webrtc/video_engine/test/auto_test/primitives/general_primitives.h" 27 #include "webrtc/video_engine/test/libvietest/include/tb_external_transport.h" 28 #include "webrtc/video_engine/test/libvietest/include/tb_interfaces.h" 29 #include "webrtc/video_engine/test/libvietest/include/vie_external_render_filter.h" 30 #include "webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h" 31 32 enum { kWaitTimeForFinalDecodeMs = 100 }; 33 34 // Writes the frames to be encoded to file and tracks which frames are sent in 35 // external transport on the local side and reports them to the 36 // FrameDropDetector class. 37 class LocalRendererEffectFilter : public webrtc::ExternalRendererEffectFilter { 38 public: 39 LocalRendererEffectFilter(webrtc::ExternalRenderer* renderer, 40 FrameDropDetector* frame_drop_detector) 41 : ExternalRendererEffectFilter(renderer), 42 frame_drop_detector_(frame_drop_detector) {} 43 int Transform(int size, 44 unsigned char* frame_buffer, 45 int64_t ntp_time_ms, 46 unsigned int timestamp, 47 unsigned int width, 48 unsigned int height) { 49 frame_drop_detector_->ReportFrameState( 50 FrameDropDetector::kCreated, 51 timestamp, 52 webrtc::TickTime::MicrosecondTimestamp()); 53 return webrtc::ExternalRendererEffectFilter::Transform( 54 size, frame_buffer, ntp_time_ms, timestamp, width, height); 55 } 56 private: 57 FrameDropDetector* frame_drop_detector_; 58 }; 59 60 // Tracks which frames are sent in external transport on the local side 61 // and reports them to the FrameDropDetector class. 62 class FrameSentCallback : public SendFrameCallback { 63 public: 64 explicit FrameSentCallback(FrameDropDetector* frame_drop_detector) 65 : frame_drop_detector_(frame_drop_detector) {} 66 virtual ~FrameSentCallback() {} 67 virtual void FrameSent(unsigned int rtp_timestamp) { 68 frame_drop_detector_->ReportFrameState( 69 FrameDropDetector::kSent, 70 rtp_timestamp, 71 webrtc::TickTime::MicrosecondTimestamp()); 72 } 73 74 private: 75 FrameDropDetector* frame_drop_detector_; 76 }; 77 78 // Tracks which frames are received in external transport on the remote side 79 // and reports them to the FrameDropDetector class. 80 class FrameReceivedCallback : public ReceiveFrameCallback { 81 public: 82 explicit FrameReceivedCallback(FrameDropDetector* frame_drop_detector) 83 : frame_drop_detector_(frame_drop_detector) {} 84 virtual ~FrameReceivedCallback() {} 85 virtual void FrameReceived(unsigned int rtp_timestamp) { 86 frame_drop_detector_->ReportFrameState( 87 FrameDropDetector::kReceived, 88 rtp_timestamp, 89 webrtc::TickTime::MicrosecondTimestamp()); 90 } 91 92 private: 93 FrameDropDetector* frame_drop_detector_; 94 }; 95 96 // Tracks when frames are decoded on the remote side (received from the 97 // jitter buffer) and reports them to the FrameDropDetector class. 98 class DecodedTimestampEffectFilter : public webrtc::ViEEffectFilter { 99 public: 100 explicit DecodedTimestampEffectFilter(FrameDropDetector* frame_drop_detector) 101 : frame_drop_detector_(frame_drop_detector) {} 102 virtual ~DecodedTimestampEffectFilter() {} 103 virtual int Transform(int size, 104 unsigned char* frame_buffer, 105 int64_t ntp_time_ms, 106 unsigned int timestamp, 107 unsigned int width, 108 unsigned int height) { 109 frame_drop_detector_->ReportFrameState( 110 FrameDropDetector::kDecoded, 111 timestamp, 112 webrtc::TickTime::MicrosecondTimestamp()); 113 return 0; 114 } 115 116 private: 117 FrameDropDetector* frame_drop_detector_; 118 }; 119 120 class Statistics { 121 public: 122 Statistics() : sum_(0.0f), sum_squared_(0.0f), count_(0) {}; 123 124 void AddSample(float sample) { 125 sum_ += sample; 126 sum_squared_ += sample * sample; 127 ++count_; 128 } 129 130 float Mean() { 131 if (count_ == 0) 132 return -1.0f; 133 return sum_ / count_; 134 } 135 136 float Variance() { 137 if (count_ == 0) 138 return -1.0f; 139 return sum_squared_ / count_ - Mean() * Mean(); 140 } 141 142 std::string AsString() { 143 std::stringstream ss; 144 ss << (Mean() >= 0 ? Mean() : -1) << ", " << 145 (Variance() >= 0 ? sqrt(Variance()) : -1); 146 return ss.str(); 147 } 148 149 private: 150 float sum_; 151 float sum_squared_; 152 int count_; 153 }; 154 155 void TestFullStack(const TbInterfaces& interfaces, 156 int capture_id, 157 int video_channel, 158 int width, 159 int height, 160 int bit_rate_kbps, 161 const NetworkParameters& network, 162 FrameDropDetector* frame_drop_detector, 163 ViEToFileRenderer* remote_file_renderer, 164 ViEToFileRenderer* local_file_renderer) { 165 webrtc::VideoEngine *video_engine_interface = interfaces.video_engine; 166 webrtc::ViEBase *base_interface = interfaces.base; 167 webrtc::ViECapture *capture_interface = interfaces.capture; 168 webrtc::ViERender *render_interface = interfaces.render; 169 webrtc::ViECodec *codec_interface = interfaces.codec; 170 webrtc::ViENetwork *network_interface = interfaces.network; 171 172 // *************************************************************** 173 // Engine ready. Begin testing class 174 // *************************************************************** 175 webrtc::VideoCodec video_codec; 176 memset(&video_codec, 0, sizeof (webrtc::VideoCodec)); 177 178 // Set up all receive codecs. This basically setup the codec interface 179 // to be able to recognize all receive codecs based on payload type. 180 for (int idx = 0; idx < codec_interface->NumberOfCodecs(); idx++) { 181 EXPECT_EQ(0, codec_interface->GetCodec(idx, video_codec)); 182 SetSuitableResolution(&video_codec, width, height); 183 184 EXPECT_EQ(0, codec_interface->SetReceiveCodec(video_channel, video_codec)); 185 } 186 187 // Configure External transport to simulate network interference: 188 TbExternalTransport external_transport(*interfaces.network, video_channel, 189 NULL); 190 external_transport.SetNetworkParameters(network); 191 192 FrameSentCallback frame_sent_callback(frame_drop_detector); 193 FrameReceivedCallback frame_received_callback(frame_drop_detector); 194 external_transport.RegisterSendFrameCallback(&frame_sent_callback); 195 external_transport.RegisterReceiveFrameCallback(&frame_received_callback); 196 EXPECT_EQ(0, network_interface->RegisterSendTransport(video_channel, 197 external_transport)); 198 RenderToFile(interfaces.render, video_channel, remote_file_renderer); 199 EXPECT_EQ(0, base_interface->StartReceive(video_channel)); 200 201 // Setup only the VP8 codec, which is what we'll use. 202 webrtc::VideoCodec codec; 203 EXPECT_TRUE(FindSpecificCodec(webrtc::kVideoCodecVP8, codec_interface, 204 &codec)); 205 codec.startBitrate = bit_rate_kbps; 206 codec.maxBitrate = bit_rate_kbps; 207 codec.width = width; 208 codec.height = height; 209 EXPECT_EQ(0, codec_interface->SetSendCodec(video_channel, codec)); 210 211 webrtc::ViEImageProcess *image_process = 212 webrtc::ViEImageProcess::GetInterface(video_engine_interface); 213 EXPECT_TRUE(image_process); 214 215 // Setup the effect filters. 216 // Local rendering at the send-side is done in an effect filter to avoid 217 // synchronization issues with the remote renderer. 218 LocalRendererEffectFilter local_renderer_filter(local_file_renderer, 219 frame_drop_detector); 220 EXPECT_EQ(0, image_process->RegisterSendEffectFilter(video_channel, 221 local_renderer_filter)); 222 DecodedTimestampEffectFilter decode_filter(frame_drop_detector); 223 EXPECT_EQ(0, image_process->RegisterRenderEffectFilter(video_channel, 224 decode_filter)); 225 // Send video. 226 EXPECT_EQ(0, base_interface->StartSend(video_channel)); 227 AutoTestSleep(kAutoTestFullStackSleepTimeMs); 228 229 ViETest::Log("Done!"); 230 231 // *************************************************************** 232 // Testing finished. Tear down Video Engine 233 // *************************************************************** 234 EXPECT_EQ(0, capture_interface->DisconnectCaptureDevice(video_channel)); 235 236 const int one_way_delay_99_percentile = network.mean_one_way_delay + 237 3 * network.std_dev_one_way_delay; 238 239 // Wait for the last packet to arrive before we tear down the receiver. 240 AutoTestSleep(2 * one_way_delay_99_percentile); 241 EXPECT_EQ(0, base_interface->StopSend(video_channel)); 242 while (!external_transport.EmptyQueue()) { 243 AutoTestSleep(one_way_delay_99_percentile); 244 } 245 EXPECT_EQ(0, base_interface->StopReceive(video_channel)); 246 EXPECT_EQ(0, network_interface->DeregisterSendTransport(video_channel)); 247 // Wait for the last frame to be decoded and rendered. There is no guarantee 248 // this wait time will be long enough. Ideally we would wait for at least one 249 // "receive-side delay", which is what the video coding module calculates 250 // based on network statistics etc. We don't have access to that value here. 251 AutoTestSleep(kWaitTimeForFinalDecodeMs); 252 // Must stop the frame drop detectors in the right order to avoid getting 253 // frames which for instance are rendered but not decoded. 254 EXPECT_EQ(0, render_interface->StopRender(video_channel)); 255 EXPECT_EQ(0, render_interface->RemoveRenderer(video_channel)); 256 EXPECT_EQ(0, image_process->DeregisterRenderEffectFilter(video_channel)); 257 EXPECT_EQ(0, image_process->DeregisterSendEffectFilter(video_channel)); 258 image_process->Release(); 259 EXPECT_EQ(0, base_interface->DeleteChannel(video_channel)); 260 261 // Collect transport statistics. 262 int32_t num_rtp_packets = 0; 263 int32_t num_dropped_packets = 0; 264 int32_t num_rtcp_packets = 0; 265 std::map<uint8_t, int> packet_counters; 266 external_transport.GetStats(num_rtp_packets, num_dropped_packets, 267 num_rtcp_packets, &packet_counters); 268 ViETest::Log("RTP packets : %5d", num_rtp_packets); 269 ViETest::Log("Dropped packets: %5d", num_dropped_packets); 270 ViETest::Log("RTCP packets : %5d", num_rtcp_packets); 271 } 272 273 void FixOutputFileForComparison(const std::string& output_file, 274 int frame_length_in_bytes, 275 const std::vector<Frame*>& frames) { 276 webrtc::test::FrameReaderImpl frame_reader(output_file, 277 frame_length_in_bytes); 278 const std::string temp_file = output_file + ".fixed"; 279 webrtc::test::FrameWriterImpl frame_writer(temp_file, frame_length_in_bytes); 280 frame_reader.Init(); 281 frame_writer.Init(); 282 283 ASSERT_FALSE(frames.front()->dropped_at_render) << "It should not be " 284 "possible to drop the first frame. Both because we don't have anything " 285 "useful to fill that gap with and it is impossible to detect it without " 286 "any previous timestamps to compare with."; 287 288 uint8_t* last_frame_data = new uint8_t[frame_length_in_bytes]; 289 290 // Process the file and write frame duplicates for all dropped frames. 291 for (std::vector<Frame*>::const_iterator it = frames.begin(); 292 it != frames.end(); ++it) { 293 if ((*it)->dropped_at_render) { 294 // Write the previous frame to the output file: 295 EXPECT_TRUE(frame_writer.WriteFrame(last_frame_data)); 296 } else { 297 EXPECT_TRUE(frame_reader.ReadFrame(last_frame_data)); 298 EXPECT_TRUE(frame_writer.WriteFrame(last_frame_data)); 299 } 300 } 301 delete[] last_frame_data; 302 frame_reader.Close(); 303 frame_writer.Close(); 304 ASSERT_EQ(0, remove(output_file.c_str())); 305 ASSERT_EQ(0, rename(temp_file.c_str(), output_file.c_str())); 306 } 307 308 void FrameDropDetector::ReportFrameState(State state, unsigned int timestamp, 309 int64_t report_time_us) { 310 dirty_ = true; 311 switch (state) { 312 case kCreated: { 313 int number = created_frames_vector_.size(); 314 Frame* frame = new Frame(number, timestamp); 315 frame->created_timestamp_in_us_ = report_time_us; 316 created_frames_vector_.push_back(frame); 317 created_frames_[timestamp] = frame; 318 num_created_frames_++; 319 break; 320 } 321 case kSent: 322 sent_frames_[timestamp] = report_time_us; 323 if (timestamp_diff_ == 0) { 324 // When the first created frame arrives we calculate the fixed 325 // difference between the timestamps of the frames entering and leaving 326 // the encoder. This diff is used to identify the frames from the 327 // created_frames_ map. 328 timestamp_diff_ = 329 timestamp - created_frames_vector_.front()->frame_timestamp_; 330 } 331 num_sent_frames_++; 332 break; 333 case kReceived: 334 received_frames_[timestamp] = report_time_us; 335 num_received_frames_++; 336 break; 337 case kDecoded: 338 decoded_frames_[timestamp] = report_time_us; 339 num_decoded_frames_++; 340 break; 341 case kRendered: 342 rendered_frames_[timestamp] = report_time_us; 343 num_rendered_frames_++; 344 break; 345 } 346 } 347 348 void FrameDropDetector::CalculateResults() { 349 // Fill in all fields of the Frame objects in the created_frames_ map. 350 // Iterate over the maps from converted timestamps to the arrival timestamps. 351 std::map<unsigned int, int64_t>::const_iterator it; 352 for (it = sent_frames_.begin(); it != sent_frames_.end(); ++it) { 353 unsigned int created_timestamp = it->first - timestamp_diff_; 354 created_frames_[created_timestamp]->sent_timestamp_in_us_ = it->second; 355 } 356 for (it = received_frames_.begin(); it != received_frames_.end(); ++it) { 357 unsigned int created_timestamp = it->first - timestamp_diff_; 358 created_frames_[created_timestamp]->received_timestamp_in_us_ = it->second; 359 } 360 for (it = decoded_frames_.begin(); it != decoded_frames_.end(); ++it) { 361 unsigned int created_timestamp = it->first - timestamp_diff_; 362 created_frames_[created_timestamp]->decoded_timestamp_in_us_ =it->second; 363 } 364 for (it = rendered_frames_.begin(); it != rendered_frames_.end(); ++it) { 365 unsigned int created_timestamp = it->first - timestamp_diff_; 366 created_frames_[created_timestamp]->rendered_timestamp_in_us_ = it->second; 367 } 368 // Find out where the frames were not present in the different states. 369 dropped_frames_at_send_ = 0; 370 dropped_frames_at_receive_ = 0; 371 dropped_frames_at_decode_ = 0; 372 dropped_frames_at_render_ = 0; 373 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin(); 374 it != created_frames_vector_.end(); ++it) { 375 int encoded_timestamp = (*it)->frame_timestamp_ + timestamp_diff_; 376 if (sent_frames_.find(encoded_timestamp) == sent_frames_.end()) { 377 (*it)->dropped_at_send = true; 378 dropped_frames_at_send_++; 379 } 380 if (received_frames_.find(encoded_timestamp) == received_frames_.end()) { 381 (*it)->dropped_at_receive = true; 382 dropped_frames_at_receive_++; 383 } 384 if (decoded_frames_.find(encoded_timestamp) == decoded_frames_.end()) { 385 (*it)->dropped_at_decode = true; 386 dropped_frames_at_decode_++; 387 } 388 if (rendered_frames_.find(encoded_timestamp) == rendered_frames_.end()) { 389 (*it)->dropped_at_render = true; 390 dropped_frames_at_render_++; 391 } 392 } 393 dirty_ = false; 394 } 395 396 void FrameDropDetector::PrintReport(const std::string& test_label) { 397 assert(!dirty_); 398 ViETest::Log("Frame Drop Detector report:"); 399 ViETest::Log(" Created frames: %ld", created_frames_.size()); 400 ViETest::Log(" Sent frames: %ld", sent_frames_.size()); 401 ViETest::Log(" Received frames: %ld", received_frames_.size()); 402 ViETest::Log(" Decoded frames: %ld", decoded_frames_.size()); 403 ViETest::Log(" Rendered frames: %ld", rendered_frames_.size()); 404 405 // Display all frames and stats for them: 406 long last_created = 0; 407 long last_sent = 0; 408 long last_received = 0; 409 long last_decoded = 0; 410 long last_rendered = 0; 411 ViETest::Log("\nDeltas between sent frames and drop status:"); 412 ViETest::Log("Unit: Microseconds"); 413 ViETest::Log("Frame Created Sent Received Decoded Rendered " 414 "Dropped at Dropped at Dropped at Dropped at"); 415 ViETest::Log(" nbr delta delta delta delta delta " 416 " Send? Receive? Decode? Render?"); 417 Statistics rendering_stats; 418 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin(); 419 it != created_frames_vector_.end(); ++it) { 420 int created_delta = 421 static_cast<int>((*it)->created_timestamp_in_us_ - last_created); 422 int sent_delta = (*it)->dropped_at_send ? -1 : 423 static_cast<int>((*it)->sent_timestamp_in_us_ - last_sent); 424 int received_delta = (*it)->dropped_at_receive ? -1 : 425 static_cast<int>((*it)->received_timestamp_in_us_ - last_received); 426 int decoded_delta = (*it)->dropped_at_decode ? -1 : 427 static_cast<int>((*it)->decoded_timestamp_in_us_ - last_decoded); 428 int rendered_delta = (*it)->dropped_at_render ? -1 : 429 static_cast<int>((*it)->rendered_timestamp_in_us_ - last_rendered); 430 431 // Set values to -1 for the first frame: 432 if ((*it)->number_ == 0) { 433 created_delta = -1; 434 sent_delta = -1; 435 received_delta = -1; 436 decoded_delta = -1; 437 rendered_delta = -1; 438 } 439 ViETest::Log("%5d %8d %8d %8d %8d %8d %10s %10s %10s %10s", 440 (*it)->number_, 441 created_delta, 442 sent_delta, 443 received_delta, 444 decoded_delta, 445 rendered_delta, 446 (*it)->dropped_at_send ? "DROPPED" : " ", 447 (*it)->dropped_at_receive ? "DROPPED" : " ", 448 (*it)->dropped_at_decode ? "DROPPED" : " ", 449 (*it)->dropped_at_render ? "DROPPED" : " "); 450 last_created = (*it)->created_timestamp_in_us_; 451 if (!(*it)->dropped_at_send) { 452 last_sent = (*it)->sent_timestamp_in_us_; 453 } 454 if (!(*it)->dropped_at_receive) { 455 last_received = (*it)->received_timestamp_in_us_; 456 } 457 if (!(*it)->dropped_at_decode) { 458 last_decoded = (*it)->decoded_timestamp_in_us_; 459 } 460 if (!(*it)->dropped_at_render) { 461 last_rendered = (*it)->rendered_timestamp_in_us_; 462 rendering_stats.AddSample(rendered_delta / 1000.0f); 463 } 464 } 465 ViETest::Log("\nLatency between states (-1 means N/A because of drop):"); 466 ViETest::Log("Unit: Microseconds"); 467 ViETest::Log("Frame Created Sent Received Decoded Total " 468 " Total"); 469 ViETest::Log(" nbr ->Sent ->Received ->Decoded ->Rendered latency " 470 " latency"); 471 ViETest::Log(" (incl network)" 472 "(excl network)"); 473 Statistics latency_incl_network_stats; 474 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin(); 475 it != created_frames_vector_.end(); ++it) { 476 int created_to_sent = (*it)->dropped_at_send ? -1 : 477 static_cast<int>((*it)->sent_timestamp_in_us_ - 478 (*it)->created_timestamp_in_us_); 479 int sent_to_received = (*it)->dropped_at_receive ? -1 : 480 static_cast<int>((*it)->received_timestamp_in_us_ - 481 (*it)->sent_timestamp_in_us_); 482 int received_to_decoded = (*it)->dropped_at_decode ? -1 : 483 static_cast<int>((*it)->decoded_timestamp_in_us_ - 484 (*it)->received_timestamp_in_us_); 485 int decoded_to_render = (*it)->dropped_at_render ? -1 : 486 static_cast<int>((*it)->rendered_timestamp_in_us_ - 487 (*it)->decoded_timestamp_in_us_); 488 int total_latency_incl_network = (*it)->dropped_at_render ? -1 : 489 static_cast<int>((*it)->rendered_timestamp_in_us_ - 490 (*it)->created_timestamp_in_us_); 491 int total_latency_excl_network = (*it)->dropped_at_render ? -1 : 492 static_cast<int>((*it)->rendered_timestamp_in_us_ - 493 (*it)->created_timestamp_in_us_ - sent_to_received); 494 if (total_latency_incl_network >= 0) 495 latency_incl_network_stats.AddSample(total_latency_incl_network / 496 1000.0f); 497 ViETest::Log("%5d %9d %9d %9d %9d %12d %12d", 498 (*it)->number_, 499 created_to_sent, 500 sent_to_received, 501 received_to_decoded, 502 decoded_to_render, 503 total_latency_incl_network, 504 total_latency_excl_network); 505 } 506 507 // Plot all measurements in the same graph since they share the same value 508 // range. 509 webrtc::test::PrintResultMeanAndError( 510 "total_delay_incl_network", "", test_label, 511 latency_incl_network_stats.AsString(), "ms", false); 512 webrtc::test::PrintResultMeanAndError( 513 "time_between_rendered_frames", "", test_label, 514 rendering_stats.AsString(), "ms", false); 515 516 517 // Find and print the dropped frames. 518 ViETest::Log("\nTotal # dropped frames at:"); 519 ViETest::Log(" Send : %d", dropped_frames_at_send_); 520 ViETest::Log(" Receive: %d", dropped_frames_at_receive_); 521 ViETest::Log(" Decode : %d", dropped_frames_at_decode_); 522 ViETest::Log(" Render : %d", dropped_frames_at_render_); 523 } 524 525 void FrameDropDetector::PrintDebugDump() { 526 assert(!dirty_); 527 ViETest::Log("\nPrintDebugDump: Frame objects:"); 528 ViETest::Log("Frame FrTimeStamp Created Sent Received Decoded" 529 " Rendered "); 530 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin(); 531 it != created_frames_vector_.end(); ++it) { 532 ViETest::Log("%5d %11u %11lld %11lld %11lld %11lld %11lld", 533 (*it)->number_, 534 (*it)->frame_timestamp_, 535 (*it)->created_timestamp_in_us_, 536 (*it)->sent_timestamp_in_us_, 537 (*it)->received_timestamp_in_us_, 538 (*it)->decoded_timestamp_in_us_, 539 (*it)->rendered_timestamp_in_us_); 540 } 541 std::vector<int> mismatch_frame_num_list; 542 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin(); 543 it != created_frames_vector_.end(); ++it) { 544 if ((*it)->dropped_at_render != (*it)->dropped_at_decode) { 545 mismatch_frame_num_list.push_back((*it)->number_); 546 } 547 } 548 if (mismatch_frame_num_list.size() > 0) { 549 ViETest::Log("\nDecoded/Rendered mismatches:"); 550 ViETest::Log("Frame FrTimeStamp Created Sent Received " 551 "Decoded Rendered "); 552 for (std::vector<int>::const_iterator it = mismatch_frame_num_list.begin(); 553 it != mismatch_frame_num_list.end(); ++it) { 554 Frame* frame = created_frames_vector_[*it]; 555 ViETest::Log("%5d %11u %11lld %11lld %11lld %11lld %11lld", 556 frame->number_, 557 frame->frame_timestamp_, 558 frame->created_timestamp_in_us_, 559 frame->sent_timestamp_in_us_, 560 frame->received_timestamp_in_us_, 561 frame->decoded_timestamp_in_us_, 562 frame->rendered_timestamp_in_us_); 563 } 564 } 565 566 ViETest::Log("\nReportFrameState method invocations:"); 567 ViETest::Log(" Created : %d", num_created_frames_); 568 ViETest::Log(" Send : %d", num_sent_frames_); 569 ViETest::Log(" Received: %d", num_received_frames_); 570 ViETest::Log(" Decoded : %d", num_decoded_frames_); 571 ViETest::Log(" Rendered: %d", num_rendered_frames_); 572 } 573 574 const std::vector<Frame*>& FrameDropDetector::GetAllFrames() { 575 assert(!dirty_); 576 return created_frames_vector_; 577 } 578 579 int FrameDropDetector::GetNumberOfFramesDroppedAt(State state) { 580 assert(!dirty_); 581 switch (state) { 582 case kSent: 583 return dropped_frames_at_send_; 584 case kReceived: 585 return dropped_frames_at_receive_; 586 case kDecoded: 587 return dropped_frames_at_decode_; 588 case kRendered: 589 return dropped_frames_at_render_; 590 default: 591 return 0; 592 } 593 } 594 595 int FrameDropMonitoringRemoteFileRenderer::DeliverFrame( 596 unsigned char *buffer, int buffer_size, uint32_t time_stamp, 597 int64_t ntp_time_ms, int64_t render_time, void* /*handle*/) { 598 // |render_time| provides the ideal render time for this frame. If that time 599 // has already passed we will render it immediately. 600 int64_t report_render_time_us = render_time * 1000; 601 int64_t time_now_us = webrtc::TickTime::MicrosecondTimestamp(); 602 if (render_time < (time_now_us + 500) / 1000) { 603 report_render_time_us = time_now_us; 604 } 605 // Register that this frame has been rendered. 606 frame_drop_detector_->ReportFrameState(FrameDropDetector::kRendered, 607 time_stamp, report_render_time_us); 608 return ViEToFileRenderer::DeliverFrame(buffer, buffer_size, 609 time_stamp, ntp_time_ms, 610 render_time, NULL); 611 } 612 613 int FrameDropMonitoringRemoteFileRenderer::FrameSizeChange( 614 unsigned int width, unsigned int height, unsigned int number_of_streams) { 615 return ViEToFileRenderer::FrameSizeChange(width, height, number_of_streams); 616 } 617