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

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

Issue 100833002: Add AshDesktopMediaList and enable Desktop Capture API on Chrome OS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years 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 | Annotate | Revision Log
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/ash_desktop_media_list.h"
6
7 #include <map>
8
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "base/hash.h"
12 #include "base/logging.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "cc/output/copy_output_request.h"
15 #include "cc/output/copy_output_result.h"
16 #include "chrome/browser/media/desktop_media_list_observer.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "grit/generated_resources.h"
19 #include "media/base/video_util.h"
20 #include "third_party/libyuv/include/libyuv/scale_argb.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/compositor/dip_util.h"
25 #include "ui/gfx/skia_util.h"
26
27 using content::BrowserThread;
28 using content::DesktopMediaID;
29
30 namespace {
31
32 // Update the list twice per second.
33 const int kDefaultUpdatePeriod = 500;
34
35 void ScaleBitmap(SkBitmap* captured_bitmap, SkBitmap* scaled_bitmap) {
36 libyuv::ARGBScale(reinterpret_cast<uint8*>(captured_bitmap->getPixels()),
37 captured_bitmap->rowBytes(),
38 captured_bitmap->width(), captured_bitmap->height(),
39 reinterpret_cast<uint8*>(scaled_bitmap->getPixels()),
40 scaled_bitmap->rowBytes(),
41 scaled_bitmap->width(), scaled_bitmap->height(),
42 libyuv::kFilterBilinear);
hshi1 2013/12/13 01:28:51 I am not familiar enough with libyuv and skia but
Sergey Ulanov 2013/12/13 02:54:29 Done. I used libyuv for scaling here because that'
43 }
44
45 } // namespace
46
47 AshDesktopMediaList::SourceDescription::SourceDescription(
48 DesktopMediaID id,
49 const string16& name)
50 : id(id),
51 name(name) {
52 }
53
54 AshDesktopMediaList::AshDesktopMediaList(int source_types)
55 : source_types_(source_types),
56 update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
57 thumbnail_size_(100, 100),
58 view_dialog_id_(-1),
59 observer_(NULL),
60 pending_window_capture_requests_(0),
61 weak_factory_(this) {
62 }
63
64 AshDesktopMediaList::~AshDesktopMediaList() {}
65
66 void AshDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) {
67 DCHECK(!observer_);
68 update_period_ = period;
69 }
70
71 void AshDesktopMediaList::SetThumbnailSize(
72 const gfx::Size& thumbnail_size) {
73 thumbnail_size_ = thumbnail_size;
74 }
75
76 void AshDesktopMediaList::SetViewDialogWindowId(
77 content::DesktopMediaID::Id dialog_id) {
78 view_dialog_id_ = dialog_id;
79 }
80
81 void AshDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) {
82 DCHECK(!observer_);
83
84 observer_ = observer;
85 Refresh();
86 }
87
88 int AshDesktopMediaList::GetSourceCount() const {
89 return sources_.size();
90 }
91
92 const DesktopMediaList::Source& AshDesktopMediaList::GetSource(
93 int index) const {
94 return sources_[index];
95 }
96
97 // static
98 bool AshDesktopMediaList::CompareSources(const SourceDescription& a,
99 const SourceDescription& b) {
100 return a.id < b.id;
101 }
102
103 void AshDesktopMediaList::Refresh() {
104 std::vector<SourceDescription> new_sources;
105 EnumerateSources(&new_sources);
106
107 // Sort the list of sources so that they appear in a predictable order.
108 std::sort(new_sources.begin(), new_sources.end(), CompareSources);
109
110 // Step through |new_sources| adding and removing entries from |sources_|, and
111 // notifying the |observer_|, until two match. Requires that |sources| and
112 // |sources_| have the same ordering.
113 size_t pos = 0;
114 while (pos < sources_.size() || pos < new_sources.size()) {
115 // If |sources_[pos]| is not in |new_sources| then remove it.
116 if (pos < sources_.size() &&
117 (pos == new_sources.size() || sources_[pos].id < new_sources[pos].id)) {
118 sources_.erase(sources_.begin() + pos);
119 observer_->OnSourceRemoved(pos);
120 continue;
121 }
122
123 if (pos == sources_.size() || !(sources_[pos].id == new_sources[pos].id)) {
124 sources_.insert(sources_.begin() + pos, Source());
125 sources_[pos].id = new_sources[pos].id;
126 sources_[pos].name = new_sources[pos].name;
127 observer_->OnSourceAdded(pos);
128 } else if (sources_[pos].name != new_sources[pos].name) {
129 sources_[pos].name = new_sources[pos].name;
130 observer_->OnSourceNameChanged(pos);
131 }
132
133 ++pos;
134 }
135
136 DCHECK_EQ(new_sources.size(), sources_.size());
137 }
138
139 void AshDesktopMediaList::EnumerateWindowsForRoot(
140 std::vector<AshDesktopMediaList::SourceDescription>* sources,
141 aura::Window* root_window,
142 int container_id) {
143 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
144
145 aura::Window* container = ash::Shell::GetContainer(root_window, container_id);
146 if (!container)
147 return;
148 for (aura::Window::Windows::const_iterator it = container->children().begin();
149 it != container->children().end(); ++it) {
150 if (!(*it)->IsVisible() || !(*it)->CanFocus())
151 continue;
152 content::DesktopMediaID id =
153 content::DesktopMediaID::RegisterAuraWindow(*it);
154 if (id.id == view_dialog_id_)
155 continue;
156 SourceDescription window_source(id, (*it)->title());
157 sources->push_back(window_source);
158
159 CaptureThumbnail(window_source.id, *it);
160 }
161 }
162
163 void AshDesktopMediaList::EnumerateSources(
164 std::vector<AshDesktopMediaList::SourceDescription>* sources) {
165 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
166
167 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
168
169 for (aura::Window::Windows::const_iterator iter = root_windows.begin();
170 iter != root_windows.end(); ++iter) {
171 if (source_types_ & SCREENS) {
172 SourceDescription screen_source(
173 content::DesktopMediaID::RegisterAuraWindow(*iter), (*iter)->title());
174 sources->push_back(screen_source);
175
176 CaptureThumbnail(screen_source.id, *iter);
177 }
178
179 if (source_types_ & WINDOWS) {
180 EnumerateWindowsForRoot(
181 sources, *iter, ash::internal::kShellWindowId_DefaultContainer);
182 EnumerateWindowsForRoot(
183 sources, *iter, ash::internal::kShellWindowId_AlwaysOnTopContainer);
184 EnumerateWindowsForRoot(
185 sources, *iter, ash::internal::kShellWindowId_DockedContainer);
186 }
187 }
188 }
189
190 void AshDesktopMediaList::CaptureThumbnail(content::DesktopMediaID id,
191 aura::Window* window) {
192 scoped_ptr<cc::CopyOutputRequest> request =
193 cc::CopyOutputRequest::CreateBitmapRequest(
194 base::Bind(&AshDesktopMediaList::OnThumbnailCaptured,
195 weak_factory_.GetWeakPtr(), id));
196 gfx::Rect window_rect = ui::ConvertRectToPixel(
197 window->layer(),
198 gfx::Rect(window->bounds().width(), window->bounds().height()));
199 request->set_area(window_rect);
200 window->layer()->RequestCopyOfOutput(request.Pass());
201 ++pending_window_capture_requests_;
202 }
203
204 void AshDesktopMediaList::OnThumbnailCaptured(
205 content::DesktopMediaID id,
206 scoped_ptr<cc::CopyOutputResult> result) {
207 if (result->IsEmpty()) {
208 OnFrameCaptureFinished();
209 return;
210 }
211
212 scoped_ptr<SkBitmap> captured_bitmap = result->TakeBitmap();
213
214 gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
215 gfx::Rect(thumbnail_size_),
216 gfx::Size(result->size().width(), result->size().height()));
217
218 scoped_ptr<SkBitmap> scaled_bitmap(new SkBitmap);
219 scaled_bitmap->setConfig(SkBitmap::kARGB_8888_Config,
220 scaled_rect.width(), scaled_rect.height(),
221 0, kOpaque_SkAlphaType);
222 scaled_bitmap->allocPixels();
223
224 scaled_bitmap->lockPixels();
225 captured_bitmap->lockPixels();
226
227 // TODO(sergeyu): Potentially images can be scaled on GPU before reading it
228 // from GPU. Image scaling is implemented in content::GlHelper, but it's can't
229 // be used here because it's not in content/public. Move the scaling code
230 // somewhere so that it can be reused here.
231 BrowserThread::PostBlockingPoolTaskAndReply(
232 FROM_HERE,
233 base::Bind(&ScaleBitmap, captured_bitmap.get(), scaled_bitmap.get()),
234 base::Bind(&AshDesktopMediaList::OnFrameScalingFinished,
235 weak_factory_.GetWeakPtr(), id,
236 base::Passed(&captured_bitmap),
237 base::Passed(&scaled_bitmap)));
238 }
239
240 void AshDesktopMediaList::OnFrameScalingFinished(
241 content::DesktopMediaID id,
242 scoped_ptr<SkBitmap> captured_bitmap,
243 scoped_ptr<SkBitmap> scaled_bitmap) {
244 scaled_bitmap->unlockPixels();
245 captured_bitmap->unlockPixels();
246
247 for (size_t i = 0; i < sources_.size(); ++i) {
248 if (sources_[i].id == id) {
249 sources_[i].thumbnail =
250 gfx::ImageSkia::CreateFrom1xBitmap(*scaled_bitmap);
251 observer_->OnSourceThumbnailChanged(i);
252 break;
253 }
254 }
255
256 OnFrameCaptureFinished();
257 }
258
259 void AshDesktopMediaList::OnFrameCaptureFinished() {
260 --pending_window_capture_requests_;
261 DCHECK_GE(pending_window_capture_requests_, 0);
262 if (!pending_window_capture_requests_) {
263 BrowserThread::PostDelayedTask(
264 BrowserThread::UI, FROM_HERE,
265 base::Bind(&AshDesktopMediaList::Refresh,
266 weak_factory_.GetWeakPtr()),
267 update_period_);
268 }
269 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698