Bug 1885671 - run the method of getting codec supported on the background thread in order not to block the main thread. r=jrmuizel

There are modifications needed for PDMfactory and the decoder modules in
order to run their methods on non-mainthread and keep them threadsafe.

Differential Revision: https://phabricator.services.mozilla.com/D206420
This commit is contained in:
alwu 2024-04-18 17:15:34 +00:00
parent bc6dca1d7f
commit 6a0a4e413c
6 changed files with 155 additions and 98 deletions

View File

@ -27,6 +27,7 @@
#include "mozilla/RemoteDecoderManagerChild.h"
#include "mozilla/RemoteDecoderModule.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/TaskQueue.h"
@ -786,9 +787,11 @@ void PDMFactory::SetCDMProxy(CDMProxy* aProxy) {
mEMEPDM = MakeRefPtr<EMEDecoderModule>(aProxy, m);
}
StaticMutex sSupportedMutex;
/* static */
media::MediaCodecsSupported PDMFactory::Supported(bool aForceRefresh) {
MOZ_ASSERT(NS_IsMainThread());
StaticMutexAutoLock lock(sSupportedMutex);
static auto calculate = []() {
auto pdm = MakeRefPtr<PDMFactory>();

View File

@ -64,21 +64,28 @@ AndroidDecoderModule::AndroidDecoderModule(CDMProxy* aProxy) {
mProxy = static_cast<MediaDrmCDMProxy*>(aProxy);
}
StaticAutoPtr<nsTArray<nsCString>> AndroidDecoderModule::sSupportedSwMimeTypes;
StaticAutoPtr<nsTArray<nsCString>> AndroidDecoderModule::sSupportedHwMimeTypes;
StaticAutoPtr<MediaCodecsSupported> AndroidDecoderModule::sSupportedCodecs;
/* static */ bool AndroidDecoderModule::AreSupportedMimeTypesReady() {
StaticMutexAutoLock lock(sMutex);
return sSupportedSwMimeTypes && sSupportedHwMimeTypes;
}
/* static */ bool AndroidDecoderModule::IsSupportedCodecsReady() {
StaticMutexAutoLock lock(sMutex);
return sSupportedCodecs;
}
/* static */
media::MediaCodecsSupported AndroidDecoderModule::GetSupportedCodecs() {
if (!sSupportedSwMimeTypes || !sSupportedHwMimeTypes || !sSupportedCodecs) {
if (!AreSupportedMimeTypesReady() || !IsSupportedCodecsReady()) {
SetSupportedMimeTypes();
}
StaticMutexAutoLock lock(sMutex);
return *sSupportedCodecs;
}
DecodeSupportSet AndroidDecoderModule::SupportsMimeType(
const nsACString& aMimeType) {
if (!sSupportedSwMimeTypes) {
if (!AreSupportedMimeTypesReady()) {
SetSupportedMimeTypes();
}
@ -135,13 +142,16 @@ DecodeSupportSet AndroidDecoderModule::SupportsMimeType(
// If a codec has no special handling or can't be determined from the
// MIME type string, check if the MIME type string itself is supported.
if (sSupportedHwMimeTypes &&
sSupportedHwMimeTypes->Contains(TranslateMimeType(aMimeType))) {
return DecodeSupport::HardwareDecode;
}
if (sSupportedSwMimeTypes &&
sSupportedSwMimeTypes->Contains(TranslateMimeType(aMimeType))) {
return DecodeSupport::SoftwareDecode;
{
StaticMutexAutoLock lock(sMutex);
if (sSupportedHwMimeTypes &&
sSupportedHwMimeTypes->Contains(TranslateMimeType(aMimeType))) {
return DecodeSupport::HardwareDecode;
}
if (sSupportedSwMimeTypes &&
sSupportedSwMimeTypes->Contains(TranslateMimeType(aMimeType))) {
return DecodeSupport::SoftwareDecode;
}
}
return media::DecodeSupportSet{};
}
@ -179,21 +189,43 @@ void AndroidDecoderModule::SetSupportedMimeTypes() {
// Inbound MIME types prefixed with SW/HW need to be processed
void AndroidDecoderModule::SetSupportedMimeTypes(
nsTArray<nsCString>&& aSupportedTypes) {
StaticMutexAutoLock lock(sMutex);
// Return if support is already cached
if (sSupportedSwMimeTypes && sSupportedHwMimeTypes && sSupportedCodecs) {
return;
}
if (!sSupportedSwMimeTypes) {
sSupportedSwMimeTypes = new nsTArray<nsCString>;
ClearOnShutdown(&sSupportedSwMimeTypes);
if (NS_IsMainThread()) {
ClearOnShutdown(&sSupportedSwMimeTypes);
} else {
Unused << NS_DispatchToMainThread(NS_NewRunnableFunction(__func__, []() {
StaticMutexAutoLock lock(sMutex);
ClearOnShutdown(&sSupportedSwMimeTypes);
}));
}
}
if (!sSupportedHwMimeTypes) {
sSupportedHwMimeTypes = new nsTArray<nsCString>;
ClearOnShutdown(&sSupportedHwMimeTypes);
if (NS_IsMainThread()) {
ClearOnShutdown(&sSupportedHwMimeTypes);
} else {
Unused << NS_DispatchToMainThread(NS_NewRunnableFunction(__func__, []() {
StaticMutexAutoLock lock(sMutex);
ClearOnShutdown(&sSupportedHwMimeTypes);
}));
}
}
if (!sSupportedCodecs) {
sSupportedCodecs = new MediaCodecsSupported();
ClearOnShutdown(&sSupportedCodecs);
if (NS_IsMainThread()) {
ClearOnShutdown(&sSupportedCodecs);
} else {
Unused << NS_DispatchToMainThread(NS_NewRunnableFunction(__func__, []() {
StaticMutexAutoLock lock(sMutex);
ClearOnShutdown(&sSupportedCodecs);
}));
}
}
DecodeSupportSet support;

View File

@ -54,16 +54,25 @@ class AndroidDecoderModule : public PlatformDecoderModule {
private:
explicit AndroidDecoderModule(CDMProxy* aProxy = nullptr);
virtual ~AndroidDecoderModule() = default;
static bool AreSupportedMimeTypesReady();
static bool IsSupportedCodecsReady();
RefPtr<MediaDrmCDMProxy> mProxy;
// SW compatible MIME type strings
static StaticAutoPtr<nsTArray<nsCString>> sSupportedSwMimeTypes;
static inline StaticAutoPtr<nsTArray<nsCString>> sSupportedSwMimeTypes
MOZ_GUARDED_BY(sMutex);
// HW compatible MIME type strings
static StaticAutoPtr<nsTArray<nsCString>> sSupportedHwMimeTypes;
static inline StaticAutoPtr<nsTArray<nsCString>> sSupportedHwMimeTypes
MOZ_GUARDED_BY(sMutex);
// EnumSet containing SW/HW codec support information parsed from
// MIME type strings. If a specific codec could not be determined
// it will not be included in this EnumSet. All supported MIME type strings
// are still stored in sSupportedSwMimeTypes and sSupportedHwMimeTypes.
static StaticAutoPtr<media::MediaCodecsSupported> sSupportedCodecs;
static inline StaticAutoPtr<media::MediaCodecsSupported> sSupportedCodecs
MOZ_GUARDED_BY(sMutex);
static inline StaticMutex sMutex;
};
extern LazyLogModule sAndroidDecoderModuleLog;

View File

@ -85,13 +85,8 @@ static bool IsRemoteAcceleratedCompositor(
ident.mParentProcessType == GeckoProcessType_GPU;
}
static Atomic<bool> sSupportedTypesInitialized(false);
static EnumSet<WMFStreamType> sSupportedTypes;
static EnumSet<WMFStreamType> sLackOfExtensionTypes;
/* static */
void WMFDecoderModule::Init(Config aConfig) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (XRE_IsContentProcess()) {
// If we're in the content process and the UseGPUDecoder pref is set, it
// means that we've given up on the GPU process (it's been crashing) so we
@ -134,6 +129,7 @@ void WMFDecoderModule::Init(Config aConfig) {
sDXVAEnabled = sDXVAEnabled && hwVideo;
mozilla::mscom::EnsureMTA([&]() {
StaticMutexAutoLock lock(sMutex);
// Store the supported MFT decoders.
sSupportedTypes.clear();
sLackOfExtensionTypes.clear();
@ -163,7 +159,10 @@ void WMFDecoderModule::Init(Config aConfig) {
}
});
sSupportedTypesInitialized = true;
{
StaticMutexAutoLock lock(sMutex);
sSupportedTypesInitialized = true;
}
WmfDecoderModuleMarkerAndLog("WMFInit Result",
"WMFDecoderModule::Init finishing");
@ -270,15 +269,13 @@ HRESULT WMFDecoderModule::CreateMFTDecoder(const WMFStreamType& aType,
/* static */
bool WMFDecoderModule::CanCreateMFTDecoder(const WMFStreamType& aType) {
MOZ_ASSERT(WMFStreamType::Unknown < aType && aType < WMFStreamType::SENTINEL);
if (!sSupportedTypesInitialized) {
if (NS_IsMainThread()) {
Init();
} else {
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction("WMFDecoderModule::Init", [&]() { Init(); });
SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(),
runnable);
}
bool hasInitialized = false;
{
StaticMutexAutoLock lock(sMutex);
hasInitialized = sSupportedTypesInitialized;
}
if (!hasInitialized) {
Init();
}
// Check prefs here rather than CreateMFTDecoder so that prefs aren't baked
@ -324,7 +321,7 @@ bool WMFDecoderModule::CanCreateMFTDecoder(const WMFStreamType& aType) {
break;
}
}
StaticMutexAutoLock lock(sMutex);
return sSupportedTypes.contains(aType);
}
@ -380,6 +377,7 @@ media::DecodeSupportSet WMFDecoderModule::Supports(
return media::DecodeSupport::SoftwareDecode;
}
}
StaticMutexAutoLock lock(sMutex);
return sLackOfExtensionTypes.contains(type)
? media::DecodeSupport::UnsureDueToLackOfExtension
: media::DecodeSupportSet{};

View File

@ -63,6 +63,12 @@ class WMFDecoderModule : public PlatformDecoderModule {
WMFDecoderModule() = default;
virtual ~WMFDecoderModule() = default;
static inline StaticMutex sMutex;
static inline bool sSupportedTypesInitialized MOZ_GUARDED_BY(sMutex) = false;
static inline EnumSet<WMFStreamType> sSupportedTypes MOZ_GUARDED_BY(sMutex);
static inline EnumSet<WMFStreamType> sLackOfExtensionTypes
MOZ_GUARDED_BY(sMutex);
};
} // namespace mozilla

View File

@ -107,62 +107,58 @@ using namespace layers;
static GPUParent* sGPUParent;
static void ReportHardwareMediaCodecSupportIfNeeded() {
MOZ_ASSERT(!NS_IsMainThread(), "Should not block main thread");
// We only need to report the result once.
static bool sReported = false;
if (sReported) {
return;
}
#if defined(XP_WIN)
NS_GetCurrentThread()->Dispatch(NS_NewRunnableFunction(
"GPUParent:ReportHardwareMediaCodecSupportIfNeeded", []() {
// Only report telemetry when hardware decoding is available.
if (!gfx::gfxVars::IsInitialized() ||
!gfx::gfxVars::CanUseHardwareVideoDecoding()) {
return;
}
sReported = true;
// Only report telemetry when hardware decoding is available.
if (!gfx::gfxVars::IsInitialized() ||
!gfx::gfxVars::CanUseHardwareVideoDecoding()) {
return;
}
sReported = true;
// TODO : we can remove this after HEVC is enabled by default.
// HEVC is not enabled. We need to force to enable it in order to know
// its support as well, and it would be turn off later.
if (StaticPrefs::media_wmf_hevc_enabled() != 1) {
WMFDecoderModule::Init(WMFDecoderModule::Config::ForceEnableHEVC);
}
const auto support = PDMFactory::Supported(true /* force refresh */);
if (support.contains(
mozilla::media::MediaCodecsSupport::H264HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, u"h264"_ns,
true);
}
if (support.contains(mozilla::media::MediaCodecsSupport::VP8HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, u"vp8"_ns,
true);
}
if (support.contains(mozilla::media::MediaCodecsSupport::VP9HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, u"vp9"_ns,
true);
}
if (support.contains(mozilla::media::MediaCodecsSupport::AV1HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, u"av1"_ns,
true);
}
if (support.contains(
mozilla::media::MediaCodecsSupport::HEVCHardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, u"hevc"_ns,
true);
}
if (StaticPrefs::media_wmf_hevc_enabled() != 1) {
WMFDecoderModule::Init();
}
// TODO : we can remove this after HEVC is enabled by default.
// HEVC is not enabled. We need to force to enable it in order to know
// its support as well, and it would be turn off later.
if (StaticPrefs::media_wmf_hevc_enabled() != 1) {
WMFDecoderModule::Init(WMFDecoderModule::Config::ForceEnableHEVC);
}
const auto support = PDMFactory::Supported(true /* force refresh */);
if (support.contains(
mozilla::media::MediaCodecsSupport::H264HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT,
u"h264"_ns, true);
}
if (support.contains(
mozilla::media::MediaCodecsSupport::VP8HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT,
u"vp8"_ns, true);
}
if (support.contains(
mozilla::media::MediaCodecsSupport::VP9HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT,
u"vp9"_ns, true);
}
if (support.contains(
mozilla::media::MediaCodecsSupport::AV1HardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT,
u"av1"_ns, true);
}
if (support.contains(
mozilla::media::MediaCodecsSupport::HEVCHardwareDecode)) {
Telemetry::ScalarSet(
Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT,
u"hevc"_ns, true);
}
if (StaticPrefs::media_wmf_hevc_enabled() != 1) {
WMFDecoderModule::Init();
}
}));
#endif
// TODO : in the future, when we have GPU procss on MacOS, then we can report
// HEVC usage as well.
@ -459,16 +455,19 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
// Dispatch a task to run when idle that will determine which codecs are
// usable. The primary goal is to determine if the media feature pack is
// installed.
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThreadQueue(
NS_NewRunnableFunction(
"GPUParent::Supported",
[]() {
auto supported = PDMFactory::Supported();
Unused << GPUParent::GetSingleton()->SendUpdateMediaCodecsSupported(
supported);
ReportHardwareMediaCodecSupportIfNeeded();
}),
2000 /* 2 seconds timeout */, EventQueuePriority::Idle));
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableFunction("GPUParent::Supported", []() {
NS_DispatchToMainThread(NS_NewRunnableFunction(
"GPUParent::UpdateMediaCodecsSupported",
[supported = PDMFactory::Supported()]() {
Unused << GPUParent::GetSingleton()
->SendUpdateMediaCodecsSupported(supported);
}));
ReportHardwareMediaCodecSupportIfNeeded();
});
MOZ_ALWAYS_SUCCEEDS(
NS_DispatchBackgroundTask(task, nsIEventTarget::DISPATCH_NORMAL));
Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_INITIALIZATION_TIME_MS,
mLaunchTime);
@ -555,10 +554,20 @@ mozilla::ipc::IPCResult GPUParent::RecvUpdateVar(const GfxVarUpdate& aUpdate) {
if (couldUseHWDecoder != gfx::gfxVars::CanUseHardwareVideoDecoding()) {
// The capabilities of the system may have changed, force a refresh by
// re-initializing the WMF PDM.
WMFDecoderModule::Init();
Unused << GPUParent::GetSingleton()->SendUpdateMediaCodecsSupported(
PDMFactory::Supported(true /* force refresh */));
ReportHardwareMediaCodecSupportIfNeeded();
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableFunction("GPUParent::RecvUpdateVar", []() {
WMFDecoderModule::Init();
NS_DispatchToMainThread(NS_NewRunnableFunction(
"GPUParent::UpdateMediaCodecsSupported",
[supported =
PDMFactory::Supported(true /* force refresh */)]() {
Unused << GPUParent::GetSingleton()
->SendUpdateMediaCodecsSupported(supported);
}));
ReportHardwareMediaCodecSupportIfNeeded();
});
MOZ_ALWAYS_SUCCEEDS(
NS_DispatchBackgroundTask(task, nsIEventTarget::DISPATCH_NORMAL));
}
});
#endif