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

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

Issue 2307083002: Cleanup: move WebRTC related files from chrome/browser/media to chrome/browser/media/webrtc/ (Closed)
Patch Set: Removed file wrongly resuscitated during rebase Created 4 years, 3 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/media/native_desktop_media_list.h"
6
7 #include "base/hash.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/threading/sequenced_worker_pool.h"
10 #include "chrome/browser/media/desktop_media_list_observer.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "media/base/video_util.h"
14 #include "third_party/libyuv/include/libyuv/scale_argb.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
17 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
18 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
19 #include "ui/aura/window.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/snapshot/snapshot.h"
22
23 #if defined(OS_WIN)
24 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
25 #endif // defined(OS_WIN)
26
27 #if defined(USE_X11) && !defined(OS_CHROMEOS)
28 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
29 #endif // defined(USE_X11) && !defined(OS_CHROMEOS)
30
31 using content::BrowserThread;
32 using content::DesktopMediaID;
33
34 namespace {
35
36 // Update the list every second.
37 const int kDefaultUpdatePeriod = 1000;
38
39 // Returns a hash of a DesktopFrame content to detect when image for a desktop
40 // media source has changed.
41 uint32_t GetFrameHash(webrtc::DesktopFrame* frame) {
42 int data_size = frame->stride() * frame->size().height();
43 return base::Hash(reinterpret_cast<char*>(frame->data()), data_size);
44 }
45
46 gfx::ImageSkia ScaleDesktopFrame(std::unique_ptr<webrtc::DesktopFrame> frame,
47 gfx::Size size) {
48 gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
49 gfx::Rect(0, 0, size.width(), size.height()),
50 gfx::Size(frame->size().width(), frame->size().height()));
51
52 SkBitmap result;
53 result.allocN32Pixels(scaled_rect.width(), scaled_rect.height(), true);
54 result.lockPixels();
55
56 uint8_t* pixels_data = reinterpret_cast<uint8_t*>(result.getPixels());
57 libyuv::ARGBScale(frame->data(), frame->stride(),
58 frame->size().width(), frame->size().height(),
59 pixels_data, result.rowBytes(),
60 scaled_rect.width(), scaled_rect.height(),
61 libyuv::kFilterBilinear);
62
63 // Set alpha channel values to 255 for all pixels.
64 // TODO(sergeyu): Fix screen/window capturers to capture alpha channel and
65 // remove this code. Currently screen/window capturers (at least some
66 // implementations) only capture R, G and B channels and set Alpha to 0.
67 // crbug.com/264424
68 for (int y = 0; y < result.height(); ++y) {
69 for (int x = 0; x < result.width(); ++x) {
70 pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3] =
71 0xff;
72 }
73 }
74
75 result.unlockPixels();
76
77 return gfx::ImageSkia::CreateFrom1xBitmap(result);
78 }
79
80 } // namespace
81
82 class NativeDesktopMediaList::Worker
83 : public webrtc::DesktopCapturer::Callback {
84 public:
85 Worker(base::WeakPtr<NativeDesktopMediaList> media_list,
86 std::unique_ptr<webrtc::ScreenCapturer> screen_capturer,
87 std::unique_ptr<webrtc::WindowCapturer> window_capturer);
88 ~Worker() override;
89
90 void Refresh(const DesktopMediaID::Id& view_dialog_id);
91
92 void RefreshThumbnails(const std::vector<DesktopMediaID>& native_ids,
93 const gfx::Size& thumbnail_size);
94
95 private:
96 typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap;
97
98 // webrtc::DesktopCapturer::Callback interface.
99 void OnCaptureResult(webrtc::DesktopCapturer::Result result,
100 std::unique_ptr<webrtc::DesktopFrame> frame) override;
101
102 base::WeakPtr<NativeDesktopMediaList> media_list_;
103
104 std::unique_ptr<webrtc::ScreenCapturer> screen_capturer_;
105 std::unique_ptr<webrtc::WindowCapturer> window_capturer_;
106
107 std::unique_ptr<webrtc::DesktopFrame> current_frame_;
108
109 ImageHashesMap image_hashes_;
110
111 DISALLOW_COPY_AND_ASSIGN(Worker);
112 };
113
114 NativeDesktopMediaList::Worker::Worker(
115 base::WeakPtr<NativeDesktopMediaList> media_list,
116 std::unique_ptr<webrtc::ScreenCapturer> screen_capturer,
117 std::unique_ptr<webrtc::WindowCapturer> window_capturer)
118 : media_list_(media_list),
119 screen_capturer_(std::move(screen_capturer)),
120 window_capturer_(std::move(window_capturer)) {
121 if (screen_capturer_)
122 screen_capturer_->Start(this);
123 if (window_capturer_)
124 window_capturer_->Start(this);
125 }
126
127 NativeDesktopMediaList::Worker::~Worker() {}
128
129 void NativeDesktopMediaList::Worker::Refresh(
130 const DesktopMediaID::Id& view_dialog_id) {
131 std::vector<SourceDescription> sources;
132
133 if (screen_capturer_) {
134 webrtc::ScreenCapturer::ScreenList screens;
135 if (screen_capturer_->GetScreenList(&screens)) {
136 bool mutiple_screens = screens.size() > 1;
137 base::string16 title;
138 for (size_t i = 0; i < screens.size(); ++i) {
139 if (mutiple_screens) {
140 // Just in case 'Screen' is inflected depending on the screen number,
141 // use plural formatter.
142 title = l10n_util::GetPluralStringFUTF16(
143 IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME,
144 static_cast<int>(i + 1));
145 } else {
146 title = l10n_util::GetStringUTF16(
147 IDS_DESKTOP_MEDIA_PICKER_SINGLE_SCREEN_NAME);
148 }
149 sources.push_back(SourceDescription(DesktopMediaID(
150 DesktopMediaID::TYPE_SCREEN, screens[i].id), title));
151 }
152 }
153 }
154
155 if (window_capturer_) {
156 webrtc::WindowCapturer::WindowList windows;
157 if (window_capturer_->GetWindowList(&windows)) {
158 for (webrtc::WindowCapturer::WindowList::iterator it = windows.begin();
159 it != windows.end(); ++it) {
160 // Skip the picker dialog window.
161 if (it->id == view_dialog_id)
162 continue;
163
164 DesktopMediaID media_id(DesktopMediaID::TYPE_WINDOW, it->id);
165 sources.push_back(
166 SourceDescription(media_id, base::UTF8ToUTF16(it->title)));
167 }
168 }
169 }
170
171 BrowserThread::PostTask(
172 BrowserThread::UI, FROM_HERE,
173 base::Bind(&NativeDesktopMediaList::RefreshForAuraWindows, media_list_,
174 sources));
175 }
176
177 void NativeDesktopMediaList::Worker::RefreshThumbnails(
178 const std::vector<DesktopMediaID>& native_ids,
179 const gfx::Size& thumbnail_size) {
180 ImageHashesMap new_image_hashes;
181
182 // Get a thumbnail for each native source.
183 for (const auto& id : native_ids) {
184 switch (id.type) {
185 case DesktopMediaID::TYPE_SCREEN:
186 if (!screen_capturer_->SelectScreen(id.id))
187 continue;
188 screen_capturer_->Capture(webrtc::DesktopRegion());
189 break;
190
191 case DesktopMediaID::TYPE_WINDOW:
192 if (!window_capturer_->SelectWindow(id.id))
193 continue;
194 window_capturer_->Capture(webrtc::DesktopRegion());
195 break;
196
197 default:
198 NOTREACHED();
199 }
200
201 // Expect that DesktopCapturer to always captures frames synchronously.
202 // |current_frame_| may be NULL if capture failed (e.g. because window has
203 // been closed).
204 if (current_frame_) {
205 uint32_t frame_hash = GetFrameHash(current_frame_.get());
206 new_image_hashes[id] = frame_hash;
207
208 // Scale the image only if it has changed.
209 ImageHashesMap::iterator it = image_hashes_.find(id);
210 if (it == image_hashes_.end() || it->second != frame_hash) {
211 gfx::ImageSkia thumbnail =
212 ScaleDesktopFrame(std::move(current_frame_), thumbnail_size);
213 BrowserThread::PostTask(
214 BrowserThread::UI, FROM_HERE,
215 base::Bind(&NativeDesktopMediaList::UpdateSourceThumbnail,
216 media_list_, id, thumbnail));
217 }
218 }
219 }
220
221 image_hashes_.swap(new_image_hashes);
222
223 BrowserThread::PostTask(
224 BrowserThread::UI, FROM_HERE,
225 base::Bind(&NativeDesktopMediaList::UpdateNativeThumbnailsFinished,
226 media_list_));
227 }
228
229 void NativeDesktopMediaList::Worker::OnCaptureResult(
230 webrtc::DesktopCapturer::Result result,
231 std::unique_ptr<webrtc::DesktopFrame> frame) {
232 current_frame_ = std::move(frame);
233 }
234
235 NativeDesktopMediaList::NativeDesktopMediaList(
236 std::unique_ptr<webrtc::ScreenCapturer> screen_capturer,
237 std::unique_ptr<webrtc::WindowCapturer> window_capturer)
238 : DesktopMediaListBase(
239 base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
240 weak_factory_(this) {
241 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
242 capture_task_runner_ = worker_pool->GetSequencedTaskRunner(
243 worker_pool->GetSequenceToken());
244
245 worker_.reset(new Worker(weak_factory_.GetWeakPtr(),
246 std::move(screen_capturer),
247 std::move(window_capturer)));
248 }
249
250 NativeDesktopMediaList::~NativeDesktopMediaList() {
251 capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release());
252 }
253
254 void NativeDesktopMediaList::Refresh() {
255 #if defined(USE_AURA)
256 DCHECK_EQ(pending_aura_capture_requests_, 0);
257 DCHECK(!pending_native_thumbnail_capture_);
258 new_aura_thumbnail_hashes_.clear();
259 #endif
260
261 capture_task_runner_->PostTask(
262 FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()),
263 view_dialog_id_.id));
264 }
265
266 void NativeDesktopMediaList::RefreshForAuraWindows(
267 std::vector<SourceDescription> sources) {
268 #if defined(USE_AURA)
269 // Associate aura id with native id.
270 for (auto& source : sources) {
271 if (source.id.type != DesktopMediaID::TYPE_WINDOW)
272 continue;
273
274 aura::Window* aura_window = NULL;
275 #if defined(OS_WIN)
276 aura_window = views::DesktopWindowTreeHostWin::GetContentWindowForHWND(
277 reinterpret_cast<HWND>(source.id.id));
278 #elif defined(USE_X11) && !defined(OS_CHROMEOS)
279 aura_window =
280 views::DesktopWindowTreeHostX11::GetContentWindowForXID(source.id.id);
281 #endif // defined(USE_X11) && !defined(OS_CHROMEOS)
282 if (aura_window) {
283 DesktopMediaID aura_id = DesktopMediaID::RegisterAuraWindow(
284 DesktopMediaID::TYPE_WINDOW, aura_window);
285 source.id.aura_id = aura_id.aura_id;
286 }
287 }
288 #endif // defined(USE_AURA)
289
290 UpdateSourcesList(sources);
291
292 // OnAuraThumbnailCaptured() and UpdateNativeThumbnailsFinished() are
293 // guaranteed to be excuted after RefreshForAuraWindows() and
294 // CaptureAuraWindowThumbnail() in the browser UI thread.
295 // Therefore pending_aura_capture_requests_ will be set the number of aura
296 // windows to be captured and pending_native_thumbnail_capture_ will be set
297 // true if native thumbnail capture is needed before OnAuraThumbnailCaptured()
298 // or UpdateNativeThumbnailsFinished() are called.
299 std::vector<DesktopMediaID> native_ids;
300 for (const auto& source : sources) {
301 #if defined(USE_AURA)
302 if (source.id.aura_id > DesktopMediaID::kNullId) {
303 CaptureAuraWindowThumbnail(source.id);
304 continue;
305 }
306 #endif // defined(USE_AURA)
307 native_ids.push_back(source.id);
308 }
309
310 if (native_ids.size() > 0) {
311 #if defined(USE_AURA)
312 pending_native_thumbnail_capture_ = true;
313 #endif
314 capture_task_runner_->PostTask(
315 FROM_HERE,
316 base::Bind(&Worker::RefreshThumbnails, base::Unretained(worker_.get()),
317 native_ids, thumbnail_size_));
318 }
319 }
320
321 void NativeDesktopMediaList::UpdateNativeThumbnailsFinished() {
322 #if defined(USE_AURA)
323 DCHECK(pending_native_thumbnail_capture_);
324 pending_native_thumbnail_capture_ = false;
325 // Schedule next refresh if native thumbnail captures finished after aura
326 // thumbnail captures.
327 if (pending_aura_capture_requests_ == 0)
328 ScheduleNextRefresh();
329 #else
330 ScheduleNextRefresh();
331 #endif // defined(USE_AURA)
332 }
333
334 #if defined(USE_AURA)
335
336 void NativeDesktopMediaList::CaptureAuraWindowThumbnail(
337 const DesktopMediaID& id) {
338 gfx::NativeWindow window = DesktopMediaID::GetAuraWindowById(id);
339 if (!window)
340 return;
341
342 gfx::Rect window_rect(window->bounds().width(), window->bounds().height());
343 gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
344 gfx::Rect(thumbnail_size_), window_rect.size());
345
346 pending_aura_capture_requests_++;
347 ui::GrabWindowSnapshotAndScaleAsync(
348 window, window_rect, scaled_rect.size(), BrowserThread::GetBlockingPool(),
349 base::Bind(&NativeDesktopMediaList::OnAuraThumbnailCaptured,
350 weak_factory_.GetWeakPtr(), id));
351 }
352
353 void NativeDesktopMediaList::OnAuraThumbnailCaptured(const DesktopMediaID& id,
354 const gfx::Image& image) {
355 if (!image.IsEmpty()) {
356 // Only new or changed thumbnail need update.
357 new_aura_thumbnail_hashes_[id] = GetImageHash(image);
358 if (!previous_aura_thumbnail_hashes_.count(id) ||
359 previous_aura_thumbnail_hashes_[id] != new_aura_thumbnail_hashes_[id]) {
360 UpdateSourceThumbnail(id, image.AsImageSkia());
361 }
362 }
363
364 // After all aura windows are processed, schedule next refresh;
365 pending_aura_capture_requests_--;
366 DCHECK_GE(pending_aura_capture_requests_, 0);
367 if (pending_aura_capture_requests_ == 0) {
368 previous_aura_thumbnail_hashes_ = std::move(new_aura_thumbnail_hashes_);
369 // Schedule next refresh if aura thumbnail captures finished after native
370 // thumbnail captures.
371 if (!pending_native_thumbnail_capture_)
372 ScheduleNextRefresh();
373 }
374 }
375
376 #endif // defined(USE_AURA)
OLDNEW
« no previous file with comments | « chrome/browser/media/native_desktop_media_list.h ('k') | chrome/browser/media/native_desktop_media_list_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698