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

Side by Side Diff: chrome/browser/media/native_desktop_media_list.cc

Issue 1763753003: Capture chrome browser windows from internal rendering procedure for windows and linux (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/media/native_desktop_media_list.h" 5 #include "chrome/browser/media/native_desktop_media_list.h"
6 6
7 #include "base/hash.h" 7 #include "base/hash.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "base/threading/sequenced_worker_pool.h" 9 #include "base/threading/sequenced_worker_pool.h"
10 #include "chrome/browser/media/desktop_media_list_observer.h" 10 #include "chrome/browser/media/desktop_media_list_observer.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_list.h"
13 #include "chrome/browser/ui/browser_window.h"
11 #include "chrome/grit/generated_resources.h" 14 #include "chrome/grit/generated_resources.h"
12 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
13 #include "media/base/video_util.h" 16 #include "media/base/video_util.h"
14 #include "third_party/libyuv/include/libyuv/scale_argb.h" 17 #include "third_party/libyuv/include/libyuv/scale_argb.h"
15 #include "third_party/skia/include/core/SkBitmap.h" 18 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
17 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" 20 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
18 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" 21 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_tree_host.h"
19 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/gfx/native_widget_types.h"
26 #include "ui/snapshot/snapshot.h"
20 27
21 using content::BrowserThread; 28 using content::BrowserThread;
22 using content::DesktopMediaID;
23 29
24 namespace { 30 namespace {
25 31
26 // Update the list every second. 32 // Update the list every second.
27 const int kDefaultUpdatePeriod = 1000; 33 const int kDefaultUpdatePeriod = 1000;
28 34
29 // Returns a hash of a DesktopFrame content to detect when image for a desktop 35 // Returns a hash of a DesktopFrame content to detect when image for a desktop
30 // media source has changed. 36 // media source has changed.
31 uint32_t GetFrameHash(webrtc::DesktopFrame* frame) { 37 uint32_t GetFrameHash(webrtc::DesktopFrame* frame) {
32 int data_size = frame->stride() * frame->size().height(); 38 int data_size = frame->stride() * frame->size().height();
33 return base::SuperFastHash(reinterpret_cast<char*>(frame->data()), data_size); 39 return base::Hash(reinterpret_cast<char*>(frame->data()), data_size);
34 } 40 }
35 41
36 gfx::ImageSkia ScaleDesktopFrame(scoped_ptr<webrtc::DesktopFrame> frame, 42 gfx::ImageSkia ScaleDesktopFrame(scoped_ptr<webrtc::DesktopFrame> frame,
37 gfx::Size size) { 43 gfx::Size size) {
38 gfx::Rect scaled_rect = media::ComputeLetterboxRegion( 44 gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
39 gfx::Rect(0, 0, size.width(), size.height()), 45 gfx::Rect(0, 0, size.width(), size.height()),
40 gfx::Size(frame->size().width(), frame->size().height())); 46 gfx::Size(frame->size().width(), frame->size().height()));
41 47
42 SkBitmap result; 48 SkBitmap result;
43 result.allocN32Pixels(scaled_rect.width(), scaled_rect.height(), true); 49 result.allocN32Pixels(scaled_rect.width(), scaled_rect.height(), true);
(...skipping 27 matching lines...) Expand all
71 77
72 class NativeDesktopMediaList::Worker 78 class NativeDesktopMediaList::Worker
73 : public webrtc::DesktopCapturer::Callback { 79 : public webrtc::DesktopCapturer::Callback {
74 public: 80 public:
75 Worker(base::WeakPtr<NativeDesktopMediaList> media_list, 81 Worker(base::WeakPtr<NativeDesktopMediaList> media_list,
76 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, 82 scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
77 scoped_ptr<webrtc::WindowCapturer> window_capturer); 83 scoped_ptr<webrtc::WindowCapturer> window_capturer);
78 ~Worker() override; 84 ~Worker() override;
79 85
80 void Refresh(const gfx::Size& thumbnail_size, 86 void Refresh(const gfx::Size& thumbnail_size,
81 content::DesktopMediaID::Id view_dialog_id); 87 DesktopMediaID::Id view_dialog_id,
88 NativeAuraIdMap native_aura_id_map);
82 89
83 private: 90 private:
84 typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap; 91 typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap;
85 92
86 // webrtc::DesktopCapturer::Callback interface. 93 // webrtc::DesktopCapturer::Callback interface.
87 void OnCaptureCompleted(webrtc::DesktopFrame* frame) override; 94 void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
88 95
89 base::WeakPtr<NativeDesktopMediaList> media_list_; 96 base::WeakPtr<NativeDesktopMediaList> media_list_;
90 97
91 scoped_ptr<webrtc::ScreenCapturer> screen_capturer_; 98 scoped_ptr<webrtc::ScreenCapturer> screen_capturer_;
(...skipping 16 matching lines...) Expand all
108 if (screen_capturer_) 115 if (screen_capturer_)
109 screen_capturer_->Start(this); 116 screen_capturer_->Start(this);
110 if (window_capturer_) 117 if (window_capturer_)
111 window_capturer_->Start(this); 118 window_capturer_->Start(this);
112 } 119 }
113 120
114 NativeDesktopMediaList::Worker::~Worker() {} 121 NativeDesktopMediaList::Worker::~Worker() {}
115 122
116 void NativeDesktopMediaList::Worker::Refresh( 123 void NativeDesktopMediaList::Worker::Refresh(
117 const gfx::Size& thumbnail_size, 124 const gfx::Size& thumbnail_size,
118 content::DesktopMediaID::Id view_dialog_id) { 125 DesktopMediaID::Id view_dialog_id,
126 NativeAuraIdMap native_aura_id_map) {
119 std::vector<SourceDescription> sources; 127 std::vector<SourceDescription> sources;
128 std::vector<DesktopMediaID> aura_media_ids;
120 129
121 if (screen_capturer_) { 130 if (screen_capturer_) {
122 webrtc::ScreenCapturer::ScreenList screens; 131 webrtc::ScreenCapturer::ScreenList screens;
123 if (screen_capturer_->GetScreenList(&screens)) { 132 if (screen_capturer_->GetScreenList(&screens)) {
124 bool mutiple_screens = screens.size() > 1; 133 bool mutiple_screens = screens.size() > 1;
125 base::string16 title; 134 base::string16 title;
126 for (size_t i = 0; i < screens.size(); ++i) { 135 for (size_t i = 0; i < screens.size(); ++i) {
127 if (mutiple_screens) { 136 if (mutiple_screens) {
128 title = l10n_util::GetStringFUTF16Int( 137 title = l10n_util::GetStringFUTF16Int(
129 IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME, 138 IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME,
130 static_cast<int>(i + 1)); 139 static_cast<int>(i + 1));
131 } else { 140 } else {
132 title = l10n_util::GetStringUTF16( 141 title = l10n_util::GetStringUTF16(
133 IDS_DESKTOP_MEDIA_PICKER_SINGLE_SCREEN_NAME); 142 IDS_DESKTOP_MEDIA_PICKER_SINGLE_SCREEN_NAME);
134 } 143 }
135 sources.push_back(SourceDescription(DesktopMediaID( 144 sources.push_back(SourceDescription(DesktopMediaID(
136 DesktopMediaID::TYPE_SCREEN, screens[i].id), title)); 145 DesktopMediaID::TYPE_SCREEN, screens[i].id), title));
137 } 146 }
138 } 147 }
139 } 148 }
140 149
141 if (window_capturer_) { 150 if (window_capturer_) {
142 webrtc::WindowCapturer::WindowList windows; 151 webrtc::WindowCapturer::WindowList windows;
143 if (window_capturer_->GetWindowList(&windows)) { 152 if (window_capturer_->GetWindowList(&windows)) {
144 for (webrtc::WindowCapturer::WindowList::iterator it = windows.begin(); 153 for (webrtc::WindowCapturer::WindowList::iterator it = windows.begin();
145 it != windows.end(); ++it) { 154 it != windows.end(); ++it) {
146 // Skip the picker dialog window. 155 // Skip the picker dialog window.
147 if (it->id != view_dialog_id) { 156 if (it->id != view_dialog_id) {
148 sources.push_back(SourceDescription( 157 DesktopMediaID media_id(DesktopMediaID::TYPE_WINDOW, it->id);
149 DesktopMediaID(DesktopMediaID::TYPE_WINDOW, it->id), 158 #if defined(USE_AURA)
150 base::UTF8ToUTF16(it->title))); 159 // Associate aura id with native id.
160 if (native_aura_id_map.count(media_id.id)) {
161 media_id.aura_id = native_aura_id_map[media_id.id];
Sergey Ulanov 2016/03/10 00:46:07 nit: here you search the map twice, which can be a
GeorgeZ 2016/03/10 21:18:46 good point.
162 aura_media_ids.push_back(media_id);
163 }
164 #endif
165 sources.push_back(
166 SourceDescription(media_id, base::UTF8ToUTF16(it->title)));
151 } 167 }
152 } 168 }
153 } 169 }
154 } 170 }
171
155 // Update list of windows before updating thumbnails. 172 // Update list of windows before updating thumbnails.
156 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 173 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
157 base::Bind(&NativeDesktopMediaList::UpdateSourcesList, 174 base::Bind(&NativeDesktopMediaList::UpdateSourcesList,
158 media_list_, sources)); 175 media_list_, sources));
159 176
160 ImageHashesMap new_image_hashes; 177 ImageHashesMap new_image_hashes;
161 178
162 // Get a thumbnail for each source. 179 // Get a thumbnail for each source.
163 for (size_t i = 0; i < sources.size(); ++i) { 180 for (size_t i = 0; i < sources.size(); ++i) {
164 SourceDescription& source = sources[i]; 181 SourceDescription& source = sources[i];
182
165 switch (source.id.type) { 183 switch (source.id.type) {
166 case DesktopMediaID::TYPE_SCREEN: 184 case DesktopMediaID::TYPE_SCREEN:
167 if (!screen_capturer_->SelectScreen(source.id.id)) 185 if (!screen_capturer_->SelectScreen(source.id.id))
168 continue; 186 continue;
169 screen_capturer_->Capture(webrtc::DesktopRegion()); 187 screen_capturer_->Capture(webrtc::DesktopRegion());
170 break; 188 break;
171 189
172 case DesktopMediaID::TYPE_WINDOW: 190 case DesktopMediaID::TYPE_WINDOW:
191 #if defined(USE_AURA)
192 // Aura window thumbmail capture is skipped here. It will be done later.
Sergey Ulanov 2016/03/10 00:46:07 maybe also mention the UI thread. Otherwise it's n
GeorgeZ 2016/03/10 21:18:46 I will also mention it will be done asynchronously
193 if (source.id.aura_id > DesktopMediaID::kNullId)
194 continue;
195 #endif
173 if (!window_capturer_->SelectWindow(source.id.id)) 196 if (!window_capturer_->SelectWindow(source.id.id))
174 continue; 197 continue;
175 window_capturer_->Capture(webrtc::DesktopRegion()); 198 window_capturer_->Capture(webrtc::DesktopRegion());
176 break; 199 break;
177 200
178 default: 201 default:
179 NOTREACHED(); 202 NOTREACHED();
180 } 203 }
181 204
182 // Expect that DesktopCapturer to always captures frames synchronously. 205 // Expect that DesktopCapturer to always captures frames synchronously.
183 // |current_frame_| may be NULL if capture failed (e.g. because window has 206 // |current_frame_| may be NULL if capture failed (e.g. because window has
184 // been closed). 207 // been closed).
185 if (current_frame_) { 208 if (current_frame_) {
186 uint32_t frame_hash = GetFrameHash(current_frame_.get()); 209 uint32_t frame_hash = GetFrameHash(current_frame_.get());
187 new_image_hashes[source.id] = frame_hash; 210 new_image_hashes[source.id] = frame_hash;
188 211
189 // Scale the image only if it has changed. 212 // Scale the image only if it has changed.
190 ImageHashesMap::iterator it = image_hashes_.find(source.id); 213 ImageHashesMap::iterator it = image_hashes_.find(source.id);
191 if (it == image_hashes_.end() || it->second != frame_hash) { 214 if (it == image_hashes_.end() || it->second != frame_hash) {
192 gfx::ImageSkia thumbnail = 215 gfx::ImageSkia thumbnail =
193 ScaleDesktopFrame(std::move(current_frame_), thumbnail_size); 216 ScaleDesktopFrame(std::move(current_frame_), thumbnail_size);
194 BrowserThread::PostTask( 217 BrowserThread::PostTask(
195 BrowserThread::UI, FROM_HERE, 218 BrowserThread::UI, FROM_HERE,
196 base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, media_list_, 219 base::Bind(&NativeDesktopMediaList::OnSourceThumbnailCaptured,
197 i, thumbnail)); 220 media_list_, i, thumbnail));
198 } 221 }
199 } 222 }
200 } 223 }
201 224
202 image_hashes_.swap(new_image_hashes); 225 image_hashes_.swap(new_image_hashes);
203 226
227 // Aura thumbnail captures have to be done in UI thread. After they are done,
228 // a refresh will be scheduled.
204 BrowserThread::PostTask( 229 BrowserThread::PostTask(
205 BrowserThread::UI, FROM_HERE, 230 BrowserThread::UI, FROM_HERE,
206 base::Bind(&NativeDesktopMediaList::ScheduleNextRefresh, media_list_)); 231 base::Bind(
232 &NativeDesktopMediaList::FinishRefreshOnUiThreadAndScheduleNext,
233 media_list_, aura_media_ids));
207 } 234 }
208 235
209 void NativeDesktopMediaList::Worker::OnCaptureCompleted( 236 void NativeDesktopMediaList::Worker::OnCaptureCompleted(
210 webrtc::DesktopFrame* frame) { 237 webrtc::DesktopFrame* frame) {
211 current_frame_.reset(frame); 238 current_frame_.reset(frame);
212 } 239 }
213 240
214 NativeDesktopMediaList::NativeDesktopMediaList( 241 NativeDesktopMediaList::NativeDesktopMediaList(
215 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, 242 scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
216 scoped_ptr<webrtc::WindowCapturer> window_capturer) 243 scoped_ptr<webrtc::WindowCapturer> window_capturer)
217 : DesktopMediaListBase( 244 : DesktopMediaListBase(
218 base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), 245 base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
219 weak_factory_(this) { 246 weak_factory_(this) {
220 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); 247 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
221 capture_task_runner_ = worker_pool->GetSequencedTaskRunner( 248 capture_task_runner_ = worker_pool->GetSequencedTaskRunner(
222 worker_pool->GetSequenceToken()); 249 worker_pool->GetSequenceToken());
223 250
224 worker_.reset(new Worker(weak_factory_.GetWeakPtr(), 251 worker_.reset(new Worker(weak_factory_.GetWeakPtr(),
225 std::move(screen_capturer), 252 std::move(screen_capturer),
226 std::move(window_capturer))); 253 std::move(window_capturer)));
227 } 254 }
228 255
229 NativeDesktopMediaList::~NativeDesktopMediaList() { 256 NativeDesktopMediaList::~NativeDesktopMediaList() {
230 capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release()); 257 capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release());
231 } 258 }
232 259
233 void NativeDesktopMediaList::Refresh() { 260 void NativeDesktopMediaList::Refresh() {
261 NativeAuraIdMap native_aura_id_map;
262 #if defined(USE_AURA)
263 native_aura_id_map = GetBrowserNativeAuraIdMap();
264 #endif
265 processed_aura_window_count_ = 0;
266 new_aura_thumbnail_hashes_.clear();
267
234 capture_task_runner_->PostTask( 268 capture_task_runner_->PostTask(
235 FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), 269 FROM_HERE,
236 thumbnail_size_, view_dialog_id_.id)); 270 base::Bind(&Worker::Refresh, base::Unretained(worker_.get()),
271 thumbnail_size_, view_dialog_id_.id, native_aura_id_map));
237 } 272 }
238 273
239 void NativeDesktopMediaList::OnSourceThumbnail(int index, 274 void NativeDesktopMediaList::OnSourceThumbnailCaptured(
240 const gfx::ImageSkia& image) { 275 int index,
276 const gfx::ImageSkia& image) {
241 UpdateSourceThumbnail(GetSource(index).id, image); 277 UpdateSourceThumbnail(GetSource(index).id, image);
242 } 278 }
279
280 void NativeDesktopMediaList::FinishRefreshOnUiThreadAndScheduleNext(
281 std::vector<DesktopMediaID> aura_ids) {
Sergey Ulanov 2016/03/10 00:46:07 use const reference for the parameter
GeorgeZ 2016/03/10 21:18:46 Done.
282 // Schedule a refresh here when there is no aura thumbanil capture or schedule
283 // a refresh in OnAuraThumbnailCaptured() after all aura thumbnails are
284 // captured.
285 total_aura_windows_ = aura_ids.size();
Sergey Ulanov 2016/03/10 00:46:07 Instead of having both processed_aura_window_count
Sergey Ulanov 2016/03/10 00:46:07 Add a DCHECK here to verify there are no pending c
GeorgeZ 2016/03/10 21:18:46 Done.
GeorgeZ 2016/03/10 21:18:46 Done.
286 if (total_aura_windows_ == 0) {
287 ScheduleNextRefresh();
288 return;
289 }
290
291 for (const auto& aura_id : aura_ids) {
292 CaptureAuraWindowThumbnail(aura_id);
293 }
294 }
295
296 void NativeDesktopMediaList::OnAuraThumbnailCaptured(DesktopMediaID id,
297 const gfx::Image& image) {
298 if (!image.IsEmpty()) {
299 // Only new or changed thumbnail need update.
300 new_aura_thumbnail_hashes_[id] = DesktopMediaListBase::GetImageHash(image);
301 if (!previous_aura_thumbnail_hashes_.count(id) ||
302 previous_aura_thumbnail_hashes_[id] != new_aura_thumbnail_hashes_[id]) {
303 UpdateSourceThumbnail(id, image.AsImageSkia());
304 }
305 }
306
307 // After all aura windows are processed, schedule next refresh;
308 processed_aura_window_count_++;
309 if (processed_aura_window_count_ == total_aura_windows_) {
310 swap(previous_aura_thumbnail_hashes_, new_aura_thumbnail_hashes_);
Sergey Ulanov 2016/03/10 00:46:07 nit: previous_aura_thumbnail_hashes_ = std::move
GeorgeZ 2016/03/10 21:18:46 good point.
311 ScheduleNextRefresh();
312 }
313 }
314
315 #if defined(USE_AURA)
316
317 NativeDesktopMediaList::NativeAuraIdMap
318 NativeDesktopMediaList::GetBrowserNativeAuraIdMap() {
Sergey Ulanov 2016/03/10 00:46:07 This function doesn't need to be a class member. M
GeorgeZ 2016/03/10 21:18:46 Done.
319 NativeAuraIdMap id_map;
320 for (auto* browser : *BrowserList::GetInstance()) {
321 const BrowserWindow* browser_window = browser->window();
Sergey Ulanov 2016/03/10 00:46:07 nit: I don't think you need this variable. Just us
GeorgeZ 2016/03/10 21:18:46 Done.
322 if (!browser_window)
323 continue;
324 const gfx::NativeWindow native_window = browser_window->GetNativeWindow();
Sergey Ulanov 2016/03/10 00:46:08 Suggest changing this to: aura::Window* aura_win
GeorgeZ 2016/03/10 21:18:46 Done.
325 if (!native_window)
326 continue;
327 aura::WindowTreeHost* host = native_window->GetHost();
328 if (!host)
329 continue;
330 gfx::AcceleratedWidget widget = host->GetAcceleratedWidget();
331 #if defined(OS_WIN)
332 DesktopMediaID::Id native_id = reinterpret_cast<DesktopMediaID::Id>(widget);
333 #else
334 DesktopMediaID::Id native_id = widget;
335 #endif
336 DesktopMediaID media_id = DesktopMediaID::RegisterAuraWindow(
337 DesktopMediaID::TYPE_WINDOW, native_window);
338 id_map.insert(std::make_pair(native_id, media_id.aura_id));
Sergey Ulanov 2016/03/10 00:46:07 nit: id_map[native_id] = media_id.aura_id; That wo
GeorgeZ 2016/03/10 21:18:46 Done.
339 }
340
341 return id_map;
342 }
343
344 void NativeDesktopMediaList::CaptureAuraWindowThumbnail(DesktopMediaID id) {
345 gfx::NativeWindow window = DesktopMediaID::GetAuraWindowById(id);
346 if (!window) {
347 OnAuraThumbnailCaptured(id, gfx::Image());
348 return;
349 }
350
351 gfx::Rect window_rect(window->bounds().width(), window->bounds().height());
352 gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
353 gfx::Rect(thumbnail_size_), window_rect.size());
354
355 ui::GrabWindowSnapshotAndScaleAsync(
356 window, window_rect, scaled_rect.size(), BrowserThread::GetBlockingPool(),
357 base::Bind(&NativeDesktopMediaList::OnAuraThumbnailCaptured,
358 weak_factory_.GetWeakPtr(), id));
359 }
360
361 #endif // defined(USE_AURA)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698