mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-24 17:37:30 +09:00
Add VP9 Hardware Decoding with DXVA (Non-MFT), Vista+
Thanks to Maggie (imjustsomeoneiguess) on discord for helping with a lot of this VP9 media code. This is the first browser so far to support VP9 Non MFT
This commit is contained in:
parent
e0fe6706d1
commit
1414824320
18 changed files with 1747 additions and 34 deletions
|
|
@ -30,9 +30,11 @@
|
||||||
#ifdef MOZ_FMP4
|
#ifdef MOZ_FMP4
|
||||||
#include "MP4Decoder.h"
|
#include "MP4Decoder.h"
|
||||||
#endif
|
#endif
|
||||||
#include "WMFDecoderModule.h"
|
#if defined(XP_WIN) && defined(MOZ_WMF)
|
||||||
#include "MediaPrefs.h"
|
#include "MediaPrefs.h"
|
||||||
|
#include "WMFDecoderModule.h"
|
||||||
#include "mozilla/gfx/gfxVars.h"
|
#include "mozilla/gfx/gfxVars.h"
|
||||||
|
#endif
|
||||||
#include "CubebUtils.h"
|
#include "CubebUtils.h"
|
||||||
|
|
||||||
#include "nsIScrollableFrame.h"
|
#include "nsIScrollableFrame.h"
|
||||||
|
|
@ -2379,17 +2381,26 @@ nsDOMWindowUtils::GetSupportsHardwareVP9Decoding(JS::MutableHandle<JS::Value> aP
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(XP_WIN) && defined(MOZ_WMF)
|
#if defined(XP_WIN) && defined(MOZ_WMF)
|
||||||
|
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||||
|
LayerManager* layerManager = widget ? widget->GetLayerManager() : nullptr;
|
||||||
if (!MediaPrefs::PDMWMFVP9DecoderEnabled()) {
|
if (!MediaPrefs::PDMWMFVP9DecoderEnabled()) {
|
||||||
promise->MaybeResolve(NS_LITERAL_STRING("No; media.wmf.vp9.enabled is false"));
|
promise->MaybeResolve(NS_LITERAL_STRING(
|
||||||
|
"No; media.wmf.vp9.enabled is false"));
|
||||||
} else if (!gfx::gfxVars::CanUseHardwareVideoDecoding()) {
|
} else if (!gfx::gfxVars::CanUseHardwareVideoDecoding()) {
|
||||||
promise->MaybeResolve(NS_LITERAL_STRING("No; hardware video decoding disabled"));
|
promise->MaybeResolve(NS_LITERAL_STRING(
|
||||||
} else if (WMFDecoderModule::HasVP9()) {
|
"No; hardware video decoding disabled"));
|
||||||
promise->MaybeResolve(NS_LITERAL_STRING("Yes"));
|
} else if (WMFDecoderModule::HasVP9MFT()) {
|
||||||
|
promise->MaybeResolve(NS_LITERAL_STRING("Yes; using MFT"));
|
||||||
|
} else if (layerManager && WMFDecoderModule::HasVP9DXVA2(
|
||||||
|
layerManager->AsShadowForwarder())) {
|
||||||
|
promise->MaybeResolve(NS_LITERAL_STRING("Yes; using DXVA2"));
|
||||||
} else {
|
} else {
|
||||||
promise->MaybeResolve(NS_LITERAL_STRING("No; MFT unavailable"));
|
promise->MaybeResolve(NS_LITERAL_STRING(
|
||||||
|
"No; no VP9 hardware decoder available"));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
promise->MaybeResolve(NS_LITERAL_STRING("No; not supported on this platform"));
|
promise->MaybeResolve(NS_LITERAL_STRING(
|
||||||
|
"No; not supported on this platform"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
aPromise.setObject(*promise->PromiseObj());
|
aPromise.setObject(*promise->PromiseObj());
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ interface nsIJSRAIIHelper;
|
||||||
interface nsIContentPermissionRequest;
|
interface nsIContentPermissionRequest;
|
||||||
interface nsIObserver;
|
interface nsIObserver;
|
||||||
|
|
||||||
[scriptable, uuid(58e97ce9-1d9e-4576-aabf-89480fdeb16d)]
|
[scriptable, uuid(16ed093c-84a7-4ca3-84c8-9ad71f8b5d82)]
|
||||||
interface nsIDOMWindowUtils : nsISupports {
|
interface nsIDOMWindowUtils : nsISupports {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1419,11 +1419,10 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||||
* in hardware.
|
* in hardware.
|
||||||
*/
|
*/
|
||||||
readonly attribute jsval supportsHardwareH264Decoding;
|
readonly attribute jsval supportsHardwareH264Decoding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Promise that will be resolved with a string once the capabilities
|
* Returns a Promise resolved with a string describing whether VP9 hardware
|
||||||
* of the vp9 decoder have been determined.
|
* decoding is available through the Windows MFT or direct DXVA2 path.
|
||||||
* Success does not mean that all vp9 video decoding will be done
|
|
||||||
* in hardware.
|
|
||||||
*/
|
*/
|
||||||
readonly attribute jsval supportsHardwareVP9Decoding;
|
readonly attribute jsval supportsHardwareVP9Decoding;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,9 @@ private:
|
||||||
DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true);
|
DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true);
|
||||||
DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false);
|
DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false);
|
||||||
DECL_MEDIA_PREF("media.decoder-doctor.wmf-disabled-is-failure", DecoderDoctorWMFDisabledIsFailure, bool, false);
|
DECL_MEDIA_PREF("media.decoder-doctor.wmf-disabled-is-failure", DecoderDoctorWMFDisabledIsFailure, bool, false);
|
||||||
|
DECL_MEDIA_PREF("media.wmf.vp9.dxva2.enabled", PDMWMFVP9DXVA2Enabled, bool, true);
|
||||||
|
DECL_MEDIA_PREF("media.wmf.vp9.mft.enabled", PDMWMFVP9MFTEnabled, bool, true);
|
||||||
|
DECL_MEDIA_PREF("media.wmf.vp9.dxva2.preferred", PDMWMFVP9DXVA2Preferred, bool, false);
|
||||||
DECL_MEDIA_PREF("media.wmf.vp9.enabled", PDMWMFVP9DecoderEnabled, bool, true);
|
DECL_MEDIA_PREF("media.wmf.vp9.enabled", PDMWMFVP9DecoderEnabled, bool, true);
|
||||||
DECL_MEDIA_PREF("media.wmf.decoder.thread-count", PDMWMFThreadCount, int32_t, -1);
|
DECL_MEDIA_PREF("media.wmf.decoder.thread-count", PDMWMFThreadCount, int32_t, -1);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ public:
|
||||||
virtual ~D3D9DXVA2Manager();
|
virtual ~D3D9DXVA2Manager();
|
||||||
|
|
||||||
HRESULT Init(layers::KnowsCompositor* aKnowsCompositor,
|
HRESULT Init(layers::KnowsCompositor* aKnowsCompositor,
|
||||||
nsACString& aFailureReason);
|
nsACString& aFailureReason, const GUID* aDecoderGUID);
|
||||||
|
|
||||||
IUnknown* GetDXVADeviceManager() override;
|
IUnknown* GetDXVADeviceManager() override;
|
||||||
|
|
||||||
|
|
@ -99,6 +99,8 @@ public:
|
||||||
const nsIntRect& aRegion,
|
const nsIntRect& aRegion,
|
||||||
Image** aOutImage) override;
|
Image** aOutImage) override;
|
||||||
|
|
||||||
|
HRESULT CopySurfaceToImage(IDirect3DSurface9* aSurface,
|
||||||
|
const nsIntRect& aRegion, Image** aOutImage) override;
|
||||||
bool SupportsConfig(IMFMediaType* aType, float aFramerate) override;
|
bool SupportsConfig(IMFMediaType* aType, float aFramerate) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -185,10 +187,6 @@ static const GUID DXVA2_Intel_ModeH264_E = {
|
||||||
0x604F8E68, 0x4951, 0x4c54, { 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6 }
|
0x604F8E68, 0x4951, 0x4c54, { 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GUID DXVA2_ModeVP9_VLD_Profile0 = {
|
|
||||||
0x463707f8, 0xa1d0, 0x4585, { 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e }
|
|
||||||
};
|
|
||||||
|
|
||||||
// This tests if a DXVA video decoder can be created for the given media type/resolution.
|
// 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
|
// It uses the same decoder device (DXVA2_ModeH264_E - DXVA2_ModeH264_VLD_NoFGT) as the H264
|
||||||
// decoder MFT provided by windows (CLSID_CMSH264DecoderMFT) uses, so we can use it to determine
|
// decoder MFT provided by windows (CLSID_CMSH264DecoderMFT) uses, so we can use it to determine
|
||||||
|
|
@ -267,7 +265,7 @@ D3D9DXVA2Manager::GetDXVADeviceManager()
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
D3D9DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
D3D9DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
||||||
nsACString& aFailureReason)
|
nsACString& aFailureReason, const GUID* aDecoderGUID)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
|
@ -388,11 +386,12 @@ D3D9DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (UINT i = 0; i < deviceCount; i++) {
|
for (UINT i = 0; i < deviceCount; i++) {
|
||||||
if (decoderDevices[i] == DXVA2_ModeH264_E ||
|
if (aDecoderGUID ? decoderDevices[i] == *aDecoderGUID :
|
||||||
decoderDevices[i] == DXVA2_Intel_ModeH264_E ||
|
(decoderDevices[i] == DXVA2_ModeH264_E ||
|
||||||
decoderDevices[i] == DXVA2_ModeVP9_VLD_Profile0) {
|
decoderDevices[i] == DXVA2_Intel_ModeH264_E)) {
|
||||||
mDecoderGUID = decoderDevices[i];
|
mDecoderGUID = decoderDevices[i];
|
||||||
found = true;
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CoTaskMemFree(decoderDevices);
|
CoTaskMemFree(decoderDevices);
|
||||||
|
|
@ -462,8 +461,15 @@ D3D9DXVA2Manager::CopyToImage(IMFSample* aSample,
|
||||||
getter_AddRefs(surface));
|
getter_AddRefs(surface));
|
||||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||||
|
|
||||||
|
return CopySurfaceToImage(surface, aRegion, aOutImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
D3D9DXVA2Manager::CopySurfaceToImage(IDirect3DSurface9* surface,
|
||||||
|
const nsIntRect& aRegion, Image** aOutImage)
|
||||||
|
{
|
||||||
RefPtr<D3D9SurfaceImage> image = new D3D9SurfaceImage();
|
RefPtr<D3D9SurfaceImage> image = new D3D9SurfaceImage();
|
||||||
hr = image->AllocateAndCopy(mTextureClientAllocator, surface, aRegion);
|
HRESULT hr = image->AllocateAndCopy(mTextureClientAllocator, surface, aRegion);
|
||||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||||
|
|
||||||
RefPtr<IDirect3DSurface9> sourceSurf = image->GetD3D9Surface();
|
RefPtr<IDirect3DSurface9> sourceSurf = image->GetD3D9Surface();
|
||||||
|
|
@ -492,7 +498,7 @@ static uint32_t sDXVAVideosCount = 0;
|
||||||
/* static */
|
/* static */
|
||||||
DXVA2Manager*
|
DXVA2Manager*
|
||||||
DXVA2Manager::CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor,
|
DXVA2Manager::CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor,
|
||||||
nsACString& aFailureReason)
|
nsACString& aFailureReason, const GUID* aDecoderGUID)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
@ -507,7 +513,7 @@ DXVA2Manager::CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
|
nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
|
||||||
hr = d3d9Manager->Init(aKnowsCompositor, aFailureReason);
|
hr = d3d9Manager->Init(aKnowsCompositor, aFailureReason, aDecoderGUID);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
return d3d9Manager.forget();
|
return d3d9Manager.forget();
|
||||||
}
|
}
|
||||||
|
|
@ -694,11 +700,10 @@ D3D11DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
||||||
for (UINT i = 0; i < profileCount; i++) {
|
for (UINT i = 0; i < profileCount; i++) {
|
||||||
GUID id;
|
GUID id;
|
||||||
hr = videoDevice->GetVideoDecoderProfile(i, &id);
|
hr = videoDevice->GetVideoDecoderProfile(i, &id);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr) && (id == DXVA2_ModeH264_E || id == DXVA2_Intel_ModeH264_E)) {
|
||||||
if (id == DXVA2_ModeH264_E || id == DXVA2_Intel_ModeH264_E || id == DXVA2_ModeVP9_VLD_Profile0) {
|
mDecoderGUID = id;
|
||||||
mDecoderGUID = id;
|
found = true;
|
||||||
found = true;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ public:
|
||||||
|
|
||||||
// Creates and initializes a DXVA2Manager. We can use DXVA2 via either
|
// Creates and initializes a DXVA2Manager. We can use DXVA2 via either
|
||||||
// D3D9Ex or D3D11.
|
// D3D9Ex or D3D11.
|
||||||
static DXVA2Manager* CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor, nsACString& aFailureReason);
|
static DXVA2Manager* CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor, nsACString& aFailureReason, const GUID* aDecoderGUID = nullptr);
|
||||||
static DXVA2Manager* CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, nsACString& aFailureReason);
|
static DXVA2Manager* CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, nsACString& aFailureReason);
|
||||||
|
|
||||||
// Returns a pointer to the D3D device manager responsible for managing the
|
// Returns a pointer to the D3D device manager responsible for managing the
|
||||||
|
|
@ -37,6 +37,10 @@ public:
|
||||||
const nsIntRect& aRegion,
|
const nsIntRect& aRegion,
|
||||||
layers::Image** aOutImage) = 0;
|
layers::Image** aOutImage) = 0;
|
||||||
|
|
||||||
|
virtual HRESULT CopySurfaceToImage(IDirect3DSurface9* aSurface,
|
||||||
|
const nsIntRect& aRegion,
|
||||||
|
layers::Image** aOutImage) { return E_NOTIMPL; }
|
||||||
|
|
||||||
virtual HRESULT ConfigureForSize(uint32_t aWidth, uint32_t aHeight) { return S_OK; }
|
virtual HRESULT ConfigureForSize(uint32_t aWidth, uint32_t aHeight) { return S_OK; }
|
||||||
|
|
||||||
virtual bool IsD3D11() { return false; }
|
virtual bool IsD3D11() { return false; }
|
||||||
|
|
|
||||||
590
dom/media/platforms/wmf/DXVAVP9Manager.cpp
Normal file
590
dom/media/platforms/wmf/DXVAVP9Manager.cpp
Normal file
|
|
@ -0,0 +1,590 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "DXVAVP9Manager.h"
|
||||||
|
#include "WMFUtils.h"
|
||||||
|
#include "nsPrintfCString.h"
|
||||||
|
#include "nsReadableUtils.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// VP9 DXVA2 GUID: {463707F8-A1D0-4585-876D-83AA6D60B89E}
|
||||||
|
// its the VP9_VLD_Profile0.
|
||||||
|
static const GUID sVP9DecoderGUID = {
|
||||||
|
0x463707f8, 0xa1d0, 0x4585,
|
||||||
|
{ 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
DXVAVP9Manager::DXVAVP9Manager()
|
||||||
|
: mNumSurfaces(kDefaultSurfaces)
|
||||||
|
, mCurrentSurface(kDefaultSurfaces - 1)
|
||||||
|
, mWidth(0)
|
||||||
|
, mHeight(0)
|
||||||
|
, mFrameCount(0)
|
||||||
|
, mLock("DXVAVP9Manager")
|
||||||
|
{
|
||||||
|
memset(mRefFrameSurface, 0xFF, sizeof(mRefFrameSurface));
|
||||||
|
memset(mRefFrameWidth, 0, sizeof(mRefFrameWidth));
|
||||||
|
memset(mRefFrameHeight, 0, sizeof(mRefFrameHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
DXVAVP9Manager::~DXVAVP9Manager()
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ const GUID&
|
||||||
|
DXVAVP9Manager::GetVP9DecoderGUID()
|
||||||
|
{
|
||||||
|
return sVP9DecoderGUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
DXVAVP9Manager::SupportsVP9(IDirect3DDeviceManager9* aDeviceManager)
|
||||||
|
{
|
||||||
|
if (!aDeviceManager) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE handle = nullptr;
|
||||||
|
HRESULT hr = aDeviceManager->OpenDeviceHandle(&handle);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<IDirectXVideoDecoderService> decoderService;
|
||||||
|
hr = aDeviceManager->GetVideoService(
|
||||||
|
handle, IID_PPV_ARGS(decoderService.StartAssignment()));
|
||||||
|
aDeviceManager->CloseDeviceHandle(handle);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT count = 0;
|
||||||
|
GUID* guids = nullptr;
|
||||||
|
hr = decoderService->GetDecoderDeviceGuids(&count, &guids);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (UINT i = 0; i < count; i++) {
|
||||||
|
if (guids[i] == sVP9DecoderGUID) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CoTaskMemFree(guids);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DXVAVP9Manager::Init(IUnknown* aDeviceManager, uint32_t aWidth,
|
||||||
|
uint32_t aHeight, nsACString& aFailureReason)
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mLock);
|
||||||
|
|
||||||
|
if (!aDeviceManager) { aFailureReason.AssignLiteral("Missing D3D9 device manager"); return false; }
|
||||||
|
|
||||||
|
HRESULT hr = aDeviceManager->QueryInterface(
|
||||||
|
__uuidof(IDirect3DDeviceManager9),
|
||||||
|
reinterpret_cast<void**>(mDeviceManager.StartAssignment()));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
aFailureReason.AssignLiteral(
|
||||||
|
"DXVAVP9: QueryInterface to IDirect3DDeviceManager9 failed — "
|
||||||
|
"D3D11 path is not supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE handle = nullptr;
|
||||||
|
hr = mDeviceManager->OpenDeviceHandle(&handle);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
aFailureReason = nsPrintfCString(
|
||||||
|
"DXVAVP9: OpenDeviceHandle failed %X", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = mDeviceManager->GetVideoService(
|
||||||
|
handle, IID_PPV_ARGS(mDecoderService.StartAssignment()));
|
||||||
|
mDeviceManager->CloseDeviceHandle(handle);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
aFailureReason = nsPrintfCString(
|
||||||
|
"DXVAVP9: GetVideoService failed %X", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SupportsVP9(mDeviceManager)) {
|
||||||
|
aFailureReason.AssignLiteral(
|
||||||
|
"DXVAVP9: VP9 DXVA2 GUID not exposed by driver — "
|
||||||
|
"GPU/driver does not support hardware VP9 decode");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWidth = aWidth ? aWidth : 1280;
|
||||||
|
mHeight = aHeight ? aHeight : 720;
|
||||||
|
|
||||||
|
hr = InitDecoder(mWidth, mHeight);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
aFailureReason = nsPrintfCString(
|
||||||
|
"DXVAVP9: InitDecoder(%ux%u) failed %X", mWidth, mHeight, hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DXVAVP9Manager::Flush()
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mLock);
|
||||||
|
mParser.Reset();
|
||||||
|
memset(mRefFrameSurface, 0xff, sizeof(mRefFrameSurface));
|
||||||
|
memset(mRefFrameWidth, 0, sizeof(mRefFrameWidth));
|
||||||
|
memset(mRefFrameHeight, 0, sizeof(mRefFrameHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DXVAVP9Manager::Shutdown()
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mLock);
|
||||||
|
FreeSurfaces();
|
||||||
|
mParser.Reset();
|
||||||
|
mDecoderService = nullptr;
|
||||||
|
mDeviceManager = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
DXVAVP9Manager::AllocateSurfaces(uint32_t aWidth, uint32_t aHeight,
|
||||||
|
uint32_t aCount)
|
||||||
|
{
|
||||||
|
FreeSurfaces();
|
||||||
|
|
||||||
|
if (aCount < kMinSurfaces || aCount > kMaxSurfaces) { return E_INVALIDARG; }
|
||||||
|
|
||||||
|
const uint32_t alignedWidth = (aWidth + 15) & ~15u;
|
||||||
|
const uint32_t alignedHeight = (aHeight + 15) & ~15u;
|
||||||
|
|
||||||
|
IDirect3DSurface9* surfaces[kMaxSurfaces] = {};
|
||||||
|
HRESULT hr = mDecoderService->CreateSurface(
|
||||||
|
alignedWidth,
|
||||||
|
alignedHeight,
|
||||||
|
aCount - 1,
|
||||||
|
(D3DFORMAT)MAKEFOURCC('N','V','1','2'),
|
||||||
|
D3DPOOL_DEFAULT,
|
||||||
|
0,
|
||||||
|
DXVA2_VideoDecoderRenderTarget,
|
||||||
|
surfaces,
|
||||||
|
nullptr);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < aCount; i++) {
|
||||||
|
mSurfaces[i] = dont_AddRef(surfaces[i]);
|
||||||
|
}
|
||||||
|
mNumSurfaces = aCount;
|
||||||
|
mCurrentSurface = aCount - 1;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DXVAVP9Manager::FreeSurfaces()
|
||||||
|
{
|
||||||
|
mDecoder = nullptr;
|
||||||
|
for (uint32_t i = 0; i < kMaxSurfaces; i++) {
|
||||||
|
mSurfaces[i] = nullptr;
|
||||||
|
}
|
||||||
|
memset(mRefFrameSurface, 0xFF, sizeof(mRefFrameSurface));
|
||||||
|
memset(mRefFrameWidth, 0, sizeof(mRefFrameWidth));
|
||||||
|
memset(mRefFrameHeight, 0, sizeof(mRefFrameHeight));
|
||||||
|
mNumSurfaces = kDefaultSurfaces;
|
||||||
|
mCurrentSurface = kDefaultSurfaces - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
DXVAVP9Manager::InitDecoder(uint32_t aWidth, uint32_t aHeight)
|
||||||
|
{
|
||||||
|
if (!aWidth || !aHeight || aWidth > 8192 || aHeight > 8192) { return E_INVALIDARG; }
|
||||||
|
UINT formatCount = 0;
|
||||||
|
D3DFORMAT* formats = nullptr;
|
||||||
|
HRESULT hr = mDecoderService->GetDecoderRenderTargets(sVP9DecoderGUID, &formatCount, &formats);
|
||||||
|
if (FAILED(hr)) { return hr; }
|
||||||
|
bool nv12 = false;
|
||||||
|
for (UINT i = 0; i < formatCount; ++i) {
|
||||||
|
nv12 |= formats[i] == (D3DFORMAT)MAKEFOURCC('N','V','1','2');
|
||||||
|
}
|
||||||
|
CoTaskMemFree(formats);
|
||||||
|
if (!nv12) { return E_FAIL; }
|
||||||
|
|
||||||
|
DXVA2_VideoDesc desc = {};
|
||||||
|
desc.SampleWidth = aWidth;
|
||||||
|
desc.SampleHeight = aHeight;
|
||||||
|
desc.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2');
|
||||||
|
desc.InputSampleFreq.Numerator = 30;
|
||||||
|
desc.InputSampleFreq.Denominator = 1;
|
||||||
|
desc.OutputFrameFreq = desc.InputSampleFreq;
|
||||||
|
|
||||||
|
UINT configCount = 0;
|
||||||
|
DXVA2_ConfigPictureDecode* configs = nullptr;
|
||||||
|
hr = mDecoderService->GetDecoderConfigurations(
|
||||||
|
sVP9DecoderGUID, &desc, nullptr, &configCount, &configs);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configCount == 0) {
|
||||||
|
CoTaskMemFree(configs);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GUID noEncrypt = {0x1b81bed0, 0xa0c7, 0x11d3,
|
||||||
|
{0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5}};
|
||||||
|
DXVA2_ConfigPictureDecode chosenConfig = {};
|
||||||
|
bool found = false;
|
||||||
|
UINT rejectedForBuffCount = 0;
|
||||||
|
UINT rejectedForRaw = 0;
|
||||||
|
UINT rejectedForEncrypt = 0;
|
||||||
|
for (UINT i = 0; i < configCount; ++i) {
|
||||||
|
if (configs[i].ConfigBitstreamRaw != 1 &&
|
||||||
|
configs[i].ConfigBitstreamRaw != 2) {
|
||||||
|
rejectedForRaw = configs[i].ConfigBitstreamRaw;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (configs[i].guidConfigBitstreamEncryption != noEncrypt &&
|
||||||
|
configs[i].guidConfigBitstreamEncryption != GUID_NULL) {
|
||||||
|
rejectedForEncrypt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (configs[i].ConfigMinRenderTargetBuffCount > kMaxSurfaces) {
|
||||||
|
rejectedForBuffCount = configs[i].ConfigMinRenderTargetBuffCount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chosenConfig = configs[i]; found = true; break;
|
||||||
|
}
|
||||||
|
CoTaskMemFree(configs);
|
||||||
|
if (!found) {
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t surfaceCount = kDefaultSurfaces;
|
||||||
|
if (chosenConfig.ConfigMinRenderTargetBuffCount > surfaceCount) {
|
||||||
|
surfaceCount = chosenConfig.ConfigMinRenderTargetBuffCount;
|
||||||
|
}
|
||||||
|
if (surfaceCount > kMaxSurfaces) { surfaceCount = kMaxSurfaces; }
|
||||||
|
|
||||||
|
hr = AllocateSurfaces(aWidth, aHeight, surfaceCount);
|
||||||
|
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||||
|
|
||||||
|
IDirect3DSurface9* surfacePtrs[kMaxSurfaces];
|
||||||
|
for (uint32_t i = 0; i < mNumSurfaces; i++) {
|
||||||
|
surfacePtrs[i] = mSurfaces[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = mDecoderService->CreateVideoDecoder(
|
||||||
|
sVP9DecoderGUID,
|
||||||
|
&desc,
|
||||||
|
&chosenConfig,
|
||||||
|
surfacePtrs,
|
||||||
|
mNumSurfaces,
|
||||||
|
mDecoder.StartAssignment());
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
DXVAVP9Manager::ConfigureForSize(uint32_t aWidth, uint32_t aHeight)
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mLock);
|
||||||
|
if (aWidth == mWidth && aHeight == mHeight) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
mWidth = aWidth;
|
||||||
|
mHeight = aHeight;
|
||||||
|
return InitDecoder(aWidth, aHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
DXVAVP9Manager::PickNextSurface() const
|
||||||
|
{
|
||||||
|
for (uint32_t tries = 0; tries < mNumSurfaces; tries++) {
|
||||||
|
uint32_t idx = (mCurrentSurface + 1 + tries) % mNumSurfaces;
|
||||||
|
bool inUse = false;
|
||||||
|
for (int slot = 0; slot < 8; slot++) {
|
||||||
|
if (mRefFrameSurface[slot] == idx) {
|
||||||
|
inUse = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inUse) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (mCurrentSurface + 1) % mNumSurfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DXVAVP9Manager::FillPicParams(const VP9FrameHeader& h,
|
||||||
|
UXP_DXVA_PicParams_VP9& p)
|
||||||
|
{
|
||||||
|
memset(&p, 0, sizeof(p));
|
||||||
|
|
||||||
|
p.CurrPic.Index7Bits = (UCHAR)mCurrentSurface;
|
||||||
|
p.CurrPic.AssociatedFlag = 0;
|
||||||
|
p.profile = 0;
|
||||||
|
|
||||||
|
p.frame_type = h.frameType;
|
||||||
|
p.show_frame = h.showFrame;
|
||||||
|
p.error_resilient_mode = h.errorResilientMode;
|
||||||
|
p.subsampling_x = h.subsamplingX;
|
||||||
|
p.subsampling_y = h.subsamplingY;
|
||||||
|
p.refresh_frame_context = h.refreshFrameContext;
|
||||||
|
p.frame_parallel_decoding_mode = h.frameParallelDecodingMode;
|
||||||
|
p.intra_only = (h.frameType != 0 && h.isIntra) ? 1 : 0;
|
||||||
|
p.frame_context_idx = h.frameContextIdx;
|
||||||
|
p.reset_frame_context = h.resetFrameContext;
|
||||||
|
p.allow_high_precision_mv = (h.frameType != 0) ? h.allowHighPrecisionMv : 0;
|
||||||
|
|
||||||
|
p.BitDepthMinus8Luma = 0;
|
||||||
|
p.BitDepthMinus8Chroma = 0;
|
||||||
|
|
||||||
|
p.interp_filter = h.interpFilter;
|
||||||
|
|
||||||
|
p.width = h.frameWidth;
|
||||||
|
p.height = h.frameHeight;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
p.ref_frame_map[i].bPicEntry = mRefFrameSurface[i];
|
||||||
|
p.ref_frame_coded_width[i] = mRefFrameWidth[i];
|
||||||
|
p.ref_frame_coded_height[i] = mRefFrameHeight[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
p.frame_refs[i].bPicEntry = 0xFF;
|
||||||
|
}
|
||||||
|
if (!h.isIntra) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
uint8_t slot = h.refFrameIdx[i] & 7;
|
||||||
|
uint8_t surfIdx = mRefFrameSurface[slot];
|
||||||
|
p.frame_refs[i].bPicEntry = surfIdx;
|
||||||
|
p.ref_frame_sign_bias[i + 1] = h.refFrameSignBias[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.filter_level = (CHAR)h.filterLevel;
|
||||||
|
p.sharpness_level = (CHAR)h.sharpnessLevel;
|
||||||
|
p.mode_ref_delta_enabled = h.modeRefLfEnabled;
|
||||||
|
p.mode_ref_delta_update = h.modeRefDeltaUpdate;
|
||||||
|
p.use_prev_in_find_mv_refs = h.usePrevFrameMvs;
|
||||||
|
for (int i = 0; i < 4; i++) { p.ref_deltas[i] = h.refDeltas[i]; }
|
||||||
|
for (int i = 0; i < 2; i++) { p.mode_deltas[i] = h.modeDeltas[i]; }
|
||||||
|
|
||||||
|
p.base_qindex = (SHORT)h.baseQIndex;
|
||||||
|
p.y_dc_delta_q = h.deltaQYDc;
|
||||||
|
p.uv_dc_delta_q = h.deltaQUvDc;
|
||||||
|
p.uv_ac_delta_q = h.deltaQUvAc;
|
||||||
|
|
||||||
|
p.stVP9Segments.enabled = h.segmentationEnabled;
|
||||||
|
p.stVP9Segments.update_map = h.segmentationUpdateMap;
|
||||||
|
p.stVP9Segments.temporal_update = h.segmentationTemporalUpdate;
|
||||||
|
p.stVP9Segments.abs_delta = h.segmentationAbsOrDelta;
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
p.stVP9Segments.tree_probs[i] = h.segmentationTreeProbs[i];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
p.stVP9Segments.pred_probs[i] = h.segmentationPredProbs[i];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
UCHAR mask = 0;
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
if (h.segFeatureEnabled[i][j]) {
|
||||||
|
mask |= (1 << j);
|
||||||
|
}
|
||||||
|
p.stVP9Segments.feature_data[i][j] = (SHORT)h.segFeatureData[i][j];
|
||||||
|
}
|
||||||
|
p.stVP9Segments.feature_mask[i] = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.log2_tile_cols = (UCHAR)h.log2TileCols;
|
||||||
|
p.log2_tile_rows = (UCHAR)h.log2TileRows;
|
||||||
|
|
||||||
|
p.first_partition_size = (USHORT)h.compressedHeaderSize;
|
||||||
|
p.uncompressed_header_size_byte_aligned = (USHORT)h.uncompressedHeaderSizeBytes;
|
||||||
|
|
||||||
|
p.StatusReportFeedbackNumber = ++mFrameCount;
|
||||||
|
if (p.StatusReportFeedbackNumber == 0) {
|
||||||
|
p.StatusReportFeedbackNumber = ++mFrameCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
DXVAVP9Manager::DecodeFrame(const uint8_t* aData, uint32_t aSize,
|
||||||
|
IDirect3DSurface9** aOutSurface,
|
||||||
|
bool* aOutShouldDisplay,
|
||||||
|
VP9FrameHeader* aOutHeader)
|
||||||
|
{
|
||||||
|
NS_ENSURE_TRUE(mDecoder, E_NOT_VALID_STATE);
|
||||||
|
NS_ENSURE_TRUE(aData && aSize > 0, E_INVALIDARG);
|
||||||
|
NS_ENSURE_TRUE(aOutSurface, E_POINTER);
|
||||||
|
NS_ENSURE_TRUE(aOutShouldDisplay, E_POINTER);
|
||||||
|
|
||||||
|
MutexAutoLock lock(mLock);
|
||||||
|
|
||||||
|
NS_ENSURE_TRUE(aOutHeader, E_POINTER);
|
||||||
|
*aOutSurface = nullptr;
|
||||||
|
*aOutShouldDisplay = false;
|
||||||
|
|
||||||
|
VP9FrameHeader header;
|
||||||
|
if (!mParser.Parse(aData, aSize, header)) {
|
||||||
|
if (header.profile != 0) {
|
||||||
|
return MF_E_INVALIDMEDIATYPE;
|
||||||
|
}
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aOutHeader = header;
|
||||||
|
|
||||||
|
if (header.showExistingFrame) {
|
||||||
|
uint8_t slot = header.frameToShowMapIdx;
|
||||||
|
uint8_t surfIdx = mRefFrameSurface[slot];
|
||||||
|
if (surfIdx == 0xFF || !mSurfaces[surfIdx]) {
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
*aOutSurface = mSurfaces[surfIdx];
|
||||||
|
(*aOutSurface)->AddRef();
|
||||||
|
*aOutShouldDisplay = true;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.frameWidth != mWidth || header.frameHeight != mHeight) {
|
||||||
|
if (header.frameType != 0) { return MF_E_INVALIDMEDIATYPE; }
|
||||||
|
HRESULT hr = InitDecoder(header.frameWidth, header.frameHeight);
|
||||||
|
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||||
|
mWidth = header.frameWidth;
|
||||||
|
mHeight = header.frameHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentSurface = PickNextSurface();
|
||||||
|
IDirect3DSurface9* currentSurf = mSurfaces[mCurrentSurface];
|
||||||
|
|
||||||
|
static const uint32_t kBeginFrameRetries = 50;
|
||||||
|
HRESULT hr = E_PENDING;
|
||||||
|
for (uint32_t attempt = 0; attempt < kBeginFrameRetries; ++attempt) {
|
||||||
|
hr = mDecoder->BeginFrame(currentSurf, nullptr);
|
||||||
|
if (hr != E_PENDING) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
::Sleep(2);
|
||||||
|
}
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto failWith = [this](HRESULT aHR) -> HRESULT {
|
||||||
|
mDecoder->EndFrame(nullptr);
|
||||||
|
return aHR;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (aSize > UINT32_MAX - 127) { return failWith(E_INVALIDARG); }
|
||||||
|
UINT bitstreamCopied = (aSize + 127) & ~127u;
|
||||||
|
{
|
||||||
|
void* buf = nullptr; UINT size = 0;
|
||||||
|
hr = mDecoder->GetBuffer(DXVA2_BitStreamDateBufferType, &buf, &size);
|
||||||
|
if (FAILED(hr)) { return failWith(hr); }
|
||||||
|
if (!buf || size < bitstreamCopied) {
|
||||||
|
mDecoder->ReleaseBuffer(DXVA2_BitStreamDateBufferType);
|
||||||
|
return failWith(E_FAIL);
|
||||||
|
}
|
||||||
|
memcpy(buf, aData, aSize);
|
||||||
|
memset(static_cast<uint8_t*>(buf) + aSize, 0, bitstreamCopied - aSize);
|
||||||
|
hr = mDecoder->ReleaseBuffer(DXVA2_BitStreamDateBufferType);
|
||||||
|
if (FAILED(hr)) { return failWith(hr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
UXP_DXVA_PicParams_VP9 picParams;
|
||||||
|
FillPicParams(header, picParams);
|
||||||
|
|
||||||
|
UXP_DXVA_Slice_VPx_Short sliceInfo = {};
|
||||||
|
sliceInfo.BSNALunitDataLocation = 0;
|
||||||
|
sliceInfo.SliceBytesInBuffer = aSize;
|
||||||
|
sliceInfo.wBadSliceChopping = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
void* buf = nullptr;
|
||||||
|
UINT size = 0;
|
||||||
|
hr = mDecoder->GetBuffer(DXVA2_PictureParametersBufferType, &buf, &size);
|
||||||
|
if (FAILED(hr)) { return failWith(hr); }
|
||||||
|
if (size < sizeof(picParams)) {
|
||||||
|
mDecoder->ReleaseBuffer(DXVA2_PictureParametersBufferType);
|
||||||
|
return failWith(E_FAIL);
|
||||||
|
}
|
||||||
|
memcpy(buf, &picParams, sizeof(picParams));
|
||||||
|
hr = mDecoder->ReleaseBuffer(DXVA2_PictureParametersBufferType);
|
||||||
|
if (FAILED(hr)) { return failWith(hr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
void* buf = nullptr;
|
||||||
|
UINT size = 0;
|
||||||
|
hr = mDecoder->GetBuffer(DXVA2_SliceControlBufferType, &buf, &size);
|
||||||
|
if (FAILED(hr)) { return failWith(hr); }
|
||||||
|
if (size < sizeof(sliceInfo)) {
|
||||||
|
mDecoder->ReleaseBuffer(DXVA2_SliceControlBufferType);
|
||||||
|
return failWith(E_FAIL);
|
||||||
|
}
|
||||||
|
memcpy(buf, &sliceInfo, sizeof(sliceInfo));
|
||||||
|
hr = mDecoder->ReleaseBuffer(DXVA2_SliceControlBufferType);
|
||||||
|
if (FAILED(hr)) { return failWith(hr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
DXVA2_DecodeBufferDesc bufDescs[3] = {};
|
||||||
|
bufDescs[0].CompressedBufferType = DXVA2_PictureParametersBufferType;
|
||||||
|
bufDescs[0].DataSize = (UINT)sizeof(picParams);
|
||||||
|
bufDescs[0].DataOffset = 0;
|
||||||
|
|
||||||
|
bufDescs[1].CompressedBufferType = DXVA2_SliceControlBufferType;
|
||||||
|
bufDescs[1].DataSize = (UINT)sizeof(sliceInfo);
|
||||||
|
bufDescs[1].DataOffset = 0;
|
||||||
|
|
||||||
|
bufDescs[2].CompressedBufferType = DXVA2_BitStreamDateBufferType;
|
||||||
|
bufDescs[2].DataSize = bitstreamCopied;
|
||||||
|
bufDescs[2].DataOffset = 0;
|
||||||
|
|
||||||
|
DXVA2_DecodeExecuteParams execParams = {};
|
||||||
|
execParams.NumCompBuffers = 3;
|
||||||
|
execParams.pCompressedBuffers = bufDescs;
|
||||||
|
|
||||||
|
hr = mDecoder->Execute(&execParams);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return failWith(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = mDecoder->EndFrame(nullptr);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (header.refreshFrameFlags & (1 << i)) {
|
||||||
|
mRefFrameSurface[i] = (uint8_t)mCurrentSurface;
|
||||||
|
mRefFrameWidth[i] = header.frameWidth;
|
||||||
|
mRefFrameHeight[i] = header.frameHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mParser.Commit(header);
|
||||||
|
|
||||||
|
*aOutSurface = currentSurf;
|
||||||
|
(*aOutSurface)->AddRef();
|
||||||
|
*aOutShouldDisplay = (header.showFrame != 0);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
82
dom/media/platforms/wmf/DXVAVP9Manager.h
Normal file
82
dom/media/platforms/wmf/DXVAVP9Manager.h
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef DXVAVP9Manager_h_
|
||||||
|
#define DXVAVP9Manager_h_
|
||||||
|
|
||||||
|
#include "WMF.h"
|
||||||
|
#include "VP9DXVA.h"
|
||||||
|
#include "VP9HeaderParser.h"
|
||||||
|
#include "mozilla/RefPtr.h"
|
||||||
|
#include "mozilla/Mutex.h"
|
||||||
|
#include "MediaInfo.h"
|
||||||
|
#include "ImageContainer.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
#include "nsPrintfCString.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace layers {
|
||||||
|
class KnowsCompositor;
|
||||||
|
class Image;
|
||||||
|
class D3D9RecycleAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DXVAVP9Manager {
|
||||||
|
public:
|
||||||
|
DXVAVP9Manager();
|
||||||
|
~DXVAVP9Manager();
|
||||||
|
|
||||||
|
bool Init(IUnknown* aDeviceManager, uint32_t aWidth, uint32_t aHeight,
|
||||||
|
nsACString& aFailureReason);
|
||||||
|
HRESULT DecodeFrame(const uint8_t* aData, uint32_t aSize,
|
||||||
|
IDirect3DSurface9** aOutSurface,
|
||||||
|
bool* aOutShouldDisplay,
|
||||||
|
VP9FrameHeader* aOutHeader);
|
||||||
|
|
||||||
|
HRESULT ConfigureForSize(uint32_t aWidth, uint32_t aHeight);
|
||||||
|
|
||||||
|
void Flush();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
bool IsValid() const { return mDecoder != nullptr; }
|
||||||
|
|
||||||
|
static const GUID& GetVP9DecoderGUID();
|
||||||
|
|
||||||
|
static bool SupportsVP9(IDirect3DDeviceManager9* aDeviceManager);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HRESULT InitDecoder(uint32_t aWidth, uint32_t aHeight);
|
||||||
|
HRESULT AllocateSurfaces(uint32_t aWidth, uint32_t aHeight, uint32_t aCount);
|
||||||
|
void FreeSurfaces();
|
||||||
|
|
||||||
|
uint32_t PickNextSurface() const;
|
||||||
|
|
||||||
|
void FillPicParams(const VP9FrameHeader& aHeader,
|
||||||
|
UXP_DXVA_PicParams_VP9& aPicParams);
|
||||||
|
|
||||||
|
RefPtr<IDirect3DDeviceManager9> mDeviceManager;
|
||||||
|
RefPtr<IDirectXVideoDecoderService> mDecoderService;
|
||||||
|
RefPtr<IDirectXVideoDecoder> mDecoder;
|
||||||
|
|
||||||
|
static const uint32_t kMinSurfaces = 9;
|
||||||
|
static const uint32_t kDefaultSurfaces = 10;
|
||||||
|
static const uint32_t kMaxSurfaces = 24;
|
||||||
|
RefPtr<IDirect3DSurface9> mSurfaces[kMaxSurfaces];
|
||||||
|
uint32_t mNumSurfaces;
|
||||||
|
uint32_t mCurrentSurface;
|
||||||
|
|
||||||
|
uint32_t mWidth;
|
||||||
|
uint32_t mHeight;
|
||||||
|
uint8_t mRefFrameSurface[8];
|
||||||
|
uint32_t mRefFrameWidth[8];
|
||||||
|
uint32_t mRefFrameHeight[8];
|
||||||
|
uint32_t mFrameCount;
|
||||||
|
|
||||||
|
VP9HeaderParser mParser;
|
||||||
|
Mutex mLock;
|
||||||
|
};
|
||||||
|
} // namespace mozilla
|
||||||
|
#endif
|
||||||
111
dom/media/platforms/wmf/VP9DXVA.h
Normal file
111
dom/media/platforms/wmf/VP9DXVA.h
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef VP9DXVA_h_
|
||||||
|
#define VP9DXVA_h_
|
||||||
|
#include <stddef.h>
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
typedef struct _UXP_DXVA_PicEntry_VPx {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
UCHAR Index7Bits : 7;
|
||||||
|
UCHAR AssociatedFlag : 1;
|
||||||
|
};
|
||||||
|
UCHAR bPicEntry;
|
||||||
|
};
|
||||||
|
} UXP_DXVA_PicEntry_VPx;
|
||||||
|
|
||||||
|
typedef struct _UXP_DXVA_segmentation_VP9 {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
UCHAR enabled : 1;
|
||||||
|
UCHAR update_map : 1;
|
||||||
|
UCHAR temporal_update : 1;
|
||||||
|
UCHAR abs_delta : 1;
|
||||||
|
UCHAR ReservedSegmentFlags4Bits : 4;
|
||||||
|
};
|
||||||
|
UCHAR wSegmentInfoFlags;
|
||||||
|
};
|
||||||
|
UCHAR tree_probs[7];
|
||||||
|
UCHAR pred_probs[3];
|
||||||
|
SHORT feature_data[8][4];
|
||||||
|
UCHAR feature_mask[8];
|
||||||
|
} UXP_DXVA_segmentation_VP9;
|
||||||
|
|
||||||
|
typedef struct _UXP_DXVA_PicParams_VP9 {
|
||||||
|
UXP_DXVA_PicEntry_VPx CurrPic;
|
||||||
|
UCHAR profile;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
USHORT frame_type : 1;
|
||||||
|
USHORT show_frame : 1;
|
||||||
|
USHORT error_resilient_mode : 1;
|
||||||
|
USHORT subsampling_x : 1;
|
||||||
|
USHORT subsampling_y : 1;
|
||||||
|
USHORT extra_plane : 1;
|
||||||
|
USHORT refresh_frame_context : 1;
|
||||||
|
USHORT frame_parallel_decoding_mode : 1;
|
||||||
|
USHORT intra_only : 1;
|
||||||
|
USHORT frame_context_idx : 2;
|
||||||
|
USHORT reset_frame_context : 2;
|
||||||
|
USHORT allow_high_precision_mv : 1;
|
||||||
|
USHORT ReservedFormatInfo2Bits : 2;
|
||||||
|
};
|
||||||
|
USHORT wFormatAndPictureInfoFlags;
|
||||||
|
};
|
||||||
|
UINT width;
|
||||||
|
UINT height;
|
||||||
|
UCHAR BitDepthMinus8Luma;
|
||||||
|
UCHAR BitDepthMinus8Chroma;
|
||||||
|
UCHAR interp_filter;
|
||||||
|
UCHAR Reserved8Bits;
|
||||||
|
UXP_DXVA_PicEntry_VPx ref_frame_map[8];
|
||||||
|
UINT ref_frame_coded_width[8];
|
||||||
|
UINT ref_frame_coded_height[8];
|
||||||
|
UXP_DXVA_PicEntry_VPx frame_refs[3];
|
||||||
|
CHAR ref_frame_sign_bias[4];
|
||||||
|
CHAR filter_level;
|
||||||
|
CHAR sharpness_level;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
UCHAR mode_ref_delta_enabled : 1;
|
||||||
|
UCHAR mode_ref_delta_update : 1;
|
||||||
|
UCHAR use_prev_in_find_mv_refs : 1;
|
||||||
|
UCHAR ReservedControlInfo5Bits : 5;
|
||||||
|
};
|
||||||
|
UCHAR wControlInfoFlags;
|
||||||
|
};
|
||||||
|
CHAR ref_deltas[4];
|
||||||
|
CHAR mode_deltas[2];
|
||||||
|
SHORT base_qindex;
|
||||||
|
CHAR y_dc_delta_q;
|
||||||
|
CHAR uv_dc_delta_q;
|
||||||
|
CHAR uv_ac_delta_q;
|
||||||
|
UXP_DXVA_segmentation_VP9 stVP9Segments;
|
||||||
|
UCHAR log2_tile_cols;
|
||||||
|
UCHAR log2_tile_rows;
|
||||||
|
USHORT uncompressed_header_size_byte_aligned;
|
||||||
|
USHORT first_partition_size;
|
||||||
|
USHORT Reserved16Bits;
|
||||||
|
UINT Reserved32Bits;
|
||||||
|
UINT StatusReportFeedbackNumber;
|
||||||
|
} UXP_DXVA_PicParams_VP9;
|
||||||
|
|
||||||
|
typedef struct _UXP_DXVA_Slice_VPx_Short {
|
||||||
|
UINT BSNALunitDataLocation;
|
||||||
|
UINT SliceBytesInBuffer;
|
||||||
|
USHORT wBadSliceChopping;
|
||||||
|
} UXP_DXVA_Slice_VPx_Short;
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
||||||
|
static_assert(sizeof(UXP_DXVA_PicParams_VP9) == 208, "VP9 picture ABI");
|
||||||
|
static_assert(sizeof(UXP_DXVA_segmentation_VP9) == 83, "VP9 segmentation ABI");
|
||||||
|
static_assert(sizeof(UXP_DXVA_Slice_VPx_Short) == 10, "VP9 slice ABI");
|
||||||
|
static_assert(offsetof(UXP_DXVA_PicParams_VP9, stVP9Segments) == 109, "VP9 segment offset");
|
||||||
|
static_assert(offsetof(UXP_DXVA_PicParams_VP9, StatusReportFeedbackNumber) == 204, "VP9 status offset");
|
||||||
|
#endif
|
||||||
464
dom/media/platforms/wmf/VP9HeaderParser.cpp
Normal file
464
dom/media/platforms/wmf/VP9HeaderParser.cpp
Normal file
|
|
@ -0,0 +1,464 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "VP9HeaderParser.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string.h>
|
||||||
|
namespace mozilla {
|
||||||
|
uint32_t
|
||||||
|
VP9BitReader::ReadBits(int n)
|
||||||
|
{
|
||||||
|
if (n < 0 || n > 32) { mError = true; return 0; }
|
||||||
|
uint32_t result = 0;
|
||||||
|
while (n > 0) {
|
||||||
|
if (mBitsLeft == 0) {
|
||||||
|
if (mBytesRead >= mSize) {
|
||||||
|
mError = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
mCurrent = mData[mBytesRead++];
|
||||||
|
mBitsLeft = 8;
|
||||||
|
}
|
||||||
|
int take = std::min(n, mBitsLeft);
|
||||||
|
result <<= take;
|
||||||
|
result |= (mCurrent >> (mBitsLeft - take)) & ((1 << take) - 1);
|
||||||
|
mBitsLeft -= take;
|
||||||
|
n -= take;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
VP9BitReader::ReadSignedBits(int n)
|
||||||
|
{
|
||||||
|
int32_t v = (int32_t)ReadBits(n);
|
||||||
|
int32_t sign = (int32_t)ReadBit();
|
||||||
|
return sign ? -v : v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ReadColorConfig(VP9BitReader& br, uint8_t profile, VP9FrameHeader& h)
|
||||||
|
{
|
||||||
|
if (profile >= 2) {
|
||||||
|
br.ReadBit();
|
||||||
|
}
|
||||||
|
h.colorSpace = (uint8_t)br.ReadBits(3);
|
||||||
|
if (h.colorSpace != 7) {
|
||||||
|
h.colorRange = (uint8_t)br.ReadBit();
|
||||||
|
if (profile == 1 || profile == 3) {
|
||||||
|
h.subsamplingX = (uint8_t)br.ReadBit();
|
||||||
|
h.subsamplingY = (uint8_t)br.ReadBit();
|
||||||
|
br.ReadBit();
|
||||||
|
} else {
|
||||||
|
h.subsamplingX = 1;
|
||||||
|
h.subsamplingY = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.colorRange = 1;
|
||||||
|
if (profile == 1 || profile == 3) {
|
||||||
|
h.subsamplingX = 0;
|
||||||
|
h.subsamplingY = 0;
|
||||||
|
br.ReadBit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
ReadFrameSize(VP9BitReader& br)
|
||||||
|
{
|
||||||
|
return br.ReadBits(16) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VP9HeaderParser::ParseLoopFilter(VP9BitReader& br, VP9FrameHeader& h)
|
||||||
|
{
|
||||||
|
h.filterLevel = (uint8_t)br.ReadBits(6);
|
||||||
|
h.sharpnessLevel = (uint8_t)br.ReadBits(3);
|
||||||
|
h.modeRefLfEnabled = 0;
|
||||||
|
|
||||||
|
uint8_t modeRefDeltaEnabled = (uint8_t)br.ReadBit();
|
||||||
|
h.modeRefDeltaUpdate = 0;
|
||||||
|
if (modeRefDeltaEnabled) {
|
||||||
|
h.modeRefLfEnabled = 1;
|
||||||
|
uint8_t modeRefDeltaUpdate = (uint8_t)br.ReadBit();
|
||||||
|
h.modeRefDeltaUpdate = modeRefDeltaUpdate;
|
||||||
|
if (modeRefDeltaUpdate) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
mRefDeltas[i] = (int8_t)br.ReadSignedBits(6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
mModeDeltas[i] = (int8_t)br.ReadSignedBits(6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 4; i++) { h.refDeltas[i] = mRefDeltas[i]; }
|
||||||
|
for (int i = 0; i < 2; i++) { h.modeDeltas[i] = mModeDeltas[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VP9HeaderParser::ParseQuantization(VP9BitReader& br, VP9FrameHeader& h)
|
||||||
|
{
|
||||||
|
h.baseQIndex = (uint8_t)br.ReadBits(8);
|
||||||
|
h.deltaQYDc = br.ReadBit() ? (int8_t)br.ReadSignedBits(4) : 0;
|
||||||
|
h.deltaQUvDc = br.ReadBit() ? (int8_t)br.ReadSignedBits(4) : 0;
|
||||||
|
h.deltaQUvAc = br.ReadBit() ? (int8_t)br.ReadSignedBits(4) : 0;
|
||||||
|
h.lossless = (h.baseQIndex == 0 &&
|
||||||
|
h.deltaQYDc == 0 &&
|
||||||
|
h.deltaQUvDc == 0 &&
|
||||||
|
h.deltaQUvAc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VP9HeaderParser::ParseSegmentation(VP9BitReader& br, VP9FrameHeader& h)
|
||||||
|
{
|
||||||
|
static const int kSegLvlMax = 4;
|
||||||
|
static const int kMaxSegments = 8;
|
||||||
|
static const int kSegFeatureBits[4] = { 8, 6, 2, 0 };
|
||||||
|
|
||||||
|
|
||||||
|
h.segmentationEnabled = (uint8_t)br.ReadBit();
|
||||||
|
if (!h.segmentationEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.segmentationUpdateMap = (uint8_t)br.ReadBit();
|
||||||
|
if (h.segmentationUpdateMap) {
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
h.segmentationTreeProbs[i] = br.ReadBit()
|
||||||
|
? (uint8_t)br.ReadBits(8)
|
||||||
|
: 255;
|
||||||
|
}
|
||||||
|
h.segmentationTemporalUpdate = (uint8_t)br.ReadBit();
|
||||||
|
memset(h.segmentationPredProbs, 255, sizeof(h.segmentationPredProbs));
|
||||||
|
if (h.segmentationTemporalUpdate) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
h.segmentationPredProbs[i] = br.ReadBit()
|
||||||
|
? (uint8_t)br.ReadBits(8)
|
||||||
|
: 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t segUpdate = (uint8_t)br.ReadBit();
|
||||||
|
if (!segUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(h.segFeatureEnabled, 0, sizeof(h.segFeatureEnabled));
|
||||||
|
memset(h.segFeatureData, 0, sizeof(h.segFeatureData));
|
||||||
|
h.segmentationAbsOrDelta = (uint8_t)br.ReadBit();
|
||||||
|
for (int i = 0; i < kMaxSegments; i++) {
|
||||||
|
for (int j = 0; j < kSegLvlMax; j++) {
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
h.segFeatureEnabled[i][j] = 1;
|
||||||
|
int bits = kSegFeatureBits[j];
|
||||||
|
if (bits > 0) {
|
||||||
|
int16_t v = (int16_t)br.ReadBits(bits);
|
||||||
|
if (j < 2 && br.ReadBit()) {
|
||||||
|
v = -v;
|
||||||
|
}
|
||||||
|
h.segFeatureData[i][j] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VP9HeaderParser::ParseTileInfo(VP9BitReader& br, VP9FrameHeader& h)
|
||||||
|
{
|
||||||
|
static const uint32_t kMaxTileWidthB64 = 64;
|
||||||
|
static const uint32_t kMinTileWidthB64 = 4;
|
||||||
|
|
||||||
|
uint32_t sbCols = (h.frameWidth + 63) >> 6;
|
||||||
|
|
||||||
|
int minLog2TileCols = 0;
|
||||||
|
while ((kMaxTileWidthB64 << minLog2TileCols) < sbCols) {
|
||||||
|
minLog2TileCols++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxLog2TileCols = 1;
|
||||||
|
while ((sbCols >> maxLog2TileCols) >= kMinTileWidthB64) {
|
||||||
|
maxLog2TileCols++;
|
||||||
|
}
|
||||||
|
maxLog2TileCols--;
|
||||||
|
if (maxLog2TileCols < minLog2TileCols) {
|
||||||
|
maxLog2TileCols = minLog2TileCols;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.log2TileCols = (uint8_t)minLog2TileCols;
|
||||||
|
while (h.log2TileCols < (uint8_t)maxLog2TileCols) {
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
h.log2TileCols++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.log2TileRows = 0;
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
h.log2TileRows = 1;
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
h.log2TileRows = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
VP9HeaderParser::ParseInternal(const uint8_t* aData, uint32_t aSize,
|
||||||
|
VP9FrameHeader& aHeader)
|
||||||
|
{
|
||||||
|
memset(&aHeader, 0, sizeof(aHeader));
|
||||||
|
|
||||||
|
if (!aData || !aSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
aHeader.subsamplingX = aHeader.subsamplingY = 1;
|
||||||
|
aHeader.colorSpace = mPrevious.colorSpace;
|
||||||
|
aHeader.colorRange = mPrevious.colorRange;
|
||||||
|
aHeader.segmentationAbsOrDelta = mPrevious.segmentationAbsOrDelta;
|
||||||
|
memcpy(aHeader.segFeatureEnabled, mPrevious.segFeatureEnabled, sizeof(aHeader.segFeatureEnabled));
|
||||||
|
memcpy(aHeader.segFeatureData, mPrevious.segFeatureData, sizeof(aHeader.segFeatureData));
|
||||||
|
memcpy(aHeader.segmentationTreeProbs, mPrevious.segmentationTreeProbs, sizeof(aHeader.segmentationTreeProbs));
|
||||||
|
memcpy(aHeader.segmentationPredProbs, mPrevious.segmentationPredProbs, sizeof(aHeader.segmentationPredProbs));
|
||||||
|
VP9BitReader br(aData, aSize);
|
||||||
|
|
||||||
|
uint32_t marker = br.ReadBits(2);
|
||||||
|
if (marker != 0x2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t profileLowBit = (uint8_t)br.ReadBit();
|
||||||
|
uint8_t profileHighBit = (uint8_t)br.ReadBit();
|
||||||
|
uint8_t profile = (profileHighBit << 1) | profileLowBit;
|
||||||
|
if (profile == 3) {
|
||||||
|
br.ReadBit();
|
||||||
|
}
|
||||||
|
aHeader.profile = profile;
|
||||||
|
|
||||||
|
if (profile != 0) { return false; }
|
||||||
|
|
||||||
|
uint8_t showExistingFrame = (uint8_t)br.ReadBit();
|
||||||
|
if (showExistingFrame) {
|
||||||
|
uint8_t mapIdx = (uint8_t)br.ReadBits(3);
|
||||||
|
aHeader.showExistingFrame = 1;
|
||||||
|
aHeader.frameToShowMapIdx = mapIdx;
|
||||||
|
aHeader.frameType = 1;
|
||||||
|
aHeader.showFrame = 1;
|
||||||
|
aHeader.frameWidth = mRefFrameWidth[mapIdx];
|
||||||
|
aHeader.frameHeight = mRefFrameHeight[mapIdx];
|
||||||
|
aHeader.isIntra = false;
|
||||||
|
aHeader.uncompressedHeaderSizeBytes = (uint32_t)br.BytesConsumed();
|
||||||
|
aHeader.compressedHeaderSize = 0;
|
||||||
|
return !br.Failed() && aHeader.frameWidth && aHeader.frameHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
aHeader.frameType = (uint8_t)br.ReadBit();
|
||||||
|
aHeader.showFrame = (uint8_t)br.ReadBit();
|
||||||
|
aHeader.errorResilientMode = (uint8_t)br.ReadBit();
|
||||||
|
|
||||||
|
if (aHeader.frameType == 0) {
|
||||||
|
uint8_t s0 = (uint8_t)br.ReadBits(8);
|
||||||
|
uint8_t s1 = (uint8_t)br.ReadBits(8);
|
||||||
|
uint8_t s2 = (uint8_t)br.ReadBits(8);
|
||||||
|
if (s0 != 0x49 || s1 != 0x83 || s2 != 0x42) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadColorConfig(br, profile, aHeader);
|
||||||
|
if (aHeader.colorSpace == 7 || aHeader.colorSpace == 6) { return false; }
|
||||||
|
|
||||||
|
aHeader.frameWidth = ReadFrameSize(br);
|
||||||
|
aHeader.frameHeight = ReadFrameSize(br);
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
aHeader.renderWidth = ReadFrameSize(br);
|
||||||
|
aHeader.renderHeight = ReadFrameSize(br);
|
||||||
|
} else {
|
||||||
|
aHeader.renderWidth = aHeader.frameWidth;
|
||||||
|
aHeader.renderHeight = aHeader.frameHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
aHeader.refreshFrameFlags = 0xFF;
|
||||||
|
aHeader.isIntra = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
aHeader.isIntra = false;
|
||||||
|
|
||||||
|
uint8_t intraOnly = 0;
|
||||||
|
if (!aHeader.showFrame) {
|
||||||
|
intraOnly = (uint8_t)br.ReadBit();
|
||||||
|
}
|
||||||
|
aHeader.isIntra = (intraOnly != 0);
|
||||||
|
|
||||||
|
if (!aHeader.errorResilientMode) {
|
||||||
|
aHeader.resetFrameContext = (uint8_t)br.ReadBits(2);
|
||||||
|
} else {
|
||||||
|
aHeader.resetFrameContext = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intraOnly) {
|
||||||
|
uint8_t s0 = (uint8_t)br.ReadBits(8);
|
||||||
|
uint8_t s1 = (uint8_t)br.ReadBits(8);
|
||||||
|
uint8_t s2 = (uint8_t)br.ReadBits(8);
|
||||||
|
if (s0 != 0x49 || s1 != 0x83 || s2 != 0x42) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (profile > 0) {
|
||||||
|
ReadColorConfig(br, profile, aHeader);
|
||||||
|
} else {
|
||||||
|
aHeader.colorSpace = 1;
|
||||||
|
aHeader.colorRange = 0;
|
||||||
|
aHeader.subsamplingX = 1;
|
||||||
|
aHeader.subsamplingY = 1;
|
||||||
|
}
|
||||||
|
aHeader.refreshFrameFlags = (uint8_t)br.ReadBits(8);
|
||||||
|
aHeader.frameWidth = ReadFrameSize(br);
|
||||||
|
aHeader.frameHeight = ReadFrameSize(br);
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
aHeader.renderWidth = ReadFrameSize(br);
|
||||||
|
aHeader.renderHeight = ReadFrameSize(br);
|
||||||
|
} else {
|
||||||
|
aHeader.renderWidth = aHeader.frameWidth;
|
||||||
|
aHeader.renderHeight = aHeader.frameHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
aHeader.refreshFrameFlags = (uint8_t)br.ReadBits(8);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
aHeader.refFrameIdx[i] = (uint8_t)br.ReadBits(3);
|
||||||
|
aHeader.refFrameSignBias[i+1] = (uint8_t)br.ReadBit();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
if (!mRefFrameWidth[aHeader.refFrameIdx[i]]) { return false; }
|
||||||
|
}
|
||||||
|
bool foundRef = false;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
aHeader.frameWidth = mRefFrameWidth[aHeader.refFrameIdx[i]];
|
||||||
|
aHeader.frameHeight = mRefFrameHeight[aHeader.refFrameIdx[i]];
|
||||||
|
foundRef = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundRef) {
|
||||||
|
aHeader.frameWidth = ReadFrameSize(br);
|
||||||
|
aHeader.frameHeight = ReadFrameSize(br);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
aHeader.renderWidth = ReadFrameSize(br);
|
||||||
|
aHeader.renderHeight = ReadFrameSize(br);
|
||||||
|
} else {
|
||||||
|
aHeader.renderWidth = aHeader.frameWidth;
|
||||||
|
aHeader.renderHeight = aHeader.frameHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
aHeader.allowHighPrecisionMv = (uint8_t)br.ReadBit();
|
||||||
|
if (br.ReadBit()) {
|
||||||
|
aHeader.interpFilter = 4;
|
||||||
|
} else {
|
||||||
|
static const uint8_t kLiteralToFilter[4] = { 1, 0, 2, 3 };
|
||||||
|
aHeader.interpFilter = kLiteralToFilter[br.ReadBits(2)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aHeader.errorResilientMode) {
|
||||||
|
aHeader.refreshFrameContext = (uint8_t)br.ReadBit();
|
||||||
|
aHeader.frameParallelDecodingMode = (uint8_t)br.ReadBit();
|
||||||
|
} else {
|
||||||
|
aHeader.refreshFrameContext = 0;
|
||||||
|
aHeader.frameParallelDecodingMode = 1;
|
||||||
|
}
|
||||||
|
aHeader.frameContextIdx = (uint8_t)br.ReadBits(2);
|
||||||
|
|
||||||
|
aHeader.usePrevFrameMvs = !aHeader.isIntra && !aHeader.errorResilientMode &&
|
||||||
|
!mPrevious.isIntra && mPrevious.showFrame && mPrevious.frameWidth == aHeader.frameWidth &&
|
||||||
|
mPrevious.frameHeight == aHeader.frameHeight;
|
||||||
|
if (aHeader.isIntra || aHeader.errorResilientMode) {
|
||||||
|
mRefDeltas[0] = 1; mRefDeltas[1] = 0;
|
||||||
|
mRefDeltas[2] = mRefDeltas[3] = -1;
|
||||||
|
mModeDeltas[0] = mModeDeltas[1] = 0;
|
||||||
|
aHeader.segmentationAbsOrDelta = 0;
|
||||||
|
memset(aHeader.segFeatureEnabled, 0, sizeof(aHeader.segFeatureEnabled));
|
||||||
|
memset(aHeader.segFeatureData, 0, sizeof(aHeader.segFeatureData));
|
||||||
|
aHeader.frameContextIdx = 0;
|
||||||
|
}
|
||||||
|
ParseLoopFilter(br, aHeader);
|
||||||
|
ParseQuantization(br, aHeader);
|
||||||
|
ParseSegmentation(br, aHeader);
|
||||||
|
ParseTileInfo(br, aHeader);
|
||||||
|
|
||||||
|
aHeader.compressedHeaderSize = br.ReadBits(16);
|
||||||
|
|
||||||
|
aHeader.uncompressedHeaderSizeBytes = (uint32_t)br.BytesConsumed();
|
||||||
|
|
||||||
|
if (aHeader.frameWidth == 0 || aHeader.frameHeight == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !br.Failed() && aHeader.compressedHeaderSize != 0 &&
|
||||||
|
aHeader.uncompressedHeaderSizeBytes <= aSize &&
|
||||||
|
aHeader.compressedHeaderSize < aSize - aHeader.uncompressedHeaderSizeBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VP9HeaderParser::Reset() {
|
||||||
|
memset(&mPrevious, 0, sizeof(mPrevious));
|
||||||
|
memset(mPrevious.segmentationTreeProbs, 255, sizeof(mPrevious.segmentationTreeProbs));
|
||||||
|
memset(mPrevious.segmentationPredProbs, 255, sizeof(mPrevious.segmentationPredProbs));
|
||||||
|
memset(mRefFrameWidth, 0, sizeof(mRefFrameWidth));
|
||||||
|
memset(mRefFrameHeight, 0, sizeof(mRefFrameHeight));
|
||||||
|
mRefDeltas[0] = 1; mRefDeltas[1] = 0; mRefDeltas[2] = mRefDeltas[3] = -1;
|
||||||
|
mModeDeltas[0] = mModeDeltas[1] = 0;
|
||||||
|
}
|
||||||
|
bool VP9HeaderParser::Parse(const uint8_t* data, uint32_t size, VP9FrameHeader& h) const {
|
||||||
|
VP9HeaderParser candidate = *this;
|
||||||
|
return candidate.ParseInternal(data, size, h);
|
||||||
|
}
|
||||||
|
void VP9HeaderParser::Commit(const VP9FrameHeader& h) {
|
||||||
|
if (h.showExistingFrame) { return; }
|
||||||
|
mPrevious = h;
|
||||||
|
memcpy(mRefDeltas, h.refDeltas, sizeof(mRefDeltas));
|
||||||
|
memcpy(mModeDeltas, h.modeDeltas, sizeof(mModeDeltas));
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
if (h.refreshFrameFlags & (1 << i)) {
|
||||||
|
mRefFrameWidth[i] = h.frameWidth;
|
||||||
|
mRefFrameHeight[i] = h.frameHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool VP9SplitSuperframe(const uint8_t* data, uint32_t size,
|
||||||
|
uint32_t (&offsets)[8], uint32_t (&sizes)[8], uint32_t& count) {
|
||||||
|
count = 0;
|
||||||
|
if (!data || !size) { return false; }
|
||||||
|
uint8_t marker = data[size - 1];
|
||||||
|
if ((marker & 0xe0) != 0xc0) {
|
||||||
|
offsets[0] = 0; sizes[0] = size; count = 1; return true;
|
||||||
|
}
|
||||||
|
uint32_t frames = (marker & 7) + 1;
|
||||||
|
uint32_t magnitude = ((marker >> 3) & 3) + 1;
|
||||||
|
uint32_t indexSize = 2 + frames * magnitude;
|
||||||
|
if (size < indexSize || data[size - indexSize] != marker) { return false; }
|
||||||
|
uint32_t pos = size - indexSize + 1, total = 0;
|
||||||
|
for (uint32_t i = 0; i < frames; ++i) {
|
||||||
|
uint32_t length = 0;
|
||||||
|
for (uint32_t j = 0; j < magnitude; ++j) { length |= uint32_t(data[pos++]) << (j * 8); }
|
||||||
|
if (!length || length > size - indexSize - total) { return false; }
|
||||||
|
offsets[i] = total; sizes[i] = length; total += length;
|
||||||
|
}
|
||||||
|
if (total != size - indexSize) { return false; }
|
||||||
|
count = frames;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
120
dom/media/platforms/wmf/VP9HeaderParser.h
Normal file
120
dom/media/platforms/wmf/VP9HeaderParser.h
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef VP9HeaderParser_h_
|
||||||
|
#define VP9HeaderParser_h_
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
namespace mozilla {
|
||||||
|
struct VP9FrameHeader {
|
||||||
|
uint8_t profile;
|
||||||
|
// 0 = key frame, 1 = non-key frame
|
||||||
|
uint8_t frameType;
|
||||||
|
uint8_t showFrame;
|
||||||
|
uint8_t showExistingFrame; // true if this packet just redisplays a ref
|
||||||
|
uint8_t frameToShowMapIdx; // valid only if showExistingFrame
|
||||||
|
uint8_t errorResilientMode;
|
||||||
|
uint8_t colorSpace;
|
||||||
|
uint8_t colorRange;
|
||||||
|
uint8_t subsamplingX;
|
||||||
|
uint8_t subsamplingY;
|
||||||
|
uint32_t frameWidth;
|
||||||
|
uint32_t frameHeight;
|
||||||
|
uint32_t renderWidth;
|
||||||
|
uint32_t renderHeight;
|
||||||
|
uint8_t refreshFrameFlags;
|
||||||
|
uint8_t refFrameIdx[3];
|
||||||
|
uint8_t refFrameSignBias[4];
|
||||||
|
uint8_t allowHighPrecisionMv;
|
||||||
|
uint8_t interpFilter;
|
||||||
|
uint8_t refreshFrameContext;
|
||||||
|
uint8_t frameParallelDecodingMode;
|
||||||
|
uint8_t frameContextIdx;
|
||||||
|
uint8_t resetFrameContext;
|
||||||
|
|
||||||
|
uint8_t segmentationEnabled;
|
||||||
|
uint8_t segmentationUpdateMap;
|
||||||
|
uint8_t segmentationTemporalUpdate;
|
||||||
|
uint8_t segmentationAbsOrDelta;
|
||||||
|
uint8_t segmentationTreeProbs[7];
|
||||||
|
uint8_t segmentationPredProbs[3];
|
||||||
|
uint8_t segFeatureEnabled[8][4];
|
||||||
|
int16_t segFeatureData[8][4];
|
||||||
|
|
||||||
|
uint8_t filterLevel;
|
||||||
|
uint8_t sharpnessLevel;
|
||||||
|
uint8_t modeRefLfEnabled;
|
||||||
|
uint8_t modeRefDeltaUpdate;
|
||||||
|
int8_t refDeltas[4];
|
||||||
|
int8_t modeDeltas[2];
|
||||||
|
|
||||||
|
uint8_t baseQIndex;
|
||||||
|
int8_t deltaQYDc;
|
||||||
|
int8_t deltaQUvDc;
|
||||||
|
int8_t deltaQUvAc;
|
||||||
|
|
||||||
|
uint8_t log2TileCols;
|
||||||
|
uint8_t log2TileRows;
|
||||||
|
|
||||||
|
uint32_t compressedHeaderSize;
|
||||||
|
|
||||||
|
uint32_t uncompressedHeaderSizeBytes;
|
||||||
|
|
||||||
|
bool usePrevFrameMvs;
|
||||||
|
bool lossless;
|
||||||
|
bool isIntra;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VP9BitReader {
|
||||||
|
public:
|
||||||
|
VP9BitReader(const uint8_t* aData, size_t aSize)
|
||||||
|
: mData(aData), mSize(aSize), mBytesRead(0), mBitsLeft(0), mCurrent(0), mError(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint32_t ReadBits(int n);
|
||||||
|
uint32_t ReadBit() { return ReadBits(1); }
|
||||||
|
uint32_t ReadLiteral(int n) { return ReadBits(n); }
|
||||||
|
int32_t ReadSignedBits(int n);
|
||||||
|
bool Failed() const { return mError; }
|
||||||
|
bool Eof() const { return mBytesRead >= mSize && mBitsLeft == 0; }
|
||||||
|
size_t BytesConsumed() const {
|
||||||
|
size_t bitsConsumed = mBytesRead * 8 - (size_t)mBitsLeft;
|
||||||
|
return (bitsConsumed + 7) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t* mData;
|
||||||
|
size_t mSize;
|
||||||
|
size_t mBytesRead;
|
||||||
|
int mBitsLeft;
|
||||||
|
uint8_t mCurrent;
|
||||||
|
bool mError;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VP9HeaderParser {
|
||||||
|
public:
|
||||||
|
VP9HeaderParser() { Reset(); }
|
||||||
|
void Reset();
|
||||||
|
bool Parse(const uint8_t* aData, uint32_t aSize, VP9FrameHeader& aHeader) const;
|
||||||
|
void Commit(const VP9FrameHeader& aHeader);
|
||||||
|
private:
|
||||||
|
bool ParseInternal(const uint8_t*, uint32_t, VP9FrameHeader&);
|
||||||
|
void ParseLoopFilter(VP9BitReader&, VP9FrameHeader&);
|
||||||
|
void ParseQuantization(VP9BitReader&, VP9FrameHeader&);
|
||||||
|
void ParseSegmentation(VP9BitReader&, VP9FrameHeader&);
|
||||||
|
void ParseTileInfo(VP9BitReader&, VP9FrameHeader&);
|
||||||
|
VP9FrameHeader mPrevious;
|
||||||
|
uint32_t mRefFrameWidth[8];
|
||||||
|
uint32_t mRefFrameHeight[8];
|
||||||
|
int8_t mRefDeltas[4];
|
||||||
|
int8_t mModeDeltas[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool VP9SplitSuperframe(const uint8_t* aData, uint32_t aSize,
|
||||||
|
uint32_t (&aOffsets)[8], uint32_t (&aSizes)[8],
|
||||||
|
uint32_t& aCount);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "WMF.h"
|
#include "WMF.h"
|
||||||
#include "WMFDecoderModule.h"
|
#include "WMFDecoderModule.h"
|
||||||
#include "WMFVideoMFTManager.h"
|
#include "WMFVideoMFTManager.h"
|
||||||
|
#include "WMFVP9MFTManager.h"
|
||||||
#include "WMFAudioMFTManager.h"
|
#include "WMFAudioMFTManager.h"
|
||||||
#include "MFTDecoder.h"
|
#include "MFTDecoder.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
|
|
@ -80,6 +81,60 @@ WMFDecoderModule::Startup()
|
||||||
return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
|
return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<MediaDataDecoder>
|
||||||
|
WMFDecoderModule::CreateVP9Decoder(const CreateDecoderParams& aParams)
|
||||||
|
{
|
||||||
|
if (!MediaPrefs::PDMWMFVP9DecoderEnabled() || !sDXVAEnabled) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool mftAllowed = MediaPrefs::PDMWMFVP9MFTEnabled() && HasVP9MFT();
|
||||||
|
const bool dxva2Allowed =
|
||||||
|
MediaPrefs::PDMWMFVP9DXVA2Enabled() && IsVistaOrLater();
|
||||||
|
const bool dxva2First =
|
||||||
|
dxva2Allowed && (!mftAllowed || MediaPrefs::PDMWMFVP9DXVA2Preferred());
|
||||||
|
|
||||||
|
if (mftAllowed && !dxva2First) {
|
||||||
|
nsAutoPtr<WMFVideoMFTManager> mft(
|
||||||
|
new WMFVideoMFTManager(aParams.VideoConfig(),
|
||||||
|
aParams.mKnowsCompositor,
|
||||||
|
aParams.mImageContainer,
|
||||||
|
sDXVAEnabled));
|
||||||
|
if (mft->Init()) {
|
||||||
|
RefPtr<MediaDataDecoder> decoder = new WMFMediaDataDecoder(
|
||||||
|
mft.forget(), aParams.mTaskQueue, aParams.mCallback);
|
||||||
|
return decoder.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dxva2Allowed) {
|
||||||
|
nsAutoPtr<WMFVP9MFTManager> vp9(
|
||||||
|
new WMFVP9MFTManager(aParams.VideoConfig(),
|
||||||
|
aParams.mKnowsCompositor,
|
||||||
|
aParams.mImageContainer));
|
||||||
|
if (vp9->Init()) {
|
||||||
|
RefPtr<MediaDataDecoder> decoder = new WMFMediaDataDecoder(
|
||||||
|
vp9.forget(), aParams.mTaskQueue, aParams.mCallback);
|
||||||
|
return decoder.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mftAllowed && dxva2First) {
|
||||||
|
nsAutoPtr<WMFVideoMFTManager> mft(
|
||||||
|
new WMFVideoMFTManager(aParams.VideoConfig(),
|
||||||
|
aParams.mKnowsCompositor,
|
||||||
|
aParams.mImageContainer,
|
||||||
|
sDXVAEnabled));
|
||||||
|
if (mft->Init()) {
|
||||||
|
RefPtr<MediaDataDecoder> decoder = new WMFMediaDataDecoder(
|
||||||
|
mft.forget(), aParams.mTaskQueue, aParams.mCallback);
|
||||||
|
return decoder.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<MediaDataDecoder>
|
already_AddRefed<MediaDataDecoder>
|
||||||
WMFDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
WMFDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||||
{
|
{
|
||||||
|
|
@ -91,6 +146,10 @@ WMFDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (VPXDecoder::IsVP9(aParams.VideoConfig().mMimeType)) {
|
||||||
|
return CreateVP9Decoder(aParams);
|
||||||
|
}
|
||||||
|
|
||||||
nsAutoPtr<WMFVideoMFTManager> manager(
|
nsAutoPtr<WMFVideoMFTManager> manager(
|
||||||
new WMFVideoMFTManager(aParams.VideoConfig(),
|
new WMFVideoMFTManager(aParams.VideoConfig(),
|
||||||
aParams.mKnowsCompositor,
|
aParams.mKnowsCompositor,
|
||||||
|
|
@ -192,11 +251,28 @@ WMFDecoderModule::HasH264()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
WMFDecoderModule::HasVP9()
|
WMFDecoderModule::HasVP9MFT()
|
||||||
{
|
{
|
||||||
return CanCreateWMFDecoder<CLSID_WebmMfVpxDec>();
|
return CanCreateWMFDecoder<CLSID_WebmMfVpxDec>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
WMFDecoderModule::HasVP9DXVA2(layers::KnowsCompositor* aKnowsCompositor)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
if (!aKnowsCompositor || !IsVistaOrLater() || !sDXVAEnabled ||
|
||||||
|
!MediaPrefs::PDMWMFVP9DecoderEnabled() ||
|
||||||
|
!MediaPrefs::PDMWMFVP9DXVA2Enabled() ||
|
||||||
|
!gfx::gfxVars::CanUseHardwareVideoDecoding()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString failureReason;
|
||||||
|
nsAutoPtr<DXVA2Manager> manager(WMFVideoMFTManager::CreateVP9DXVA(
|
||||||
|
aKnowsCompositor, failureReason, DXVAVP9Manager::GetVP9DecoderGUID()));
|
||||||
|
return !!manager;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
WMFDecoderModule::HasAAC()
|
WMFDecoderModule::HasAAC()
|
||||||
{
|
{
|
||||||
|
|
@ -254,8 +330,17 @@ WMFDecoderModule::Supports(const TrackInfo& aTrackInfo,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (MediaPrefs::PDMWMFVP9DecoderEnabled() && sDXVAEnabled) {
|
if (MediaPrefs::PDMWMFVP9DecoderEnabled() && sDXVAEnabled) {
|
||||||
if ((VPXDecoder::IsVP8(aTrackInfo.mMimeType) ||
|
if (VPXDecoder::IsVP9(aTrackInfo.mMimeType)) {
|
||||||
VPXDecoder::IsVP9(aTrackInfo.mMimeType)) &&
|
const bool dxva2 =
|
||||||
|
MediaPrefs::PDMWMFVP9DXVA2Enabled() && IsVistaOrLater();
|
||||||
|
const bool mft =
|
||||||
|
MediaPrefs::PDMWMFVP9MFTEnabled() && CanCreateWMFDecoder<CLSID_WebmMfVpxDec>();
|
||||||
|
if (dxva2 || mft) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// vp8 needs mft, no dxva for it , useless anyways.
|
||||||
|
if (VPXDecoder::IsVP8(aTrackInfo.mMimeType) &&
|
||||||
CanCreateWMFDecoder<CLSID_WebmMfVpxDec>()) {
|
CanCreateWMFDecoder<CLSID_WebmMfVpxDec>()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace layers {
|
||||||
|
class KnowsCompositor;
|
||||||
|
}
|
||||||
|
|
||||||
class WMFDecoderModule : public PlatformDecoderModule {
|
class WMFDecoderModule : public PlatformDecoderModule {
|
||||||
public:
|
public:
|
||||||
WMFDecoderModule();
|
WMFDecoderModule();
|
||||||
|
|
@ -24,6 +28,9 @@ public:
|
||||||
already_AddRefed<MediaDataDecoder>
|
already_AddRefed<MediaDataDecoder>
|
||||||
CreateAudioDecoder(const CreateDecoderParams& aParams) override;
|
CreateAudioDecoder(const CreateDecoderParams& aParams) override;
|
||||||
|
|
||||||
|
already_AddRefed<MediaDataDecoder>
|
||||||
|
CreateVP9Decoder(const CreateDecoderParams& aParams);
|
||||||
|
|
||||||
bool SupportsMimeType(const nsACString& aMimeType,
|
bool SupportsMimeType(const nsACString& aMimeType,
|
||||||
DecoderDoctorDiagnostics* aDiagnostics) const override;
|
DecoderDoctorDiagnostics* aDiagnostics) const override;
|
||||||
bool Supports(const TrackInfo& aTrackInfo,
|
bool Supports(const TrackInfo& aTrackInfo,
|
||||||
|
|
@ -43,7 +50,8 @@ public:
|
||||||
// require a "Media Feature Pack" to be installed.
|
// require a "Media Feature Pack" to be installed.
|
||||||
static bool HasAAC();
|
static bool HasAAC();
|
||||||
static bool HasH264();
|
static bool HasH264();
|
||||||
static bool HasVP9();
|
static bool HasVP9MFT();
|
||||||
|
static bool HasVP9DXVA2(layers::KnowsCompositor* aKnowsCompositor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mWMFInitialized;
|
bool mWMFInitialized;
|
||||||
|
|
|
||||||
158
dom/media/platforms/wmf/WMFVP9MFTManager.cpp
Normal file
158
dom/media/platforms/wmf/WMFVP9MFTManager.cpp
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "WMFVP9MFTManager.h"
|
||||||
|
#include "WMFVideoMFTManager.h"
|
||||||
|
#include "ImageContainer.h"
|
||||||
|
#include "Layers.h"
|
||||||
|
#include "VideoUtils.h"
|
||||||
|
#include "mozilla/gfx/gfxVars.h"
|
||||||
|
#include "mozilla/WindowsVersion.h"
|
||||||
|
#include "mozilla/CheckedInt.h"
|
||||||
|
#include "mozilla/Logging.h"
|
||||||
|
#include "nsPrintfCString.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
struct VP9ShownFrame {
|
||||||
|
RefPtr<layers::Image> mImage;
|
||||||
|
nsIntRect mPicture;
|
||||||
|
bool mKeyframe;
|
||||||
|
};
|
||||||
|
|
||||||
|
WMFVP9MFTManager::WMFVP9MFTManager(const VideoInfo& aConfig,
|
||||||
|
layers::KnowsCompositor* aCompositor, layers::ImageContainer* aContainer)
|
||||||
|
: mVideoInfo(aConfig), mKnowsCompositor(aCompositor), mImageContainer(aContainer), mIsValid(false)
|
||||||
|
{}
|
||||||
|
WMFVP9MFTManager::~WMFVP9MFTManager() { Shutdown(); }
|
||||||
|
bool WMFVP9MFTManager::Init()
|
||||||
|
{
|
||||||
|
if (!IsVistaOrLater()) {
|
||||||
|
mFailureReason.AssignLiteral("VP9 DXVA2 requires Windows Vista or later");
|
||||||
|
} else if (!gfx::gfxVars::CanUseHardwareVideoDecoding()) {
|
||||||
|
mFailureReason.AssignLiteral("Hardware video decoding is disabled or blocklisted");
|
||||||
|
} else if (!mKnowsCompositor) {
|
||||||
|
mFailureReason.AssignLiteral("No compositor available for VP9 DXVA2");
|
||||||
|
} else if (mVideoInfo.HasAlpha()) {
|
||||||
|
mFailureReason.AssignLiteral("VP9 DXVA2 cannot decode streams with alpha");
|
||||||
|
} else if (mVideoInfo.mBitDepth != 8) {
|
||||||
|
mFailureReason = nsPrintfCString(
|
||||||
|
"VP9 DXVA2 supports profile 0 only; stream is %u-bit", mVideoInfo.mBitDepth);
|
||||||
|
} else if (mVideoInfo.mImage.width < 16 || mVideoInfo.mImage.height < 16 ||
|
||||||
|
mVideoInfo.mImage.width > 8192 || mVideoInfo.mImage.height > 8192) {
|
||||||
|
mFailureReason = nsPrintfCString(
|
||||||
|
"VP9 DXVA2 does not accept a coded size of %dx%d",
|
||||||
|
mVideoInfo.mImage.width, mVideoInfo.mImage.height);
|
||||||
|
}
|
||||||
|
if (!mFailureReason.IsEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto backend = mKnowsCompositor->GetCompositorBackendType();
|
||||||
|
if (backend != layers::LayersBackend::LAYERS_D3D9 &&
|
||||||
|
backend != layers::LayersBackend::LAYERS_D3D11) {
|
||||||
|
mFailureReason = nsPrintfCString(
|
||||||
|
"VP9 DXVA2 needs a Direct3D compositor; layers backend is %d", int(backend));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDXVA2Manager = WMFVideoMFTManager::CreateVP9DXVA(mKnowsCompositor,
|
||||||
|
mFailureReason, DXVAVP9Manager::GetVP9DecoderGUID());
|
||||||
|
if (!mDXVA2Manager) {
|
||||||
|
if (mFailureReason.IsEmpty()) {
|
||||||
|
mFailureReason.AssignLiteral(
|
||||||
|
"Could not create a D3D9 DXVA2 device for the VP9 profile-0 GUID");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mVP9Decoder = new DXVAVP9Manager();
|
||||||
|
if (!mVP9Decoder->Init(mDXVA2Manager->GetDXVADeviceManager(),
|
||||||
|
mVideoInfo.mImage.width, mVideoInfo.mImage.height, mFailureReason)) {
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsValid = true;
|
||||||
|
mFailureReason.AssignLiteral("Using VP9 DXVA2 profile 0");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
HRESULT WMFVP9MFTManager::Input(MediaRawData* aSample)
|
||||||
|
{
|
||||||
|
if (!mIsValid) { return E_UNEXPECTED; }
|
||||||
|
if (!aSample || aSample->Size() > UINT32_MAX) { return E_INVALIDARG; }
|
||||||
|
CheckedInt<int64_t> sampleEnd = CheckedInt<int64_t>(aSample->mTime) + aSample->mDuration;
|
||||||
|
if (!sampleEnd.isValid() || aSample->mDuration < 0) { return E_INVALIDARG; }
|
||||||
|
uint32_t offsets[8], sizes[8], count;
|
||||||
|
if (!VP9SplitSuperframe(aSample->Data(), uint32_t(aSample->Size()), offsets, sizes, count)) {
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
AutoTArray<VP9ShownFrame, 2> shown;
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
RefPtr<IDirect3DSurface9> surface;
|
||||||
|
bool display = false;
|
||||||
|
VP9FrameHeader header;
|
||||||
|
HRESULT hr = mVP9Decoder->DecodeFrame(aSample->Data() + offsets[i], sizes[i],
|
||||||
|
getter_AddRefs(surface), &display, &header);
|
||||||
|
if (FAILED(hr)) { Flush(); return hr; }
|
||||||
|
if (!display) { continue; }
|
||||||
|
if (mSeekTargetThreshold.isSome() &&
|
||||||
|
sampleEnd.value() < mSeekTargetThreshold.ref().ToMicroseconds()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nsIntRect picture = mVideoInfo.ScaledImageRect(header.frameWidth, header.frameHeight);
|
||||||
|
RefPtr<layers::Image> image;
|
||||||
|
hr = mDXVA2Manager->CopySurfaceToImage(surface, picture, getter_AddRefs(image));
|
||||||
|
if (FAILED(hr)) { Flush(); return hr; }
|
||||||
|
VP9ShownFrame* entry = shown.AppendElement();
|
||||||
|
entry->mImage = image;
|
||||||
|
entry->mPicture = picture;
|
||||||
|
entry->mKeyframe = !header.showExistingFrame && header.frameType == 0;
|
||||||
|
}
|
||||||
|
if (shown.IsEmpty()) { return S_OK; }
|
||||||
|
mSeekTargetThreshold.reset();
|
||||||
|
|
||||||
|
const uint32_t shownCount = shown.Length();
|
||||||
|
const int64_t slice = aSample->mDuration / shownCount;
|
||||||
|
for (uint32_t i = 0; i < shownCount; ++i) {
|
||||||
|
const int64_t time = aSample->mTime + int64_t(i) * slice;
|
||||||
|
const int64_t duration = (i + 1 == shownCount)
|
||||||
|
? (aSample->mTime + aSample->mDuration - time)
|
||||||
|
: slice;
|
||||||
|
RefPtr<VideoData> frame = VideoData::CreateFromImage(mVideoInfo,
|
||||||
|
aSample->mOffset, time, duration, shown[i].mImage,
|
||||||
|
shown[i].mKeyframe, -1, shown[i].mPicture);
|
||||||
|
if (!frame) { return E_OUTOFMEMORY; }
|
||||||
|
mPendingFrames.AppendElement(frame);
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT WMFVP9MFTManager::Output(int64_t, RefPtr<MediaData>& aOutput)
|
||||||
|
{
|
||||||
|
aOutput = nullptr;
|
||||||
|
if (mPendingFrames.IsEmpty()) { return MF_E_TRANSFORM_NEED_MORE_INPUT; }
|
||||||
|
aOutput = mPendingFrames[0];
|
||||||
|
mPendingFrames.RemoveElementAt(0);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
void WMFVP9MFTManager::Flush()
|
||||||
|
{
|
||||||
|
mPendingFrames.Clear();
|
||||||
|
mSeekTargetThreshold.reset();
|
||||||
|
if (mVP9Decoder) { mVP9Decoder->Flush(); }
|
||||||
|
}
|
||||||
|
void WMFVP9MFTManager::Shutdown()
|
||||||
|
{
|
||||||
|
mPendingFrames.Clear();
|
||||||
|
mVP9Decoder = nullptr;
|
||||||
|
if (mDXVA2Manager) { DeleteOnMainThread(mDXVA2Manager); }
|
||||||
|
mIsValid = false;
|
||||||
|
}
|
||||||
|
bool WMFVP9MFTManager::IsHardwareAccelerated(nsACString& aReason) const
|
||||||
|
{
|
||||||
|
aReason = mFailureReason;
|
||||||
|
return mIsValid;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
dom/media/platforms/wmf/WMFVP9MFTManager.h
Normal file
39
dom/media/platforms/wmf/WMFVP9MFTManager.h
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef WMFVP9MFTManager_h_
|
||||||
|
#define WMFVP9MFTManager_h_
|
||||||
|
#include "WMF.h"
|
||||||
|
#include "WMFMediaDataDecoder.h"
|
||||||
|
#include "DXVA2Manager.h"
|
||||||
|
#include "DXVAVP9Manager.h"
|
||||||
|
#include "MediaInfo.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
namespace mozilla {
|
||||||
|
class WMFVP9MFTManager : public MFTManager {
|
||||||
|
public:
|
||||||
|
WMFVP9MFTManager(const VideoInfo&, layers::KnowsCompositor*, layers::ImageContainer*);
|
||||||
|
~WMFVP9MFTManager();
|
||||||
|
bool Init();
|
||||||
|
HRESULT Input(MediaRawData*) override;
|
||||||
|
HRESULT Output(int64_t, RefPtr<MediaData>&) override;
|
||||||
|
void Flush() override;
|
||||||
|
void Drain() override {}
|
||||||
|
void Shutdown() override;
|
||||||
|
bool IsHardwareAccelerated(nsACString&) const override;
|
||||||
|
TrackInfo::TrackType GetType() override { return TrackInfo::kVideoTrack; }
|
||||||
|
const char* GetDescriptionName() const override { return "VP9 DXVA2 profile 0 hardware decoder"; }
|
||||||
|
private:
|
||||||
|
VideoInfo mVideoInfo;
|
||||||
|
RefPtr<layers::KnowsCompositor> mKnowsCompositor;
|
||||||
|
RefPtr<layers::ImageContainer> mImageContainer;
|
||||||
|
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
|
||||||
|
nsAutoPtr<DXVAVP9Manager> mVP9Decoder;
|
||||||
|
nsTArray<RefPtr<MediaData>> mPendingFrames;
|
||||||
|
nsCString mFailureReason;
|
||||||
|
bool mIsValid;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -314,6 +314,28 @@ FindD3D9BlacklistedDLL() {
|
||||||
"media.wmf.disable-d3d9-for-dlls");
|
"media.wmf.disable-d3d9-for-dlls");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DXVA2Manager*
|
||||||
|
WMFVideoMFTManager::CreateVP9DXVA(layers::KnowsCompositor* aCompositor,
|
||||||
|
nsACString& aFailureReason, const GUID& aGUID)
|
||||||
|
{
|
||||||
|
DXVA2Manager* result = nullptr;
|
||||||
|
nsCOMPtr<nsIRunnable> event = NS_NewRunnableFunction([&]() {
|
||||||
|
const nsCString& blocked = FindD3D9BlacklistedDLL();
|
||||||
|
if (!blocked.IsEmpty()) {
|
||||||
|
aFailureReason.AssignLiteral("D3D9 DLL is blocklisted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = DXVA2Manager::CreateD3D9DXVA(aCompositor, aFailureReason, &aGUID);
|
||||||
|
});
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
event->Run();
|
||||||
|
} else {
|
||||||
|
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||||
|
SyncRunnable::DispatchToThread(mainThread, event);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
class CreateDXVAManagerEvent : public Runnable {
|
class CreateDXVAManagerEvent : public Runnable {
|
||||||
public:
|
public:
|
||||||
CreateDXVAManagerEvent(LayersBackend aBackend,
|
CreateDXVAManagerEvent(LayersBackend aBackend,
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ public:
|
||||||
~WMFVideoMFTManager();
|
~WMFVideoMFTManager();
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
|
static DXVA2Manager* CreateVP9DXVA(layers::KnowsCompositor* aCompositor,
|
||||||
|
nsACString& aFailureReason, const GUID& aGUID);
|
||||||
|
|
||||||
HRESULT Input(MediaRawData* aSample) override;
|
HRESULT Input(MediaRawData* aSample) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,17 @@
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'DXVA2Manager.h',
|
'DXVA2Manager.h',
|
||||||
|
'DXVAVP9Manager.h',
|
||||||
'MFTDecoder.h',
|
'MFTDecoder.h',
|
||||||
|
'VP9DXVA.h',
|
||||||
|
'VP9HeaderParser.h',
|
||||||
'WMF.h',
|
'WMF.h',
|
||||||
'WMFAudioMFTManager.h',
|
'WMFAudioMFTManager.h',
|
||||||
'WMFDecoderModule.h',
|
'WMFDecoderModule.h',
|
||||||
'WMFMediaDataDecoder.h',
|
'WMFMediaDataDecoder.h',
|
||||||
'WMFUtils.h',
|
'WMFUtils.h',
|
||||||
'WMFVideoMFTManager.h',
|
'WMFVideoMFTManager.h',
|
||||||
|
'WMFVP9MFTManager.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
|
|
@ -24,7 +28,10 @@ UNIFIED_SOURCES += [
|
||||||
]
|
]
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
|
'DXVAVP9Manager.cpp',
|
||||||
|
'VP9HeaderParser.cpp',
|
||||||
'WMFUtils.cpp',
|
'WMFUtils.cpp',
|
||||||
|
'WMFVP9MFTManager.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
include('/ipc/chromium/chromium-config.mozbuild')
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
|
|
||||||
|
|
@ -405,6 +405,9 @@ pref("media.wmf.decoder.thread-count", -1);
|
||||||
pref("media.wmf.low-latency.enabled", false);
|
pref("media.wmf.low-latency.enabled", false);
|
||||||
pref("media.wmf.skip-blacklist", false);
|
pref("media.wmf.skip-blacklist", false);
|
||||||
pref("media.wmf.vp9.enabled", true);
|
pref("media.wmf.vp9.enabled", true);
|
||||||
|
pref("media.wmf.vp9.dxva2.enabled", true);
|
||||||
|
pref("media.wmf.vp9.mft.enabled", true);
|
||||||
|
pref("media.wmf.vp9.dxva2.preferred", false);
|
||||||
pref("media.windows-media-foundation.allow-d3d11-dxva", true);
|
pref("media.windows-media-foundation.allow-d3d11-dxva", true);
|
||||||
pref("media.wmf.disable-d3d11-for-dlls", "igd11dxva64.dll: 20.19.15.4463, 20.19.15.4454, 20.19.15.4444, 20.19.15.4416, 20.19.15.4404, 20.19.15.4390, 20.19.15.4380, 20.19.15.4377, 20.19.15.4364, 20.19.15.4360, 20.19.15.4352, 20.19.15.4331, 20.19.15.4326, 20.19.15.4300; igd10iumd32.dll: 20.19.15.4444, 20.19.15.4424, 20.19.15.4409, 20.19.15.4390, 20.19.15.4380, 20.19.15.4360, 10.18.10.4358, 20.19.15.4331, 20.19.15.4312, 20.19.15.4300, 10.18.15.4281, 10.18.15.4279, 10.18.10.4276, 10.18.15.4268, 10.18.15.4256, 10.18.10.4252, 10.18.15.4248, 10.18.14.4112, 10.18.10.3958, 10.18.10.3496, 10.18.10.3431, 10.18.10.3412, 10.18.10.3355, 9.18.10.3234, 9.18.10.3071, 9.18.10.3055, 9.18.10.3006; igd10umd32.dll: 9.17.10.4229, 9.17.10.3040, 9.17.10.2857, 8.15.10.2274, 8.15.10.2272, 8.15.10.2246, 8.15.10.1840, 8.15.10.1808; igd10umd64.dll: 9.17.10.4229, 9.17.10.2857, 10.18.10.3496; isonyvideoprocessor.dll: 4.1.2247.8090, 4.1.2153.6200; tosqep.dll: 1.2.15.526, 1.1.12.201, 1.0.11.318, 1.0.11.215, 1.0.10.1224; tosqep64.dll: 1.1.12.201, 1.0.11.215; nvwgf2um.dll: 22.21.13.8253, 22.21.13.8233, 22.21.13.8205, 22.21.13.8189, 22.21.13.8178, 22.21.13.8165, 21.21.13.7892, 21.21.13.7878, 21.21.13.7866, 21.21.13.7849, 21.21.13.7654, 21.21.13.7653, 21.21.13.7633, 21.21.13.7619, 21.21.13.7563, 21.21.13.7306, 21.21.13.7290, 21.21.13.7270, 21.21.13.7254, 21.21.13.6939, 21.21.13.6926, 21.21.13.6909, 21.21.13.4201, 21.21.13.4200, 10.18.13.6881, 10.18.13.6839, 10.18.13.6510, 10.18.13.6472, 10.18.13.6143, 10.18.13.5946, 10.18.13.5923, 10.18.13.5921, 10.18.13.5891, 10.18.13.5887, 10.18.13.5582, 10.18.13.5445, 10.18.13.5382, 10.18.13.5362, 9.18.13.4788, 9.18.13.4752, 9.18.13.4725, 9.18.13.4709, 9.18.13.4195, 9.18.13.4192, 9.18.13.4144, 9.18.13.4052, 9.18.13.3788, 9.18.13.3523, 9.18.13.3235, 9.18.13.3165, 9.18.13.2723, 9.18.13.2702, 9.18.13.1422, 9.18.13.1407, 9.18.13.1106, 9.18.13.546; atidxx32.dll: 21.19.151.3, 21.19.142.257, 21.19.137.514, 21.19.137.1, 21.19.134.1, 21.19.128.7, 21.19.128.4, 20.19.0.32837, 20.19.0.32832, 8.17.10.682, 8.17.10.671, 8.17.10.661, 8.17.10.648, 8.17.10.644, 8.17.10.625, 8.17.10.605, 8.17.10.581, 8.17.10.569, 8.17.10.560, 8.17.10.545, 8.17.10.539, 8.17.10.531, 8.17.10.525, 8.17.10.520, 8.17.10.519, 8.17.10.514, 8.17.10.511, 8.17.10.494, 8.17.10.489, 8.17.10.483, 8.17.10.453, 8.17.10.451, 8.17.10.441, 8.17.10.436, 8.17.10.432, 8.17.10.425, 8.17.10.418, 8.17.10.414, 8.17.10.401, 8.17.10.395, 8.17.10.385, 8.17.10.378, 8.17.10.362, 8.17.10.355, 8.17.10.342, 8.17.10.331, 8.17.10.318, 8.17.10.310, 8.17.10.286, 8.17.10.269, 8.17.10.261, 8.17.10.247, 8.17.10.240, 8.15.10.212; atidxx64.dll: 21.19.151.3, 21.19.142.257, 21.19.137.514, 21.19.137.1, 21.19.134.1, 21.19.128.7, 21.19.128.4, 20.19.0.32832, 8.17.10.682, 8.17.10.661, 8.17.10.644, 8.17.10.625; nvumdshim.dll: 10.18.13.6822");
|
pref("media.wmf.disable-d3d11-for-dlls", "igd11dxva64.dll: 20.19.15.4463, 20.19.15.4454, 20.19.15.4444, 20.19.15.4416, 20.19.15.4404, 20.19.15.4390, 20.19.15.4380, 20.19.15.4377, 20.19.15.4364, 20.19.15.4360, 20.19.15.4352, 20.19.15.4331, 20.19.15.4326, 20.19.15.4300; igd10iumd32.dll: 20.19.15.4444, 20.19.15.4424, 20.19.15.4409, 20.19.15.4390, 20.19.15.4380, 20.19.15.4360, 10.18.10.4358, 20.19.15.4331, 20.19.15.4312, 20.19.15.4300, 10.18.15.4281, 10.18.15.4279, 10.18.10.4276, 10.18.15.4268, 10.18.15.4256, 10.18.10.4252, 10.18.15.4248, 10.18.14.4112, 10.18.10.3958, 10.18.10.3496, 10.18.10.3431, 10.18.10.3412, 10.18.10.3355, 9.18.10.3234, 9.18.10.3071, 9.18.10.3055, 9.18.10.3006; igd10umd32.dll: 9.17.10.4229, 9.17.10.3040, 9.17.10.2857, 8.15.10.2274, 8.15.10.2272, 8.15.10.2246, 8.15.10.1840, 8.15.10.1808; igd10umd64.dll: 9.17.10.4229, 9.17.10.2857, 10.18.10.3496; isonyvideoprocessor.dll: 4.1.2247.8090, 4.1.2153.6200; tosqep.dll: 1.2.15.526, 1.1.12.201, 1.0.11.318, 1.0.11.215, 1.0.10.1224; tosqep64.dll: 1.1.12.201, 1.0.11.215; nvwgf2um.dll: 22.21.13.8253, 22.21.13.8233, 22.21.13.8205, 22.21.13.8189, 22.21.13.8178, 22.21.13.8165, 21.21.13.7892, 21.21.13.7878, 21.21.13.7866, 21.21.13.7849, 21.21.13.7654, 21.21.13.7653, 21.21.13.7633, 21.21.13.7619, 21.21.13.7563, 21.21.13.7306, 21.21.13.7290, 21.21.13.7270, 21.21.13.7254, 21.21.13.6939, 21.21.13.6926, 21.21.13.6909, 21.21.13.4201, 21.21.13.4200, 10.18.13.6881, 10.18.13.6839, 10.18.13.6510, 10.18.13.6472, 10.18.13.6143, 10.18.13.5946, 10.18.13.5923, 10.18.13.5921, 10.18.13.5891, 10.18.13.5887, 10.18.13.5582, 10.18.13.5445, 10.18.13.5382, 10.18.13.5362, 9.18.13.4788, 9.18.13.4752, 9.18.13.4725, 9.18.13.4709, 9.18.13.4195, 9.18.13.4192, 9.18.13.4144, 9.18.13.4052, 9.18.13.3788, 9.18.13.3523, 9.18.13.3235, 9.18.13.3165, 9.18.13.2723, 9.18.13.2702, 9.18.13.1422, 9.18.13.1407, 9.18.13.1106, 9.18.13.546; atidxx32.dll: 21.19.151.3, 21.19.142.257, 21.19.137.514, 21.19.137.1, 21.19.134.1, 21.19.128.7, 21.19.128.4, 20.19.0.32837, 20.19.0.32832, 8.17.10.682, 8.17.10.671, 8.17.10.661, 8.17.10.648, 8.17.10.644, 8.17.10.625, 8.17.10.605, 8.17.10.581, 8.17.10.569, 8.17.10.560, 8.17.10.545, 8.17.10.539, 8.17.10.531, 8.17.10.525, 8.17.10.520, 8.17.10.519, 8.17.10.514, 8.17.10.511, 8.17.10.494, 8.17.10.489, 8.17.10.483, 8.17.10.453, 8.17.10.451, 8.17.10.441, 8.17.10.436, 8.17.10.432, 8.17.10.425, 8.17.10.418, 8.17.10.414, 8.17.10.401, 8.17.10.395, 8.17.10.385, 8.17.10.378, 8.17.10.362, 8.17.10.355, 8.17.10.342, 8.17.10.331, 8.17.10.318, 8.17.10.310, 8.17.10.286, 8.17.10.269, 8.17.10.261, 8.17.10.247, 8.17.10.240, 8.15.10.212; atidxx64.dll: 21.19.151.3, 21.19.142.257, 21.19.137.514, 21.19.137.1, 21.19.134.1, 21.19.128.7, 21.19.128.4, 20.19.0.32832, 8.17.10.682, 8.17.10.661, 8.17.10.644, 8.17.10.625; nvumdshim.dll: 10.18.13.6822");
|
||||||
pref("media.wmf.disable-d3d9-for-dlls", "igdumd64.dll: 8.15.10.2189, 8.15.10.2119, 8.15.10.2104, 8.15.10.2102, 8.771.1.0; atiumd64.dll: 7.14.10.833, 7.14.10.867, 7.14.10.885, 7.14.10.903, 7.14.10.911, 8.14.10.768, 9.14.10.1001, 9.14.10.1017, 9.14.10.1080, 9.14.10.1128, 9.14.10.1162, 9.14.10.1171, 9.14.10.1183, 9.14.10.1197, 9.14.10.945, 9.14.10.972, 9.14.10.984, 9.14.10.996");
|
pref("media.wmf.disable-d3d9-for-dlls", "igdumd64.dll: 8.15.10.2189, 8.15.10.2119, 8.15.10.2104, 8.15.10.2102, 8.771.1.0; atiumd64.dll: 7.14.10.833, 7.14.10.867, 7.14.10.885, 7.14.10.903, 7.14.10.911, 8.14.10.768, 9.14.10.1001, 9.14.10.1017, 9.14.10.1080, 9.14.10.1128, 9.14.10.1162, 9.14.10.1171, 9.14.10.1183, 9.14.10.1197, 9.14.10.945, 9.14.10.972, 9.14.10.984, 9.14.10.996");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue