| 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 |