Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 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 | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #include "webrtc/modules/desktop_capture/win/desktop_frame_win_dxgi.h" | |
| 12 | |
| 13 #include <string.h> | |
| 14 | |
| 15 #include <comdef.h> | |
| 16 #include <D3D11.h> | |
| 17 | |
| 18 #include "webrtc/base/checks.h" | |
| 19 #include "webrtc/base/scoped_ptr.h" | |
| 20 #include "webrtc/system_wrappers/include/logging.h" | |
| 21 | |
| 22 namespace webrtc { | |
| 23 | |
| 24 using std::unique_ptr; | |
| 25 using Microsoft::WRL::ComPtr; | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 ID3D11Device* device = nullptr; | |
| 30 ID3D11DeviceContext* context = nullptr; | |
| 31 | |
| 32 } // namespace | |
| 33 | |
| 34 void DesktopFrameWinDxgi::Initialize(ID3D11Device* dev, | |
| 35 ID3D11DeviceContext* ctx) { | |
| 36 RTC_DCHECK(dev != nullptr); | |
| 37 RTC_DCHECK(ctx != nullptr); | |
| 38 RTC_DCHECK(device == nullptr); | |
| 39 RTC_DCHECK(context == nullptr); | |
| 40 | |
| 41 device = dev; | |
| 42 context = ctx; | |
| 43 } | |
| 44 | |
| 45 DesktopFrameWinDxgi::DesktopFrameWinDxgi(DesktopSize size, | |
| 46 int stride, | |
| 47 SharedMemory* shared_memory) | |
| 48 : DesktopFrame(size, | |
| 49 stride, | |
| 50 nullptr, // Data will always be returned from rect_.pBits. | |
| 51 shared_memory) { | |
| 52 RTC_DCHECK(device != nullptr); | |
| 53 RTC_DCHECK(context != nullptr); | |
| 54 } | |
| 55 | |
| 56 DesktopFrameWinDxgi::~DesktopFrameWinDxgi() {} | |
| 57 | |
| 58 unique_ptr<DesktopFrameWinDxgi> DesktopFrameWinDxgi::Create( | |
| 59 DesktopSize size, | |
| 60 SharedMemoryFactory* shared_memory_factory) { | |
| 61 int stride = size.width() * DesktopFrame::kBytesPerPixel; | |
| 62 int buffer_size = stride * size.height(); | |
| 63 rtc::scoped_ptr<SharedMemory> shared_memory; | |
| 64 if (shared_memory_factory != nullptr) { | |
| 65 shared_memory = shared_memory_factory->CreateSharedMemory(buffer_size); | |
| 66 if (!shared_memory) { | |
| 67 LOG(LS_ERROR) << "Failed to create shared memory with size " | |
| 68 << buffer_size; | |
| 69 // Well, we are still able to work without shared_memory. | |
| 70 } | |
| 71 } else { | |
| 72 LOG(LS_WARNING) << "No SharedMemoryFactory provided"; | |
| 73 } | |
| 74 | |
| 75 return unique_ptr<DesktopFrameWinDxgi>( | |
| 76 new DesktopFrameWinDxgi(size, stride, shared_memory.release())); | |
| 77 } | |
| 78 | |
| 79 bool DesktopFrameWinDxgi::Capture(const DXGI_OUTDUPL_FRAME_INFO& frame_info, | |
| 80 IDXGIResource* resource) { | |
| 81 if (resource == nullptr || frame_info.AccumulatedFrames == 0) { | |
| 82 // Nothing updated, but current data is still valid. | |
| 83 return false; | |
| 84 } | |
| 85 | |
| 86 ComPtr<ID3D11Texture2D> texture; | |
| 87 _com_error err(resource->QueryInterface( | |
| 88 __uuidof(ID3D11Texture2D), | |
| 89 reinterpret_cast<void**>(texture.GetAddressOf()))); | |
| 90 if (err.Error() != S_OK || !texture) { | |
| 91 LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, " | |
| 92 "error " | |
| 93 << err.ErrorMessage() << ", code " << err.Error(); | |
| 94 return false; | |
| 95 } | |
| 96 | |
| 97 // AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to | |
| 98 // make a copy. | |
| 99 if (!CreateTexture(texture.Get())) { | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 context->CopyResource(static_cast<ID3D11Resource*>(stage_.Get()), | |
| 104 static_cast<ID3D11Resource*>(texture.Get())); | |
| 105 | |
| 106 rect_ = {0}; | |
| 107 err = _com_error(surface_->Map(&rect_, DXGI_MAP_READ)); | |
| 108 if (err.Error() != S_OK) { | |
| 109 LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap, error " | |
| 110 << err.ErrorMessage() << ", code " << err.Error(); | |
| 111 return false; | |
| 112 } | |
| 113 | |
| 114 if (rect_.Pitch != stride()) { | |
| 115 // Unfortunately we cannot check whether the buffer size is also consistent. | |
| 116 LOG(LS_ERROR) << "System returns a different size of bitmap, with pitch " | |
| 117 << rect_.Pitch; | |
| 118 return false; | |
| 119 } | |
| 120 | |
| 121 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
| |
| 122 // If there is a shared_memory, we need to copy the data to it, so other | |
| 123 // processes can use it. | |
| 124 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
| |
| 125 } | |
| 126 // surface_->Unmap will be called next time we capture an image to avoid | |
| 127 // memory copy without shared_memory. | |
| 128 return true; | |
| 129 } | |
| 130 | |
| 131 bool DesktopFrameWinDxgi::CreateTexture(ID3D11Texture2D* texture) { | |
| 132 RTC_DCHECK(texture != nullptr); | |
| 133 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.
| |
| 134 texture->GetDesc(&desc); | |
| 135 // TODO(zijiehe): Debug | |
| 136 // desc.ArraySize = 1; // Capture only one frame. | |
| 137 desc.BindFlags = 0; | |
| 138 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; | |
| 139 // desc.MipLevels = 1; | |
| 140 desc.MiscFlags = 0; | |
| 141 // desc.SampleDesc.Count = 1; | |
| 142 // 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.
| |
| 143 desc.Usage = D3D11_USAGE_STAGING; | |
| 144 if (stage_) { | |
| 145 // Make sure stage_ and surface_ are always pointing to a same object. | |
| 146 // We need an ID3D11Texture2D instance for | |
| 147 // ID3D11DeviceContext::CopySubresourceRegion, but an IDXGISurface for | |
| 148 // IDXGISurface::Map. | |
| 149 { | |
| 150 ComPtr<IUnknown> left; | |
| 151 ComPtr<IUnknown> right; | |
| 152 bool left_result = SUCCEEDED(stage_.As(&left)); | |
| 153 bool right_result = SUCCEEDED(surface_.As(&right)); | |
| 154 RTC_DCHECK(left_result); | |
| 155 RTC_DCHECK(right_result); | |
| 156 RTC_DCHECK(left.Get() == right.Get()); | |
| 157 } | |
| 158 | |
| 159 // This buffer should be used already. | |
| 160 _com_error err = _com_error(surface_->Unmap()); | |
| 161 if (err.Error() == S_OK) { | |
| 162 D3D11_TEXTURE2D_DESC orgi_desc; | |
| 163 stage_->GetDesc(&orgi_desc); | |
| 164 if (memcmp(&desc, &orgi_desc, sizeof(D3D11_TEXTURE2D_DESC)) == 0) { | |
| 165 return true; | |
| 166 } | |
| 167 } else { | |
| 168 // Let's recreate stage_ and surface_ later. | |
| 169 LOG(LS_ERROR) << "Failed to unmap surface, error " << err.ErrorMessage() | |
| 170 << ", code " << err.Error(); | |
| 171 } | |
| 172 | |
| 173 stage_.Reset(); | |
| 174 surface_.Reset(); | |
| 175 } else { | |
| 176 RTC_DCHECK(!surface_); | |
| 177 } | |
| 178 | |
| 179 _com_error err = _com_error( | |
| 180 device->CreateTexture2D(&desc, nullptr, stage_.GetAddressOf())); | |
| 181 if (err.Error() != S_OK || !stage_) { | |
| 182 LOG(LS_ERROR) << "Failed to create a new ID3D11Texture2D as stage, " | |
| 183 "error " | |
| 184 << err.ErrorMessage() << ", code " << err.Error(); | |
| 185 return false; | |
| 186 } | |
| 187 | |
| 188 err = _com_error(stage_.As(&surface_)); | |
| 189 if (err.Error() != S_OK || !surface_) { | |
| 190 LOG(LS_ERROR) << "Failed to convert ID3D11Texture2D to IDXGISurface, " | |
| 191 "error " | |
| 192 << err.ErrorMessage() << ", code " << err.Error(); | |
| 193 return false; | |
| 194 } | |
| 195 | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 199 } // namespace webrtc | |
| OLD | NEW |