| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 #include <stdio.h> | 10 #include <stdio.h> |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <deque> | 13 #include <deque> |
| 14 #include <map> | 14 #include <map> |
| 15 #include <sstream> | 15 #include <sstream> |
| 16 #include <string> | 16 #include <string> |
| 17 #include <vector> | 17 #include <vector> |
| 18 | 18 |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 20 |
| 21 #include "webrtc/base/checks.h" | 21 #include "webrtc/base/checks.h" |
| 22 #include "webrtc/base/event.h" |
| 22 #include "webrtc/base/format_macros.h" | 23 #include "webrtc/base/format_macros.h" |
| 23 #include "webrtc/base/scoped_ptr.h" | 24 #include "webrtc/base/scoped_ptr.h" |
| 24 #include "webrtc/call.h" | 25 #include "webrtc/call.h" |
| 25 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 26 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
| 26 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" | 27 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" |
| 27 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" | 28 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" |
| 28 #include "webrtc/system_wrappers/include/cpu_info.h" | 29 #include "webrtc/system_wrappers/include/cpu_info.h" |
| 29 #include "webrtc/test/layer_filtering_transport.h" | 30 #include "webrtc/test/layer_filtering_transport.h" |
| 30 #include "webrtc/test/run_loop.h" | 31 #include "webrtc/test/run_loop.h" |
| 31 #include "webrtc/test/statistics.h" | 32 #include "webrtc/test/statistics.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 ssrc_to_analyze_(ssrc_to_analyze), | 65 ssrc_to_analyze_(ssrc_to_analyze), |
| 65 frames_to_process_(duration_frames), | 66 frames_to_process_(duration_frames), |
| 66 frames_recorded_(0), | 67 frames_recorded_(0), |
| 67 frames_processed_(0), | 68 frames_processed_(0), |
| 68 dropped_frames_(0), | 69 dropped_frames_(0), |
| 69 last_render_time_(0), | 70 last_render_time_(0), |
| 70 rtp_timestamp_delta_(0), | 71 rtp_timestamp_delta_(0), |
| 71 avg_psnr_threshold_(avg_psnr_threshold), | 72 avg_psnr_threshold_(avg_psnr_threshold), |
| 72 avg_ssim_threshold_(avg_ssim_threshold), | 73 avg_ssim_threshold_(avg_ssim_threshold), |
| 73 stats_polling_thread_(&PollStatsThread, this, "StatsPoller"), | 74 stats_polling_thread_(&PollStatsThread, this, "StatsPoller"), |
| 74 comparison_available_event_(EventWrapper::Create()), | 75 comparison_available_event_(false, false), |
| 75 done_(EventWrapper::Create()) { | 76 done_(false, false) { |
| 76 // Create thread pool for CPU-expensive PSNR/SSIM calculations. | 77 // Create thread pool for CPU-expensive PSNR/SSIM calculations. |
| 77 | 78 |
| 78 // Try to use about as many threads as cores, but leave kMinCoresLeft alone, | 79 // Try to use about as many threads as cores, but leave kMinCoresLeft alone, |
| 79 // so that we don't accidentally starve "real" worker threads (codec etc). | 80 // so that we don't accidentally starve "real" worker threads (codec etc). |
| 80 // Also, don't allocate more than kMaxComparisonThreads, even if there are | 81 // Also, don't allocate more than kMaxComparisonThreads, even if there are |
| 81 // spare cores. | 82 // spare cores. |
| 82 | 83 |
| 83 uint32_t num_cores = CpuInfo::DetectNumberOfCores(); | 84 uint32_t num_cores = CpuInfo::DetectNumberOfCores(); |
| 84 RTC_DCHECK_GE(num_cores, 1u); | 85 RTC_DCHECK_GE(num_cores, 1u); |
| 85 static const uint32_t kMinCoresLeft = 4; | 86 static const uint32_t kMinCoresLeft = 4; |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 bool IsTextureSupported() const override { return false; } | 217 bool IsTextureSupported() const override { return false; } |
| 217 | 218 |
| 218 void Wait() { | 219 void Wait() { |
| 219 // Frame comparisons can be very expensive. Wait for test to be done, but | 220 // Frame comparisons can be very expensive. Wait for test to be done, but |
| 220 // at time-out check if frames_processed is going up. If so, give it more | 221 // at time-out check if frames_processed is going up. If so, give it more |
| 221 // time, otherwise fail. Hopefully this will reduce test flakiness. | 222 // time, otherwise fail. Hopefully this will reduce test flakiness. |
| 222 | 223 |
| 223 stats_polling_thread_.Start(); | 224 stats_polling_thread_.Start(); |
| 224 | 225 |
| 225 int last_frames_processed = -1; | 226 int last_frames_processed = -1; |
| 226 EventTypeWrapper eventType; | |
| 227 int iteration = 0; | 227 int iteration = 0; |
| 228 while ((eventType = done_->Wait(VideoQualityTest::kDefaultTimeoutMs)) != | 228 while (!done_.Wait(VideoQualityTest::kDefaultTimeoutMs)) { |
| 229 kEventSignaled) { | |
| 230 int frames_processed; | 229 int frames_processed; |
| 231 { | 230 { |
| 232 rtc::CritScope crit(&comparison_lock_); | 231 rtc::CritScope crit(&comparison_lock_); |
| 233 frames_processed = frames_processed_; | 232 frames_processed = frames_processed_; |
| 234 } | 233 } |
| 235 | 234 |
| 236 // Print some output so test infrastructure won't think we've crashed. | 235 // Print some output so test infrastructure won't think we've crashed. |
| 237 const char* kKeepAliveMessages[3] = { | 236 const char* kKeepAliveMessages[3] = { |
| 238 "Uh, I'm-I'm not quite dead, sir.", | 237 "Uh, I'm-I'm not quite dead, sir.", |
| 239 "Uh, I-I think uh, I could pull through, sir.", | 238 "Uh, I-I think uh, I could pull through, sir.", |
| 240 "Actually, I think I'm all right to come with you--"}; | 239 "Actually, I think I'm all right to come with you--"}; |
| 241 printf("- %s\n", kKeepAliveMessages[iteration++ % 3]); | 240 printf("- %s\n", kKeepAliveMessages[iteration++ % 3]); |
| 242 | 241 |
| 243 if (last_frames_processed == -1) { | 242 if (last_frames_processed == -1) { |
| 244 last_frames_processed = frames_processed; | 243 last_frames_processed = frames_processed; |
| 245 continue; | 244 continue; |
| 246 } | 245 } |
| 247 ASSERT_GT(frames_processed, last_frames_processed) | 246 ASSERT_GT(frames_processed, last_frames_processed) |
| 248 << "Analyzer stalled while waiting for test to finish."; | 247 << "Analyzer stalled while waiting for test to finish."; |
| 249 last_frames_processed = frames_processed; | 248 last_frames_processed = frames_processed; |
| 250 } | 249 } |
| 251 | 250 |
| 252 if (iteration > 0) | 251 if (iteration > 0) |
| 253 printf("- Farewell, sweet Concorde!\n"); | 252 printf("- Farewell, sweet Concorde!\n"); |
| 254 | 253 |
| 255 // Signal stats polling thread if that is still waiting and stop it now, | 254 // Signal stats polling thread if that is still waiting and stop it now, |
| 256 // since it uses the send_stream_ reference that might be reclaimed after | 255 // since it uses the send_stream_ reference that might be reclaimed after |
| 257 // returning from this method. | 256 // returning from this method. |
| 258 done_->Set(); | 257 done_.Set(); |
| 259 stats_polling_thread_.Stop(); | 258 stats_polling_thread_.Stop(); |
| 260 } | 259 } |
| 261 | 260 |
| 262 VideoCaptureInput* input_; | 261 VideoCaptureInput* input_; |
| 263 test::LayerFilteringTransport* const transport_; | 262 test::LayerFilteringTransport* const transport_; |
| 264 PacketReceiver* receiver_; | 263 PacketReceiver* receiver_; |
| 265 VideoSendStream* send_stream_; | 264 VideoSendStream* send_stream_; |
| 266 | 265 |
| 267 private: | 266 private: |
| 268 struct FrameComparison { | 267 struct FrameComparison { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 | 344 |
| 346 VideoFrame reference_copy; | 345 VideoFrame reference_copy; |
| 347 VideoFrame render_copy; | 346 VideoFrame render_copy; |
| 348 reference_copy.CopyFrame(reference); | 347 reference_copy.CopyFrame(reference); |
| 349 render_copy.CopyFrame(render); | 348 render_copy.CopyFrame(render); |
| 350 | 349 |
| 351 rtc::CritScope crit(&comparison_lock_); | 350 rtc::CritScope crit(&comparison_lock_); |
| 352 comparisons_.push_back(FrameComparison(reference_copy, render_copy, dropped, | 351 comparisons_.push_back(FrameComparison(reference_copy, render_copy, dropped, |
| 353 send_time_ms, recv_time_ms, | 352 send_time_ms, recv_time_ms, |
| 354 render_time_ms, encoded_size)); | 353 render_time_ms, encoded_size)); |
| 355 comparison_available_event_->Set(); | 354 comparison_available_event_.Set(); |
| 356 } | 355 } |
| 357 | 356 |
| 358 static bool PollStatsThread(void* obj) { | 357 static bool PollStatsThread(void* obj) { |
| 359 return static_cast<VideoAnalyzer*>(obj)->PollStats(); | 358 return static_cast<VideoAnalyzer*>(obj)->PollStats(); |
| 360 } | 359 } |
| 361 | 360 |
| 362 bool PollStats() { | 361 bool PollStats() { |
| 363 switch (done_->Wait(kSendStatsPollingIntervalMs)) { | 362 if (done_.Wait(kSendStatsPollingIntervalMs)) { |
| 364 case kEventSignaled: | 363 // Set event again to make sure main thread is also signaled, then we're |
| 365 case kEventError: | 364 // done. |
| 366 done_->Set(); // Make sure main thread is also signaled. | 365 done_.Set(); |
| 367 return false; | 366 return false; |
| 368 case kEventTimeout: | |
| 369 break; | |
| 370 default: | |
| 371 RTC_NOTREACHED(); | |
| 372 } | 367 } |
| 373 | 368 |
| 374 VideoSendStream::Stats stats = send_stream_->GetStats(); | 369 VideoSendStream::Stats stats = send_stream_->GetStats(); |
| 375 | 370 |
| 376 rtc::CritScope crit(&comparison_lock_); | 371 rtc::CritScope crit(&comparison_lock_); |
| 377 encode_frame_rate_.AddSample(stats.encode_frame_rate); | 372 encode_frame_rate_.AddSample(stats.encode_frame_rate); |
| 378 encode_time_ms.AddSample(stats.avg_encode_time_ms); | 373 encode_time_ms.AddSample(stats.avg_encode_time_ms); |
| 379 encode_usage_percent.AddSample(stats.encode_usage_percent); | 374 encode_usage_percent.AddSample(stats.encode_usage_percent); |
| 380 media_bitrate_bps.AddSample(stats.media_bitrate_bps); | 375 media_bitrate_bps.AddSample(stats.media_bitrate_bps); |
| 381 | 376 |
| 382 return true; | 377 return true; |
| 383 } | 378 } |
| 384 | 379 |
| 385 static bool FrameComparisonThread(void* obj) { | 380 static bool FrameComparisonThread(void* obj) { |
| 386 return static_cast<VideoAnalyzer*>(obj)->CompareFrames(); | 381 return static_cast<VideoAnalyzer*>(obj)->CompareFrames(); |
| 387 } | 382 } |
| 388 | 383 |
| 389 bool CompareFrames() { | 384 bool CompareFrames() { |
| 390 if (AllFramesRecorded()) | 385 if (AllFramesRecorded()) |
| 391 return false; | 386 return false; |
| 392 | 387 |
| 393 VideoFrame reference; | 388 VideoFrame reference; |
| 394 VideoFrame render; | 389 VideoFrame render; |
| 395 FrameComparison comparison; | 390 FrameComparison comparison; |
| 396 | 391 |
| 397 if (!PopComparison(&comparison)) { | 392 if (!PopComparison(&comparison)) { |
| 398 // Wait until new comparison task is available, or test is done. | 393 // Wait until new comparison task is available, or test is done. |
| 399 // If done, wake up remaining threads waiting. | 394 // If done, wake up remaining threads waiting. |
| 400 comparison_available_event_->Wait(1000); | 395 comparison_available_event_.Wait(1000); |
| 401 if (AllFramesRecorded()) { | 396 if (AllFramesRecorded()) { |
| 402 comparison_available_event_->Set(); | 397 comparison_available_event_.Set(); |
| 403 return false; | 398 return false; |
| 404 } | 399 } |
| 405 return true; // Try again. | 400 return true; // Try again. |
| 406 } | 401 } |
| 407 | 402 |
| 408 PerformFrameComparison(comparison); | 403 PerformFrameComparison(comparison); |
| 409 | 404 |
| 410 if (FrameProcessed()) { | 405 if (FrameProcessed()) { |
| 411 PrintResults(); | 406 PrintResults(); |
| 412 if (graph_data_output_file_) | 407 if (graph_data_output_file_) |
| 413 PrintSamplesToFile(); | 408 PrintSamplesToFile(); |
| 414 done_->Set(); | 409 done_.Set(); |
| 415 comparison_available_event_->Set(); | 410 comparison_available_event_.Set(); |
| 416 return false; | 411 return false; |
| 417 } | 412 } |
| 418 | 413 |
| 419 return true; | 414 return true; |
| 420 } | 415 } |
| 421 | 416 |
| 422 bool PopComparison(FrameComparison* comparison) { | 417 bool PopComparison(FrameComparison* comparison) { |
| 423 rtc::CritScope crit(&comparison_lock_); | 418 rtc::CritScope crit(&comparison_lock_); |
| 424 // If AllFramesRecorded() is true, it means we have already popped | 419 // If AllFramesRecorded() is true, it means we have already popped |
| 425 // frames_to_process_ frames from comparisons_, so there is no more work | 420 // frames_to_process_ frames from comparisons_, so there is no more work |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 std::map<uint32_t, int64_t> send_times_ GUARDED_BY(crit_); | 591 std::map<uint32_t, int64_t> send_times_ GUARDED_BY(crit_); |
| 597 std::map<uint32_t, int64_t> recv_times_ GUARDED_BY(crit_); | 592 std::map<uint32_t, int64_t> recv_times_ GUARDED_BY(crit_); |
| 598 std::map<uint32_t, size_t> encoded_frame_sizes_ GUARDED_BY(crit_); | 593 std::map<uint32_t, size_t> encoded_frame_sizes_ GUARDED_BY(crit_); |
| 599 VideoFrame first_send_frame_ GUARDED_BY(crit_); | 594 VideoFrame first_send_frame_ GUARDED_BY(crit_); |
| 600 const double avg_psnr_threshold_; | 595 const double avg_psnr_threshold_; |
| 601 const double avg_ssim_threshold_; | 596 const double avg_ssim_threshold_; |
| 602 | 597 |
| 603 rtc::CriticalSection comparison_lock_; | 598 rtc::CriticalSection comparison_lock_; |
| 604 std::vector<rtc::PlatformThread*> comparison_thread_pool_; | 599 std::vector<rtc::PlatformThread*> comparison_thread_pool_; |
| 605 rtc::PlatformThread stats_polling_thread_; | 600 rtc::PlatformThread stats_polling_thread_; |
| 606 const rtc::scoped_ptr<EventWrapper> comparison_available_event_; | 601 rtc::Event comparison_available_event_; |
| 607 std::deque<FrameComparison> comparisons_ GUARDED_BY(comparison_lock_); | 602 std::deque<FrameComparison> comparisons_ GUARDED_BY(comparison_lock_); |
| 608 const rtc::scoped_ptr<EventWrapper> done_; | 603 rtc::Event done_; |
| 609 }; | 604 }; |
| 610 | 605 |
| 611 VideoQualityTest::VideoQualityTest() : clock_(Clock::GetRealTimeClock()) {} | 606 VideoQualityTest::VideoQualityTest() : clock_(Clock::GetRealTimeClock()) {} |
| 612 | 607 |
| 613 void VideoQualityTest::TestBody() {} | 608 void VideoQualityTest::TestBody() {} |
| 614 | 609 |
| 615 std::string VideoQualityTest::GenerateGraphTitle() const { | 610 std::string VideoQualityTest::GenerateGraphTitle() const { |
| 616 std::stringstream ss; | 611 std::stringstream ss; |
| 617 ss << params_.common.codec; | 612 ss << params_.common.codec; |
| 618 ss << " (" << params_.common.target_bitrate_bps / 1000 << "kbps"; | 613 ss << " (" << params_.common.target_bitrate_bps / 1000 << "kbps"; |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1066 send_stream_->Stop(); | 1061 send_stream_->Stop(); |
| 1067 receive_stream->Stop(); | 1062 receive_stream->Stop(); |
| 1068 | 1063 |
| 1069 call->DestroyVideoReceiveStream(receive_stream); | 1064 call->DestroyVideoReceiveStream(receive_stream); |
| 1070 call->DestroyVideoSendStream(send_stream_); | 1065 call->DestroyVideoSendStream(send_stream_); |
| 1071 | 1066 |
| 1072 transport.StopSending(); | 1067 transport.StopSending(); |
| 1073 } | 1068 } |
| 1074 | 1069 |
| 1075 } // namespace webrtc | 1070 } // namespace webrtc |
| OLD | NEW |