mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-21 07:47:32 +09:00
Merge branch '14.0' of https://repo.dactyloidae.xyz/Dactyloidae/UXP into 14.0
This commit is contained in:
commit
f56f753c74
18 changed files with 1747 additions and 34 deletions
|
|
@ -30,9 +30,11 @@
|
|||
#ifdef MOZ_FMP4
|
||||
#include "MP4Decoder.h"
|
||||
#endif
|
||||
#include "WMFDecoderModule.h"
|
||||
#if defined(XP_WIN) && defined(MOZ_WMF)
|
||||
#include "MediaPrefs.h"
|
||||
#include "WMFDecoderModule.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#endif
|
||||
#include "CubebUtils.h"
|
||||
|
||||
#include "nsIScrollableFrame.h"
|
||||
|
|
@ -2379,17 +2381,26 @@ nsDOMWindowUtils::GetSupportsHardwareVP9Decoding(JS::MutableHandle<JS::Value> aP
|
|||
}
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_WMF)
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
LayerManager* layerManager = widget ? widget->GetLayerManager() : nullptr;
|
||||
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()) {
|
||||
promise->MaybeResolve(NS_LITERAL_STRING("No; hardware video decoding disabled"));
|
||||
} else if (WMFDecoderModule::HasVP9()) {
|
||||
promise->MaybeResolve(NS_LITERAL_STRING("Yes"));
|
||||
promise->MaybeResolve(NS_LITERAL_STRING(
|
||||
"No; hardware video decoding disabled"));
|
||||
} 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 {
|
||||
promise->MaybeResolve(NS_LITERAL_STRING("No; MFT unavailable"));
|
||||
promise->MaybeResolve(NS_LITERAL_STRING(
|
||||
"No; no VP9 hardware decoder available"));
|
||||
}
|
||||
#else
|
||||
promise->MaybeResolve(NS_LITERAL_STRING("No; not supported on this platform"));
|
||||
promise->MaybeResolve(NS_LITERAL_STRING(
|
||||
"No; not supported on this platform"));
|
||||
#endif
|
||||
|
||||
aPromise.setObject(*promise->PromiseObj());
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ interface nsIJSRAIIHelper;
|
|||
interface nsIContentPermissionRequest;
|
||||
interface nsIObserver;
|
||||
|
||||
[scriptable, uuid(58e97ce9-1d9e-4576-aabf-89480fdeb16d)]
|
||||
[scriptable, uuid(16ed093c-84a7-4ca3-84c8-9ad71f8b5d82)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
|
|
@ -1419,11 +1419,10 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
* in hardware.
|
||||
*/
|
||||
readonly attribute jsval supportsHardwareH264Decoding;
|
||||
|
||||
/**
|
||||
* Returns a Promise that will be resolved with a string once the capabilities
|
||||
* of the vp9 decoder have been determined.
|
||||
* Success does not mean that all vp9 video decoding will be done
|
||||
* in hardware.
|
||||
* Returns a Promise resolved with a string describing whether VP9 hardware
|
||||
* decoding is available through the Windows MFT or direct DXVA2 path.
|
||||
*/
|
||||
readonly attribute jsval supportsHardwareVP9Decoding;
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,9 @@ private:
|
|||
DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true);
|
||||
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.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.decoder.thread-count", PDMWMFThreadCount, int32_t, -1);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ public:
|
|||
virtual ~D3D9DXVA2Manager();
|
||||
|
||||
HRESULT Init(layers::KnowsCompositor* aKnowsCompositor,
|
||||
nsACString& aFailureReason);
|
||||
nsACString& aFailureReason, const GUID* aDecoderGUID);
|
||||
|
||||
IUnknown* GetDXVADeviceManager() override;
|
||||
|
||||
|
|
@ -99,6 +99,8 @@ public:
|
|||
const nsIntRect& aRegion,
|
||||
Image** aOutImage) override;
|
||||
|
||||
HRESULT CopySurfaceToImage(IDirect3DSurface9* aSurface,
|
||||
const nsIntRect& aRegion, Image** aOutImage) override;
|
||||
bool SupportsConfig(IMFMediaType* aType, float aFramerate) override;
|
||||
|
||||
private:
|
||||
|
|
@ -185,10 +187,6 @@ static const GUID DXVA2_Intel_ModeH264_E = {
|
|||
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.
|
||||
// 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
|
||||
|
|
@ -267,7 +265,7 @@ D3D9DXVA2Manager::GetDXVADeviceManager()
|
|||
|
||||
HRESULT
|
||||
D3D9DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
||||
nsACString& aFailureReason)
|
||||
nsACString& aFailureReason, const GUID* aDecoderGUID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
|
@ -388,11 +386,12 @@ D3D9DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
|||
|
||||
bool found = false;
|
||||
for (UINT i = 0; i < deviceCount; i++) {
|
||||
if (decoderDevices[i] == DXVA2_ModeH264_E ||
|
||||
decoderDevices[i] == DXVA2_Intel_ModeH264_E ||
|
||||
decoderDevices[i] == DXVA2_ModeVP9_VLD_Profile0) {
|
||||
if (aDecoderGUID ? decoderDevices[i] == *aDecoderGUID :
|
||||
(decoderDevices[i] == DXVA2_ModeH264_E ||
|
||||
decoderDevices[i] == DXVA2_Intel_ModeH264_E)) {
|
||||
mDecoderGUID = decoderDevices[i];
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(decoderDevices);
|
||||
|
|
@ -462,8 +461,15 @@ D3D9DXVA2Manager::CopyToImage(IMFSample* aSample,
|
|||
getter_AddRefs(surface));
|
||||
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();
|
||||
hr = image->AllocateAndCopy(mTextureClientAllocator, surface, aRegion);
|
||||
HRESULT hr = image->AllocateAndCopy(mTextureClientAllocator, surface, aRegion);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
RefPtr<IDirect3DSurface9> sourceSurf = image->GetD3D9Surface();
|
||||
|
|
@ -492,7 +498,7 @@ static uint32_t sDXVAVideosCount = 0;
|
|||
/* static */
|
||||
DXVA2Manager*
|
||||
DXVA2Manager::CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor,
|
||||
nsACString& aFailureReason)
|
||||
nsACString& aFailureReason, const GUID* aDecoderGUID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
HRESULT hr;
|
||||
|
|
@ -507,7 +513,7 @@ DXVA2Manager::CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor,
|
|||
}
|
||||
|
||||
nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
|
||||
hr = d3d9Manager->Init(aKnowsCompositor, aFailureReason);
|
||||
hr = d3d9Manager->Init(aKnowsCompositor, aFailureReason, aDecoderGUID);
|
||||
if (SUCCEEDED(hr)) {
|
||||
return d3d9Manager.forget();
|
||||
}
|
||||
|
|
@ -694,11 +700,10 @@ D3D11DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
|||
for (UINT i = 0; i < profileCount; i++) {
|
||||
GUID id;
|
||||
hr = videoDevice->GetVideoDecoderProfile(i, &id);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (id == DXVA2_ModeH264_E || id == DXVA2_Intel_ModeH264_E || id == DXVA2_ModeVP9_VLD_Profile0) {
|
||||
mDecoderGUID = id;
|
||||
found = true;
|
||||
}
|
||||
if (SUCCEEDED(hr) && (id == DXVA2_ModeH264_E || id == DXVA2_Intel_ModeH264_E)) {
|
||||
mDecoderGUID = id;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public:
|
|||
|
||||
// Creates and initializes a DXVA2Manager. We can use DXVA2 via either
|
||||
// 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);
|
||||
|
||||
// Returns a pointer to the D3D device manager responsible for managing the
|
||||
|
|
@ -37,6 +37,10 @@ public:
|
|||
const nsIntRect& aRegion,
|
||||
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 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 "WMFDecoderModule.h"
|
||||
#include "WMFVideoMFTManager.h"
|
||||
#include "WMFVP9MFTManager.h"
|
||||
#include "WMFAudioMFTManager.h"
|
||||
#include "MFTDecoder.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
|
@ -80,6 +81,60 @@ WMFDecoderModule::Startup()
|
|||
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>
|
||||
WMFDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||
{
|
||||
|
|
@ -91,6 +146,10 @@ WMFDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (VPXDecoder::IsVP9(aParams.VideoConfig().mMimeType)) {
|
||||
return CreateVP9Decoder(aParams);
|
||||
}
|
||||
|
||||
nsAutoPtr<WMFVideoMFTManager> manager(
|
||||
new WMFVideoMFTManager(aParams.VideoConfig(),
|
||||
aParams.mKnowsCompositor,
|
||||
|
|
@ -192,11 +251,28 @@ WMFDecoderModule::HasH264()
|
|||
}
|
||||
|
||||
/* static */ bool
|
||||
WMFDecoderModule::HasVP9()
|
||||
WMFDecoderModule::HasVP9MFT()
|
||||
{
|
||||
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
|
||||
WMFDecoderModule::HasAAC()
|
||||
{
|
||||
|
|
@ -254,8 +330,17 @@ WMFDecoderModule::Supports(const TrackInfo& aTrackInfo,
|
|||
return true;
|
||||
}
|
||||
if (MediaPrefs::PDMWMFVP9DecoderEnabled() && sDXVAEnabled) {
|
||||
if ((VPXDecoder::IsVP8(aTrackInfo.mMimeType) ||
|
||||
VPXDecoder::IsVP9(aTrackInfo.mMimeType)) &&
|
||||
if (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>()) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class KnowsCompositor;
|
||||
}
|
||||
|
||||
class WMFDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
WMFDecoderModule();
|
||||
|
|
@ -24,6 +28,9 @@ public:
|
|||
already_AddRefed<MediaDataDecoder>
|
||||
CreateAudioDecoder(const CreateDecoderParams& aParams) override;
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
CreateVP9Decoder(const CreateDecoderParams& aParams);
|
||||
|
||||
bool SupportsMimeType(const nsACString& aMimeType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics) const override;
|
||||
bool Supports(const TrackInfo& aTrackInfo,
|
||||
|
|
@ -43,7 +50,8 @@ public:
|
|||
// require a "Media Feature Pack" to be installed.
|
||||
static bool HasAAC();
|
||||
static bool HasH264();
|
||||
static bool HasVP9();
|
||||
static bool HasVP9MFT();
|
||||
static bool HasVP9DXVA2(layers::KnowsCompositor* aKnowsCompositor);
|
||||
|
||||
private:
|
||||
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");
|
||||
}
|
||||
|
||||
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 {
|
||||
public:
|
||||
CreateDXVAManagerEvent(LayersBackend aBackend,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public:
|
|||
~WMFVideoMFTManager();
|
||||
|
||||
bool Init();
|
||||
static DXVA2Manager* CreateVP9DXVA(layers::KnowsCompositor* aCompositor,
|
||||
nsACString& aFailureReason, const GUID& aGUID);
|
||||
|
||||
HRESULT Input(MediaRawData* aSample) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,17 @@
|
|||
|
||||
EXPORTS += [
|
||||
'DXVA2Manager.h',
|
||||
'DXVAVP9Manager.h',
|
||||
'MFTDecoder.h',
|
||||
'VP9DXVA.h',
|
||||
'VP9HeaderParser.h',
|
||||
'WMF.h',
|
||||
'WMFAudioMFTManager.h',
|
||||
'WMFDecoderModule.h',
|
||||
'WMFMediaDataDecoder.h',
|
||||
'WMFUtils.h',
|
||||
'WMFVideoMFTManager.h',
|
||||
'WMFVP9MFTManager.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
|
@ -24,7 +28,10 @@ UNIFIED_SOURCES += [
|
|||
]
|
||||
|
||||
SOURCES += [
|
||||
'DXVAVP9Manager.cpp',
|
||||
'VP9HeaderParser.cpp',
|
||||
'WMFUtils.cpp',
|
||||
'WMFVP9MFTManager.cpp',
|
||||
]
|
||||
|
||||
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.skip-blacklist", false);
|
||||
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.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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue