Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Unified Diff: webrtc/modules/desktop_capture/win/desktop_frame_win_dxgi.cc

Issue 1845113002: DirectX based screen capturer logic (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Lint errors Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/desktop_capture/win/desktop_frame_win_dxgi.cc
diff --git a/webrtc/modules/desktop_capture/win/desktop_frame_win_dxgi.cc b/webrtc/modules/desktop_capture/win/desktop_frame_win_dxgi.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7d55934d91874261a097f13b79bc9acd17846b04
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/desktop_frame_win_dxgi.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/win/desktop_frame_win_dxgi.h"
+
+#include <string.h>
+
+#include <comdef.h>
+#include <D3D11.h>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/logging.h"
+
+namespace webrtc {
+
+using std::unique_ptr;
+using Microsoft::WRL::ComPtr;
+
+namespace {
+
+ID3D11Device* device = nullptr;
+ID3D11DeviceContext* context = nullptr;
+
+} // namespace
+
+void DesktopFrameWinDxgi::Initialize(ID3D11Device* dev,
+ ID3D11DeviceContext* ctx) {
+ RTC_DCHECK(dev != nullptr);
+ RTC_DCHECK(ctx != nullptr);
+ RTC_DCHECK(device == nullptr);
+ RTC_DCHECK(context == nullptr);
+
+ device = dev;
+ context = ctx;
+}
+
+DesktopFrameWinDxgi::DesktopFrameWinDxgi(DesktopSize size,
+ int stride,
+ SharedMemory* shared_memory)
+ : DesktopFrame(size,
+ stride,
+ nullptr, // Data will always be returned from rect_.pBits.
+ shared_memory) {
+ RTC_DCHECK(device != nullptr);
+ RTC_DCHECK(context != nullptr);
+}
+
+DesktopFrameWinDxgi::~DesktopFrameWinDxgi() {}
+
+unique_ptr<DesktopFrameWinDxgi> DesktopFrameWinDxgi::Create(
+ DesktopSize size,
+ SharedMemoryFactory* shared_memory_factory) {
+ int stride = size.width() * DesktopFrame::kBytesPerPixel;
+ int buffer_size = stride * size.height();
+ rtc::scoped_ptr<SharedMemory> shared_memory;
+ if (shared_memory_factory != nullptr) {
+ shared_memory = shared_memory_factory->CreateSharedMemory(buffer_size);
+ if (!shared_memory) {
+ LOG(LS_ERROR) << "Failed to create shared memory with size "
+ << buffer_size;
+ // Well, we are still able to work without shared_memory.
+ }
+ } else {
+ LOG(LS_WARNING) << "No SharedMemoryFactory provided";
+ }
+
+ return unique_ptr<DesktopFrameWinDxgi>(
+ new DesktopFrameWinDxgi(size, stride, shared_memory.release()));
+}
+
+bool DesktopFrameWinDxgi::Capture(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
+ IDXGIResource* resource) {
+ if (resource == nullptr || frame_info.AccumulatedFrames == 0) {
+ // Nothing updated, but current data is still valid.
+ return false;
+ }
+
+ ComPtr<ID3D11Texture2D> texture;
+ _com_error err(resource->QueryInterface(
+ __uuidof(ID3D11Texture2D),
+ reinterpret_cast<void**>(texture.GetAddressOf())));
+ if (err.Error() != S_OK || !texture) {
+ LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, "
+ "error "
+ << err.ErrorMessage() << ", code " << err.Error();
+ return false;
+ }
+
+ // AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to
+ // make a copy.
+ if (!CreateTexture(texture.Get())) {
+ return false;
+ }
+
+ context->CopyResource(static_cast<ID3D11Resource*>(stage_.Get()),
+ static_cast<ID3D11Resource*>(texture.Get()));
+
+ rect_ = {0};
+ err = _com_error(surface_->Map(&rect_, DXGI_MAP_READ));
+ if (err.Error() != S_OK) {
+ LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap, error "
+ << err.ErrorMessage() << ", code " << err.Error();
+ return false;
+ }
+
+ if (rect_.Pitch != stride()) {
+ // Unfortunately we cannot check whether the buffer size is also consistent.
+ LOG(LS_ERROR) << "System returns a different size of bitmap, with pitch "
+ << rect_.Pitch;
+ return false;
+ }
+
+ if (shared_memory() != nullptr) {
Sergey Ulanov 2016/04/08 21:22:26 There are two cases: 1. SharedMemoryFactory is se
Hzj_jie 2016/04/11 22:19:16 There are two reasons I used current solution. 1.
Sergey Ulanov 2016/04/12 03:00:46 ScreenCaptureFrameQueue is not the only place wher
Hzj_jie 2016/04/12 17:40:40 For the reason we make a copy to stage_, it's a Wi
+ // If there is a shared_memory, we need to copy the data to it, so other
+ // processes can use it.
+ memcpy(shared_memory()->data(), rect_.pBits, shared_memory()->size());
Sergey Ulanov 2016/04/08 21:22:26 This copies the whole frame every time. It should
Hzj_jie 2016/04/11 22:19:16 What's my initial plan is to move all variables fr
Sergey Ulanov 2016/04/12 03:00:47 IMO ScreenCapturerFrameQueue would a better place
+ }
+ // surface_->Unmap will be called next time we capture an image to avoid
+ // memory copy without shared_memory.
+ return true;
+}
+
+bool DesktopFrameWinDxgi::CreateTexture(ID3D11Texture2D* texture) {
+ RTC_DCHECK(texture != nullptr);
+ D3D11_TEXTURE2D_DESC desc;
Sergey Ulanov 2016/04/08 21:22:26 memset the struct to 0?
Hzj_jie 2016/04/11 22:19:16 Done.
+ texture->GetDesc(&desc);
+ // TODO(zijiehe): Debug
+ // desc.ArraySize = 1; // Capture only one frame.
+ desc.BindFlags = 0;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ // desc.MipLevels = 1;
+ desc.MiscFlags = 0;
+ // desc.SampleDesc.Count = 1;
+ // desc.SampleDesc.Quality = 0;
Sergey Ulanov 2016/04/08 21:22:26 remove commented code?
Hzj_jie 2016/04/11 22:19:16 Yes, should be, sorry.
+ desc.Usage = D3D11_USAGE_STAGING;
+ if (stage_) {
+ // Make sure stage_ and surface_ are always pointing to a same object.
+ // We need an ID3D11Texture2D instance for
+ // ID3D11DeviceContext::CopySubresourceRegion, but an IDXGISurface for
+ // IDXGISurface::Map.
+ {
+ ComPtr<IUnknown> left;
+ ComPtr<IUnknown> right;
+ bool left_result = SUCCEEDED(stage_.As(&left));
+ bool right_result = SUCCEEDED(surface_.As(&right));
+ RTC_DCHECK(left_result);
+ RTC_DCHECK(right_result);
+ RTC_DCHECK(left.Get() == right.Get());
+ }
+
+ // This buffer should be used already.
+ _com_error err = _com_error(surface_->Unmap());
+ if (err.Error() == S_OK) {
+ D3D11_TEXTURE2D_DESC orgi_desc;
+ stage_->GetDesc(&orgi_desc);
+ if (memcmp(&desc, &orgi_desc, sizeof(D3D11_TEXTURE2D_DESC)) == 0) {
+ return true;
+ }
+ } else {
+ // Let's recreate stage_ and surface_ later.
+ LOG(LS_ERROR) << "Failed to unmap surface, error " << err.ErrorMessage()
+ << ", code " << err.Error();
+ }
+
+ stage_.Reset();
+ surface_.Reset();
+ } else {
+ RTC_DCHECK(!surface_);
+ }
+
+ _com_error err = _com_error(
+ device->CreateTexture2D(&desc, nullptr, stage_.GetAddressOf()));
+ if (err.Error() != S_OK || !stage_) {
+ LOG(LS_ERROR) << "Failed to create a new ID3D11Texture2D as stage, "
+ "error "
+ << err.ErrorMessage() << ", code " << err.Error();
+ return false;
+ }
+
+ err = _com_error(stage_.As(&surface_));
+ if (err.Error() != S_OK || !surface_) {
+ LOG(LS_ERROR) << "Failed to convert ID3D11Texture2D to IDXGISurface, "
+ "error "
+ << err.ErrorMessage() << ", code " << err.Error();
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698