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 |