зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1652945 - Added support for the Windows Media Foundation AV1 decoder for hardware decoding. r=alwu
The method of creating decoder MFTs was replaced with MFEnumEx queries in order to get an instance of the AV1 decoder. Differential Revision: https://phabricator.services.mozilla.com/D138884
This commit is contained in:
Родитель
7cde443dc0
Коммит
b2ffa025f0
|
@ -239,6 +239,26 @@ static const GUID DXVA2_Intel_ModeH264_E = {
|
|||
0x4c54,
|
||||
{0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6}};
|
||||
|
||||
// VP8, VP9 and AV1 from:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/medfound/direct3d-12-video-guids
|
||||
static const GUID DXVA2_ModeVP8_VLD = {
|
||||
0x90b899ea,
|
||||
0x3a62,
|
||||
0x4705,
|
||||
{0x88, 0xb3, 0x8d, 0xf0, 0x4b, 0x27, 0x44, 0xe7}};
|
||||
|
||||
static const GUID DXVA2_ModeVP9_VLD_Profile0 = {
|
||||
0x463707f8,
|
||||
0xa1d0,
|
||||
0x4585,
|
||||
{0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e}};
|
||||
|
||||
static const GUID DXVA2_ModeAV1_Profile0 = {
|
||||
0xb8be4ccb,
|
||||
0xcf53,
|
||||
0x46ba,
|
||||
{0x8d, 0x59, 0xd6, 0xb8, 0xa6, 0xda, 0x5d, 0x2a}};
|
||||
|
||||
// This tests if a DXVA video decoder can be created for the given media
|
||||
// type/resolution. It uses the same decoder device (DXVA2_ModeH264_E -
|
||||
// DXVA2_ModeH264_VLD_NoFGT) as the H264 decoder MFT provided by windows
|
||||
|
@ -614,15 +634,37 @@ class D3D11DXVA2Manager : public DXVA2Manager {
|
|||
};
|
||||
|
||||
bool D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType, float aFramerate) {
|
||||
D3D11_VIDEO_DECODER_DESC desc;
|
||||
desc.Guid = mDecoderGUID;
|
||||
desc.OutputFormat = DXGI_FORMAT_NV12;
|
||||
D3D11_VIDEO_DECODER_DESC desc = {.OutputFormat = DXGI_FORMAT_NV12};
|
||||
GUID subtype;
|
||||
|
||||
HRESULT hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &desc.SampleWidth,
|
||||
&desc.SampleHeight);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
NS_ENSURE_TRUE(desc.SampleWidth <= MAX_VIDEO_WIDTH, false);
|
||||
NS_ENSURE_TRUE(desc.SampleHeight <= MAX_VIDEO_HEIGHT, false);
|
||||
|
||||
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
|
||||
if (subtype == MFVideoFormat_H264) {
|
||||
// IsUnsupportedResolution is only used to work around an AMD H264 issue.
|
||||
NS_ENSURE_FALSE(IsUnsupportedResolution(desc.SampleWidth, desc.SampleHeight,
|
||||
aFramerate),
|
||||
false);
|
||||
// Use the GUID defined earlier since some systems use an Intel-provided
|
||||
// decoder.
|
||||
// TODO: Move Intel-specific check from ::InitInternal to here.
|
||||
desc.Guid = mDecoderGUID;
|
||||
} else if (subtype == MFVideoFormat_VP80) {
|
||||
desc.Guid = DXVA2_ModeVP8_VLD;
|
||||
} else if (subtype == MFVideoFormat_VP90) {
|
||||
desc.Guid = DXVA2_ModeVP9_VLD_Profile0;
|
||||
} else if (subtype == MFVideoFormat_AV1) {
|
||||
desc.Guid = DXVA2_ModeAV1_Profile0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CanCreateDecoder(desc, aFramerate);
|
||||
}
|
||||
|
||||
|
@ -733,11 +775,13 @@ D3D11DXVA2Manager::InitInternal(layers::KnowsCompositor* aKnowsCompositor,
|
|||
RefPtr<MFTDecoder> mft;
|
||||
mozilla::mscom::EnsureMTA([&]() -> void {
|
||||
mft = new MFTDecoder();
|
||||
hr = mft->Create(CLSID_VideoProcessorMFT);
|
||||
hr = mft->Create(MFT_CATEGORY_VIDEO_PROCESSOR, MFVideoFormat_NV12,
|
||||
MFVideoFormat_ARGB32);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
aFailureReason = nsPrintfCString(
|
||||
"MFTDecoder::Create(CLSID_VideoProcessorMFT) failed with code %X",
|
||||
"MFTDecoder::Create of Video Processor MFT for color conversion "
|
||||
"failed with code %X",
|
||||
hr);
|
||||
return;
|
||||
}
|
||||
|
@ -1194,10 +1238,6 @@ D3D11DXVA2Manager::ConfigureForSize(IMFMediaType* aInputType,
|
|||
|
||||
bool D3D11DXVA2Manager::CanCreateDecoder(const D3D11_VIDEO_DECODER_DESC& aDesc,
|
||||
const float aFramerate) const {
|
||||
if (IsUnsupportedResolution(aDesc.SampleWidth, aDesc.SampleHeight,
|
||||
aFramerate)) {
|
||||
return false;
|
||||
}
|
||||
RefPtr<ID3D11VideoDecoder> decoder = CreateDecoder(aDesc);
|
||||
return decoder.get() != nullptr;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MFTDecoder::MFTDecoder() {
|
||||
memset(&mInputStreamInfo, 0, sizeof(MFT_INPUT_STREAM_INFO));
|
||||
memset(&mOutputStreamInfo, 0, sizeof(MFT_OUTPUT_STREAM_INFO));
|
||||
|
@ -23,13 +22,52 @@ MFTDecoder::MFTDecoder() {
|
|||
MFTDecoder::~MFTDecoder() {}
|
||||
|
||||
HRESULT
|
||||
MFTDecoder::Create(const GUID& aMFTClsID) {
|
||||
MFTDecoder::Create(const GUID& aCategory, const GUID& aInSubtype,
|
||||
const GUID& aOutSubtype) {
|
||||
// Note: IMFTransform is documented to only be safe on MTA threads.
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
// Create the IMFTransform to do the decoding.
|
||||
|
||||
// Use video by default, but select audio if necessary.
|
||||
const GUID major = aCategory == MFT_CATEGORY_AUDIO_DECODER
|
||||
? MFMediaType_Audio
|
||||
: MFMediaType_Video;
|
||||
|
||||
// Ignore null GUIDs to allow searching for all decoders supporting
|
||||
// just one input or output type.
|
||||
auto createInfo = [&major](const GUID& subtype) -> MFT_REGISTER_TYPE_INFO* {
|
||||
if (IsEqualGUID(subtype, GUID_NULL)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MFT_REGISTER_TYPE_INFO* info = new MFT_REGISTER_TYPE_INFO();
|
||||
info->guidMajorType = major;
|
||||
info->guidSubtype = subtype;
|
||||
return info;
|
||||
};
|
||||
const MFT_REGISTER_TYPE_INFO* inInfo = createInfo(aInSubtype);
|
||||
const MFT_REGISTER_TYPE_INFO* outInfo = createInfo(aOutSubtype);
|
||||
|
||||
// Request a decoder from the Windows API.
|
||||
HRESULT hr;
|
||||
hr = CoCreateInstance(
|
||||
aMFTClsID, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IMFActivate** acts = nullptr;
|
||||
UINT32 actsNum = 0;
|
||||
|
||||
hr = wmf::MFTEnumEx(aCategory, MFT_ENUM_FLAG_SORTANDFILTER, inInfo, outInfo,
|
||||
&acts, &actsNum);
|
||||
delete inInfo;
|
||||
delete outInfo;
|
||||
NS_ENSURE_TRUE(actsNum > 0, WINCODEC_ERR_COMPONENTNOTFOUND);
|
||||
|
||||
auto guard = MakeScopeExit([&] {
|
||||
for (int i = 0; i < actsNum; i++) {
|
||||
acts[i]->Release();
|
||||
}
|
||||
});
|
||||
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Create the IMFTransform to do the decoding.
|
||||
hr = acts[0]->ActivateObject(
|
||||
IID_PPV_ARGS(static_cast<IMFTransform**>(getter_AddRefs(mDecoder))));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
|
@ -344,6 +382,13 @@ MFTDecoder::Flush() {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFTDecoder::GetInputMediaType(RefPtr<IMFMediaType>& aMediaType) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
NS_ENSURE_TRUE(mDecoder, E_POINTER);
|
||||
return mDecoder->GetInputCurrentType(0, getter_AddRefs(aMediaType));
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFTDecoder::GetOutputMediaType(RefPtr<IMFMediaType>& aMediaType) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
|
|
@ -22,12 +22,17 @@ class MFTDecoder final {
|
|||
|
||||
MFTDecoder();
|
||||
|
||||
// Creates the MFT. First thing to do as part of setup.
|
||||
// Creates the MFT by querying a category and media subtype.
|
||||
// First thing to do as part of setup.
|
||||
//
|
||||
// Params:
|
||||
// - aMFTClsID the clsid used by CoCreateInstance to instantiate the
|
||||
// decoder MFT.
|
||||
HRESULT Create(const GUID& aMFTClsID);
|
||||
// - aCategory the GUID of the MFT category to use.
|
||||
// - aInSubType the GUID of the input MFT media type to use.
|
||||
// GUID_NULL may be used as a wildcard.
|
||||
// - aOutSubType the GUID of the output MFT media type to use.
|
||||
// GUID_NULL may be used as a wildcard.
|
||||
HRESULT Create(const GUID& aCategory, const GUID& aInSubtype,
|
||||
const GUID& aOutSubtype);
|
||||
|
||||
// Sets the input and output media types. Call after Init().
|
||||
//
|
||||
|
@ -47,6 +52,9 @@ class MFTDecoder final {
|
|||
// Returns the MFT's IMFAttributes object for an output stream.
|
||||
already_AddRefed<IMFAttributes> GetOutputStreamAttributes();
|
||||
|
||||
// Retrieves the media type being input.
|
||||
HRESULT GetInputMediaType(RefPtr<IMFMediaType>& aMediaType);
|
||||
|
||||
// Retrieves the media type being output. This may not be valid until
|
||||
// the first sample is decoded.
|
||||
HRESULT GetOutputMediaType(RefPtr<IMFMediaType>& aMediaType);
|
||||
|
|
|
@ -32,12 +32,6 @@
|
|||
# undef max
|
||||
#endif
|
||||
|
||||
// Some SDK versions don't define the AAC decoder CLSID.
|
||||
#ifndef CLSID_CMSAACDecMFT
|
||||
extern "C" const CLSID CLSID_CMSAACDecMFT;
|
||||
# define WMF_MUST_DEFINE_AAC_MFT_CLSID
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace wmf {
|
||||
|
||||
|
|
|
@ -103,18 +103,6 @@ WMFAudioMFTManager::~WMFAudioMFTManager() {
|
|||
MOZ_COUNT_DTOR(WMFAudioMFTManager);
|
||||
}
|
||||
|
||||
const GUID& WMFAudioMFTManager::GetMFTGUID() {
|
||||
MOZ_ASSERT(mStreamType != Unknown);
|
||||
switch (mStreamType) {
|
||||
case AAC:
|
||||
return CLSID_CMSAACDecMFT;
|
||||
case MP3:
|
||||
return CLSID_CMP3DecMediaObject;
|
||||
default:
|
||||
return GUID_NULL;
|
||||
};
|
||||
}
|
||||
|
||||
const GUID& WMFAudioMFTManager::GetMediaSubtypeGUID() {
|
||||
MOZ_ASSERT(mStreamType != Unknown);
|
||||
switch (mStreamType) {
|
||||
|
@ -131,8 +119,10 @@ bool WMFAudioMFTManager::Init() {
|
|||
NS_ENSURE_TRUE(mStreamType != Unknown, false);
|
||||
|
||||
RefPtr<MFTDecoder> decoder(new MFTDecoder());
|
||||
|
||||
HRESULT hr = decoder->Create(GetMFTGUID());
|
||||
// Note: MP3 MFT isn't registered as supporting Float output, but it works.
|
||||
// Find PCM output MFTs as this is the common type.
|
||||
HRESULT hr = decoder->Create(MFT_CATEGORY_AUDIO_DECODER,
|
||||
GetMediaSubtypeGUID(), MFAudioFormat_PCM);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
|
||||
// Setup input/output media types
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "MediaInfo.h"
|
||||
#include "PDMFactory.h"
|
||||
#include "VPXDecoder.h"
|
||||
#include "AOMDecoder.h"
|
||||
#include "WMF.h"
|
||||
#include "WMFAudioMFTManager.h"
|
||||
#include "WMFMediaDataDecoder.h"
|
||||
|
@ -37,8 +38,6 @@
|
|||
|
||||
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
extern const GUID CLSID_WebmMfVpxDec;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Helper function to add a profile marker and log at the same time.
|
||||
|
@ -85,7 +84,19 @@ static bool IsRemoteAcceleratedCompositor(
|
|||
ident.mParentProcessType == GeckoProcessType_GPU;
|
||||
}
|
||||
|
||||
static bool CanCreateMFTDecoder(const GUID& aGuid) {
|
||||
static bool CanCreateMFTDecoder(const GUID& aCategory, const GUID& aInSubtype) {
|
||||
const GUID outSubtype = [&]() {
|
||||
if (aCategory == MFT_CATEGORY_VIDEO_DECODER) {
|
||||
// H264 decoder MFT doesn't always support NV12
|
||||
if (aInSubtype == MFVideoFormat_H264) {
|
||||
return GUID_NULL;
|
||||
}
|
||||
return MFVideoFormat_NV12;
|
||||
} else {
|
||||
return MFAudioFormat_PCM;
|
||||
}
|
||||
}();
|
||||
|
||||
// The IMFTransform interface used by MFTDecoder is documented to require to
|
||||
// run on an MTA thread.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85).aspx#components
|
||||
|
@ -98,7 +109,8 @@ static bool CanCreateMFTDecoder(const GUID& aGuid) {
|
|||
return;
|
||||
}
|
||||
RefPtr<MFTDecoder> decoder(new MFTDecoder());
|
||||
canCreateDecoder = SUCCEEDED(decoder->Create(aGuid));
|
||||
canCreateDecoder =
|
||||
SUCCEEDED(decoder->Create(aCategory, aInSubtype, outSubtype));
|
||||
wmf::MFShutdown();
|
||||
});
|
||||
return canCreateDecoder;
|
||||
|
@ -137,7 +149,9 @@ void WMFDecoderModule::Init() {
|
|||
WmfDecoderModuleMarkerAndLog("WMFInit VPx Pending",
|
||||
"Attempting to create MFT decoder for VPx");
|
||||
|
||||
sUsableVPXMFT = CanCreateMFTDecoder(CLSID_WebmMfVpxDec);
|
||||
sUsableVPXMFT =
|
||||
CanCreateMFTDecoder(MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_VP80) &&
|
||||
CanCreateMFTDecoder(MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_VP90);
|
||||
|
||||
WmfDecoderModuleMarkerAndLog("WMFInit VPx Initialized",
|
||||
"CanCreateMFTDecoder returned %s for VPx",
|
||||
|
@ -240,40 +254,48 @@ already_AddRefed<MediaDataDecoder> WMFDecoderModule::CreateAudioDecoder(
|
|||
return decoder.forget();
|
||||
}
|
||||
|
||||
template <const GUID& aGuid>
|
||||
template <const GUID& aCategory, const GUID& aInSubtype>
|
||||
static bool CanCreateWMFDecoder() {
|
||||
static StaticMutex sMutex MOZ_UNANNOTATED;
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
static Maybe<bool> result;
|
||||
if (result.isNothing()) {
|
||||
result.emplace(CanCreateMFTDecoder(aGuid));
|
||||
result.emplace(CanCreateMFTDecoder(aCategory, aInSubtype));
|
||||
}
|
||||
return result.value();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool WMFDecoderModule::HasH264() {
|
||||
return CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>();
|
||||
return CanCreateWMFDecoder<MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_H264>();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool WMFDecoderModule::HasVP8() {
|
||||
return sUsableVPXMFT && CanCreateWMFDecoder<CLSID_WebmMfVpxDec>();
|
||||
return sUsableVPXMFT &&
|
||||
CanCreateWMFDecoder<MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_VP80>();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool WMFDecoderModule::HasVP9() {
|
||||
return sUsableVPXMFT && CanCreateWMFDecoder<CLSID_WebmMfVpxDec>();
|
||||
return sUsableVPXMFT &&
|
||||
CanCreateWMFDecoder<MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_VP90>();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool WMFDecoderModule::HasAV1() {
|
||||
return StaticPrefs::media_wmf_av1_enabled() &&
|
||||
CanCreateWMFDecoder<MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_AV1>();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool WMFDecoderModule::HasAAC() {
|
||||
return CanCreateWMFDecoder<CLSID_CMSAACDecMFT>();
|
||||
return CanCreateWMFDecoder<MFT_CATEGORY_AUDIO_DECODER, MFAudioFormat_AAC>();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool WMFDecoderModule::HasMP3() {
|
||||
return CanCreateWMFDecoder<CLSID_CMP3DecMediaObject>();
|
||||
return CanCreateWMFDecoder<MFT_CATEGORY_AUDIO_DECODER, MFAudioFormat_MP3>();
|
||||
}
|
||||
|
||||
bool WMFDecoderModule::SupportsMimeType(
|
||||
|
@ -326,6 +348,10 @@ bool WMFDecoderModule::Supports(const SupportDecoderParams& aParams,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (AOMDecoder::IsAV1(trackInfo.mMimeType) && WMFDecoderModule::HasAV1()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Some unsupported codec.
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ class WMFDecoderModule : public PlatformDecoderModule {
|
|||
static bool HasH264();
|
||||
static bool HasVP8();
|
||||
static bool HasVP9();
|
||||
static bool HasAV1();
|
||||
static bool HasAAC();
|
||||
static bool HasMP3();
|
||||
|
||||
|
|
|
@ -21,13 +21,6 @@
|
|||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
|
||||
// Some SDK versions don't define the AAC decoder CLSID.
|
||||
// {32D186A7-218F-4C75-8876-DD77273A8999}
|
||||
DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD,
|
||||
0x77, 0x27, 0x3A, 0x89, 0x99);
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using media::TimeUnit;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "MediaInfo.h"
|
||||
#include "MediaTelemetryConstants.h"
|
||||
#include "VPXDecoder.h"
|
||||
#include "AOMDecoder.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "WMFDecoderModule.h"
|
||||
#include "WMFUtils.h"
|
||||
|
@ -62,14 +63,6 @@ const GUID MFVideoFormat_VP90 = {
|
|||
{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
||||
#endif
|
||||
|
||||
// Note: CLSID_WebmMfVpxDec needs to be extern for the CanCreateWMFDecoder
|
||||
// template in WMFDecoderModule.cpp to work.
|
||||
extern const GUID CLSID_WebmMfVpxDec = {
|
||||
0xe3aaf548,
|
||||
0xc9a4,
|
||||
0x4c6e,
|
||||
{0x23, 0x4d, 0x5a, 0xda, 0x37, 0x4b, 0x00, 0x00}};
|
||||
|
||||
#if !defined(__MINGW32__) && _WIN32_WINNT < _WIN32_WINNT_WIN8
|
||||
const GUID MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT = {
|
||||
0x851745d5,
|
||||
|
@ -162,6 +155,8 @@ WMFVideoMFTManager::WMFVideoMFTManager(
|
|||
mStreamType = VP8;
|
||||
} else if (VPXDecoder::IsVP9(aConfig.mMimeType)) {
|
||||
mStreamType = VP9;
|
||||
} else if (AOMDecoder::IsAV1(aConfig.mMimeType)) {
|
||||
mStreamType = AV1;
|
||||
} else {
|
||||
mStreamType = Unknown;
|
||||
}
|
||||
|
@ -178,20 +173,6 @@ WMFVideoMFTManager::~WMFVideoMFTManager() {
|
|||
MOZ_COUNT_DTOR(WMFVideoMFTManager);
|
||||
}
|
||||
|
||||
const GUID& WMFVideoMFTManager::GetMFTGUID() {
|
||||
MOZ_ASSERT(mStreamType != Unknown);
|
||||
switch (mStreamType) {
|
||||
case H264:
|
||||
return CLSID_CMSH264DecoderMFT;
|
||||
case VP8:
|
||||
return CLSID_WebmMfVpxDec;
|
||||
case VP9:
|
||||
return CLSID_WebmMfVpxDec;
|
||||
default:
|
||||
return GUID_NULL;
|
||||
};
|
||||
}
|
||||
|
||||
const GUID& WMFVideoMFTManager::GetMediaSubtypeGUID() {
|
||||
MOZ_ASSERT(mStreamType != Unknown);
|
||||
switch (mStreamType) {
|
||||
|
@ -201,6 +182,8 @@ const GUID& WMFVideoMFTManager::GetMediaSubtypeGUID() {
|
|||
return MFVideoFormat_VP80;
|
||||
case VP9:
|
||||
return MFVideoFormat_VP90;
|
||||
case AV1:
|
||||
return MFVideoFormat_AV1;
|
||||
default:
|
||||
return GUID_NULL;
|
||||
};
|
||||
|
@ -310,7 +293,16 @@ MediaResult WMFVideoMFTManager::InitInternal() {
|
|||
InitializeDXVA();
|
||||
|
||||
RefPtr<MFTDecoder> decoder = new MFTDecoder();
|
||||
HRESULT hr = decoder->Create(GetMFTGUID());
|
||||
const GUID subtype = GetMediaSubtypeGUID();
|
||||
HRESULT hr =
|
||||
decoder->Create(MFT_CATEGORY_VIDEO_DECODER, subtype, MFVideoFormat_NV12);
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING(
|
||||
"Hardware decoder MFT creation failed, trying software decoding");
|
||||
hr = decoder->Create(
|
||||
MFT_CATEGORY_VIDEO_DECODER, subtype,
|
||||
mStreamType == H264 ? MFVideoFormat_YUY2 : MFVideoFormat_YV12);
|
||||
}
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr),
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Can't create the MFT decoder.")));
|
||||
|
@ -377,10 +369,11 @@ MediaResult WMFVideoMFTManager::InitInternal() {
|
|||
// MFT_MESSAGE_SET_D3D_MANAGER failed
|
||||
mDXVA2Manager.reset();
|
||||
}
|
||||
if (mStreamType == VP9 || mStreamType == VP8) {
|
||||
return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Use VP8/9 MFT only if HW acceleration "
|
||||
"is available."));
|
||||
if (mStreamType == VP9 || mStreamType == VP8 || mStreamType == AV1) {
|
||||
return MediaResult(
|
||||
NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Use VP8/VP9/AV1 MFT only if HW acceleration "
|
||||
"is available."));
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
|
||||
uint32_t(media::MediaDecoderBackend::WMFSoftware));
|
||||
|
@ -393,14 +386,14 @@ MediaResult WMFVideoMFTManager::InitInternal() {
|
|||
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Fail to set the decoder media types.")));
|
||||
|
||||
RefPtr<IMFMediaType> outputType;
|
||||
hr = mDecoder->GetOutputMediaType(outputType);
|
||||
RefPtr<IMFMediaType> inputType;
|
||||
hr = mDecoder->GetInputMediaType(inputType);
|
||||
NS_ENSURE_TRUE(
|
||||
SUCCEEDED(hr),
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Fail to get the output media type.")));
|
||||
RESULT_DETAIL("Fail to get the input media type.")));
|
||||
|
||||
if (mUseHwAccel && !CanUseDXVA(outputType, mFramerate)) {
|
||||
if (mUseHwAccel && !CanUseDXVA(inputType, mFramerate)) {
|
||||
mDXVAEnabled = false;
|
||||
// DXVA initialization with current decoder actually failed,
|
||||
// re-do initialization.
|
||||
|
@ -410,6 +403,13 @@ MediaResult WMFVideoMFTManager::InitInternal() {
|
|||
LOG("Video Decoder initialized, Using DXVA: %s",
|
||||
(mUseHwAccel ? "Yes" : "No"));
|
||||
|
||||
RefPtr<IMFMediaType> outputType;
|
||||
hr = mDecoder->GetOutputMediaType(outputType);
|
||||
NS_ENSURE_TRUE(
|
||||
SUCCEEDED(hr),
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Fail to get the output media type.")));
|
||||
|
||||
if (mUseHwAccel) {
|
||||
hr = mDXVA2Manager->ConfigureForSize(
|
||||
outputType,
|
||||
|
@ -536,29 +536,31 @@ WMFVideoMFTManager::Input(MediaRawData* aSample) {
|
|||
return mDecoder->Input(inputSample);
|
||||
}
|
||||
|
||||
// The MFTransform we use for decoding h264 video will silently fall
|
||||
// The MFTransforms we use for decoding H264 and AV1 video will silently fall
|
||||
// back to software decoding (even if we've negotiated DXVA) if the GPU
|
||||
// doesn't support decoding the given resolution. It will then upload
|
||||
// doesn't support decoding the given codec and resolution. It will then upload
|
||||
// the software decoded frames into d3d textures to preserve behaviour.
|
||||
//
|
||||
// Unfortunately this seems to cause corruption (see bug 1193547) and is
|
||||
// slow because the upload is done into a non-shareable texture and requires
|
||||
// us to copy it.
|
||||
//
|
||||
// This code tests if the given resolution can be supported directly on the GPU,
|
||||
// and makes sure we only ask the MFT for DXVA if it can be supported properly.
|
||||
// This code tests if the given codec and resolution can be supported directly
|
||||
// on the GPU, and makes sure we only ask the MFT for DXVA if it can be
|
||||
// supported properly.
|
||||
//
|
||||
// Ideally we'd know the framerate during initialization and would also ensure
|
||||
// that new decoders are created if the resolution changes. Then we could move
|
||||
// this check into Init and consolidate the main thread blocking code.
|
||||
bool WMFVideoMFTManager::CanUseDXVA(IMFMediaType* aType, float aFramerate) {
|
||||
MOZ_ASSERT(mDXVA2Manager);
|
||||
// SupportsConfig only checks for valid h264 decoders currently.
|
||||
if (mStreamType != H264) {
|
||||
return true;
|
||||
// Check if we're able to use hardware decoding with H264 or AV1.
|
||||
// TODO: Do the same for VPX, if the VPX MFT has a slow software fallback?
|
||||
if (mStreamType == H264 || mStreamType == AV1) {
|
||||
return mDXVA2Manager->SupportsConfig(aType, aFramerate);
|
||||
}
|
||||
|
||||
return mDXVA2Manager->SupportsConfig(aType, aFramerate);
|
||||
return true;
|
||||
}
|
||||
|
||||
TimeUnit WMFVideoMFTManager::GetSampleDurationOrLastKnownDuration(
|
||||
|
@ -855,6 +857,18 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset, RefPtr<MediaData>& aOutData) {
|
|||
}
|
||||
TimeUnit pts = GetSampleTime(sample);
|
||||
TimeUnit duration = GetSampleDurationOrLastKnownDuration(sample);
|
||||
|
||||
// AV1 MFT fix: Sample duration after seeking is always equal to the
|
||||
// sample time, for some reason. Set it to last duration instead.
|
||||
if (mStreamType == AV1 && duration == pts) {
|
||||
LOG("Video sample duration (%" PRId64 ") matched timestamp (%" PRId64
|
||||
"), setting to previous sample duration (%" PRId64 ") instead.",
|
||||
pts.ToMicroseconds(), duration.ToMicroseconds(),
|
||||
mLastDuration.ToMicroseconds());
|
||||
duration = mLastDuration;
|
||||
sample->SetSampleDuration(UsecsToHNs(duration.ToMicroseconds()));
|
||||
}
|
||||
|
||||
if (!pts.IsValid() || !duration.IsValid()) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ class WMFVideoMFTManager : public MFTManager {
|
|||
|
||||
nsCString mDXVAFailureReason;
|
||||
|
||||
enum StreamType { Unknown, H264, VP8, VP9 };
|
||||
enum StreamType { Unknown, H264, VP8, VP9, AV1 };
|
||||
|
||||
StreamType mStreamType;
|
||||
|
||||
|
@ -110,13 +110,14 @@ class WMFVideoMFTManager : public MFTManager {
|
|||
return "VP8";
|
||||
case StreamType::VP9:
|
||||
return "VP9";
|
||||
case StreamType::AV1:
|
||||
return "AV1";
|
||||
default:
|
||||
MOZ_ASSERT(mStreamType == StreamType::Unknown);
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const GUID& GetMFTGUID();
|
||||
const GUID& GetMediaSubtypeGUID();
|
||||
|
||||
uint32_t mNullOutputCount = 0;
|
||||
|
|
|
@ -8995,6 +8995,11 @@
|
|||
value: true
|
||||
mirror: once
|
||||
|
||||
- name: media.wmf.av1.enabled
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
#endif # MOZ_WMF
|
||||
|
||||
- name: media.decoder-doctor.testing
|
||||
|
|
Загрузка…
Ссылка в новой задаче