1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// found in the LICENSE file. 4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/media/native_desktop_media_list.h" 6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include <map> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <set> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <sstream> 10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/hash.h" 12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/logging.h" 13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/media/desktop_media_list_observer.h" 1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/generated_resources.h" 17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "media/base/video_util.h" 19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "third_party/libyuv/include/libyuv/scale_argb.h" 20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h" 21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" 23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/window_capturer.h" 24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ui/gfx/skia_util.h" 26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)using content::BrowserThread; 28ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochusing content::DesktopMediaID; 29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)namespace { 31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Update the list every second. 33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const int kDefaultUpdatePeriod = 1000; 34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Returns a hash of a DesktopFrame content to detect when image for a desktop 36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// media source has changed. 37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)uint32 GetFrameHash(webrtc::DesktopFrame* frame) { 38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) int data_size = frame->stride() * frame->size().height(); 39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return base::SuperFastHash(reinterpret_cast<char*>(frame->data()), data_size); 40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)gfx::ImageSkia ScaleDesktopFrame(scoped_ptr<webrtc::DesktopFrame> frame, 43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) gfx::Size size) { 44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) gfx::Rect scaled_rect = media::ComputeLetterboxRegion( 45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) gfx::Rect(0, 0, size.width(), size.height()), 46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) gfx::Size(frame->size().width(), frame->size().height())); 47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) SkBitmap result; 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch result.allocN32Pixels(scaled_rect.width(), scaled_rect.height(), true); 50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) result.lockPixels(); 51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint8* pixels_data = reinterpret_cast<uint8*>(result.getPixels()); 53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) libyuv::ARGBScale(frame->data(), frame->stride(), 54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) frame->size().width(), frame->size().height(), 55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) pixels_data, result.rowBytes(), 56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scaled_rect.width(), scaled_rect.height(), 57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) libyuv::kFilterBilinear); 58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Set alpha channel values to 255 for all pixels. 60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // TODO(sergeyu): Fix screen/window capturers to capture alpha channel and 61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // remove this code. Currently screen/window capturers (at least some 62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // implementations) only capture R, G and B channels and set Alpha to 0. 63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // crbug.com/264424 64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) for (int y = 0; y < result.height(); ++y) { 65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) for (int x = 0; x < result.width(); ++x) { 66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3] = 67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 0xff; 68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) result.unlockPixels(); 72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return gfx::ImageSkia::CreateFrom1xBitmap(result); 74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} // namespace 77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)NativeDesktopMediaList::SourceDescription::SourceDescription( 79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch DesktopMediaID id, 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& name) 81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) : id(id), 82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) name(name) { 83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class NativeDesktopMediaList::Worker 86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) : public webrtc::DesktopCapturer::Callback { 87a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public: 88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Worker(base::WeakPtr<NativeDesktopMediaList> media_list, 89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<webrtc::ScreenCapturer> screen_capturer, 90a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<webrtc::WindowCapturer> window_capturer); 91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) virtual ~Worker(); 92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) void Refresh(const gfx::Size& thumbnail_size, 9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) content::DesktopMediaID::Id view_dialog_id); 95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private: 97ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch typedef std::map<DesktopMediaID, uint32> ImageHashesMap; 98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // webrtc::DesktopCapturer::Callback interface. 100a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE; 101a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE; 102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::WeakPtr<NativeDesktopMediaList> media_list_; 104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 105a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<webrtc::ScreenCapturer> screen_capturer_; 106a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<webrtc::WindowCapturer> window_capturer_; 107a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<webrtc::DesktopFrame> current_frame_; 109a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 110a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ImageHashesMap image_hashes_; 111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Worker); 113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}; 114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)NativeDesktopMediaList::Worker::Worker( 116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::WeakPtr<NativeDesktopMediaList> media_list, 117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<webrtc::ScreenCapturer> screen_capturer, 118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) scoped_ptr<webrtc::WindowCapturer> window_capturer) 119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : media_list_(media_list), 120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) screen_capturer_(screen_capturer.Pass()), 121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) window_capturer_(window_capturer.Pass()) { 122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (screen_capturer_) 123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) screen_capturer_->Start(this); 124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (window_capturer_) 125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) window_capturer_->Start(this); 126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)NativeDesktopMediaList::Worker::~Worker() {} 129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::Worker::Refresh( 13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const gfx::Size& thumbnail_size, 13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) content::DesktopMediaID::Id view_dialog_id) { 133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::vector<SourceDescription> sources; 134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (screen_capturer_) { 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) webrtc::ScreenCapturer::ScreenList screens; 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (screen_capturer_->GetScreenList(&screens)) { 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool mutiple_screens = screens.size() > 1; 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 title; 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < screens.size(); ++i) { 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (mutiple_screens) { 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) title = l10n_util::GetStringFUTF16Int( 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME, 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static_cast<int>(i + 1)); 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) title = l10n_util::GetStringUTF16( 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IDS_DESKTOP_MEDIA_PICKER_SINGLE_SCREEN_NAME); 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sources.push_back(SourceDescription(DesktopMediaID( 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DesktopMediaID::TYPE_SCREEN, screens[i].id), title)); 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (window_capturer_) { 156a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) webrtc::WindowCapturer::WindowList windows; 157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (window_capturer_->GetWindowList(&windows)) { 158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) for (webrtc::WindowCapturer::WindowList::iterator it = windows.begin(); 159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) it != windows.end(); ++it) { 16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Skip the picker dialog window. 16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (it->id != view_dialog_id) { 16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) sources.push_back(SourceDescription( 16368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DesktopMediaID(DesktopMediaID::TYPE_WINDOW, it->id), 16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) base::UTF8ToUTF16(it->title))); 16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 169a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Update list of windows before updating thumbnails. 170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::PostTask( 171a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Bind(&NativeDesktopMediaList::OnSourcesList, 173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) media_list_, sources)); 174a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ImageHashesMap new_image_hashes; 176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 177a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Get a thumbnail for each source. 178a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) for (size_t i = 0; i < sources.size(); ++i) { 179a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) SourceDescription& source = sources[i]; 180a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) switch (source.id.type) { 181ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch case DesktopMediaID::TYPE_SCREEN: 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!screen_capturer_->SelectScreen(source.id.id)) 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) screen_capturer_->Capture(webrtc::DesktopRegion()); 185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 187ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch case DesktopMediaID::TYPE_WINDOW: 188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!window_capturer_->SelectWindow(source.id.id)) 189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) continue; 190a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) window_capturer_->Capture(webrtc::DesktopRegion()); 191a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 192a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 193a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) default: 194a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) NOTREACHED(); 195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Expect that DesktopCapturer to always captures frames synchronously. 198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // |current_frame_| may be NULL if capture failed (e.g. because window has 199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // been closed). 200a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (current_frame_) { 201a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 frame_hash = GetFrameHash(current_frame_.get()); 202a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) new_image_hashes[source.id] = frame_hash; 203a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 204a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Scale the image only if it has changed. 205a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ImageHashesMap::iterator it = image_hashes_.find(source.id); 206a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (it == image_hashes_.end() || it->second != frame_hash) { 207a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) gfx::ImageSkia thumbnail = 208a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ScaleDesktopFrame(current_frame_.Pass(), thumbnail_size); 209a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::PostTask( 210a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, 212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) media_list_, i, thumbnail)); 213a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 214a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 215a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 216a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 217a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) image_hashes_.swap(new_image_hashes); 218a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::PostTask( 220a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Bind(&NativeDesktopMediaList::OnRefreshFinished, media_list_)); 222a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 223a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)webrtc::SharedMemory* NativeDesktopMediaList::Worker::CreateSharedMemory( 225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) size_t size) { 226a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return NULL; 227a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 228a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 229a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::Worker::OnCaptureCompleted( 230a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) webrtc::DesktopFrame* frame) { 231a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) current_frame_.reset(frame); 232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 233a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)NativeDesktopMediaList::NativeDesktopMediaList( 2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) scoped_ptr<webrtc::ScreenCapturer> screen_capturer, 2363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) scoped_ptr<webrtc::WindowCapturer> window_capturer) 2373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) : screen_capturer_(screen_capturer.Pass()), 2383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) window_capturer_(window_capturer.Pass()), 2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), 240a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) thumbnail_size_(100, 100), 24168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) view_dialog_id_(-1), 242a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) observer_(NULL), 243a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) weak_factory_(this) { 244a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); 245a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) capture_task_runner_ = worker_pool->GetSequencedTaskRunner( 246a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) worker_pool->GetSequenceToken()); 247a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 248a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)NativeDesktopMediaList::~NativeDesktopMediaList() { 250a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release()); 251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 252a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) { 254a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(!observer_); 255a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) update_period_ = period; 256a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 257a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::SetThumbnailSize( 259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const gfx::Size& thumbnail_size) { 260a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) thumbnail_size_ = thumbnail_size; 261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 262a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::SetViewDialogWindowId( 26468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) content::DesktopMediaID::Id dialog_id) { 26568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) view_dialog_id_ = dialog_id; 26668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 26768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { 269a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(!observer_); 270a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(screen_capturer_ || window_capturer_); 271a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) observer_ = observer; 273a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 274a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) worker_.reset(new Worker(weak_factory_.GetWeakPtr(), 275a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) screen_capturer_.Pass(), window_capturer_.Pass())); 276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) Refresh(); 277a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)int NativeDesktopMediaList::GetSourceCount() const { 28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return sources_.size(); 28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( 28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) int index) const { 28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return sources_[index]; 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::Refresh() { 289a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) capture_task_runner_->PostTask( 290a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), 29168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) thumbnail_size_, view_dialog_id_)); 292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 293a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::OnSourcesList( 295a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const std::vector<SourceDescription>& new_sources) { 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) typedef std::set<content::DesktopMediaID> SourceSet; 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SourceSet new_source_set; 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < new_sources.size(); ++i) { 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new_source_set.insert(new_sources[i].id); 3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Iterate through the old sources to find the removed sources. 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < sources_.size(); ++i) { 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (new_source_set.find(sources_[i].id) == new_source_set.end()) { 3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sources_.erase(sources_.begin() + i); 3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) observer_->OnSourceRemoved(i); 3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) --i; 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Iterate through the new sources to find the added sources. 3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (new_sources.size() > sources_.size()) { 3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SourceSet old_source_set; 3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < sources_.size(); ++i) { 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) old_source_set.insert(sources_[i].id); 3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < new_sources.size(); ++i) { 3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (old_source_set.find(new_sources[i].id) == old_source_set.end()) { 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sources_.insert(sources_.begin() + i, Source()); 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sources_[i].id = new_sources[i].id; 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sources_[i].name = new_sources[i].name; 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) observer_->OnSourceAdded(i); 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_EQ(new_sources.size(), sources_.size()); 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Find the moved/changed sources. 328a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) size_t pos = 0; 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (pos < sources_.size()) { 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!(sources_[pos].id == new_sources[pos].id)) { 3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Find the source that should be moved to |pos|, starting from |pos + 1| 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // of |sources_|, because entries before |pos| should have been sorted. 3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t old_pos = pos + 1; 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (; old_pos < sources_.size(); ++old_pos) { 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (sources_[old_pos].id == new_sources[pos].id) 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(sources_[old_pos].id == new_sources[pos].id); 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Move the source from |old_pos| to |pos|. 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Source temp = sources_[old_pos]; 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sources_.erase(sources_.begin() + old_pos); 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sources_.insert(sources_.begin() + pos, temp); 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) observer_->OnSourceMoved(old_pos, pos); 346a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 347a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (sources_[pos].name != new_sources[pos].name) { 349a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) sources_[pos].name = new_sources[pos].name; 350a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) observer_->OnSourceNameChanged(pos); 351a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 352a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ++pos; 353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 354a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 355a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 356a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::OnSourceThumbnail( 357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int index, 358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const gfx::ImageSkia& image) { 359a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK_LT(index, static_cast<int>(sources_.size())); 360a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) sources_[index].thumbnail = image; 361a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) observer_->OnSourceThumbnailChanged(index); 362a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 363a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NativeDesktopMediaList::OnRefreshFinished() { 365a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::PostDelayedTask( 366a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Bind(&NativeDesktopMediaList::Refresh, 36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_factory_.GetWeakPtr()), 369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) update_period_); 370a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 371