Chromium Code Reviews| Index: chrome/browser/media/native_desktop_media_list.cc |
| diff --git a/chrome/browser/media/native_desktop_media_list.cc b/chrome/browser/media/native_desktop_media_list.cc |
| index 48c76f974e7342447080de9c5436ebe4d6a371a0..e42daa47c50b6901093b88ba0258a4dad0db2939 100644 |
| --- a/chrome/browser/media/native_desktop_media_list.cc |
| +++ b/chrome/browser/media/native_desktop_media_list.cc |
| @@ -8,6 +8,9 @@ |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "chrome/browser/media/desktop_media_list_observer.h" |
| +#include "chrome/browser/ui/browser.h" |
| +#include "chrome/browser/ui/browser_list.h" |
| +#include "chrome/browser/ui/browser_window.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "media/base/video_util.h" |
| @@ -16,10 +19,13 @@ |
| #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" |
| #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" |
| +#include "ui/aura/window.h" |
| +#include "ui/aura/window_tree_host.h" |
| #include "ui/base/l10n/l10n_util.h" |
| +#include "ui/gfx/native_widget_types.h" |
| +#include "ui/snapshot/snapshot.h" |
| using content::BrowserThread; |
| -using content::DesktopMediaID; |
| namespace { |
| @@ -30,7 +36,7 @@ const int kDefaultUpdatePeriod = 1000; |
| // media source has changed. |
| uint32_t GetFrameHash(webrtc::DesktopFrame* frame) { |
| int data_size = frame->stride() * frame->size().height(); |
| - return base::SuperFastHash(reinterpret_cast<char*>(frame->data()), data_size); |
| + return base::Hash(reinterpret_cast<char*>(frame->data()), data_size); |
| } |
| gfx::ImageSkia ScaleDesktopFrame(scoped_ptr<webrtc::DesktopFrame> frame, |
| @@ -78,7 +84,8 @@ class NativeDesktopMediaList::Worker |
| ~Worker() override; |
| void Refresh(const gfx::Size& thumbnail_size, |
| - content::DesktopMediaID::Id view_dialog_id); |
| + DesktopMediaID::Id view_dialog_id, |
| + NativeAuraIdMap native_aura_id_map); |
| private: |
| typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap; |
| @@ -115,8 +122,10 @@ NativeDesktopMediaList::Worker::~Worker() {} |
| void NativeDesktopMediaList::Worker::Refresh( |
| const gfx::Size& thumbnail_size, |
| - content::DesktopMediaID::Id view_dialog_id) { |
| + DesktopMediaID::Id view_dialog_id, |
| + NativeAuraIdMap native_aura_id_map) { |
| std::vector<SourceDescription> sources; |
| + std::vector<DesktopMediaID> aura_media_ids; |
| if (screen_capturer_) { |
| webrtc::ScreenCapturer::ScreenList screens; |
| @@ -145,13 +154,21 @@ void NativeDesktopMediaList::Worker::Refresh( |
| it != windows.end(); ++it) { |
| // Skip the picker dialog window. |
| if (it->id != view_dialog_id) { |
| - sources.push_back(SourceDescription( |
| - DesktopMediaID(DesktopMediaID::TYPE_WINDOW, it->id), |
| - base::UTF8ToUTF16(it->title))); |
| + DesktopMediaID media_id(DesktopMediaID::TYPE_WINDOW, it->id); |
| +#if defined(USE_AURA) |
| + // Associate aura id with native id. |
| + if (native_aura_id_map.count(media_id.id)) { |
| + media_id.aura_id = native_aura_id_map[media_id.id]; |
|
Sergey Ulanov
2016/03/10 00:46:07
nit: here you search the map twice, which can be a
GeorgeZ
2016/03/10 21:18:46
good point.
|
| + aura_media_ids.push_back(media_id); |
| + } |
| +#endif |
| + sources.push_back( |
| + SourceDescription(media_id, base::UTF8ToUTF16(it->title))); |
| } |
| } |
| } |
| } |
| + |
| // Update list of windows before updating thumbnails. |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| base::Bind(&NativeDesktopMediaList::UpdateSourcesList, |
| @@ -162,6 +179,7 @@ void NativeDesktopMediaList::Worker::Refresh( |
| // Get a thumbnail for each source. |
| for (size_t i = 0; i < sources.size(); ++i) { |
| SourceDescription& source = sources[i]; |
| + |
| switch (source.id.type) { |
| case DesktopMediaID::TYPE_SCREEN: |
| if (!screen_capturer_->SelectScreen(source.id.id)) |
| @@ -170,6 +188,11 @@ void NativeDesktopMediaList::Worker::Refresh( |
| break; |
| case DesktopMediaID::TYPE_WINDOW: |
| +#if defined(USE_AURA) |
| + // Aura window thumbmail capture is skipped here. It will be done later. |
|
Sergey Ulanov
2016/03/10 00:46:07
maybe also mention the UI thread. Otherwise it's n
GeorgeZ
2016/03/10 21:18:46
I will also mention it will be done asynchronously
|
| + if (source.id.aura_id > DesktopMediaID::kNullId) |
| + continue; |
| +#endif |
| if (!window_capturer_->SelectWindow(source.id.id)) |
| continue; |
| window_capturer_->Capture(webrtc::DesktopRegion()); |
| @@ -193,17 +216,21 @@ void NativeDesktopMediaList::Worker::Refresh( |
| ScaleDesktopFrame(std::move(current_frame_), thumbnail_size); |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| - base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, media_list_, |
| - i, thumbnail)); |
| + base::Bind(&NativeDesktopMediaList::OnSourceThumbnailCaptured, |
| + media_list_, i, thumbnail)); |
| } |
| } |
| } |
| image_hashes_.swap(new_image_hashes); |
| + // Aura thumbnail captures have to be done in UI thread. After they are done, |
| + // a refresh will be scheduled. |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| - base::Bind(&NativeDesktopMediaList::ScheduleNextRefresh, media_list_)); |
| + base::Bind( |
| + &NativeDesktopMediaList::FinishRefreshOnUiThreadAndScheduleNext, |
| + media_list_, aura_media_ids)); |
| } |
| void NativeDesktopMediaList::Worker::OnCaptureCompleted( |
| @@ -231,12 +258,104 @@ NativeDesktopMediaList::~NativeDesktopMediaList() { |
| } |
| void NativeDesktopMediaList::Refresh() { |
| + NativeAuraIdMap native_aura_id_map; |
| +#if defined(USE_AURA) |
| + native_aura_id_map = GetBrowserNativeAuraIdMap(); |
| +#endif |
| + processed_aura_window_count_ = 0; |
| + new_aura_thumbnail_hashes_.clear(); |
| + |
| capture_task_runner_->PostTask( |
| - FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), |
| - thumbnail_size_, view_dialog_id_.id)); |
| + FROM_HERE, |
| + base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), |
| + thumbnail_size_, view_dialog_id_.id, native_aura_id_map)); |
| } |
| -void NativeDesktopMediaList::OnSourceThumbnail(int index, |
| - const gfx::ImageSkia& image) { |
| +void NativeDesktopMediaList::OnSourceThumbnailCaptured( |
| + int index, |
| + const gfx::ImageSkia& image) { |
| UpdateSourceThumbnail(GetSource(index).id, image); |
| } |
| + |
| +void NativeDesktopMediaList::FinishRefreshOnUiThreadAndScheduleNext( |
| + std::vector<DesktopMediaID> aura_ids) { |
|
Sergey Ulanov
2016/03/10 00:46:07
use const reference for the parameter
GeorgeZ
2016/03/10 21:18:46
Done.
|
| + // Schedule a refresh here when there is no aura thumbanil capture or schedule |
| + // a refresh in OnAuraThumbnailCaptured() after all aura thumbnails are |
| + // captured. |
| + total_aura_windows_ = aura_ids.size(); |
|
Sergey Ulanov
2016/03/10 00:46:07
Instead of having both processed_aura_window_count
Sergey Ulanov
2016/03/10 00:46:07
Add a DCHECK here to verify there are no pending c
GeorgeZ
2016/03/10 21:18:46
Done.
GeorgeZ
2016/03/10 21:18:46
Done.
|
| + if (total_aura_windows_ == 0) { |
| + ScheduleNextRefresh(); |
| + return; |
| + } |
| + |
| + for (const auto& aura_id : aura_ids) { |
| + CaptureAuraWindowThumbnail(aura_id); |
| + } |
| +} |
| + |
| +void NativeDesktopMediaList::OnAuraThumbnailCaptured(DesktopMediaID id, |
| + const gfx::Image& image) { |
| + if (!image.IsEmpty()) { |
| + // Only new or changed thumbnail need update. |
| + new_aura_thumbnail_hashes_[id] = DesktopMediaListBase::GetImageHash(image); |
| + if (!previous_aura_thumbnail_hashes_.count(id) || |
| + previous_aura_thumbnail_hashes_[id] != new_aura_thumbnail_hashes_[id]) { |
| + UpdateSourceThumbnail(id, image.AsImageSkia()); |
| + } |
| + } |
| + |
| + // After all aura windows are processed, schedule next refresh; |
| + processed_aura_window_count_++; |
| + if (processed_aura_window_count_ == total_aura_windows_) { |
| + swap(previous_aura_thumbnail_hashes_, new_aura_thumbnail_hashes_); |
|
Sergey Ulanov
2016/03/10 00:46:07
nit:
previous_aura_thumbnail_hashes_ = std::move
GeorgeZ
2016/03/10 21:18:46
good point.
|
| + ScheduleNextRefresh(); |
| + } |
| +} |
| + |
| +#if defined(USE_AURA) |
| + |
| +NativeDesktopMediaList::NativeAuraIdMap |
| +NativeDesktopMediaList::GetBrowserNativeAuraIdMap() { |
|
Sergey Ulanov
2016/03/10 00:46:07
This function doesn't need to be a class member. M
GeorgeZ
2016/03/10 21:18:46
Done.
|
| + NativeAuraIdMap id_map; |
| + for (auto* browser : *BrowserList::GetInstance()) { |
| + const BrowserWindow* browser_window = browser->window(); |
|
Sergey Ulanov
2016/03/10 00:46:07
nit: I don't think you need this variable. Just us
GeorgeZ
2016/03/10 21:18:46
Done.
|
| + if (!browser_window) |
| + continue; |
| + const gfx::NativeWindow native_window = browser_window->GetNativeWindow(); |
|
Sergey Ulanov
2016/03/10 00:46:08
Suggest changing this to:
aura::Window* aura_win
GeorgeZ
2016/03/10 21:18:46
Done.
|
| + if (!native_window) |
| + continue; |
| + aura::WindowTreeHost* host = native_window->GetHost(); |
| + if (!host) |
| + continue; |
| + gfx::AcceleratedWidget widget = host->GetAcceleratedWidget(); |
| +#if defined(OS_WIN) |
| + DesktopMediaID::Id native_id = reinterpret_cast<DesktopMediaID::Id>(widget); |
| +#else |
| + DesktopMediaID::Id native_id = widget; |
| +#endif |
| + DesktopMediaID media_id = DesktopMediaID::RegisterAuraWindow( |
| + DesktopMediaID::TYPE_WINDOW, native_window); |
| + id_map.insert(std::make_pair(native_id, media_id.aura_id)); |
|
Sergey Ulanov
2016/03/10 00:46:07
nit: id_map[native_id] = media_id.aura_id;
That wo
GeorgeZ
2016/03/10 21:18:46
Done.
|
| + } |
| + |
| + return id_map; |
| +} |
| + |
| +void NativeDesktopMediaList::CaptureAuraWindowThumbnail(DesktopMediaID id) { |
| + gfx::NativeWindow window = DesktopMediaID::GetAuraWindowById(id); |
| + if (!window) { |
| + OnAuraThumbnailCaptured(id, gfx::Image()); |
| + return; |
| + } |
| + |
| + gfx::Rect window_rect(window->bounds().width(), window->bounds().height()); |
| + gfx::Rect scaled_rect = media::ComputeLetterboxRegion( |
| + gfx::Rect(thumbnail_size_), window_rect.size()); |
| + |
| + ui::GrabWindowSnapshotAndScaleAsync( |
| + window, window_rect, scaled_rect.size(), BrowserThread::GetBlockingPool(), |
| + base::Bind(&NativeDesktopMediaList::OnAuraThumbnailCaptured, |
| + weak_factory_.GetWeakPtr(), id)); |
| +} |
| + |
| +#endif // defined(USE_AURA) |