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:
LocalRendererEffectFilter(webrtc::ExternalRenderer * renderer,FrameDropDetector * frame_drop_detector)39 LocalRendererEffectFilter(webrtc::ExternalRenderer* renderer,
40 FrameDropDetector* frame_drop_detector)
41 : ExternalRendererEffectFilter(renderer),
42 frame_drop_detector_(frame_drop_detector) {}
Transform(int size,unsigned char * frame_buffer,int64_t ntp_time_ms,unsigned int timestamp,unsigned int width,unsigned int height)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:
FrameSentCallback(FrameDropDetector * frame_drop_detector)64 explicit FrameSentCallback(FrameDropDetector* frame_drop_detector)
65 : frame_drop_detector_(frame_drop_detector) {}
~FrameSentCallback()66 virtual ~FrameSentCallback() {}
FrameSent(unsigned int rtp_timestamp)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:
FrameReceivedCallback(FrameDropDetector * frame_drop_detector)82 explicit FrameReceivedCallback(FrameDropDetector* frame_drop_detector)
83 : frame_drop_detector_(frame_drop_detector) {}
~FrameReceivedCallback()84 virtual ~FrameReceivedCallback() {}
FrameReceived(unsigned int rtp_timestamp)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:
DecodedTimestampEffectFilter(FrameDropDetector * frame_drop_detector)100 explicit DecodedTimestampEffectFilter(FrameDropDetector* frame_drop_detector)
101 : frame_drop_detector_(frame_drop_detector) {}
~DecodedTimestampEffectFilter()102 virtual ~DecodedTimestampEffectFilter() {}
Transform(int size,unsigned char * frame_buffer,int64_t ntp_time_ms,unsigned int timestamp,unsigned int width,unsigned int height)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:
Statistics()122 Statistics() : sum_(0.0f), sum_squared_(0.0f), count_(0) {};
123
AddSample(float sample)124 void AddSample(float sample) {
125 sum_ += sample;
126 sum_squared_ += sample * sample;
127 ++count_;
128 }
129
Mean()130 float Mean() {
131 if (count_ == 0)
132 return -1.0f;
133 return sum_ / count_;
134 }
135
Variance()136 float Variance() {
137 if (count_ == 0)
138 return -1.0f;
139 return sum_squared_ / count_ - Mean() * Mean();
140 }
141
AsString()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
TestFullStack(const TbInterfaces & interfaces,int capture_id,int video_channel,int width,int height,int bit_rate_kbps,const NetworkParameters & network,FrameDropDetector * frame_drop_detector,ViEToFileRenderer * remote_file_renderer,ViEToFileRenderer * local_file_renderer)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
FixOutputFileForComparison(const std::string & output_file,int frame_length_in_bytes,const std::vector<Frame * > & frames)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
ReportFrameState(State state,unsigned int timestamp,int64_t report_time_us)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
CalculateResults()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
PrintReport(const std::string & test_label)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
PrintDebugDump()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
GetAllFrames()574 const std::vector<Frame*>& FrameDropDetector::GetAllFrames() {
575 assert(!dirty_);
576 return created_frames_vector_;
577 }
578
GetNumberOfFramesDroppedAt(State state)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
DeliverFrame(unsigned char * buffer,int buffer_size,uint32_t time_stamp,int64_t ntp_time_ms,int64_t render_time,void *)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
FrameSizeChange(unsigned int width,unsigned int height,unsigned int number_of_streams)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