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