зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1060738 - Add support for webrtc ThreadWindowsUI for use by webrtc desktop capture thread. r=jesup
This commit is contained in:
Родитель
c1af3e274a
Коммит
ca55661c9f
|
@ -57,6 +57,11 @@ class ThreadWrapper {
|
|||
ThreadPriority prio = kNormalPriority,
|
||||
const char* thread_name = 0);
|
||||
|
||||
static ThreadWrapper* CreateUIThread(ThreadRunFunction func,
|
||||
ThreadObj obj,
|
||||
ThreadPriority prio = kNormalPriority,
|
||||
const char* thread_name = 0);
|
||||
|
||||
// Get the current thread's kernel thread ID.
|
||||
static uint32_t GetThreadId();
|
||||
|
||||
|
@ -85,6 +90,10 @@ class ThreadWrapper {
|
|||
// Multiple tries to Stop are allowed (e.g. to wait longer than 2 seconds).
|
||||
// It's ok to call Stop() even if the spawned thread has been reclaimed.
|
||||
virtual bool Stop() = 0;
|
||||
|
||||
// Request a timed callback for ThreadRunFunction. Currently only
|
||||
// implemented for a specific type of thread on Windows.
|
||||
virtual bool RequestCallbackTimer(unsigned int milliseconds);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -28,9 +28,23 @@ ThreadWrapper* ThreadWrapper::CreateThread(ThreadRunFunction func,
|
|||
#endif
|
||||
}
|
||||
|
||||
ThreadWrapper* ThreadWrapper::CreateUIThread(ThreadRunFunction func,
|
||||
ThreadObj obj, ThreadPriority prio,
|
||||
const char* thread_name) {
|
||||
#if defined(_WIN32)
|
||||
return new ThreadWindowsUI(func, obj, prio, thread_name);
|
||||
#else
|
||||
return ThreadPosix::Create(func, obj, prio, thread_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ThreadWrapper::SetAffinity(const int* processor_numbers,
|
||||
const unsigned int amount_of_processors) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ThreadWrapper::RequestCallbackTimer(unsigned int milliseconds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -20,6 +20,13 @@
|
|||
|
||||
namespace webrtc {
|
||||
|
||||
// For use in ThreadWindowsUI callbacks
|
||||
static UINT static_reg_windows_msg = RegisterWindowMessageW(L"WebrtcWindowsUIThreadEvent");
|
||||
// timer id used in delayed callbacks
|
||||
static const UINT_PTR kTimerId = 1;
|
||||
static const wchar_t kThisProperty[] = L"ThreadWindowsUIPtr";
|
||||
static const wchar_t kThreadWindow[] = L"WebrtcWindowsUIThread";
|
||||
|
||||
ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj,
|
||||
ThreadPriority prio, const char* thread_name)
|
||||
: ThreadWrapper(),
|
||||
|
@ -150,11 +157,7 @@ bool ThreadWindows::Stop() {
|
|||
}
|
||||
}
|
||||
|
||||
void ThreadWindows::Run() {
|
||||
alive_ = true;
|
||||
dead_ = false;
|
||||
event_->Set();
|
||||
|
||||
void ThreadWindows::SetThreadNameHelper() {
|
||||
// All tracing must be after event_->Set to avoid deadlock in Trace.
|
||||
if (set_thread_name_) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
|
||||
|
@ -164,6 +167,24 @@ void ThreadWindows::Run() {
|
|||
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
|
||||
"Thread without name started");
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadWindows::ThreadStoppedHelper() {
|
||||
if (set_thread_name_) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
|
||||
"Thread with name:%s stopped", name_);
|
||||
} else {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
|
||||
"Thread without name stopped");
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadWindows::Run() {
|
||||
alive_ = true;
|
||||
dead_ = false;
|
||||
event_->Set();
|
||||
|
||||
SetThreadNameHelper();
|
||||
|
||||
do {
|
||||
if (run_function_) {
|
||||
|
@ -175,13 +196,7 @@ void ThreadWindows::Run() {
|
|||
}
|
||||
} while (alive_);
|
||||
|
||||
if (set_thread_name_) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
|
||||
"Thread with name:%s stopped", name_);
|
||||
} else {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
|
||||
"Thread without name stopped");
|
||||
}
|
||||
ThreadStoppedHelper();
|
||||
|
||||
critsect_stop_->Enter();
|
||||
|
||||
|
@ -195,4 +210,152 @@ void ThreadWindows::Run() {
|
|||
critsect_stop_->Leave();
|
||||
};
|
||||
|
||||
bool ThreadWindowsUI::Start(unsigned int& thread_id) {
|
||||
return InternalInit() ? ThreadWindows::Start(thread_id) : false;
|
||||
}
|
||||
|
||||
bool ThreadWindowsUI::Stop() {
|
||||
critsect_stop_->Enter();
|
||||
|
||||
// Prevents the handle from being closed in ThreadWindows::Run()
|
||||
do_not_close_handle_ = true;
|
||||
alive_ = false;
|
||||
|
||||
// Shut down the dispatch loop and let the background thread exit.
|
||||
if (timerid_) {
|
||||
KillTimer(hwnd_, timerid_);
|
||||
timerid_ = 0;
|
||||
}
|
||||
|
||||
RemovePropW(hwnd_, kThisProperty);
|
||||
PostMessage(hwnd_, WM_CLOSE, 0, 0);
|
||||
|
||||
bool signaled = false;
|
||||
if (thread_ && !dead_) {
|
||||
critsect_stop_->Leave();
|
||||
|
||||
// Wait up to 2 seconds for the thread to complete.
|
||||
if (WAIT_OBJECT_0 == WaitForSingleObject(thread_, 2000)) {
|
||||
signaled = true;
|
||||
}
|
||||
critsect_stop_->Enter();
|
||||
}
|
||||
if (thread_) {
|
||||
CloseHandle(thread_);
|
||||
thread_ = NULL;
|
||||
}
|
||||
critsect_stop_->Leave();
|
||||
|
||||
if (dead_ || signaled) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadWindowsUI::InternalInit() {
|
||||
// Create an event window for use in generating callbacks to capture
|
||||
// objects.
|
||||
if (hwnd_ == nullptr) {
|
||||
WNDCLASSW wc;
|
||||
HMODULE hModule = GetModuleHandle(nullptr);
|
||||
if (!GetClassInfoW(hModule, kThreadWindow, &wc)) {
|
||||
ZeroMemory(&wc, sizeof(WNDCLASSW));
|
||||
wc.hInstance = hModule;
|
||||
wc.lpfnWndProc = EventWindowProc;
|
||||
wc.lpszClassName = kThreadWindow;
|
||||
RegisterClassW(&wc);
|
||||
}
|
||||
hwnd_ = CreateWindowW(kThreadWindow, L"",
|
||||
0, 0, 0, 0, 0,
|
||||
nullptr, nullptr, hModule, nullptr);
|
||||
assert(hwnd_);
|
||||
SetPropW(hwnd_, kThisProperty, this);
|
||||
}
|
||||
return !!hwnd_;
|
||||
}
|
||||
|
||||
void ThreadWindowsUI::RequestCallback() {
|
||||
assert(hwnd_);
|
||||
assert(static_reg_windows_msg);
|
||||
PostMessage(hwnd_, static_reg_windows_msg, 0, 0);
|
||||
}
|
||||
|
||||
bool ThreadWindowsUI::RequestCallbackTimer(unsigned int milliseconds) {
|
||||
assert(hwnd_);
|
||||
if (timerid_) {
|
||||
KillTimer(hwnd_, timerid_);
|
||||
}
|
||||
timerid_ = SetTimer(hwnd_, kTimerId, milliseconds, nullptr);
|
||||
return !!timerid_;
|
||||
}
|
||||
|
||||
void ThreadWindowsUI::Run() {
|
||||
assert(hwnd_);
|
||||
|
||||
alive_ = true;
|
||||
dead_ = false;
|
||||
|
||||
event_->Set();
|
||||
SetThreadNameHelper();
|
||||
|
||||
do {
|
||||
if (!run_function_) {
|
||||
alive_ = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// blocks
|
||||
MSG msg;
|
||||
if (GetMessage(&msg, NULL, 0, 0)) {
|
||||
if (msg.message == WM_CLOSE) {
|
||||
alive_ = false;
|
||||
break;
|
||||
}
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
} while (alive_);
|
||||
|
||||
ThreadStoppedHelper();
|
||||
DestroyWindow(hwnd_);
|
||||
|
||||
critsect_stop_->Enter();
|
||||
|
||||
if (thread_ && !do_not_close_handle_) {
|
||||
HANDLE thread = thread_;
|
||||
thread_ = NULL;
|
||||
CloseHandle(thread);
|
||||
}
|
||||
dead_ = true;
|
||||
|
||||
critsect_stop_->Leave();
|
||||
};
|
||||
|
||||
void
|
||||
ThreadWindowsUI::NativeEventCallback() {
|
||||
if (!run_function_) {
|
||||
alive_ = false;
|
||||
return;
|
||||
}
|
||||
alive_ = run_function_(obj_);
|
||||
}
|
||||
|
||||
/* static */
|
||||
LRESULT CALLBACK
|
||||
ThreadWindowsUI::EventWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
ThreadWindowsUI *twui = static_cast<ThreadWindowsUI*>(GetPropW(hwnd, kThisProperty));
|
||||
if (!twui) {
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
if ((uMsg == static_reg_windows_msg && uMsg != WM_NULL) ||
|
||||
(uMsg == WM_TIMER && wParam == kTimerId)) {
|
||||
twui->NativeEventCallback();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -37,7 +37,9 @@ class ThreadWindows : public ThreadWrapper {
|
|||
protected:
|
||||
virtual void Run();
|
||||
|
||||
private:
|
||||
void SetThreadNameHelper();
|
||||
void ThreadStoppedHelper();
|
||||
|
||||
ThreadRunFunction run_function_;
|
||||
ThreadObj obj_;
|
||||
|
||||
|
@ -60,6 +62,41 @@ class ThreadWindows : public ThreadWrapper {
|
|||
|
||||
};
|
||||
|
||||
class ThreadWindowsUI : public ThreadWindows {
|
||||
public:
|
||||
ThreadWindowsUI(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio,
|
||||
const char* thread_name) :
|
||||
ThreadWindows(func, obj, prio, thread_name),
|
||||
hwnd_(nullptr),
|
||||
timerid_(0) {
|
||||
}
|
||||
|
||||
virtual bool Start(unsigned int& id);
|
||||
virtual bool Stop();
|
||||
|
||||
/**
|
||||
* Request an async callback soon.
|
||||
*/
|
||||
void RequestCallback();
|
||||
|
||||
/**
|
||||
* Request a recurring callback.
|
||||
*/
|
||||
bool RequestCallbackTimer(unsigned int milliseconds);
|
||||
|
||||
protected:
|
||||
virtual void Run();
|
||||
|
||||
private:
|
||||
static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
void NativeEventCallback();
|
||||
bool InternalInit();
|
||||
|
||||
HWND hwnd_;
|
||||
UINT_PTR timerid_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
|
||||
|
|
|
@ -475,7 +475,11 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id)
|
|||
Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() -
|
||||
TickTime::MillisecondTimestamp()),
|
||||
time_event_(*EventWrapper::Create()),
|
||||
#if defined(_WIN32)
|
||||
capturer_thread_(*ThreadWrapper::CreateUIThread(Run, this, kHighPriority, "ScreenCaptureThread")) {
|
||||
#else
|
||||
capturer_thread_(*ThreadWrapper::CreateThread(Run, this, kHighPriority, "ScreenCaptureThread")) {
|
||||
#endif
|
||||
_requestedCapability.width = kDefaultWidth;
|
||||
_requestedCapability.height = kDefaultHeight;
|
||||
_requestedCapability.maxFPS = 30;
|
||||
|
@ -758,6 +762,12 @@ int32_t DesktopCaptureImpl::StartCapture(const VideoCaptureCapability& capabilit
|
|||
desktop_capturer_cursor_composer_->Start(this);
|
||||
unsigned int t_id =0;
|
||||
capturer_thread_.Start(t_id);
|
||||
|
||||
#if defined(_WIN32)
|
||||
uint32_t maxFPSNeeded = 1000/_requestedCapability.maxFPS;
|
||||
capturer_thread_.RequestCallbackTimer(maxFPSNeeded);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -797,8 +807,13 @@ void DesktopCaptureImpl::process() {
|
|||
DesktopRect desktop_rect;
|
||||
DesktopRegion desktop_region;
|
||||
|
||||
#if !defined(_WIN32)
|
||||
TickTime startProcessTime = TickTime::Now();
|
||||
#endif
|
||||
|
||||
desktop_capturer_cursor_composer_->Capture(DesktopRegion());
|
||||
|
||||
#if !defined(_WIN32)
|
||||
const uint32_t processTime =
|
||||
(uint32_t)(TickTime::Now() - startProcessTime).Milliseconds();
|
||||
// Use at most x% CPU or limit framerate
|
||||
|
@ -806,6 +821,7 @@ void DesktopCaptureImpl::process() {
|
|||
const float sleepTimeFactor = (100.0f / kMaxDesktopCaptureCpuUsage) - 1.0f;
|
||||
const uint32_t sleepTime = sleepTimeFactor * processTime;
|
||||
time_event_.Wait(std::max<uint32_t>(maxFPSNeeded, sleepTime));
|
||||
#endif
|
||||
}
|
||||
|
||||
void DesktopCaptureImpl::OnCursorShapeChanged(MouseCursorShape* cursor_shape) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче