refactor: desktop capturer module (#14835)
* Revert "post all desktop capturer apis to worker threads"
This reverts commit 5a28759fea
.
* refactor: desktop capturer module
* Creates the screen and window capturer for the liftime of the app
* Fixes incorrect usage of weak ptr
* build: add //ui/snapshot to chromium_src deps
* fix: handle scenarios when there are no captured sources
This commit is contained in:
parent
e06bc311a9
commit
596ae2c2df
13 changed files with 465 additions and 829 deletions
|
@ -8,20 +8,17 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using base::PlatformThreadRef;
|
||||
|
||||
#include "atom/common/api/atom_api_native_image.h"
|
||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task_scheduler/post_task.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "chrome/browser/media/desktop_media_list.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_media_list.h"
|
||||
#include "content/public/browser/desktop_capture.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
|
||||
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "third_party/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h"
|
||||
#include "third_party/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h"
|
||||
|
@ -51,63 +48,121 @@ struct Converter<atom::api::DesktopCapturer::Source> {
|
|||
|
||||
} // namespace mate
|
||||
|
||||
namespace {
|
||||
namespace atom {
|
||||
|
||||
void EmitFinished(
|
||||
const std::vector<atom::api::DesktopCapturer::Source>& sources,
|
||||
atom::api::DesktopCapturer* cap) {
|
||||
cap->Emit("finished", sources);
|
||||
namespace api {
|
||||
|
||||
DesktopCapturer::DesktopCapturer(v8::Isolate* isolate) {
|
||||
Init(isolate);
|
||||
}
|
||||
|
||||
void StartHandlingTask(bool capture_window,
|
||||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size,
|
||||
atom::api::DesktopCapturer* cap) {
|
||||
DesktopCapturer::~DesktopCapturer() {}
|
||||
|
||||
void DesktopCapturer::StartHandling(bool capture_window,
|
||||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size) {
|
||||
#if defined(OS_WIN)
|
||||
if (content::desktop_capture::CreateDesktopCaptureOptions()
|
||||
.allow_directx_capturer()) {
|
||||
// DxgiDuplicatorController should be alive in this scope according to
|
||||
// screen_capturer_win.cc.
|
||||
auto duplicator = webrtc::DxgiDuplicatorController::Instance();
|
||||
cap->using_directx_capturer_ =
|
||||
webrtc::ScreenCapturerWinDirectx::IsSupported();
|
||||
using_directx_capturer_ = webrtc::ScreenCapturerWinDirectx::IsSupported();
|
||||
}
|
||||
#endif // defined(OS_WIN)
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer(
|
||||
capture_screen ? content::desktop_capture::CreateScreenCapturer()
|
||||
: nullptr);
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer(
|
||||
capture_window ? content::desktop_capture::CreateWindowCapturer()
|
||||
: nullptr);
|
||||
cap->media_list_.reset(new NativeDesktopMediaList(
|
||||
std::move(screen_capturer), std::move(window_capturer)));
|
||||
|
||||
cap->media_list_->SetThumbnailSize(thumbnail_size);
|
||||
cap->media_list_->StartUpdating(cap);
|
||||
// clear any existing captured sources.
|
||||
captured_sources_.clear();
|
||||
|
||||
// Start listening for captured sources.
|
||||
capture_window_ = capture_window;
|
||||
capture_screen_ = capture_screen;
|
||||
|
||||
{
|
||||
// Remove this once
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=795340 is fixed.
|
||||
base::ScopedAllowBaseSyncPrimitivesForTesting
|
||||
scoped_allow_base_sync_primitives;
|
||||
// Initialize the source list.
|
||||
// Apply the new thumbnail size and restart capture.
|
||||
if (capture_window) {
|
||||
window_capturer_.reset(new NativeDesktopMediaList(
|
||||
content::DesktopMediaID::TYPE_WINDOW,
|
||||
content::desktop_capture::CreateWindowCapturer()));
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
window_capturer_->AddObserver(this);
|
||||
window_capturer_->StartUpdating();
|
||||
}
|
||||
|
||||
if (capture_screen) {
|
||||
screen_capturer_.reset(new NativeDesktopMediaList(
|
||||
content::DesktopMediaID::TYPE_SCREEN,
|
||||
content::desktop_capture::CreateScreenCapturer()));
|
||||
screen_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
screen_capturer_->AddObserver(this);
|
||||
screen_capturer_->StartUpdating();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnRefreshFinishedTask(atom::api::DesktopCapturer* cap) {
|
||||
const auto media_list_sources = cap->media_list_->GetSources();
|
||||
std::vector<atom::api::DesktopCapturer::Source> sources;
|
||||
for (const auto& media_list_source : media_list_sources) {
|
||||
sources.emplace_back(
|
||||
atom::api::DesktopCapturer::Source{media_list_source, std::string()});
|
||||
void DesktopCapturer::OnSourceAdded(DesktopMediaList* list, int index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceRemoved(DesktopMediaList* list, int index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceMoved(DesktopMediaList* list,
|
||||
int old_index,
|
||||
int new_index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceNameChanged(DesktopMediaList* list, int index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceThumbnailChanged(DesktopMediaList* list,
|
||||
int index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceUnchanged(DesktopMediaList* list) {
|
||||
UpdateSourcesList(list);
|
||||
}
|
||||
|
||||
bool DesktopCapturer::ShouldScheduleNextRefresh(DesktopMediaList* list) {
|
||||
UpdateSourcesList(list);
|
||||
return false;
|
||||
}
|
||||
|
||||
void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
std::vector<DesktopCapturer::Source> window_sources;
|
||||
if (capture_window_ &&
|
||||
list->GetMediaListType() == content::DesktopMediaID::TYPE_WINDOW) {
|
||||
capture_window_ = false;
|
||||
const auto& media_list_sources = list->GetSources();
|
||||
for (const auto& media_list_source : media_list_sources) {
|
||||
window_sources.emplace_back(
|
||||
DesktopCapturer::Source{media_list_source, std::string()});
|
||||
}
|
||||
std::move(window_sources.begin(), window_sources.end(),
|
||||
std::back_inserter(captured_sources_));
|
||||
}
|
||||
|
||||
std::vector<DesktopCapturer::Source> screen_sources;
|
||||
if (capture_screen_ &&
|
||||
list->GetMediaListType() == content::DesktopMediaID::TYPE_SCREEN) {
|
||||
capture_screen_ = false;
|
||||
const auto& media_list_sources = list->GetSources();
|
||||
for (const auto& media_list_source : media_list_sources) {
|
||||
screen_sources.emplace_back(
|
||||
DesktopCapturer::Source{media_list_source, std::string()});
|
||||
}
|
||||
#if defined(OS_WIN)
|
||||
// Gather the same unique screen IDs used by the electron.screen API in order
|
||||
// to provide an association between it and desktopCapturer/getUserMedia.
|
||||
// This is only required when using the DirectX capturer, otherwise the IDs
|
||||
// across the APIs already match.
|
||||
if (cap->using_directx_capturer_) {
|
||||
std::vector<std::string> device_names;
|
||||
// Crucially, this list of device names will be in the same order as
|
||||
// |media_list_sources|.
|
||||
webrtc::DxgiDuplicatorController::Instance()->GetDeviceNames(&device_names);
|
||||
int device_name_index = 0;
|
||||
for (auto& source : sources) {
|
||||
if (source.media_list_source.id.type ==
|
||||
content::DesktopMediaID::TYPE_SCREEN) {
|
||||
// Gather the same unique screen IDs used by the electron.screen API in
|
||||
// order to provide an association between it and
|
||||
// desktopCapturer/getUserMedia. This is only required when using the
|
||||
// DirectX capturer, otherwise the IDs across the APIs already match.
|
||||
if (using_directx_capturer_) {
|
||||
std::vector<std::string> device_names;
|
||||
// Crucially, this list of device names will be in the same order as
|
||||
// |media_list_sources|.
|
||||
webrtc::DxgiDuplicatorController::Instance()->GetDeviceNames(
|
||||
&device_names);
|
||||
int device_name_index = 0;
|
||||
for (auto& source : screen_sources) {
|
||||
const auto& device_name = device_names[device_name_index++];
|
||||
std::wstring wide_device_name;
|
||||
base::UTF8ToWide(device_name.c_str(), device_name.size(),
|
||||
|
@ -118,61 +173,21 @@ void OnRefreshFinishedTask(atom::api::DesktopCapturer* cap) {
|
|||
source.display_id = base::Int64ToString(device_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(OS_MACOSX)
|
||||
// On Mac, the IDs across the APIs match.
|
||||
for (auto& source : sources) {
|
||||
if (source.media_list_source.id.type ==
|
||||
content::DesktopMediaID::TYPE_SCREEN) {
|
||||
// On Mac, the IDs across the APIs match.
|
||||
for (auto& source : screen_sources) {
|
||||
source.display_id = base::Int64ToString(source.media_list_source.id.id);
|
||||
}
|
||||
}
|
||||
#endif // defined(OS_WIN)
|
||||
// TODO(ajmacd): Add Linux support. The IDs across APIs differ but Chrome only
|
||||
// supports capturing the entire desktop on Linux. Revisit this if individual
|
||||
// screen support is added.
|
||||
// TODO(ajmacd): Add Linux support. The IDs across APIs differ but Chrome
|
||||
// only supports capturing the entire desktop on Linux. Revisit this if
|
||||
// individual screen support is added.
|
||||
std::move(screen_sources.begin(), screen_sources.end(),
|
||||
std::back_inserter(captured_sources_));
|
||||
}
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(EmitFinished, sources, cap));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
DesktopCapturer::DesktopCapturer(v8::Isolate* isolate) {
|
||||
Init(isolate);
|
||||
capture_thread_ = base::CreateSequencedTaskRunnerWithTraits(
|
||||
{base::WithBaseSyncPrimitives(), base::MayBlock(),
|
||||
base::TaskPriority::USER_VISIBLE});
|
||||
}
|
||||
|
||||
DesktopCapturer::~DesktopCapturer() {}
|
||||
|
||||
void DesktopCapturer::StartHandling(bool capture_window,
|
||||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size) {
|
||||
capture_thread_->PostTask(
|
||||
FROM_HERE, base::BindOnce(StartHandlingTask, capture_window,
|
||||
capture_screen, thumbnail_size, this));
|
||||
}
|
||||
|
||||
void DesktopCapturer::OnSourceAdded(int index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceRemoved(int index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceMoved(int old_index, int new_index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceNameChanged(int index) {}
|
||||
|
||||
void DesktopCapturer::OnSourceThumbnailChanged(int index) {}
|
||||
|
||||
bool DesktopCapturer::OnRefreshFinished() {
|
||||
capture_thread_->PostTask(FROM_HERE,
|
||||
base::BindOnce(OnRefreshFinishedTask, this));
|
||||
return false;
|
||||
if (!capture_window_ && !capture_screen_)
|
||||
Emit("finished", captured_sources_);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "chrome/browser/media/desktop_media_list_observer.h"
|
||||
#include "chrome/browser/media/native_desktop_media_list.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
|
||||
#include "chrome/browser/media/webrtc/native_desktop_media_list.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
namespace atom {
|
||||
|
@ -35,25 +36,32 @@ class DesktopCapturer : public mate::EventEmitter<DesktopCapturer>,
|
|||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size);
|
||||
|
||||
std::unique_ptr<DesktopMediaList> media_list_;
|
||||
#if defined(OS_WIN)
|
||||
bool using_directx_capturer_ = false;
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
protected:
|
||||
explicit DesktopCapturer(v8::Isolate* isolate);
|
||||
~DesktopCapturer() override;
|
||||
|
||||
// DesktopMediaListObserver overrides.
|
||||
void OnSourceAdded(int index) override;
|
||||
void OnSourceRemoved(int index) override;
|
||||
void OnSourceMoved(int old_index, int new_index) override;
|
||||
void OnSourceNameChanged(int index) override;
|
||||
void OnSourceThumbnailChanged(int index) override;
|
||||
bool OnRefreshFinished() override;
|
||||
void OnSourceAdded(DesktopMediaList* list, int index) override;
|
||||
void OnSourceRemoved(DesktopMediaList* list, int index) override;
|
||||
void OnSourceMoved(DesktopMediaList* list,
|
||||
int old_index,
|
||||
int new_index) override;
|
||||
void OnSourceNameChanged(DesktopMediaList* list, int index) override;
|
||||
void OnSourceThumbnailChanged(DesktopMediaList* list, int index) override;
|
||||
void OnSourceUnchanged(DesktopMediaList* list) override;
|
||||
bool ShouldScheduleNextRefresh(DesktopMediaList* list) override;
|
||||
|
||||
private:
|
||||
scoped_refptr<base::SequencedTaskRunner> capture_thread_;
|
||||
void UpdateSourcesList(DesktopMediaList* list);
|
||||
|
||||
std::unique_ptr<DesktopMediaList> window_capturer_;
|
||||
std::unique_ptr<DesktopMediaList> screen_capturer_;
|
||||
std::vector<DesktopCapturer::Source> captured_sources_;
|
||||
bool capture_window_ = false;
|
||||
bool capture_screen_ = false;
|
||||
#if defined(OS_WIN)
|
||||
bool using_directx_capturer_ = false;
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DesktopCapturer);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
# Use of this source code is governed by the MIT license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//electron/buildflags/buildflags.gni")
|
||||
|
||||
# Builds some of the chrome sources that Electron depends
|
||||
# on unconditionally.
|
||||
source_set("chrome") {
|
||||
|
@ -10,6 +12,22 @@ source_set("chrome") {
|
|||
"//chrome/browser/ssl/security_state_tab_helper.cc",
|
||||
"//chrome/browser/ssl/security_state_tab_helper.h",
|
||||
]
|
||||
public_deps = [ "//content/public/browser" ]
|
||||
deps = [ "//components/security_state/content" ]
|
||||
public_deps = [
|
||||
"//content/public/browser",
|
||||
]
|
||||
deps = [
|
||||
"//components/security_state/content",
|
||||
]
|
||||
|
||||
if (enable_desktop_capturer) {
|
||||
sources += [
|
||||
"//chrome/browser/media/webrtc/desktop_media_list.h",
|
||||
"//chrome/browser/media/webrtc/desktop_media_list_base.cc",
|
||||
"//chrome/browser/media/webrtc/desktop_media_list_base.h",
|
||||
"//chrome/browser/media/webrtc/desktop_media_list_observer.h",
|
||||
"//chrome/browser/media/webrtc/native_desktop_media_list.cc",
|
||||
"//chrome/browser/media/webrtc/native_desktop_media_list.h",
|
||||
]
|
||||
deps += [ "//ui/snapshot" ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_
|
||||
#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_
|
||||
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/time/time.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
class DesktopMediaListObserver;
|
||||
|
||||
// DesktopMediaList provides the list of desktop media source (screens, windows,
|
||||
// tabs), and their thumbnails, to the desktop media picker dialog. It
|
||||
// transparently updates the list in the background, and notifies the desktop
|
||||
// media picker when something changes.
|
||||
class DesktopMediaList {
|
||||
public:
|
||||
// Struct used to represent each entry in the list.
|
||||
struct Source {
|
||||
// Id of the source.
|
||||
content::DesktopMediaID id;
|
||||
|
||||
// Name of the source that should be shown to the user.
|
||||
base::string16 name;
|
||||
|
||||
// The thumbnail for the source.
|
||||
gfx::ImageSkia thumbnail;
|
||||
};
|
||||
|
||||
virtual ~DesktopMediaList() {}
|
||||
|
||||
// Sets time interval between updates. By default list of sources and their
|
||||
// thumbnail are updated once per second. If called after StartUpdating() then
|
||||
// it will take effect only after the next update.
|
||||
virtual void SetUpdatePeriod(base::TimeDelta period) = 0;
|
||||
|
||||
// Sets size to which the thumbnails should be scaled. If called after
|
||||
// StartUpdating() then some thumbnails may be still scaled to the old size
|
||||
// until they are updated.
|
||||
virtual void SetThumbnailSize(const gfx::Size& thumbnail_size) = 0;
|
||||
|
||||
// Sets ID of the hosting desktop picker dialog. The window with this ID will
|
||||
// be filtered out from the list of sources.
|
||||
virtual void SetViewDialogWindowId(content::DesktopMediaID::Id dialog_id) = 0;
|
||||
|
||||
// Starts updating the model. The model is initially empty, so OnSourceAdded()
|
||||
// notifications will be generated for each existing source as it is
|
||||
// enumerated. After the initial enumeration the model will be refreshed based
|
||||
// on the update period, and notifications generated only for changes in the
|
||||
// model.
|
||||
virtual void StartUpdating(DesktopMediaListObserver* observer) = 0;
|
||||
|
||||
virtual int GetSourceCount() const = 0;
|
||||
virtual const Source& GetSource(int index) const = 0;
|
||||
virtual std::vector<Source> GetSources() const = 0;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_
|
||||
#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_
|
||||
|
||||
// Interface implemented by the desktop media picker dialog to receive
|
||||
// notifications about changes in DesktopMediaList.
|
||||
class DesktopMediaListObserver {
|
||||
public:
|
||||
virtual void OnSourceAdded(int index) = 0;
|
||||
virtual void OnSourceRemoved(int index) = 0;
|
||||
virtual void OnSourceMoved(int old_index, int new_index) = 0;
|
||||
virtual void OnSourceNameChanged(int index) = 0;
|
||||
virtual void OnSourceThumbnailChanged(int index) = 0;
|
||||
|
||||
// Return false to stop refreshing. The associated |DesktopMediaList| should
|
||||
// no longer be used.
|
||||
virtual bool OnRefreshFinished() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DesktopMediaListObserver() {}
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_
|
|
@ -1,367 +0,0 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/media/native_desktop_media_list.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
using base::PlatformThreadRef;
|
||||
|
||||
#include "base/hash.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task_scheduler/post_task.h"
|
||||
#include "chrome/browser/media/desktop_media_list_observer.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "media/base/video_util.h"
|
||||
#include "third_party/libyuv/include/libyuv/scale_argb.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
|
||||
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/gfx/skia_util.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
using content::DesktopMediaID;
|
||||
|
||||
namespace {
|
||||
|
||||
// Update the list every second.
|
||||
const int kDefaultUpdatePeriod = 1000;
|
||||
|
||||
// Returns a hash of a DesktopFrame content to detect when image for a desktop
|
||||
// media source has changed.
|
||||
uint32_t GetFrameHash(webrtc::DesktopFrame* frame) {
|
||||
int data_size = frame->stride() * frame->size().height();
|
||||
return base::Hash(frame->data(), data_size);
|
||||
}
|
||||
|
||||
gfx::ImageSkia ScaleDesktopFrame(std::unique_ptr<webrtc::DesktopFrame> frame,
|
||||
gfx::Size size) {
|
||||
gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
|
||||
gfx::Rect(0, 0, size.width(), size.height()),
|
||||
gfx::Size(frame->size().width(), frame->size().height()));
|
||||
|
||||
SkBitmap result;
|
||||
result.allocN32Pixels(scaled_rect.width(), scaled_rect.height(), true);
|
||||
|
||||
uint8* pixels_data = reinterpret_cast<uint8*>(result.getPixels());
|
||||
libyuv::ARGBScale(frame->data(), frame->stride(), frame->size().width(),
|
||||
frame->size().height(), pixels_data, result.rowBytes(),
|
||||
scaled_rect.width(), scaled_rect.height(),
|
||||
libyuv::kFilterBilinear);
|
||||
|
||||
// Set alpha channel values to 255 for all pixels.
|
||||
// TODO(sergeyu): Fix screen/window capturers to capture alpha channel and
|
||||
// remove this code. Currently screen/window capturers (at least some
|
||||
// implementations) only capture R, G and B channels and set Alpha to 0.
|
||||
// crbug.com/264424
|
||||
for (int y = 0; y < result.height(); ++y) {
|
||||
for (int x = 0; x < result.width(); ++x) {
|
||||
pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3] =
|
||||
0xff;
|
||||
}
|
||||
}
|
||||
|
||||
return gfx::ImageSkia::CreateFrom1xBitmap(result);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeDesktopMediaList::SourceDescription::SourceDescription(
|
||||
DesktopMediaID id,
|
||||
const base::string16& name)
|
||||
: id(id), name(name) {}
|
||||
|
||||
class NativeDesktopMediaList::Worker
|
||||
: public webrtc::DesktopCapturer::Callback {
|
||||
public:
|
||||
Worker(base::WeakPtr<NativeDesktopMediaList> media_list,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer);
|
||||
~Worker() override;
|
||||
|
||||
void Refresh(const gfx::Size& thumbnail_size,
|
||||
content::DesktopMediaID::Id view_dialog_id);
|
||||
|
||||
private:
|
||||
typedef std::map<DesktopMediaID, uint32> ImageHashesMap;
|
||||
|
||||
// webrtc::DesktopCapturer::Callback interface.
|
||||
void OnCaptureResult(webrtc::DesktopCapturer::Result result,
|
||||
std::unique_ptr<webrtc::DesktopFrame> frame) override;
|
||||
|
||||
base::WeakPtr<NativeDesktopMediaList> media_list_;
|
||||
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer_;
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer_;
|
||||
|
||||
std::unique_ptr<webrtc::DesktopFrame> current_frame_;
|
||||
|
||||
ImageHashesMap image_hashes_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Worker);
|
||||
};
|
||||
|
||||
NativeDesktopMediaList::Worker::Worker(
|
||||
base::WeakPtr<NativeDesktopMediaList> media_list,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer)
|
||||
: media_list_(media_list),
|
||||
screen_capturer_(std::move(screen_capturer)),
|
||||
window_capturer_(std::move(window_capturer)) {
|
||||
if (screen_capturer_)
|
||||
screen_capturer_->Start(this);
|
||||
if (window_capturer_)
|
||||
window_capturer_->Start(this);
|
||||
}
|
||||
|
||||
NativeDesktopMediaList::Worker::~Worker() {}
|
||||
|
||||
void NativeDesktopMediaList::Worker::Refresh(
|
||||
const gfx::Size& thumbnail_size,
|
||||
content::DesktopMediaID::Id view_dialog_id) {
|
||||
std::vector<SourceDescription> sources;
|
||||
|
||||
if (screen_capturer_) {
|
||||
webrtc::DesktopCapturer::SourceList screens;
|
||||
if (screen_capturer_->GetSourceList(&screens)) {
|
||||
bool mutiple_screens = screens.size() > 1;
|
||||
base::string16 title;
|
||||
for (size_t i = 0; i < screens.size(); ++i) {
|
||||
if (mutiple_screens) {
|
||||
title = base::UTF8ToUTF16("Screen " + base::IntToString(i + 1));
|
||||
} else {
|
||||
title = base::UTF8ToUTF16("Entire screen");
|
||||
}
|
||||
sources.push_back(SourceDescription(
|
||||
DesktopMediaID(DesktopMediaID::TYPE_SCREEN, screens[i].id), title));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (window_capturer_) {
|
||||
webrtc::DesktopCapturer::SourceList windows;
|
||||
if (window_capturer_->GetSourceList(&windows)) {
|
||||
for (auto it = windows.begin(); 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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update list of windows before updating thumbnails.
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&NativeDesktopMediaList::OnSourcesList, media_list_, sources));
|
||||
|
||||
ImageHashesMap new_image_hashes;
|
||||
|
||||
// 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_->SelectSource(source.id.id))
|
||||
continue;
|
||||
screen_capturer_->CaptureFrame();
|
||||
break;
|
||||
|
||||
case DesktopMediaID::TYPE_WINDOW:
|
||||
if (!window_capturer_->SelectSource(source.id.id))
|
||||
continue;
|
||||
window_capturer_->CaptureFrame();
|
||||
break;
|
||||
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
// Expect that DesktopCapturer to always captures frames synchronously.
|
||||
// |current_frame_| may be NULL if capture failed (e.g. because window has
|
||||
// been closed).
|
||||
if (current_frame_) {
|
||||
uint32_t frame_hash = GetFrameHash(current_frame_.get());
|
||||
new_image_hashes[source.id] = frame_hash;
|
||||
|
||||
// Scale the image only if it has changed.
|
||||
ImageHashesMap::iterator it = image_hashes_.find(source.id);
|
||||
if (it == image_hashes_.end() || it->second != frame_hash) {
|
||||
gfx::ImageSkia thumbnail =
|
||||
ScaleDesktopFrame(std::move(current_frame_), thumbnail_size);
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, media_list_,
|
||||
i, thumbnail));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
image_hashes_.swap(new_image_hashes);
|
||||
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&NativeDesktopMediaList::OnRefreshFinished, media_list_));
|
||||
|
||||
// Destroy capturers when done.
|
||||
screen_capturer_.reset();
|
||||
window_capturer_.reset();
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::Worker::OnCaptureResult(
|
||||
webrtc::DesktopCapturer::Result result,
|
||||
std::unique_ptr<webrtc::DesktopFrame> frame) {
|
||||
current_frame_ = std::move(frame);
|
||||
}
|
||||
|
||||
NativeDesktopMediaList::NativeDesktopMediaList(
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer)
|
||||
: screen_capturer_(std::move(screen_capturer)),
|
||||
window_capturer_(std::move(window_capturer)),
|
||||
update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
|
||||
thumbnail_size_(100, 100),
|
||||
view_dialog_id_(-1),
|
||||
observer_(NULL),
|
||||
weak_factory_(this) {
|
||||
capture_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
|
||||
{base::WithBaseSyncPrimitives(), base::MayBlock(),
|
||||
base::TaskPriority::USER_VISIBLE});
|
||||
}
|
||||
|
||||
NativeDesktopMediaList::~NativeDesktopMediaList() {
|
||||
capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release());
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) {
|
||||
DCHECK(!observer_);
|
||||
update_period_ = period;
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::SetThumbnailSize(const gfx::Size& thumbnail_size) {
|
||||
thumbnail_size_ = thumbnail_size;
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::SetViewDialogWindowId(
|
||||
content::DesktopMediaID::Id dialog_id) {
|
||||
view_dialog_id_ = dialog_id;
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) {
|
||||
DCHECK(!observer_);
|
||||
DCHECK(screen_capturer_ || window_capturer_);
|
||||
|
||||
observer_ = observer;
|
||||
|
||||
worker_.reset(new Worker(weak_factory_.GetWeakPtr(),
|
||||
std::move(screen_capturer_),
|
||||
std::move(window_capturer_)));
|
||||
Refresh();
|
||||
}
|
||||
|
||||
int NativeDesktopMediaList::GetSourceCount() const {
|
||||
return sources_.size();
|
||||
}
|
||||
|
||||
const DesktopMediaList::Source& NativeDesktopMediaList::GetSource(
|
||||
int index) const {
|
||||
return sources_[index];
|
||||
}
|
||||
|
||||
std::vector<DesktopMediaList::Source> NativeDesktopMediaList::GetSources()
|
||||
const {
|
||||
return sources_;
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::Refresh() {
|
||||
capture_task_runner_->PostTask(
|
||||
FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()),
|
||||
thumbnail_size_, view_dialog_id_));
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::OnSourcesList(
|
||||
const std::vector<SourceDescription>& new_sources) {
|
||||
typedef std::set<content::DesktopMediaID> SourceSet;
|
||||
SourceSet new_source_set;
|
||||
for (size_t i = 0; i < new_sources.size(); ++i) {
|
||||
new_source_set.insert(new_sources[i].id);
|
||||
}
|
||||
// Iterate through the old sources to find the removed sources.
|
||||
for (size_t i = 0; i < sources_.size(); ++i) {
|
||||
if (new_source_set.find(sources_[i].id) == new_source_set.end()) {
|
||||
observer_->OnSourceRemoved(i);
|
||||
sources_.erase(sources_.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
// Iterate through the new sources to find the added sources.
|
||||
if (new_sources.size() > sources_.size()) {
|
||||
SourceSet old_source_set;
|
||||
for (size_t i = 0; i < sources_.size(); ++i) {
|
||||
old_source_set.insert(sources_[i].id);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < new_sources.size(); ++i) {
|
||||
if (old_source_set.find(new_sources[i].id) == old_source_set.end()) {
|
||||
sources_.insert(sources_.begin() + i, Source());
|
||||
sources_[i].id = new_sources[i].id;
|
||||
sources_[i].name = new_sources[i].name;
|
||||
observer_->OnSourceAdded(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
DCHECK_EQ(new_sources.size(), sources_.size());
|
||||
|
||||
// Find the moved/changed sources.
|
||||
size_t pos = 0;
|
||||
while (pos < sources_.size()) {
|
||||
if (!(sources_[pos].id == new_sources[pos].id)) {
|
||||
// Find the source that should be moved to |pos|, starting from |pos + 1|
|
||||
// of |sources_|, because entries before |pos| should have been sorted.
|
||||
size_t old_pos = pos + 1;
|
||||
for (; old_pos < sources_.size(); ++old_pos) {
|
||||
if (sources_[old_pos].id == new_sources[pos].id)
|
||||
break;
|
||||
}
|
||||
DCHECK(sources_[old_pos].id == new_sources[pos].id);
|
||||
|
||||
// Move the source from |old_pos| to |pos|.
|
||||
Source temp = sources_[old_pos];
|
||||
sources_.erase(sources_.begin() + old_pos);
|
||||
sources_.insert(sources_.begin() + pos, temp);
|
||||
|
||||
observer_->OnSourceMoved(old_pos, pos);
|
||||
}
|
||||
|
||||
if (sources_[pos].name != new_sources[pos].name) {
|
||||
sources_[pos].name = new_sources[pos].name;
|
||||
observer_->OnSourceNameChanged(pos);
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::OnSourceThumbnail(int index,
|
||||
const gfx::ImageSkia& image) {
|
||||
DCHECK_LT(index, static_cast<int>(sources_.size()));
|
||||
sources_[index].thumbnail = image;
|
||||
observer_->OnSourceThumbnailChanged(index);
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::OnRefreshFinished() {
|
||||
// Give a chance to the observer to stop the refresh work.
|
||||
bool is_continue = observer_->OnRefreshFinished();
|
||||
if (is_continue) {
|
||||
BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&NativeDesktopMediaList::Refresh,
|
||||
weak_factory_.GetWeakPtr()),
|
||||
update_period_);
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_
|
||||
#define CHROME_BROWSER_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/sequenced_task_runner.h"
|
||||
#include "chrome/browser/media/desktop_media_list.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
namespace webrtc {
|
||||
class DesktopCapturer;
|
||||
}
|
||||
|
||||
// Implementation of DesktopMediaList that shows native screens and
|
||||
// native windows.
|
||||
class NativeDesktopMediaList : public DesktopMediaList {
|
||||
public:
|
||||
// Caller may pass NULL for either of the arguments in case when only some
|
||||
// types of sources the model should be populated with (e.g. it will only
|
||||
// contain windows, if |screen_capturer| is NULL).
|
||||
NativeDesktopMediaList(
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer);
|
||||
~NativeDesktopMediaList() override;
|
||||
|
||||
// DesktopMediaList interface.
|
||||
void SetUpdatePeriod(base::TimeDelta period) override;
|
||||
void SetThumbnailSize(const gfx::Size& thumbnail_size) override;
|
||||
void StartUpdating(DesktopMediaListObserver* observer) override;
|
||||
int GetSourceCount() const override;
|
||||
const Source& GetSource(int index) const override;
|
||||
std::vector<Source> GetSources() const override;
|
||||
void SetViewDialogWindowId(content::DesktopMediaID::Id dialog_id) override;
|
||||
|
||||
private:
|
||||
class Worker;
|
||||
friend class Worker;
|
||||
|
||||
// Struct used to represent sources list the model gets from the Worker.
|
||||
struct SourceDescription {
|
||||
SourceDescription(content::DesktopMediaID id, const base::string16& name);
|
||||
|
||||
content::DesktopMediaID id;
|
||||
base::string16 name;
|
||||
};
|
||||
|
||||
// Order comparator for sources. Used to sort list of sources.
|
||||
static bool CompareSources(const SourceDescription& a,
|
||||
const SourceDescription& b);
|
||||
|
||||
// Post a task for the |worker_| to update list of windows and get thumbnails.
|
||||
void Refresh();
|
||||
|
||||
// Called by |worker_| to refresh the model. First it posts tasks for
|
||||
// OnSourcesList() with the fresh list of sources, then follows with
|
||||
// OnSourceThumbnail() for each changed thumbnail and then calls
|
||||
// OnRefreshFinished() at the end.
|
||||
void OnSourcesList(const std::vector<SourceDescription>& sources);
|
||||
void OnSourceThumbnail(int index, const gfx::ImageSkia& thumbnail);
|
||||
void OnRefreshFinished();
|
||||
|
||||
// Capturers specified in SetCapturers() and passed to the |worker_| later.
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer_;
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer_;
|
||||
|
||||
// Time interval between mode updates.
|
||||
base::TimeDelta update_period_;
|
||||
|
||||
// Size of thumbnails generated by the model.
|
||||
gfx::Size thumbnail_size_;
|
||||
|
||||
// ID of the hosting dialog.
|
||||
content::DesktopMediaID::Id view_dialog_id_;
|
||||
|
||||
// The observer passed to StartUpdating().
|
||||
DesktopMediaListObserver* observer_;
|
||||
|
||||
// Task runner used for the |worker_|.
|
||||
scoped_refptr<base::SequencedTaskRunner> capture_task_runner_;
|
||||
|
||||
// An object that does all the work of getting list of sources on a background
|
||||
// thread (see |capture_task_runner_|). Destroyed on |capture_task_runner_|
|
||||
// after the model is destroyed.
|
||||
std::unique_ptr<Worker> worker_;
|
||||
|
||||
// Current list of sources.
|
||||
std::vector<Source> sources_;
|
||||
|
||||
base::WeakPtrFactory<NativeDesktopMediaList> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeDesktopMediaList);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_
|
|
@ -587,10 +587,6 @@ filenames = {
|
|||
"chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h",
|
||||
"chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc",
|
||||
"chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h",
|
||||
"chromium_src/chrome/browser/media/desktop_media_list.h",
|
||||
"chromium_src/chrome/browser/media/desktop_media_list_observer.h",
|
||||
"chromium_src/chrome/browser/media/native_desktop_media_list.cc",
|
||||
"chromium_src/chrome/browser/media/native_desktop_media_list.h",
|
||||
"chromium_src/chrome/browser/printing/print_job.cc",
|
||||
"chromium_src/chrome/browser/printing/print_job.h",
|
||||
"chromium_src/chrome/browser/printing/print_job_manager.cc",
|
||||
|
|
|
@ -469,3 +469,11 @@ patches:
|
|||
* Fixes a main_application_delegate SDK change
|
||||
* Fixes a non-null SDK change in a net unittest.
|
||||
This is needed for Electron to compile with XCode 10.0.
|
||||
-
|
||||
author: deepak1556 <hop2deep@gmail.com>
|
||||
file: desktop_media_list.patch
|
||||
description: |
|
||||
* Adds a new observer method to DesktopMediaListObserver for
|
||||
desktop capture api.
|
||||
* Backports https://chromium-review.googlesource.com/c/chromium/src/+/1199806
|
||||
that fixes crash with screen capturer, can be removed in 71.0.3539.0
|
||||
|
|
304
patches/common/chromium/desktop_media_list.patch
Normal file
304
patches/common/chromium/desktop_media_list.patch
Normal file
|
@ -0,0 +1,304 @@
|
|||
diff --git a/chrome/browser/media/webrtc/desktop_media_list.h b/chrome/browser/media/webrtc/desktop_media_list.h
|
||||
index 8e02a8a95eb0..3497b85428a5 100644
|
||||
--- a/chrome/browser/media/webrtc/desktop_media_list.h
|
||||
+++ b/chrome/browser/media/webrtc/desktop_media_list.h
|
||||
@@ -32,6 +32,9 @@ class DesktopMediaList {
|
||||
|
||||
virtual ~DesktopMediaList() {}
|
||||
|
||||
+ // Allows listening to notifications generated by the model.
|
||||
+ virtual void AddObserver(DesktopMediaListObserver* observer) = 0;
|
||||
+
|
||||
// Sets time interval between updates. By default list of sources and their
|
||||
// thumbnail are updated once per second. If called after StartUpdating() then
|
||||
// it will take effect only after the next update.
|
||||
@@ -51,10 +54,11 @@ class DesktopMediaList {
|
||||
// enumerated. After the initial enumeration the model will be refreshed based
|
||||
// on the update period, and notifications generated only for changes in the
|
||||
// model.
|
||||
- virtual void StartUpdating(DesktopMediaListObserver* observer) = 0;
|
||||
+ virtual void StartUpdating() = 0;
|
||||
|
||||
virtual int GetSourceCount() const = 0;
|
||||
virtual const Source& GetSource(int index) const = 0;
|
||||
+ virtual const std::vector<Source>& GetSources() const = 0;
|
||||
|
||||
virtual content::DesktopMediaID::Type GetMediaListType() const = 0;
|
||||
};
|
||||
diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.cc b/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
index 43dd95ef72f5..d4662708f649 100644
|
||||
--- a/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
+++ b/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
@@ -18,6 +18,11 @@ DesktopMediaListBase::DesktopMediaListBase(base::TimeDelta update_period)
|
||||
|
||||
DesktopMediaListBase::~DesktopMediaListBase() {}
|
||||
|
||||
+void DesktopMediaListBase::AddObserver(DesktopMediaListObserver* observer) {
|
||||
+ DCHECK(!observer_);
|
||||
+ observer_ = observer;
|
||||
+}
|
||||
+
|
||||
void DesktopMediaListBase::SetUpdatePeriod(base::TimeDelta period) {
|
||||
DCHECK(!observer_);
|
||||
update_period_ = period;
|
||||
@@ -31,10 +36,7 @@ void DesktopMediaListBase::SetViewDialogWindowId(DesktopMediaID dialog_id) {
|
||||
view_dialog_id_ = dialog_id;
|
||||
}
|
||||
|
||||
-void DesktopMediaListBase::StartUpdating(DesktopMediaListObserver* observer) {
|
||||
- DCHECK(!observer_);
|
||||
-
|
||||
- observer_ = observer;
|
||||
+void DesktopMediaListBase::StartUpdating() {
|
||||
Refresh();
|
||||
}
|
||||
|
||||
@@ -49,6 +51,11 @@ const DesktopMediaList::Source& DesktopMediaListBase::GetSource(
|
||||
return sources_[index];
|
||||
}
|
||||
|
||||
+const std::vector<DesktopMediaList::Source>& DesktopMediaListBase::GetSources()
|
||||
+ const {
|
||||
+ return sources_;
|
||||
+}
|
||||
+
|
||||
DesktopMediaID::Type DesktopMediaListBase::GetMediaListType() const {
|
||||
return type_;
|
||||
}
|
||||
@@ -60,6 +67,12 @@ DesktopMediaListBase::SourceDescription::SourceDescription(
|
||||
|
||||
void DesktopMediaListBase::UpdateSourcesList(
|
||||
const std::vector<SourceDescription>& new_sources) {
|
||||
+ // Notify observer when there was no new source captured.
|
||||
+ if (new_sources.empty()) {
|
||||
+ observer_->OnSourceUnchanged(this);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
typedef std::set<DesktopMediaID> SourceSet;
|
||||
SourceSet new_source_set;
|
||||
for (size_t i = 0; i < new_sources.size(); ++i) {
|
||||
@@ -132,6 +145,8 @@ void DesktopMediaListBase::UpdateSourceThumbnail(DesktopMediaID id,
|
||||
}
|
||||
|
||||
void DesktopMediaListBase::ScheduleNextRefresh() {
|
||||
+ if (!observer_->ShouldScheduleNextRefresh(this))
|
||||
+ return;
|
||||
BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
|
||||
base::BindOnce(&DesktopMediaListBase::Refresh,
|
||||
weak_factory_.GetWeakPtr()),
|
||||
diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.h b/chrome/browser/media/webrtc/desktop_media_list_base.h
|
||||
index 746df1210aa9..461e0edf8509 100644
|
||||
--- a/chrome/browser/media/webrtc/desktop_media_list_base.h
|
||||
+++ b/chrome/browser/media/webrtc/desktop_media_list_base.h
|
||||
@@ -24,12 +24,14 @@ class DesktopMediaListBase : public DesktopMediaList {
|
||||
~DesktopMediaListBase() override;
|
||||
|
||||
// DesktopMediaList interface.
|
||||
+ void AddObserver(DesktopMediaListObserver* observer) override;
|
||||
void SetUpdatePeriod(base::TimeDelta period) override;
|
||||
void SetThumbnailSize(const gfx::Size& thumbnail_size) override;
|
||||
void SetViewDialogWindowId(content::DesktopMediaID dialog_id) override;
|
||||
- void StartUpdating(DesktopMediaListObserver* observer) override;
|
||||
+ void StartUpdating() override;
|
||||
int GetSourceCount() const override;
|
||||
const Source& GetSource(int index) const override;
|
||||
+ const std::vector<Source>& GetSources() const override;
|
||||
content::DesktopMediaID::Type GetMediaListType() const override;
|
||||
|
||||
static uint32_t GetImageHash(const gfx::Image& image);
|
||||
diff --git a/chrome/browser/media/webrtc/desktop_media_list_observer.h b/chrome/browser/media/webrtc/desktop_media_list_observer.h
|
||||
index 47401abc984e..ca6a527ffac8 100644
|
||||
--- a/chrome/browser/media/webrtc/desktop_media_list_observer.h
|
||||
+++ b/chrome/browser/media/webrtc/desktop_media_list_observer.h
|
||||
@@ -18,6 +18,10 @@ class DesktopMediaListObserver {
|
||||
int new_index) = 0;
|
||||
virtual void OnSourceNameChanged(DesktopMediaList* list, int index) = 0;
|
||||
virtual void OnSourceThumbnailChanged(DesktopMediaList* list, int index) = 0;
|
||||
+ virtual void OnSourceUnchanged(DesktopMediaList* list) = 0;
|
||||
+ // Return value indicates whether the observer should continue listening
|
||||
+ // for capture updates.
|
||||
+ virtual bool ShouldScheduleNextRefresh(DesktopMediaList* list) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DesktopMediaListObserver() {}
|
||||
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
index 0c9ba953cb3c..5a2d853aeeac 100644
|
||||
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
@@ -5,10 +5,16 @@
|
||||
#include "chrome/browser/media/webrtc/native_desktop_media_list.h"
|
||||
|
||||
#include "base/hash.h"
|
||||
+#include "base/single_thread_task_runner.h"
|
||||
+#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task_scheduler/post_task.h"
|
||||
+#include "base/threading/thread_restrictions.h"
|
||||
+#include "build/build_config.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
|
||||
+#if 0
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
+#endif
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "media/base/video_util.h"
|
||||
#include "third_party/libyuv/include/libyuv/scale_argb.h"
|
||||
@@ -76,11 +82,13 @@ gfx::ImageSkia ScaleDesktopFrame(std::unique_ptr<webrtc::DesktopFrame> frame,
|
||||
class NativeDesktopMediaList::Worker
|
||||
: public webrtc::DesktopCapturer::Callback {
|
||||
public:
|
||||
- Worker(base::WeakPtr<NativeDesktopMediaList> media_list,
|
||||
+ Worker(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
||||
+ base::WeakPtr<NativeDesktopMediaList> media_list,
|
||||
DesktopMediaID::Type type,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> capturer);
|
||||
~Worker() override;
|
||||
|
||||
+ void Start();
|
||||
void Refresh(const DesktopMediaID::Id& view_dialog_id);
|
||||
|
||||
void RefreshThumbnails(const std::vector<DesktopMediaID>& native_ids,
|
||||
@@ -93,6 +101,9 @@ class NativeDesktopMediaList::Worker
|
||||
void OnCaptureResult(webrtc::DesktopCapturer::Result result,
|
||||
std::unique_ptr<webrtc::DesktopFrame> frame) override;
|
||||
|
||||
+ // Task runner used for capturing operations.
|
||||
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
||||
+
|
||||
base::WeakPtr<NativeDesktopMediaList> media_list_;
|
||||
|
||||
DesktopMediaID::Type type_;
|
||||
@@ -106,17 +117,27 @@ class NativeDesktopMediaList::Worker
|
||||
};
|
||||
|
||||
NativeDesktopMediaList::Worker::Worker(
|
||||
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
||||
base::WeakPtr<NativeDesktopMediaList> media_list,
|
||||
DesktopMediaID::Type type,
|
||||
std::unique_ptr<webrtc::DesktopCapturer> capturer)
|
||||
- : media_list_(media_list), type_(type), capturer_(std::move(capturer)) {
|
||||
- capturer_->Start(this);
|
||||
+ : task_runner_(task_runner),
|
||||
+ media_list_(media_list),
|
||||
+ type_(type),
|
||||
+ capturer_(std::move(capturer)) {}
|
||||
+
|
||||
+NativeDesktopMediaList::Worker::~Worker() {
|
||||
+ DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
}
|
||||
|
||||
-NativeDesktopMediaList::Worker::~Worker() {}
|
||||
+void NativeDesktopMediaList::Worker::Start() {
|
||||
+ DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
+ capturer_->Start(this);
|
||||
+}
|
||||
|
||||
void NativeDesktopMediaList::Worker::Refresh(
|
||||
const DesktopMediaID::Id& view_dialog_id) {
|
||||
+ DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
std::vector<SourceDescription> result;
|
||||
|
||||
webrtc::DesktopCapturer::SourceList sources;
|
||||
@@ -133,11 +154,8 @@ void NativeDesktopMediaList::Worker::Refresh(
|
||||
// Just in case 'Screen' is inflected depending on the screen number,
|
||||
// use plural formatter.
|
||||
title = mutiple_sources
|
||||
- ? l10n_util::GetPluralStringFUTF16(
|
||||
- IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME,
|
||||
- static_cast<int>(i + 1))
|
||||
- : l10n_util::GetStringUTF16(
|
||||
- IDS_DESKTOP_MEDIA_PICKER_SINGLE_SCREEN_NAME);
|
||||
+ ? base::UTF8ToUTF16("Screen " + base::IntToString(i + 1))
|
||||
+ : base::UTF8ToUTF16("Entire screen");
|
||||
break;
|
||||
|
||||
case DesktopMediaID::TYPE_WINDOW:
|
||||
@@ -163,6 +181,7 @@ void NativeDesktopMediaList::Worker::Refresh(
|
||||
void NativeDesktopMediaList::Worker::RefreshThumbnails(
|
||||
const std::vector<DesktopMediaID>& native_ids,
|
||||
const gfx::Size& thumbnail_size) {
|
||||
+ DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
ImageHashesMap new_image_hashes;
|
||||
|
||||
// Get a thumbnail for each native source.
|
||||
@@ -210,17 +229,30 @@ NativeDesktopMediaList::NativeDesktopMediaList(
|
||||
std::unique_ptr<webrtc::DesktopCapturer> capturer)
|
||||
: DesktopMediaListBase(base::TimeDelta::FromMilliseconds(
|
||||
kDefaultNativeDesktopMediaListUpdatePeriod)),
|
||||
+ thread_("DesktopMediaListCaptureThread"),
|
||||
weak_factory_(this) {
|
||||
type_ = type;
|
||||
- capture_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
|
||||
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
|
||||
|
||||
- worker_.reset(
|
||||
- new Worker(weak_factory_.GetWeakPtr(), type, std::move(capturer)));
|
||||
+#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||
+ // On Windows/OSX the thread must be a UI thread.
|
||||
+ base::MessageLoop::Type thread_type = base::MessageLoop::TYPE_UI;
|
||||
+#else
|
||||
+ base::MessageLoop::Type thread_type = base::MessageLoop::TYPE_DEFAULT;
|
||||
+#endif
|
||||
+ thread_.StartWithOptions(base::Thread::Options(thread_type, 0));
|
||||
+
|
||||
+ worker_.reset(new Worker(thread_.task_runner(), weak_factory_.GetWeakPtr(),
|
||||
+ type, std::move(capturer)));
|
||||
+
|
||||
+ thread_.task_runner()->PostTask(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(&Worker::Start, base::Unretained(worker_.get())));
|
||||
}
|
||||
|
||||
NativeDesktopMediaList::~NativeDesktopMediaList() {
|
||||
- capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release());
|
||||
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
+ thread_.task_runner()->DeleteSoon(FROM_HERE, worker_.release());
|
||||
+ thread_.Stop();
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::Refresh() {
|
||||
@@ -230,7 +262,7 @@ void NativeDesktopMediaList::Refresh() {
|
||||
new_aura_thumbnail_hashes_.clear();
|
||||
#endif
|
||||
|
||||
- capture_task_runner_->PostTask(
|
||||
+ thread_.task_runner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&Worker::Refresh, base::Unretained(worker_.get()),
|
||||
view_dialog_id_.id));
|
||||
@@ -280,7 +312,7 @@ void NativeDesktopMediaList::RefreshForAuraWindows(
|
||||
#if defined(USE_AURA)
|
||||
pending_native_thumbnail_capture_ = true;
|
||||
#endif
|
||||
- capture_task_runner_->PostTask(
|
||||
+ thread_.task_runner()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&Worker::RefreshThumbnails,
|
||||
base::Unretained(worker_.get()), native_ids,
|
||||
thumbnail_size_));
|
||||
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.h b/chrome/browser/media/webrtc/native_desktop_media_list.h
|
||||
index e6f0e17b05ee..75c9ca04ce48 100644
|
||||
--- a/chrome/browser/media/webrtc/native_desktop_media_list.h
|
||||
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.h
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
-#include "base/sequenced_task_runner.h"
|
||||
+#include "base/threading/thread.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_media_list_base.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
@@ -44,12 +44,7 @@ class NativeDesktopMediaList : public DesktopMediaListBase {
|
||||
gfx::Image image);
|
||||
#endif
|
||||
|
||||
- // Task runner used for the |worker_|.
|
||||
- scoped_refptr<base::SequencedTaskRunner> capture_task_runner_;
|
||||
-
|
||||
- // An object that does all the work of getting list of sources on a background
|
||||
- // thread (see |capture_task_runner_|). Destroyed on |capture_task_runner_|
|
||||
- // after the model is destroyed.
|
||||
+ base::Thread thread_;
|
||||
std::unique_ptr<Worker> worker_;
|
||||
|
||||
#if defined(USE_AURA)
|
|
@ -1,13 +1,5 @@
|
|||
repo: src/third_party/webrtc
|
||||
patches:
|
||||
-
|
||||
author: null
|
||||
file: webrtc-desktop_capturer_mac.patch
|
||||
description: null
|
||||
-
|
||||
author: null
|
||||
file: webrtc-rwlock_null.patch
|
||||
description: null
|
||||
-
|
||||
author: Nitish Sakhawalkar <nitsakh@icloud.com>
|
||||
file: disable-warning-win.patch
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
diff --git a/modules/desktop_capture/mac/screen_capturer_mac.mm b/modules/desktop_capture/mac/screen_capturer_mac.mm
|
||||
index df18777226..6a1e3da6ab 100644
|
||||
--- a/modules/desktop_capture/mac/screen_capturer_mac.mm
|
||||
+++ b/modules/desktop_capture/mac/screen_capturer_mac.mm
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/constructormagic.h"
|
||||
#include "rtc_base/logging.h"
|
||||
+#include "rtc_base/synchronization/rw_lock_wrapper.h"
|
||||
#include "rtc_base/timeutils.h"
|
||||
#include "sdk/objc/Framework/Classes/Common/scoped_cftyperef.h"
|
||||
|
||||
@@ -28,18 +29,31 @@ namespace webrtc {
|
||||
// destroy itself once it's done.
|
||||
class DisplayStreamManager {
|
||||
public:
|
||||
- int GetUniqueId() { return ++unique_id_generator_; }
|
||||
- void DestroyStream(int unique_id) {
|
||||
- auto it = display_stream_wrappers_.find(unique_id);
|
||||
- RTC_CHECK(it != display_stream_wrappers_.end());
|
||||
- RTC_CHECK(!it->second.active);
|
||||
- CFRelease(it->second.stream);
|
||||
- display_stream_wrappers_.erase(it);
|
||||
+ DisplayStreamManager() : rw_lock_(RWLockWrapper::CreateRWLock()) {}
|
||||
+ RWLockWrapper* GetLock() {return rw_lock_.get();};
|
||||
|
||||
- if (ready_for_self_destruction_ && display_stream_wrappers_.empty()) delete this;
|
||||
+ int GetUniqueId() {
|
||||
+ WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_);
|
||||
+ return ++unique_id_generator_;
|
||||
+ }
|
||||
+ void DestroyStream(int unique_id) {
|
||||
+ bool finalize;
|
||||
+ {
|
||||
+ WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_);
|
||||
+ auto it = display_stream_wrappers_.find(unique_id);
|
||||
+ RTC_CHECK(it != display_stream_wrappers_.end());
|
||||
+ RTC_CHECK(!it->second.active);
|
||||
+ CFRelease(it->second.stream);
|
||||
+ display_stream_wrappers_.erase(it);
|
||||
+ finalize = ready_for_self_destruction_ && display_stream_wrappers_.empty();
|
||||
+ }
|
||||
+ if (finalize) {
|
||||
+ delete this;
|
||||
+ }
|
||||
}
|
||||
|
||||
void SaveStream(int unique_id, CGDisplayStreamRef stream) {
|
||||
+ WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_);
|
||||
RTC_CHECK(unique_id <= unique_id_generator_);
|
||||
DisplayStreamWrapper wrapper;
|
||||
wrapper.stream = stream;
|
||||
@@ -47,6 +61,7 @@ class DisplayStreamManager {
|
||||
}
|
||||
|
||||
void UnregisterActiveStreams() {
|
||||
+ WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_);
|
||||
for (auto& pair : display_stream_wrappers_) {
|
||||
DisplayStreamWrapper& wrapper = pair.second;
|
||||
if (wrapper.active) {
|
||||
@@ -61,12 +76,23 @@ class DisplayStreamManager {
|
||||
void PrepareForSelfDestruction() {
|
||||
ready_for_self_destruction_ = true;
|
||||
|
||||
- if (display_stream_wrappers_.empty()) delete this;
|
||||
+ bool finalize;
|
||||
+ {
|
||||
+ WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_);
|
||||
+ ready_for_self_destruction_ = true;
|
||||
+ finalize = display_stream_wrappers_.empty();
|
||||
+ }
|
||||
+ if (finalize) {
|
||||
+ delete this;
|
||||
+ }
|
||||
}
|
||||
|
||||
// Once the DisplayStreamManager is ready for destruction, the
|
||||
// ScreenCapturerMac is no longer present. Any updates should be ignored.
|
||||
- bool ShouldIgnoreUpdates() { return ready_for_self_destruction_; }
|
||||
+ // Note: not thread-safe! Acquire and release a lock manually.
|
||||
+ bool ShouldIgnoreUpdates() {
|
||||
+ return ready_for_self_destruction_;
|
||||
+ }
|
||||
|
||||
private:
|
||||
struct DisplayStreamWrapper {
|
||||
@@ -81,6 +107,7 @@ class DisplayStreamManager {
|
||||
std::map<int, DisplayStreamWrapper> display_stream_wrappers_;
|
||||
int unique_id_generator_ = 0;
|
||||
bool ready_for_self_destruction_ = false;
|
||||
+ std::unique_ptr<RWLockWrapper> rw_lock_;
|
||||
};
|
||||
|
||||
namespace {
|
||||
@@ -507,8 +534,6 @@ bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() {
|
||||
return;
|
||||
}
|
||||
|
||||
- if (manager->ShouldIgnoreUpdates()) return;
|
||||
-
|
||||
// Only pay attention to frame updates.
|
||||
if (status != kCGDisplayStreamFrameStatusFrameComplete) return;
|
||||
|
||||
@@ -518,7 +543,12 @@ bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() {
|
||||
if (count != 0) {
|
||||
// According to CGDisplayStream.h, it's safe to call
|
||||
// CGDisplayStreamStop() from within the callback.
|
||||
- ScreenRefresh(count, rects, display_origin);
|
||||
+ manager->GetLock()->AcquireLockShared();
|
||||
+ bool screen_capturer_mac_invalidated = manager->ShouldIgnoreUpdates();
|
||||
+ if (!screen_capturer_mac_invalidated) {
|
||||
+ ScreenRefresh(count, rects, display_origin);
|
||||
+ }
|
||||
+ manager->GetLock()->ReleaseLockShared();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
diff --git a/rtc_base/synchronization/rw_lock_wrapper.cc b/rtc_base/synchronization/rw_lock_wrapper.cc
|
||||
index c8cd17edb8..50c6e25ad9 100644
|
||||
--- a/rtc_base/synchronization/rw_lock_wrapper.cc
|
||||
+++ b/rtc_base/synchronization/rw_lock_wrapper.cc
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "rtc_base/synchronization/rw_lock_wrapper.h"
|
||||
|
||||
#include <assert.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+#include "system_wrappers/include/sleep.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "rtc_base/synchronization/rw_lock_win.h"
|
||||
@@ -21,11 +23,19 @@
|
||||
namespace webrtc {
|
||||
|
||||
RWLockWrapper* RWLockWrapper::CreateRWLock() {
|
||||
+ RWLockWrapper* rw_lock_ptr;
|
||||
#ifdef _WIN32
|
||||
- return RWLockWin::Create();
|
||||
+ rw_lock_ptr = RWLockWin::Create();
|
||||
#else
|
||||
- return RWLockPosix::Create();
|
||||
+ rw_lock_ptr = RWLockPosix::Create();
|
||||
#endif
|
||||
+ if (rw_lock_ptr != NULL) {
|
||||
+ return rw_lock_ptr;
|
||||
+ } else {
|
||||
+ int msec_wait = 10 + (rand() % 90);
|
||||
+ SleepMs(msec_wait);
|
||||
+ return CreateRWLock();
|
||||
+ }
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
Loading…
Reference in a new issue