• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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