OLD | NEW |
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/desktop_media_picker_model.h" | 5 #include "chrome/browser/media/native_desktop_media_list.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/hash.h" | 9 #include "base/hash.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "base/threading/sequenced_worker_pool.h" | 12 #include "base/threading/sequenced_worker_pool.h" |
| 13 #include "chrome/browser/media/desktop_media_list_observer.h" |
13 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
14 #include "grit/generated_resources.h" | 15 #include "grit/generated_resources.h" |
15 #include "media/base/video_util.h" | 16 #include "media/base/video_util.h" |
16 #include "third_party/libyuv/include/libyuv/scale_argb.h" | 17 #include "third_party/libyuv/include/libyuv/scale_argb.h" |
17 #include "third_party/skia/include/core/SkBitmap.h" | 18 #include "third_party/skia/include/core/SkBitmap.h" |
18 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
19 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" | 20 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" |
20 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" | 21 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" |
21 #include "ui/base/l10n/l10n_util.h" | 22 #include "ui/base/l10n/l10n_util.h" |
22 #include "ui/gfx/skia_util.h" | 23 #include "ui/gfx/skia_util.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 } | 69 } |
69 } | 70 } |
70 | 71 |
71 result.unlockPixels(); | 72 result.unlockPixels(); |
72 | 73 |
73 return gfx::ImageSkia::CreateFrom1xBitmap(result); | 74 return gfx::ImageSkia::CreateFrom1xBitmap(result); |
74 } | 75 } |
75 | 76 |
76 } // namespace | 77 } // namespace |
77 | 78 |
78 DesktopMediaPickerModel::Source::Source(DesktopMediaID id, const string16& name) | 79 NativeDesktopMediaList::SourceDescription::SourceDescription( |
79 : id(id), | |
80 name(name) { | |
81 } | |
82 | |
83 DesktopMediaPickerModelImpl::SourceDescription::SourceDescription( | |
84 DesktopMediaID id, | 80 DesktopMediaID id, |
85 const string16& name) | 81 const string16& name) |
86 : id(id), | 82 : id(id), |
87 name(name) { | 83 name(name) { |
88 } | 84 } |
89 | 85 |
90 class DesktopMediaPickerModelImpl::Worker | 86 class NativeDesktopMediaList::Worker |
91 : public webrtc::DesktopCapturer::Callback { | 87 : public webrtc::DesktopCapturer::Callback { |
92 public: | 88 public: |
93 Worker(base::WeakPtr<DesktopMediaPickerModelImpl> model, | 89 Worker(base::WeakPtr<NativeDesktopMediaList> media_list, |
94 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, | 90 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, |
95 scoped_ptr<webrtc::WindowCapturer> window_capturer); | 91 scoped_ptr<webrtc::WindowCapturer> window_capturer); |
96 virtual ~Worker(); | 92 virtual ~Worker(); |
97 | 93 |
98 void Refresh(const gfx::Size& thumbnail_size, | 94 void Refresh(const gfx::Size& thumbnail_size, |
99 content::DesktopMediaID::Id view_dialog_id); | 95 content::DesktopMediaID::Id view_dialog_id); |
100 | 96 |
101 private: | 97 private: |
102 typedef std::map<DesktopMediaID, uint32> ImageHashesMap; | 98 typedef std::map<DesktopMediaID, uint32> ImageHashesMap; |
103 | 99 |
104 // webrtc::DesktopCapturer::Callback interface. | 100 // webrtc::DesktopCapturer::Callback interface. |
105 virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE; | 101 virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE; |
106 virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE; | 102 virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE; |
107 | 103 |
108 base::WeakPtr<DesktopMediaPickerModelImpl> model_; | 104 base::WeakPtr<NativeDesktopMediaList> media_list_; |
109 | 105 |
110 scoped_ptr<webrtc::ScreenCapturer> screen_capturer_; | 106 scoped_ptr<webrtc::ScreenCapturer> screen_capturer_; |
111 scoped_ptr<webrtc::WindowCapturer> window_capturer_; | 107 scoped_ptr<webrtc::WindowCapturer> window_capturer_; |
112 | 108 |
113 scoped_ptr<webrtc::DesktopFrame> current_frame_; | 109 scoped_ptr<webrtc::DesktopFrame> current_frame_; |
114 | 110 |
115 ImageHashesMap image_hashes_; | 111 ImageHashesMap image_hashes_; |
116 | 112 |
117 DISALLOW_COPY_AND_ASSIGN(Worker); | 113 DISALLOW_COPY_AND_ASSIGN(Worker); |
118 }; | 114 }; |
119 | 115 |
120 DesktopMediaPickerModelImpl::Worker::Worker( | 116 NativeDesktopMediaList::Worker::Worker( |
121 base::WeakPtr<DesktopMediaPickerModelImpl> model, | 117 base::WeakPtr<NativeDesktopMediaList> media_list, |
122 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, | 118 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, |
123 scoped_ptr<webrtc::WindowCapturer> window_capturer) | 119 scoped_ptr<webrtc::WindowCapturer> window_capturer) |
124 : model_(model), | 120 : media_list_(media_list), |
125 screen_capturer_(screen_capturer.Pass()), | 121 screen_capturer_(screen_capturer.Pass()), |
126 window_capturer_(window_capturer.Pass()) { | 122 window_capturer_(window_capturer.Pass()) { |
127 if (screen_capturer_) | 123 if (screen_capturer_) |
128 screen_capturer_->Start(this); | 124 screen_capturer_->Start(this); |
129 if (window_capturer_) | 125 if (window_capturer_) |
130 window_capturer_->Start(this); | 126 window_capturer_->Start(this); |
131 } | 127 } |
132 | 128 |
133 DesktopMediaPickerModelImpl::Worker::~Worker() {} | 129 NativeDesktopMediaList::Worker::~Worker() {} |
134 | 130 |
135 void DesktopMediaPickerModelImpl::Worker::Refresh( | 131 void NativeDesktopMediaList::Worker::Refresh( |
136 const gfx::Size& thumbnail_size, | 132 const gfx::Size& thumbnail_size, |
137 content::DesktopMediaID::Id view_dialog_id) { | 133 content::DesktopMediaID::Id view_dialog_id) { |
138 std::vector<SourceDescription> sources; | 134 std::vector<SourceDescription> sources; |
139 | 135 |
140 if (screen_capturer_) { | 136 if (screen_capturer_) { |
141 // TODO(sergeyu): Enumerate each screen when ScreenCapturer supports it. | 137 // TODO(sergeyu): Enumerate each screen when ScreenCapturer supports it. |
142 sources.push_back(SourceDescription(DesktopMediaID( | 138 sources.push_back(SourceDescription(DesktopMediaID( |
143 DesktopMediaID::TYPE_SCREEN, 0), | 139 DesktopMediaID::TYPE_SCREEN, 0), |
144 l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_SCREEN_NAME))); | 140 l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_SCREEN_NAME))); |
145 } | 141 } |
(...skipping 12 matching lines...) Expand all Loading... |
158 } | 154 } |
159 } | 155 } |
160 } | 156 } |
161 | 157 |
162 // Sort the list of sources so that they appear in a predictable order. | 158 // Sort the list of sources so that they appear in a predictable order. |
163 std::sort(sources.begin(), sources.end(), CompareSources); | 159 std::sort(sources.begin(), sources.end(), CompareSources); |
164 | 160 |
165 // Update list of windows before updating thumbnails. | 161 // Update list of windows before updating thumbnails. |
166 BrowserThread::PostTask( | 162 BrowserThread::PostTask( |
167 BrowserThread::UI, FROM_HERE, | 163 BrowserThread::UI, FROM_HERE, |
168 base::Bind(&DesktopMediaPickerModelImpl::OnSourcesList, model_, sources)); | 164 base::Bind(&NativeDesktopMediaList::OnSourcesList, |
| 165 media_list_, sources)); |
169 | 166 |
170 ImageHashesMap new_image_hashes; | 167 ImageHashesMap new_image_hashes; |
171 | 168 |
172 // Get a thumbnail for each source. | 169 // Get a thumbnail for each source. |
173 for (size_t i = 0; i < sources.size(); ++i) { | 170 for (size_t i = 0; i < sources.size(); ++i) { |
174 SourceDescription& source = sources[i]; | 171 SourceDescription& source = sources[i]; |
175 switch (source.id.type) { | 172 switch (source.id.type) { |
176 case DesktopMediaID::TYPE_SCREEN: | 173 case DesktopMediaID::TYPE_SCREEN: |
177 screen_capturer_->Capture(webrtc::DesktopRegion()); | 174 screen_capturer_->Capture(webrtc::DesktopRegion()); |
178 DCHECK(current_frame_); | 175 DCHECK(current_frame_); |
(...skipping 16 matching lines...) Expand all Loading... |
195 uint32 frame_hash = GetFrameHash(current_frame_.get()); | 192 uint32 frame_hash = GetFrameHash(current_frame_.get()); |
196 new_image_hashes[source.id] = frame_hash; | 193 new_image_hashes[source.id] = frame_hash; |
197 | 194 |
198 // Scale the image only if it has changed. | 195 // Scale the image only if it has changed. |
199 ImageHashesMap::iterator it = image_hashes_.find(source.id); | 196 ImageHashesMap::iterator it = image_hashes_.find(source.id); |
200 if (it == image_hashes_.end() || it->second != frame_hash) { | 197 if (it == image_hashes_.end() || it->second != frame_hash) { |
201 gfx::ImageSkia thumbnail = | 198 gfx::ImageSkia thumbnail = |
202 ScaleDesktopFrame(current_frame_.Pass(), thumbnail_size); | 199 ScaleDesktopFrame(current_frame_.Pass(), thumbnail_size); |
203 BrowserThread::PostTask( | 200 BrowserThread::PostTask( |
204 BrowserThread::UI, FROM_HERE, | 201 BrowserThread::UI, FROM_HERE, |
205 base::Bind(&DesktopMediaPickerModelImpl::OnSourceThumbnail, model_, | 202 base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, |
206 i, thumbnail)); | 203 media_list_, i, thumbnail)); |
207 } | 204 } |
208 } | 205 } |
209 } | 206 } |
210 | 207 |
211 image_hashes_.swap(new_image_hashes); | 208 image_hashes_.swap(new_image_hashes); |
212 | 209 |
213 BrowserThread::PostTask( | 210 BrowserThread::PostTask( |
214 BrowserThread::UI, FROM_HERE, | 211 BrowserThread::UI, FROM_HERE, |
215 base::Bind(&DesktopMediaPickerModelImpl::OnRefreshFinished, model_)); | 212 base::Bind(&NativeDesktopMediaList::OnRefreshFinished, media_list_)); |
216 } | 213 } |
217 | 214 |
218 webrtc::SharedMemory* DesktopMediaPickerModelImpl::Worker::CreateSharedMemory( | 215 webrtc::SharedMemory* NativeDesktopMediaList::Worker::CreateSharedMemory( |
219 size_t size) { | 216 size_t size) { |
220 return NULL; | 217 return NULL; |
221 } | 218 } |
222 | 219 |
223 void DesktopMediaPickerModelImpl::Worker::OnCaptureCompleted( | 220 void NativeDesktopMediaList::Worker::OnCaptureCompleted( |
224 webrtc::DesktopFrame* frame) { | 221 webrtc::DesktopFrame* frame) { |
225 current_frame_.reset(frame); | 222 current_frame_.reset(frame); |
226 } | 223 } |
227 | 224 |
228 DesktopMediaPickerModelImpl::DesktopMediaPickerModelImpl( | 225 NativeDesktopMediaList::NativeDesktopMediaList( |
229 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, | 226 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, |
230 scoped_ptr<webrtc::WindowCapturer> window_capturer) | 227 scoped_ptr<webrtc::WindowCapturer> window_capturer) |
231 : screen_capturer_(screen_capturer.Pass()), | 228 : screen_capturer_(screen_capturer.Pass()), |
232 window_capturer_(window_capturer.Pass()), | 229 window_capturer_(window_capturer.Pass()), |
233 update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), | 230 update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), |
234 thumbnail_size_(100, 100), | 231 thumbnail_size_(100, 100), |
235 view_dialog_id_(-1), | 232 view_dialog_id_(-1), |
236 observer_(NULL), | 233 observer_(NULL), |
237 weak_factory_(this) { | 234 weak_factory_(this) { |
238 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); | 235 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); |
239 capture_task_runner_ = worker_pool->GetSequencedTaskRunner( | 236 capture_task_runner_ = worker_pool->GetSequencedTaskRunner( |
240 worker_pool->GetSequenceToken()); | 237 worker_pool->GetSequenceToken()); |
241 } | 238 } |
242 | 239 |
243 DesktopMediaPickerModelImpl::~DesktopMediaPickerModelImpl() { | 240 NativeDesktopMediaList::~NativeDesktopMediaList() { |
244 capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release()); | 241 capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release()); |
245 } | 242 } |
246 | 243 |
247 void DesktopMediaPickerModelImpl::SetUpdatePeriod(base::TimeDelta period) { | 244 void NativeDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) { |
248 DCHECK(!observer_); | 245 DCHECK(!observer_); |
249 update_period_ = period; | 246 update_period_ = period; |
250 } | 247 } |
251 | 248 |
252 void DesktopMediaPickerModelImpl::SetThumbnailSize( | 249 void NativeDesktopMediaList::SetThumbnailSize( |
253 const gfx::Size& thumbnail_size) { | 250 const gfx::Size& thumbnail_size) { |
254 thumbnail_size_ = thumbnail_size; | 251 thumbnail_size_ = thumbnail_size; |
255 } | 252 } |
256 | 253 |
257 void DesktopMediaPickerModelImpl::SetViewDialogWindowId( | 254 void NativeDesktopMediaList::SetViewDialogWindowId( |
258 content::DesktopMediaID::Id dialog_id) { | 255 content::DesktopMediaID::Id dialog_id) { |
259 view_dialog_id_ = dialog_id; | 256 view_dialog_id_ = dialog_id; |
260 } | 257 } |
261 | 258 |
262 void DesktopMediaPickerModelImpl::StartUpdating(Observer* observer) { | 259 void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { |
263 DCHECK(!observer_); | 260 DCHECK(!observer_); |
264 DCHECK(screen_capturer_ || window_capturer_); | 261 DCHECK(screen_capturer_ || window_capturer_); |
265 | 262 |
266 observer_ = observer; | 263 observer_ = observer; |
267 | 264 |
268 worker_.reset(new Worker(weak_factory_.GetWeakPtr(), | 265 worker_.reset(new Worker(weak_factory_.GetWeakPtr(), |
269 screen_capturer_.Pass(), window_capturer_.Pass())); | 266 screen_capturer_.Pass(), window_capturer_.Pass())); |
270 Refresh(); | 267 Refresh(); |
271 } | 268 } |
272 | 269 |
273 int DesktopMediaPickerModelImpl::source_count() const { | 270 int NativeDesktopMediaList::GetSourceCount() const { |
274 return sources_.size(); | 271 return sources_.size(); |
275 } | 272 } |
276 | 273 |
277 const DesktopMediaPickerModel::Source& DesktopMediaPickerModelImpl::source( | 274 const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( |
278 int index) const { | 275 int index) const { |
279 return sources_[index]; | 276 return sources_[index]; |
280 } | 277 } |
281 | 278 |
282 // static | 279 // static |
283 bool DesktopMediaPickerModelImpl::CompareSources(const SourceDescription& a, | 280 bool NativeDesktopMediaList::CompareSources(const SourceDescription& a, |
284 const SourceDescription& b) { | 281 const SourceDescription& b) { |
285 return a.id < b.id; | 282 return a.id < b.id; |
286 } | 283 } |
287 | 284 |
288 void DesktopMediaPickerModelImpl::Refresh() { | 285 void NativeDesktopMediaList::Refresh() { |
289 capture_task_runner_->PostTask( | 286 capture_task_runner_->PostTask( |
290 FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), | 287 FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), |
291 thumbnail_size_, view_dialog_id_)); | 288 thumbnail_size_, view_dialog_id_)); |
292 } | 289 } |
293 | 290 |
294 void DesktopMediaPickerModelImpl::OnSourcesList( | 291 void NativeDesktopMediaList::OnSourcesList( |
295 const std::vector<SourceDescription>& new_sources) { | 292 const std::vector<SourceDescription>& new_sources) { |
296 // Step through |new_sources| adding and removing entries from |sources_|, and | 293 // Step through |new_sources| adding and removing entries from |sources_|, and |
297 // notifying the |observer_|, until two match. Requires that |sources| and | 294 // notifying the |observer_|, until two match. Requires that |sources| and |
298 // |sources_| have the same ordering. | 295 // |sources_| have the same ordering. |
299 size_t pos = 0; | 296 size_t pos = 0; |
300 while (pos < sources_.size() || pos < new_sources.size()) { | 297 while (pos < sources_.size() || pos < new_sources.size()) { |
301 // If |sources_[pos]| is not in |new_sources| then remove it. | 298 // If |sources_[pos]| is not in |new_sources| then remove it. |
302 if (pos < sources_.size() && | 299 if (pos < sources_.size() && |
303 (pos == new_sources.size() || sources_[pos].id < new_sources[pos].id)) { | 300 (pos == new_sources.size() || sources_[pos].id < new_sources[pos].id)) { |
304 sources_.erase(sources_.begin() + pos); | 301 sources_.erase(sources_.begin() + pos); |
305 observer_->OnSourceRemoved(pos); | 302 observer_->OnSourceRemoved(pos); |
306 continue; | 303 continue; |
307 } | 304 } |
308 | 305 |
309 if (pos == sources_.size() || !(sources_[pos].id == new_sources[pos].id)) { | 306 if (pos == sources_.size() || !(sources_[pos].id == new_sources[pos].id)) { |
310 sources_.insert(sources_.begin() + pos, | 307 sources_.insert(sources_.begin() + pos, Source()); |
311 Source(new_sources[pos].id, new_sources[pos].name)); | 308 sources_[pos].id = new_sources[pos].id; |
| 309 sources_[pos].name = new_sources[pos].name; |
312 observer_->OnSourceAdded(pos); | 310 observer_->OnSourceAdded(pos); |
313 } else if (sources_[pos].name != new_sources[pos].name) { | 311 } else if (sources_[pos].name != new_sources[pos].name) { |
314 sources_[pos].name = new_sources[pos].name; | 312 sources_[pos].name = new_sources[pos].name; |
315 observer_->OnSourceNameChanged(pos); | 313 observer_->OnSourceNameChanged(pos); |
316 } | 314 } |
317 | 315 |
318 ++pos; | 316 ++pos; |
319 } | 317 } |
320 | 318 |
321 DCHECK_EQ(new_sources.size(), sources_.size()); | 319 DCHECK_EQ(new_sources.size(), sources_.size()); |
322 } | 320 } |
323 | 321 |
324 void DesktopMediaPickerModelImpl::OnSourceThumbnail(int index, | 322 void NativeDesktopMediaList::OnSourceThumbnail( |
325 const gfx::ImageSkia& image) { | 323 int index, |
| 324 const gfx::ImageSkia& image) { |
326 DCHECK_LT(index, static_cast<int>(sources_.size())); | 325 DCHECK_LT(index, static_cast<int>(sources_.size())); |
327 sources_[index].thumbnail = image; | 326 sources_[index].thumbnail = image; |
328 observer_->OnSourceThumbnailChanged(index); | 327 observer_->OnSourceThumbnailChanged(index); |
329 } | 328 } |
330 | 329 |
331 void DesktopMediaPickerModelImpl::OnRefreshFinished() { | 330 void NativeDesktopMediaList::OnRefreshFinished() { |
332 BrowserThread::PostDelayedTask( | 331 BrowserThread::PostDelayedTask( |
333 BrowserThread::UI, FROM_HERE, | 332 BrowserThread::UI, FROM_HERE, |
334 base::Bind(&DesktopMediaPickerModelImpl::Refresh, | 333 base::Bind(&NativeDesktopMediaList::Refresh, |
335 weak_factory_.GetWeakPtr()), | 334 weak_factory_.GetWeakPtr()), |
336 update_period_); | 335 update_period_); |
337 } | 336 } |
OLD | NEW |