blob: dc95cbafdb99b099017def0f7a13538e4ead75ce [file] [log] [blame]
// Copyright 2020 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 "third_party/blink/renderer/platform/peerconnection/gpu_codec_support_waiter.h"
#include "base/sequenced_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
namespace blink {
namespace {
// Codec support known callback can potentially be called after the waiter is
// destroyed. RefCountedWaitableEvent is used for the event which callback sets
// to keep it alive in such case.
class RefCountedWaitableEvent
: public base::WaitableEvent,
public WTF::ThreadSafeRefCounted<RefCountedWaitableEvent> {
public:
RefCountedWaitableEvent()
: base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
private:
friend class WTF::ThreadSafeRefCounted<RefCountedWaitableEvent>;
~RefCountedWaitableEvent() = default;
};
base::Optional<base::TimeDelta> GetCodecSupportWaitTimeoutMs() {
if (!base::FeatureList::IsEnabled(features::kRTCGpuCodecSupportWaiter)) {
return base::nullopt;
}
int timeout_ms = base::GetFieldTrialParamByFeatureAsInt(
features::kRTCGpuCodecSupportWaiter,
features::kRTCGpuCodecSupportWaiterTimeoutParam.name,
features::kRTCGpuCodecSupportWaiterTimeoutParam.default_value);
return base::TimeDelta::FromMilliseconds(timeout_ms);
}
void OnCodecSupportKnown(
scoped_refptr<RefCountedWaitableEvent> codec_support_known) {
codec_support_known->Signal();
}
} // namespace
GpuCodecSupportWaiter::GpuCodecSupportWaiter(
media::GpuVideoAcceleratorFactories* gpu_factories)
: gpu_factories_(gpu_factories),
wait_timeout_ms_(GetCodecSupportWaitTimeoutMs()) {}
bool GpuCodecSupportWaiter::IsCodecSupportKnown(bool is_encoder) const {
if (is_encoder) {
if (gpu_factories_->IsEncoderSupportKnown()) {
return true;
}
} else if (gpu_factories_->IsDecoderSupportKnown()) {
return true;
}
if (!wait_timeout_ms_) {
return false;
}
// crbug.com/1047994. GPU might not be initialized by the time it is queried
// for supported codecs. Request support status notification and block
// execution with timeout.
// https://github.com/w3c/webrtc-extensions/issues/49 is a request for async
// WebRTC API.
scoped_refptr<RefCountedWaitableEvent> codec_support_known =
base::MakeRefCounted<RefCountedWaitableEvent>();
// Callback passed to Notify{Decoder|Decoder}SupportKnown is called on
// caller's sequence. To not block the callback while waiting for it, request
// notification on a separate sequence.
scoped_refptr<base::SequencedTaskRunner> task_runner =
base::ThreadPool::CreateSequencedTaskRunner({});
bool is_support_notification_requested = task_runner->PostTask(
FROM_HERE,
base::BindOnce(
[](media::GpuVideoAcceleratorFactories* gpu_factories,
scoped_refptr<RefCountedWaitableEvent> codec_support_known,
bool is_encoder) {
if (is_encoder) {
gpu_factories->NotifyEncoderSupportKnown(
base::BindOnce(&OnCodecSupportKnown, codec_support_known));
} else {
gpu_factories->NotifyDecoderSupportKnown(
base::BindOnce(&OnCodecSupportKnown, codec_support_known));
}
},
gpu_factories_, codec_support_known, is_encoder));
if (!is_support_notification_requested) {
DLOG(WARNING) << "Failed to request codec support notification.";
return false;
}
return codec_support_known->TimedWait(*wait_timeout_ms_);
}
bool GpuCodecSupportWaiter::IsDecoderSupportKnown() const {
return IsCodecSupportKnown(/*is_encoder=*/false);
}
bool GpuCodecSupportWaiter::IsEncoderSupportKnown() const {
return IsCodecSupportKnown(/*is_encoder=*/true);
}
} // namespace blink