| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 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 | 10 |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 rtc::CritScope lock(&g_container->duplication_lock); | 406 rtc::CritScope lock(&g_container->duplication_lock); |
| 407 // Make sure nobody is using current instance. | 407 // Make sure nobody is using current instance. |
| 408 rtc::CritScope lock2(&g_container->acquire_lock); | 408 rtc::CritScope lock2(&g_container->acquire_lock); |
| 409 if (g_container->duplication) { | 409 if (g_container->duplication) { |
| 410 return true; | 410 return true; |
| 411 } | 411 } |
| 412 | 412 |
| 413 _com_error error = g_container->output1->DuplicateOutput( | 413 _com_error error = g_container->output1->DuplicateOutput( |
| 414 static_cast<IUnknown*>(g_container->device), | 414 static_cast<IUnknown*>(g_container->device), |
| 415 g_container->duplication.GetAddressOf()); | 415 g_container->duplication.GetAddressOf()); |
| 416 if (error.Error() != S_OK || !g_container->duplication) { | 416 if (error.Error() == S_OK && g_container->duplication) { |
| 417 memset(&g_container->duplication_desc, 0, sizeof(DXGI_OUTDUPL_DESC)); |
| 418 g_container->duplication->GetDesc(&g_container->duplication_desc); |
| 419 if (g_container->duplication_desc.ModeDesc.Format != |
| 420 DXGI_FORMAT_B8G8R8A8_UNORM) { |
| 421 g_container->duplication.Reset(); |
| 422 LOG(LS_ERROR) << "IDXGIDuplicateOutput does not use RGBA (8 bit) " |
| 423 "format, which is required by downstream components, " |
| 424 "format is " |
| 425 << g_container->duplication_desc.ModeDesc.Format; |
| 426 return false; |
| 427 } |
| 428 return true; |
| 429 } else { |
| 430 // Make sure we have correct signal and duplicate the output next time. |
| 417 g_container->duplication.Reset(); | 431 g_container->duplication.Reset(); |
| 418 LOG(LS_WARNING) << "Failed to duplicate output from IDXGIOutput1, error " | 432 LOG(LS_WARNING) << "Failed to duplicate output from IDXGIOutput1, error " |
| 419 << error.ErrorMessage() << ", with code " | 433 << error.ErrorMessage() << ", with code " |
| 420 << error.Error(); | 434 << error.Error(); |
| 421 return false; | |
| 422 } | 435 } |
| 423 | 436 |
| 424 memset(&g_container->duplication_desc, 0, sizeof(DXGI_OUTDUPL_DESC)); | 437 return false; |
| 425 g_container->duplication->GetDesc(&g_container->duplication_desc); | |
| 426 if (g_container->duplication_desc.ModeDesc.Format != | |
| 427 DXGI_FORMAT_B8G8R8A8_UNORM) { | |
| 428 g_container->duplication.Reset(); | |
| 429 LOG(LS_ERROR) << "IDXGIDuplicateOutput does not use RGBA (8 bit) " | |
| 430 "format, which is required by downstream components, " | |
| 431 "format is " | |
| 432 << g_container->duplication_desc.ModeDesc.Format; | |
| 433 return false; | |
| 434 } | |
| 435 | |
| 436 return true; | |
| 437 } | 438 } |
| 438 | 439 |
| 439 bool ScreenCapturerWinDirectx::ForceDuplicateOutput() { | 440 bool ScreenCapturerWinDirectx::ForceDuplicateOutput() { |
| 440 // We are updating the instance. | 441 // We are updating the instance. |
| 441 rtc::CritScope lock(&g_container->duplication_lock); | 442 rtc::CritScope lock(&g_container->duplication_lock); |
| 442 // Make sure nobody is using current instance. | 443 // Make sure nobody is using current instance. |
| 443 rtc::CritScope lock2(&g_container->acquire_lock); | 444 rtc::CritScope lock2(&g_container->acquire_lock); |
| 444 | 445 |
| 445 if (g_container->duplication) { | 446 if (g_container->duplication) { |
| 446 g_container->duplication->ReleaseFrame(); | 447 g_container->duplication->ReleaseFrame(); |
| 447 g_container->duplication.Reset(); | 448 g_container->duplication.Reset(); |
| 448 } | 449 } |
| 449 | 450 |
| 450 return DuplicateOutput(); | 451 return DuplicateOutput(); |
| 451 } | 452 } |
| 452 | 453 |
| 453 ScreenCapturerWinDirectx::ScreenCapturerWinDirectx( | 454 ScreenCapturerWinDirectx::ScreenCapturerWinDirectx( |
| 454 const DesktopCaptureOptions& options) | 455 const DesktopCaptureOptions& options) |
| 455 : callback_(nullptr), set_thread_execution_state_failed_(false) { | 456 : callback_(nullptr), set_thread_execution_state_failed_(false) { |
| 456 RTC_DCHECK(g_container && g_container->initialize_result); | 457 RTC_DCHECK(g_container && g_container->initialize_result); |
| 457 | 458 |
| 458 // Texture instance won't change forever. | 459 // Texture instance won't change forever. |
| 459 while (!surfaces_.current_frame()) { | 460 while (!surfaces_.current_frame()) { |
| 460 surfaces_.ReplaceCurrentFrame(std::unique_ptr<rtc::scoped_refptr<Texture>>( | 461 surfaces_.ReplaceCurrentFrame( |
| 461 new rtc::scoped_refptr<Texture>(new Texture()))); | 462 new rtc::scoped_refptr<Texture>(new Texture())); |
| 462 surfaces_.MoveToNextFrame(); | 463 surfaces_.MoveToNextFrame(); |
| 463 } | 464 } |
| 464 } | 465 } |
| 465 | 466 |
| 466 ScreenCapturerWinDirectx::~ScreenCapturerWinDirectx() {} | 467 ScreenCapturerWinDirectx::~ScreenCapturerWinDirectx() {} |
| 467 | 468 |
| 468 void ScreenCapturerWinDirectx::Start(Callback* callback) { | 469 void ScreenCapturerWinDirectx::Start(Callback* callback) { |
| 469 RTC_DCHECK(!callback_); | 470 RTC_DCHECK(!callback_); |
| 470 RTC_DCHECK(callback); | 471 RTC_DCHECK(callback); |
| 471 | 472 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 // Current frame does not have a same size as last captured surface. | 586 // Current frame does not have a same size as last captured surface. |
| 586 std::unique_ptr<DesktopFrame> new_frame = | 587 std::unique_ptr<DesktopFrame> new_frame = |
| 587 SharedMemoryDesktopFrame::Create( | 588 SharedMemoryDesktopFrame::Create( |
| 588 surfaces_.current_frame()->get()->size(), | 589 surfaces_.current_frame()->get()->size(), |
| 589 shared_memory_factory_.get()); | 590 shared_memory_factory_.get()); |
| 590 if (!new_frame) { | 591 if (!new_frame) { |
| 591 LOG(LS_ERROR) << "Failed to allocate a new SharedMemoryDesktopFrame"; | 592 LOG(LS_ERROR) << "Failed to allocate a new SharedMemoryDesktopFrame"; |
| 592 return std::unique_ptr<DesktopFrame>(); | 593 return std::unique_ptr<DesktopFrame>(); |
| 593 } | 594 } |
| 594 frames_.ReplaceCurrentFrame( | 595 frames_.ReplaceCurrentFrame( |
| 595 SharedDesktopFrame::Wrap(std::move(new_frame))); | 596 SharedDesktopFrame::Wrap(new_frame.release())); |
| 596 } | 597 } |
| 597 result = frames_.current_frame()->Share(); | 598 result.reset(frames_.current_frame()->Share()); |
| 598 | 599 |
| 599 std::unique_ptr<DesktopFrame> frame( | 600 std::unique_ptr<DesktopFrame> frame( |
| 600 new DxgiDesktopFrame(*surfaces_.current_frame())); | 601 new DxgiDesktopFrame(*surfaces_.current_frame())); |
| 601 // Copy data into SharedMemory. | 602 // Copy data into SharedMemory. |
| 602 for (DesktopRegion::Iterator it( | 603 for (DesktopRegion::Iterator it( |
| 603 surfaces_.current_frame()->get()->copied_region()); | 604 surfaces_.current_frame()->get()->copied_region()); |
| 604 !it.IsAtEnd(); | 605 !it.IsAtEnd(); |
| 605 it.Advance()) { | 606 it.Advance()) { |
| 606 result->CopyPixelsFrom(*frame, it.rect().top_left(), it.rect()); | 607 result->CopyPixelsFrom(*frame, it.rect().top_left(), it.rect()); |
| 607 } | 608 } |
| 608 result->set_dpi(frame->dpi()); | 609 result->set_dpi(frame->dpi()); |
| 609 } else { | 610 } else { |
| 610 result.reset(new DxgiDesktopFrame(*surfaces_.current_frame())); | 611 result.reset(new DxgiDesktopFrame(*surfaces_.current_frame())); |
| 611 } | 612 } |
| 612 RTC_DCHECK(result); | 613 RTC_DCHECK(result); |
| 613 *result->mutable_updated_region() = | 614 *result->mutable_updated_region() = |
| 614 surfaces_.current_frame()->get()->updated_region(); | 615 surfaces_.current_frame()->get()->updated_region(); |
| 615 return result; | 616 return result; |
| 616 } | 617 } |
| 617 | 618 |
| 618 void ScreenCapturerWinDirectx::Capture(const DesktopRegion& region) { | 619 void ScreenCapturerWinDirectx::Capture(const DesktopRegion& region) { |
| 619 RTC_DCHECK(callback_); | 620 RTC_DCHECK(callback_); |
| 620 | 621 |
| 621 if (!g_container->duplication && !DuplicateOutput()) { | 622 if (!g_container->duplication && !DuplicateOutput()) { |
| 622 // Failed to initialize desktop duplication. | 623 // Receive a capture request when application is shutting down, or between |
| 623 callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr); | 624 // mode change. |
| 625 callback_->OnCaptureCompleted(nullptr); |
| 624 return; | 626 return; |
| 625 } | 627 } |
| 626 | 628 |
| 627 RTC_DCHECK(g_container->duplication); | 629 RTC_DCHECK(g_container->duplication); |
| 628 int64_t capture_start_time_nanos = rtc::TimeNanos(); | 630 int64_t capture_start_time_nanos = rtc::TimeNanos(); |
| 629 | 631 |
| 630 if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) { | 632 if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) { |
| 631 if (!set_thread_execution_state_failed_) { | 633 if (!set_thread_execution_state_failed_) { |
| 632 set_thread_execution_state_failed_ = true; | 634 set_thread_execution_state_failed_ = true; |
| 633 LOG(LS_WARNING) << "Failed to make system & display power assertion: " | 635 LOG(LS_WARNING) << "Failed to make system & display power assertion: " |
| (...skipping 13 matching lines...) Expand all Loading... |
| 647 EmitCurrentFrame(); | 649 EmitCurrentFrame(); |
| 648 return; | 650 return; |
| 649 } | 651 } |
| 650 | 652 |
| 651 if (error.Error() != S_OK) { | 653 if (error.Error() != S_OK) { |
| 652 LOG(LS_ERROR) << "Failed to capture frame, error " << error.ErrorMessage() | 654 LOG(LS_ERROR) << "Failed to capture frame, error " << error.ErrorMessage() |
| 653 << ", code " << error.Error(); | 655 << ", code " << error.Error(); |
| 654 if (ForceDuplicateOutput()) { | 656 if (ForceDuplicateOutput()) { |
| 655 EmitCurrentFrame(); | 657 EmitCurrentFrame(); |
| 656 } else { | 658 } else { |
| 657 callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); | 659 callback_->OnCaptureCompleted(nullptr); |
| 658 } | 660 } |
| 659 return; | 661 return; |
| 660 } | 662 } |
| 661 | 663 |
| 662 if (frame_info.AccumulatedFrames == 0) { | 664 if (frame_info.AccumulatedFrames == 0) { |
| 663 g_container->duplication->ReleaseFrame(); | 665 g_container->duplication->ReleaseFrame(); |
| 664 EmitCurrentFrame(); | 666 EmitCurrentFrame(); |
| 665 return; | 667 return; |
| 666 } | 668 } |
| 667 | 669 |
| 668 // Everything looks good so far, build next frame. | 670 // Everything looks good so far, build next frame. |
| 669 std::unique_ptr<DesktopFrame> result = | 671 std::unique_ptr<DesktopFrame> result = |
| 670 ProcessFrame(frame_info, resource.Get()); | 672 ProcessFrame(frame_info, resource.Get()); |
| 671 // DetectUpdatedRegion may release last g_container->duplication. But | 673 // DetectUpdatedRegion may release last g_container->duplication. But |
| 672 // ForctDuplicateOutput function will always release last frame, so there is | 674 // ForctDuplicateOutput function will always release last frame, so there is |
| 673 // no potential leak. | 675 // no potential leak. |
| 674 if (g_container->duplication) { | 676 if (g_container->duplication) { |
| 675 g_container->duplication->ReleaseFrame(); | 677 g_container->duplication->ReleaseFrame(); |
| 676 } | 678 } |
| 677 if (!result) { | 679 if (!result) { |
| 678 callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); | 680 callback_->OnCaptureCompleted(nullptr); |
| 679 return; | 681 return; |
| 680 } | 682 } |
| 681 | 683 |
| 682 result->set_capture_time_ms( | 684 result->set_capture_time_ms( |
| 683 (rtc::TimeNanos() - capture_start_time_nanos) / | 685 (rtc::TimeNanos() - capture_start_time_nanos) / |
| 684 rtc::kNumNanosecsPerMillisec); | 686 rtc::kNumNanosecsPerMillisec); |
| 685 callback_->OnCaptureResult(Result::SUCCESS, std::move(result)); | 687 callback_->OnCaptureCompleted(result.release()); |
| 686 } | 688 } |
| 687 | 689 |
| 688 bool ScreenCapturerWinDirectx::GetScreenList(ScreenList* screens) { | 690 bool ScreenCapturerWinDirectx::GetScreenList(ScreenList* screens) { |
| 689 return true; | 691 return true; |
| 690 } | 692 } |
| 691 | 693 |
| 692 bool ScreenCapturerWinDirectx::SelectScreen(ScreenId id) { | 694 bool ScreenCapturerWinDirectx::SelectScreen(ScreenId id) { |
| 693 // Only full desktop capture is supported. | 695 // Only full desktop capture is supported. |
| 694 return id == kFullDesktopScreenId; | 696 return id == kFullDesktopScreenId; |
| 695 } | 697 } |
| 696 | 698 |
| 697 void ScreenCapturerWinDirectx::EmitCurrentFrame() { | 699 void ScreenCapturerWinDirectx::EmitCurrentFrame() { |
| 698 if (!surfaces_.current_frame()->get()->bits()) { | 700 if (!surfaces_.current_frame()->get()->bits()) { |
| 699 // At the very begining, we have not captured any frames. | 701 // At the very begining, we have not captured any frames. |
| 700 callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); | 702 callback_->OnCaptureCompleted(nullptr); |
| 701 return; | 703 return; |
| 702 } | 704 } |
| 703 | 705 |
| 704 if (shared_memory_factory_) { | 706 if (shared_memory_factory_) { |
| 705 // If shared_memory_factory_ is provided, last frame is stored in frames_ | 707 // If shared_memory_factory_ is provided, last frame is stored in frames_ |
| 706 // queue. If there is not an existing frame (at the very begining), we can | 708 // queue. If there is not an existing frame (at the very begining), we can |
| 707 // only return a nullptr. | 709 // only return a nullptr. |
| 708 if (frames_.current_frame()) { | 710 if (frames_.current_frame()) { |
| 709 std::unique_ptr<SharedDesktopFrame> frame = | 711 std::unique_ptr<SharedDesktopFrame> frame( |
| 710 frames_.current_frame()->Share(); | 712 frames_.current_frame()->Share()); |
| 711 frame->mutable_updated_region()->Clear(); | 713 frame->mutable_updated_region()->Clear(); |
| 712 callback_->OnCaptureResult(Result::SUCCESS, std::move(frame)); | 714 callback_->OnCaptureCompleted(frame.release()); |
| 713 } else { | 715 } else { |
| 714 callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); | 716 callback_->OnCaptureCompleted(nullptr); |
| 715 } | 717 } |
| 716 return; | 718 return; |
| 717 } | 719 } |
| 718 | 720 |
| 719 // If there is no shared_memory_factory_, last frame is stored in surfaces_ | 721 // If there is no shared_memory_factory_, last frame is stored in surfaces_ |
| 720 // queue. | 722 // queue. |
| 721 std::unique_ptr<DesktopFrame> frame( | 723 std::unique_ptr<DesktopFrame> frame( |
| 722 new DxgiDesktopFrame(*surfaces_.current_frame())); | 724 new DxgiDesktopFrame(*surfaces_.current_frame())); |
| 723 callback_->OnCaptureResult(Result::SUCCESS, std::move(frame)); | 725 callback_->OnCaptureCompleted(frame.release()); |
| 724 } | 726 } |
| 725 | 727 |
| 726 } // namespace webrtc | 728 } // namespace webrtc |
| OLD | NEW |