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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 if (error.Error() != S_OK) { | 111 if (error.Error() != S_OK) { |
112 LOG(LS_ERROR) << "Failed to release frame from IDXGIOutputDuplication, " | 112 LOG(LS_ERROR) << "Failed to release frame from IDXGIOutputDuplication, " |
113 "error" | 113 "error" |
114 << error.ErrorMessage() << ", code " << error.Error(); | 114 << error.ErrorMessage() << ", code " << error.Error(); |
115 return false; | 115 return false; |
116 } | 116 } |
117 return true; | 117 return true; |
118 } | 118 } |
119 | 119 |
120 bool DxgiOutputDuplicator::Duplicate(Context* context, | 120 bool DxgiOutputDuplicator::Duplicate(Context* context, |
121 const DesktopFrame* last_frame, | |
122 const DesktopVector offset, | 121 const DesktopVector offset, |
123 DesktopFrame* target) { | 122 SharedDesktopFrame* target) { |
124 RTC_DCHECK(duplication_); | 123 RTC_DCHECK(duplication_); |
125 RTC_DCHECK(texture_); | 124 RTC_DCHECK(texture_); |
126 RTC_DCHECK(target); | 125 RTC_DCHECK(target); |
| 126 if (!DesktopRect::MakeSize(target->size()) |
| 127 .ContainsRect(TranslatedDesktopRect(offset))) { |
| 128 // target size is not large enough to cover current output region. |
| 129 return false; |
| 130 } |
| 131 |
127 DXGI_OUTDUPL_FRAME_INFO frame_info; | 132 DXGI_OUTDUPL_FRAME_INFO frame_info; |
128 memset(&frame_info, 0, sizeof(frame_info)); | 133 memset(&frame_info, 0, sizeof(frame_info)); |
129 ComPtr<IDXGIResource> resource; | 134 ComPtr<IDXGIResource> resource; |
130 _com_error error = duplication_->AcquireNextFrame( | 135 _com_error error = duplication_->AcquireNextFrame( |
131 kAcquireTimeoutMs, &frame_info, resource.GetAddressOf()); | 136 kAcquireTimeoutMs, &frame_info, resource.GetAddressOf()); |
132 if (error.Error() != S_OK && error.Error() != DXGI_ERROR_WAIT_TIMEOUT) { | 137 if (error.Error() != S_OK && error.Error() != DXGI_ERROR_WAIT_TIMEOUT) { |
133 LOG(LS_ERROR) << "Failed to capture frame, error " << error.ErrorMessage() | 138 LOG(LS_ERROR) << "Failed to capture frame, error " << error.ErrorMessage() |
134 << ", code " << error.Error(); | 139 << ", code " << error.Error(); |
135 return false; | 140 return false; |
136 } | 141 } |
137 | 142 |
138 // We need to merge updated region with the one from last frame, since current | 143 // We need to merge updated region with the one from last frame, since current |
139 // frame contains the content one frame before. Note, this is for double | 144 // frame contains the content one frame before. Note, this is for double |
140 // buffering implementation, as what we have in ScreenCapturerWinDirectx. If | 145 // buffering implementation, as what we have in ScreenCapturerWinDirectx. If |
141 // a consumer uses single buffering, we should clear context->updated_region | 146 // a consumer uses single buffering, we should clear context->updated_region |
142 // after it has been merged to updated_region. | 147 // after it has been merged to updated_region. |
143 DesktopRegion updated_region = context->updated_region; | 148 DesktopRegion updated_region; |
| 149 updated_region.Swap(&context->updated_region); |
144 if (error.Error() == S_OK && frame_info.AccumulatedFrames > 0) { | 150 if (error.Error() == S_OK && frame_info.AccumulatedFrames > 0) { |
145 DetectUpdatedRegion(frame_info, offset, &context->updated_region); | 151 DetectUpdatedRegion(frame_info, offset, &context->updated_region); |
| 152 if (!texture_->CopyFrom(frame_info, resource.Get(), |
| 153 context->updated_region)) { |
| 154 return false; |
| 155 } |
146 SpreadContextChange(context); | 156 SpreadContextChange(context); |
147 updated_region.AddRegion(context->updated_region); | 157 updated_region.AddRegion(context->updated_region); |
148 if (!texture_->CopyFrom(frame_info, resource.Get(), updated_region)) { | |
149 return false; | |
150 } | |
151 | |
152 const DesktopFrame& source = texture_->AsDesktopFrame(); | 158 const DesktopFrame& source = texture_->AsDesktopFrame(); |
153 DesktopRect target_rect(DesktopRect::MakeSize(target->size())); | |
154 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); | 159 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); |
155 it.Advance()) { | 160 it.Advance()) { |
156 if (!target_rect.ContainsRect(it.rect())) { | |
157 // target size is not large enough to copy the pixel from texture. | |
158 return false; | |
159 } | |
160 target->CopyPixelsFrom(source, it.rect().top_left().subtract(offset), | 161 target->CopyPixelsFrom(source, it.rect().top_left().subtract(offset), |
161 it.rect()); | 162 it.rect()); |
162 } | 163 } |
| 164 last_frame_ = target->Share(); |
| 165 last_frame_offset_ = offset; |
163 target->mutable_updated_region()->AddRegion(updated_region); | 166 target->mutable_updated_region()->AddRegion(updated_region); |
164 return texture_->Release() && ReleaseFrame(); | 167 return texture_->Release() && ReleaseFrame(); |
165 } | 168 } |
166 | 169 |
167 if (last_frame != nullptr) { | 170 if (last_frame_) { |
168 // DxgiOutputDuplicatorContainer::Duplicate() makes sure target size and | |
169 // last frame size are consistent. | |
170 RTC_DCHECK(target->size().equals(last_frame->size())); | |
171 // No change since last frame or AcquireNextFrame() timed out, we will | 171 // No change since last frame or AcquireNextFrame() timed out, we will |
172 // export last frame to the target. | 172 // export last frame to the target. |
173 context->updated_region.Clear(); | 173 context->updated_region.Clear(); |
174 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); | 174 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); |
175 it.Advance()) { | 175 it.Advance()) { |
176 target->CopyPixelsFrom(*last_frame, it.rect().top_left(), it.rect()); | 176 target->CopyPixelsFrom(*last_frame_, last_frame_offset_, it.rect()); |
177 } | 177 } |
178 target->mutable_updated_region()->AddRegion(updated_region); | 178 target->mutable_updated_region()->AddRegion(updated_region); |
179 } | 179 } |
180 // If AcquireNextFrame() failed with timeout error, we do not need to release | 180 // If AcquireNextFrame() failed with timeout error, we do not need to release |
181 // the frame. | 181 // the frame. |
182 return error.Error() == DXGI_ERROR_WAIT_TIMEOUT || ReleaseFrame(); | 182 return error.Error() == DXGI_ERROR_WAIT_TIMEOUT || ReleaseFrame(); |
183 } | 183 } |
184 | 184 |
185 DesktopRect DxgiOutputDuplicator::TranslatedDesktopRect( | 185 DesktopRect DxgiOutputDuplicator::TranslatedDesktopRect( |
186 const DesktopVector offset) { | 186 const DesktopVector offset) { |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 | 295 |
296 void DxgiOutputDuplicator::SpreadContextChange(const Context* const source) { | 296 void DxgiOutputDuplicator::SpreadContextChange(const Context* const source) { |
297 for (Context* dest : contexts_) { | 297 for (Context* dest : contexts_) { |
298 if (dest != source) { | 298 if (dest != source) { |
299 dest->updated_region.AddRegion(source->updated_region); | 299 dest->updated_region.AddRegion(source->updated_region); |
300 } | 300 } |
301 } | 301 } |
302 } | 302 } |
303 | 303 |
304 } // namespace webrtc | 304 } // namespace webrtc |
OLD | NEW |