blob: 6d63532979c08bef393e52ec264880292b525c0e [file] [log] [blame]
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +00001/*
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 <cassert>
12#include <string>
13
andrew@webrtc.org5f6856f2012-10-30 21:58:00 +000014#include "webrtc/modules/video_capture/include/video_capture_factory.h"
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +000015#include "system_wrappers/interface/tick_util.h"
16#include "testsupport/fileutils.h"
17#include "testsupport/frame_reader.h"
18#include "testsupport/frame_writer.h"
19#include "video_engine/test/auto_test/interface/vie_autotest.h"
20#include "video_engine/test/auto_test/interface/vie_autotest_defines.h"
21#include "video_engine/test/auto_test/primitives/framedrop_primitives.h"
22#include "video_engine/test/auto_test/primitives/general_primitives.h"
23#include "video_engine/test/libvietest/include/tb_interfaces.h"
24#include "video_engine/test/libvietest/include/tb_external_transport.h"
25#include "video_engine/test/libvietest/include/vie_to_file_renderer.h"
26
27// Tracks which frames are created on the local side and reports them to the
28// FrameDropDetector class.
29class CreatedTimestampEffectFilter : public webrtc::ViEEffectFilter {
30 public:
31 explicit CreatedTimestampEffectFilter(FrameDropDetector* frame_drop_detector)
32 : frame_drop_detector_(frame_drop_detector) {}
33 virtual ~CreatedTimestampEffectFilter() {}
34 virtual int Transform(int size, unsigned char* frameBuffer,
35 unsigned int timeStamp90KHz, unsigned int width,
36 unsigned int height) {
37 frame_drop_detector_->ReportFrameState(FrameDropDetector::kCreated,
38 timeStamp90KHz);
39 return 0;
40 }
41
42 private:
43 FrameDropDetector* frame_drop_detector_;
44};
45
46// Tracks which frames are sent in external transport on the local side
47// and reports them to the FrameDropDetector class.
48class FrameSentCallback : public SendFrameCallback {
49 public:
50 explicit FrameSentCallback(FrameDropDetector* frame_drop_detector)
51 : frame_drop_detector_(frame_drop_detector) {}
52 virtual ~FrameSentCallback() {}
53 virtual void FrameSent(unsigned int rtp_timestamp) {
54 frame_drop_detector_->ReportFrameState(FrameDropDetector::kSent,
55 rtp_timestamp);
56 }
57
58 private:
59 FrameDropDetector* frame_drop_detector_;
60};
61
62// Tracks which frames are received in external transport on the remote side
63// and reports them to the FrameDropDetector class.
64class FrameReceivedCallback : public ReceiveFrameCallback {
65 public:
66 explicit FrameReceivedCallback(FrameDropDetector* frame_drop_detector)
67 : frame_drop_detector_(frame_drop_detector) {}
68 virtual ~FrameReceivedCallback() {}
69 virtual void FrameReceived(unsigned int rtp_timestamp) {
70 frame_drop_detector_->ReportFrameState(FrameDropDetector::kReceived,
71 rtp_timestamp);
72 }
73
74 private:
75 FrameDropDetector* frame_drop_detector_;
76};
77
78// Tracks when frames are decoded on the remote side (received from the
79// jitter buffer) and reports them to the FrameDropDetector class.
80class DecodedTimestampEffectFilter : public webrtc::ViEEffectFilter {
81 public:
82 explicit DecodedTimestampEffectFilter(FrameDropDetector* frame_drop_detector)
83 : frame_drop_detector_(frame_drop_detector) {}
84 virtual ~DecodedTimestampEffectFilter() {}
85 virtual int Transform(int size, unsigned char* frameBuffer,
86 unsigned int timeStamp90KHz, unsigned int width,
87 unsigned int height) {
88 frame_drop_detector_->ReportFrameState(FrameDropDetector::kDecoded,
89 timeStamp90KHz);
90 return 0;
91 }
92
93 private:
94 FrameDropDetector* frame_drop_detector_;
95};
96
97void TestFullStack(const TbInterfaces& interfaces,
98 int capture_id,
99 int video_channel,
100 int width,
101 int height,
102 int bit_rate_kbps,
103 int packet_loss_percent,
104 int network_delay_ms,
105 FrameDropDetector* frame_drop_detector) {
106 webrtc::VideoEngine *video_engine_interface = interfaces.video_engine;
107 webrtc::ViEBase *base_interface = interfaces.base;
108 webrtc::ViECapture *capture_interface = interfaces.capture;
109 webrtc::ViERender *render_interface = interfaces.render;
110 webrtc::ViECodec *codec_interface = interfaces.codec;
111 webrtc::ViENetwork *network_interface = interfaces.network;
112
113 // ***************************************************************
114 // Engine ready. Begin testing class
115 // ***************************************************************
116 webrtc::VideoCodec video_codec;
117 memset(&video_codec, 0, sizeof (webrtc::VideoCodec));
118
119 // Set up all receive codecs. This basically setup the codec interface
120 // to be able to recognize all receive codecs based on payload type.
121 for (int idx = 0; idx < codec_interface->NumberOfCodecs(); idx++) {
122 EXPECT_EQ(0, codec_interface->GetCodec(idx, video_codec));
123 SetSuitableResolution(&video_codec, width, height);
124
125 EXPECT_EQ(0, codec_interface->SetReceiveCodec(video_channel, video_codec));
126 }
127
128 // Configure External transport to simulate network interference:
129 TbExternalTransport external_transport(*interfaces.network, video_channel,
130 NULL);
131 external_transport.SetPacketLoss(packet_loss_percent);
132 external_transport.SetNetworkDelay(network_delay_ms);
133
134 FrameSentCallback frame_sent_callback(frame_drop_detector);
135 FrameReceivedCallback frame_received_callback(frame_drop_detector);
136 external_transport.RegisterSendFrameCallback(&frame_sent_callback);
137 external_transport.RegisterReceiveFrameCallback(&frame_received_callback);
138 EXPECT_EQ(0, network_interface->RegisterSendTransport(video_channel,
139 external_transport));
140 EXPECT_EQ(0, base_interface->StartReceive(video_channel));
141
142 // Setup only the VP8 codec, which is what we'll use.
143 webrtc::VideoCodec codec;
144 EXPECT_TRUE(FindSpecificCodec(webrtc::kVideoCodecVP8, codec_interface,
145 &codec));
146 codec.startBitrate = bit_rate_kbps;
147 codec.maxBitrate = bit_rate_kbps;
148 codec.width = width;
149 codec.height = height;
150 EXPECT_EQ(0, codec_interface->SetSendCodec(video_channel, codec));
151
152 webrtc::ViEImageProcess *image_process =
153 webrtc::ViEImageProcess::GetInterface(video_engine_interface);
154 EXPECT_TRUE(image_process);
155
156 // Setup the effect filters
157 CreatedTimestampEffectFilter create_filter(frame_drop_detector);
158 EXPECT_EQ(0, image_process->RegisterSendEffectFilter(video_channel,
159 create_filter));
160 DecodedTimestampEffectFilter decode_filter(frame_drop_detector);
161 EXPECT_EQ(0, image_process->RegisterRenderEffectFilter(video_channel,
162 decode_filter));
163 // Send video.
164 EXPECT_EQ(0, base_interface->StartSend(video_channel));
165 AutoTestSleep(KAutoTestSleepTimeMs);
166
167 // Cleanup.
168 EXPECT_EQ(0, image_process->DeregisterSendEffectFilter(video_channel));
169 EXPECT_EQ(0, image_process->DeregisterRenderEffectFilter(video_channel));
170 image_process->Release();
171 ViETest::Log("Done!");
172
173 WebRtc_Word32 num_rtp_packets = 0;
174 WebRtc_Word32 num_dropped_packets = 0;
175 WebRtc_Word32 num_rtcp_packets = 0;
176 external_transport.GetStats(num_rtp_packets, num_dropped_packets,
177 num_rtcp_packets);
178 ViETest::Log("RTP packets : %5d", num_rtp_packets);
179 ViETest::Log("Dropped packets: %5d", num_dropped_packets);
180 ViETest::Log("RTCP packets : %5d", num_rtcp_packets);
181
182 // ***************************************************************
183 // Testing finished. Tear down Video Engine
184 // ***************************************************************
185 EXPECT_EQ(0, base_interface->StopSend(video_channel));
186 EXPECT_EQ(0, base_interface->StopReceive(video_channel));
187 EXPECT_EQ(0, network_interface->DeregisterSendTransport(video_channel));
188 EXPECT_EQ(0, render_interface->StopRender(capture_id));
189 EXPECT_EQ(0, render_interface->StopRender(video_channel));
190 EXPECT_EQ(0, render_interface->RemoveRenderer(capture_id));
191 EXPECT_EQ(0, render_interface->RemoveRenderer(video_channel));
192 EXPECT_EQ(0, capture_interface->DisconnectCaptureDevice(video_channel));
193 EXPECT_EQ(0, base_interface->DeleteChannel(video_channel));
194}
195
196void FixOutputFileForComparison(const std::string& output_file,
197 int frame_length_in_bytes,
198 const std::vector<Frame*>& frames) {
199 webrtc::test::FrameReaderImpl frame_reader(output_file,
200 frame_length_in_bytes);
201 const std::string temp_file = output_file + ".fixed";
202 webrtc::test::FrameWriterImpl frame_writer(temp_file, frame_length_in_bytes);
203 frame_reader.Init();
204 frame_writer.Init();
205
206 ASSERT_FALSE(frames.front()->dropped_at_render) << "It should not be "
207 "possible to drop the first frame. Both because we don't have anything "
208 "useful to fill that gap with and it is impossible to detect it without "
209 "any previous timestamps to compare with.";
210
211 WebRtc_UWord8* last_frame_data = new WebRtc_UWord8[frame_length_in_bytes];
212
213 // Process the file and write frame duplicates for all dropped frames.
214 for (std::vector<Frame*>::const_iterator it = frames.begin();
215 it != frames.end(); ++it) {
216 if ((*it)->dropped_at_render) {
217 // Write the previous frame to the output file:
218 EXPECT_TRUE(frame_writer.WriteFrame(last_frame_data));
219 } else {
220 EXPECT_TRUE(frame_reader.ReadFrame(last_frame_data));
221 EXPECT_TRUE(frame_writer.WriteFrame(last_frame_data));
222 }
223 }
224 delete[] last_frame_data;
225 frame_reader.Close();
226 frame_writer.Close();
227 ASSERT_EQ(0, std::remove(output_file.c_str()));
228 ASSERT_EQ(0, std::rename(temp_file.c_str(), output_file.c_str()));
229}
230
231void FrameDropDetector::ReportFrameState(State state, unsigned int timestamp) {
232 dirty_ = true;
233 switch (state) {
234 case kCreated: {
235 int number = created_frames_vector_.size();
236 Frame* frame = new Frame(number, timestamp);
237 frame->created_timestamp_in_us_ =
238 webrtc::TickTime::MicrosecondTimestamp();
239 created_frames_vector_.push_back(frame);
240 created_frames_[timestamp] = frame;
241 num_created_frames_++;
242 break;
243 }
244 case kSent:
245 sent_frames_[timestamp] = webrtc::TickTime::MicrosecondTimestamp();
246 if (timestamp_diff_ == 0) {
247 // When the first created frame arrives we calculate the fixed
248 // difference between the timestamps of the frames entering and leaving
249 // the encoder. This diff is used to identify the frames from the
250 // created_frames_ map.
251 timestamp_diff_ =
252 timestamp - created_frames_vector_.front()->frame_timestamp_;
253 }
254 num_sent_frames_++;
255 break;
256 case kReceived:
257 received_frames_[timestamp] = webrtc::TickTime::MicrosecondTimestamp();
258 num_received_frames_++;
259 break;
260 case kDecoded:
261 decoded_frames_[timestamp] = webrtc::TickTime::MicrosecondTimestamp();
262 num_decoded_frames_++;
263 break;
264 case kRendered:
265 rendered_frames_[timestamp] = webrtc::TickTime::MicrosecondTimestamp();
266 num_rendered_frames_++;
267 break;
268 }
269}
270
271void FrameDropDetector::CalculateResults() {
272 // Fill in all fields of the Frame objects in the created_frames_ map.
273 // Iterate over the maps from converted timestamps to the arrival timestamps.
274 std::map<unsigned int, int64_t>::const_iterator it;
275 for (it = sent_frames_.begin(); it != sent_frames_.end(); ++it) {
276 int created_timestamp = it->first - timestamp_diff_;
277 created_frames_[created_timestamp]->sent_timestamp_in_us_ = it->second;
278 }
279 for (it = received_frames_.begin(); it != received_frames_.end(); ++it) {
280 int created_timestamp = it->first - timestamp_diff_;
281 created_frames_[created_timestamp]->received_timestamp_in_us_ = it->second;
282 }
283 for (it = decoded_frames_.begin(); it != decoded_frames_.end(); ++it) {
284 int created_timestamp = it->first - timestamp_diff_;
285 created_frames_[created_timestamp]->decoded_timestamp_in_us_ =it->second;
286 }
287 for (it = rendered_frames_.begin(); it != rendered_frames_.end(); ++it) {
288 int created_timestamp = it->first - timestamp_diff_;
289 created_frames_[created_timestamp]->rendered_timestamp_in_us_ = it->second;
290 }
291 // Find out where the frames were not present in the different states.
292 dropped_frames_at_send_ = 0;
293 dropped_frames_at_receive_ = 0;
294 dropped_frames_at_decode_ = 0;
295 dropped_frames_at_render_ = 0;
296 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin();
297 it != created_frames_vector_.end(); ++it) {
298 int encoded_timestamp = (*it)->frame_timestamp_ + timestamp_diff_;
299 if (sent_frames_.find(encoded_timestamp) == sent_frames_.end()) {
300 (*it)->dropped_at_send = true;
301 dropped_frames_at_send_++;
302 }
303 if (received_frames_.find(encoded_timestamp) == received_frames_.end()) {
304 (*it)->dropped_at_receive = true;
305 dropped_frames_at_receive_++;
306 }
307 if (decoded_frames_.find(encoded_timestamp) == decoded_frames_.end()) {
308 (*it)->dropped_at_decode = true;
309 dropped_frames_at_decode_++;
310 }
311 if (rendered_frames_.find(encoded_timestamp) == rendered_frames_.end()) {
312 (*it)->dropped_at_render = true;
313 dropped_frames_at_render_++;
314 }
315 }
316 dirty_ = false;
317}
318
319void FrameDropDetector::PrintReport() {
320 assert(!dirty_);
321 ViETest::Log("Frame Drop Detector report:");
322 ViETest::Log(" Created frames: %ld", created_frames_.size());
323 ViETest::Log(" Sent frames: %ld", sent_frames_.size());
324 ViETest::Log(" Received frames: %ld", received_frames_.size());
325 ViETest::Log(" Decoded frames: %ld", decoded_frames_.size());
326 ViETest::Log(" Rendered frames: %ld", rendered_frames_.size());
327
328 // Display all frames and stats for them:
329 long last_created = 0;
330 long last_sent = 0;
331 long last_received = 0;
332 long last_decoded = 0;
333 long last_rendered = 0;
334 ViETest::Log("\nDeltas between sent frames and drop status:");
335 ViETest::Log("Unit: Microseconds");
336 ViETest::Log("Frame Created Sent Received Decoded Rendered "
337 "Dropped at Dropped at Dropped at Dropped at");
338 ViETest::Log(" nbr delta delta delta delta delta "
339 " Send? Receive? Decode? Render?");
340 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin();
341 it != created_frames_vector_.end(); ++it) {
342 int created_delta =
343 static_cast<int>((*it)->created_timestamp_in_us_ - last_created);
344 int sent_delta = (*it)->dropped_at_send ? -1 :
345 static_cast<int>((*it)->sent_timestamp_in_us_ - last_sent);
346 int received_delta = (*it)->dropped_at_receive ? -1 :
347 static_cast<int>((*it)->received_timestamp_in_us_ - last_received);
348 int decoded_delta = (*it)->dropped_at_decode ? -1 :
349 static_cast<int>((*it)->decoded_timestamp_in_us_ - last_decoded);
350 int rendered_delta = (*it)->dropped_at_render ? -1 :
351 static_cast<int>((*it)->rendered_timestamp_in_us_ - last_rendered);
352
353 // Set values to -1 for the first frame:
354 if ((*it)->number_ == 0) {
355 created_delta = -1;
356 sent_delta = -1;
357 received_delta = -1;
358 decoded_delta = -1;
359 rendered_delta = -1;
360 }
361 ViETest::Log("%5d %8d %8d %8d %8d %8d %10s %10s %10s %10s",
362 (*it)->number_,
363 created_delta,
364 sent_delta,
365 received_delta,
366 decoded_delta,
367 rendered_delta,
368 (*it)->dropped_at_send ? "DROPPED" : " ",
369 (*it)->dropped_at_receive ? "DROPPED" : " ",
370 (*it)->dropped_at_decode ? "DROPPED" : " ",
371 (*it)->dropped_at_render ? "DROPPED" : " ");
372 last_created = (*it)->created_timestamp_in_us_;
373 if (!(*it)->dropped_at_send) {
374 last_sent = (*it)->sent_timestamp_in_us_;
375 }
376 if (!(*it)->dropped_at_receive) {
377 last_received = (*it)->received_timestamp_in_us_;
378 }
379 if (!(*it)->dropped_at_decode) {
380 last_decoded = (*it)->decoded_timestamp_in_us_;
381 }
382 if (!(*it)->dropped_at_render) {
383 last_rendered = (*it)->rendered_timestamp_in_us_;
384 }
385 }
386 ViETest::Log("\nLatency between states (-1 means N/A because of drop):");
387 ViETest::Log("Unit: Microseconds");
388 ViETest::Log("Frame Created Sent Received Decoded Total "
389 " Total");
390 ViETest::Log(" nbr ->Sent ->Received ->Decoded ->Rendered latency "
391 " latency");
392 ViETest::Log(" (incl network)"
393 "(excl network)");
394 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin();
395 it != created_frames_vector_.end(); ++it) {
396 int created_to_sent = (*it)->dropped_at_send ? -1 :
397 static_cast<int>((*it)->sent_timestamp_in_us_ -
398 (*it)->created_timestamp_in_us_);
399 int sent_to_received = (*it)->dropped_at_receive ? -1 :
400 static_cast<int>((*it)->received_timestamp_in_us_ -
401 (*it)->sent_timestamp_in_us_);
402 int received_to_decoded = (*it)->dropped_at_decode ? -1 :
403 static_cast<int>((*it)->decoded_timestamp_in_us_ -
404 (*it)->received_timestamp_in_us_);
405 int decoded_to_render = (*it)->dropped_at_render ? -1 :
406 static_cast<int>((*it)->rendered_timestamp_in_us_ -
407 (*it)->decoded_timestamp_in_us_);
408 int total_latency_incl_network = (*it)->dropped_at_render ? -1 :
409 static_cast<int>((*it)->rendered_timestamp_in_us_ -
410 (*it)->created_timestamp_in_us_);
411 int total_latency_excl_network = (*it)->dropped_at_render ? -1 :
412 static_cast<int>((*it)->rendered_timestamp_in_us_ -
413 (*it)->created_timestamp_in_us_ - sent_to_received);
414 ViETest::Log("%5d %9d %9d %9d %9d %12d %12d",
415 (*it)->number_,
416 created_to_sent,
417 sent_to_received,
418 received_to_decoded,
419 decoded_to_render,
420 total_latency_incl_network,
421 total_latency_excl_network);
422 }
423 // Find and print the dropped frames.
424 ViETest::Log("\nTotal # dropped frames at:");
425 ViETest::Log(" Send : %d", dropped_frames_at_send_);
426 ViETest::Log(" Receive: %d", dropped_frames_at_receive_);
427 ViETest::Log(" Decode : %d", dropped_frames_at_decode_);
428 ViETest::Log(" Render : %d", dropped_frames_at_render_);
429}
430
431void FrameDropDetector::PrintDebugDump() {
432 assert(!dirty_);
433 ViETest::Log("\nPrintDebugDump: Frame objects:");
434 ViETest::Log("Frame FrTimeStamp Created Sent Received Decoded"
435 " Rendered ");
436 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin();
437 it != created_frames_vector_.end(); ++it) {
438 ViETest::Log("%5d %11d %11d %11d %11d %11d %11d",
439 (*it)->number_,
440 (*it)->frame_timestamp_,
441 (*it)->created_timestamp_in_us_,
442 (*it)->sent_timestamp_in_us_,
443 (*it)->received_timestamp_in_us_,
444 (*it)->decoded_timestamp_in_us_,
445 (*it)->rendered_timestamp_in_us_);
446 }
447 std::vector<int> mismatch_frame_num_list;
448 for (std::vector<Frame*>::const_iterator it = created_frames_vector_.begin();
449 it != created_frames_vector_.end(); ++it) {
450 if ((*it)->dropped_at_render != (*it)->dropped_at_decode) {
451 mismatch_frame_num_list.push_back((*it)->number_);
452 }
453 }
454 if (mismatch_frame_num_list.size() > 0) {
455 ViETest::Log("\nDecoded/Rendered mismatches:");
456 ViETest::Log("Frame FrTimeStamp Created Sent Received "
457 "Decoded Rendered ");
458 for (std::vector<int>::const_iterator it = mismatch_frame_num_list.begin();
459 it != mismatch_frame_num_list.end(); ++it) {
460 Frame* frame = created_frames_vector_[*it];
461 ViETest::Log("%5d %11d %11d %11d %11d %11d %11d",
462 frame->number_,
463 frame->frame_timestamp_,
464 frame->created_timestamp_in_us_,
465 frame->sent_timestamp_in_us_,
466 frame->received_timestamp_in_us_,
467 frame->decoded_timestamp_in_us_,
468 frame->rendered_timestamp_in_us_);
469 }
470 }
471
472 ViETest::Log("\nReportFrameState method invocations:");
473 ViETest::Log(" Created : %d", num_created_frames_);
474 ViETest::Log(" Send : %d", num_sent_frames_);
475 ViETest::Log(" Received: %d", num_received_frames_);
476 ViETest::Log(" Decoded : %d", num_decoded_frames_);
477 ViETest::Log(" Rendered: %d", num_rendered_frames_);
478}
479
480const std::vector<Frame*>& FrameDropDetector::GetAllFrames() {
481 assert(!dirty_);
482 return created_frames_vector_;
483}
484
485int FrameDropDetector::GetNumberOfFramesDroppedAt(State state) {
486 assert(!dirty_);
487 switch (state) {
488 case kSent:
489 return dropped_frames_at_send_;
490 case kReceived:
491 return dropped_frames_at_receive_;
492 case kDecoded:
493 return dropped_frames_at_decode_;
494 case kRendered:
495 return dropped_frames_at_render_;
496 default:
497 return 0;
498 }
499}
500
501int FrameDropMonitoringRemoteFileRenderer::DeliverFrame(
502 unsigned char *buffer, int buffer_size, uint32_t time_stamp,
503 int64_t render_time) {
504 // Register that this frame has been rendered:
505 frame_drop_detector_->ReportFrameState(FrameDropDetector::kRendered,
506 time_stamp);
507 return ViEToFileRenderer::DeliverFrame(buffer, buffer_size,
508 time_stamp, render_time);
509}
510
511int FrameDropMonitoringRemoteFileRenderer::FrameSizeChange(
512 unsigned int width, unsigned int height, unsigned int number_of_streams) {
513 return ViEToFileRenderer::FrameSizeChange(width, height, number_of_streams);
514}