gecko-dev/dom/media/platforms/wmf/WMFUtils.cpp
Jean-Yves Avenard e4508d8aa1 Bug 1217226: P1. Use VideoInfo display size data rather than attempt to detect value in stream. r=cpearce
The VideoInfo data now contains accurate and up to date information about the video display size, its aspect ratio and borders.

While the WMF can determine those values for H264 through the SPS NAL, it can't be done reliably for a VP9 stream.

Picture size is still determined by the WMF to ensure the allocated DXVA texture has the right size.
2015-10-29 00:46:30 +11:00

297 lines
8.9 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "WMFUtils.h"
#include <stdint.h>
#include "mozilla/ArrayUtils.h"
#include "mozilla/RefPtr.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/Logging.h"
#include "nsThreadUtils.h"
#include "nsWindowsHelpers.h"
#include "mozilla/CheckedInt.h"
#include "VideoUtils.h"
#include <initguid.h>
#include "nsTArray.h"
#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
// Some SDK versions don't define the AAC decoder CLSID.
// {32D186A7-218F-4C75-8876-DD77273A8999}
DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD, 0x77, 0x27, 0x3A, 0x89, 0x99);
#endif
namespace mozilla {
HRESULT
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames)
{
MOZ_ASSERT(aOutFrames);
const int64_t HNS_PER_S = USECS_PER_S * 10;
CheckedInt<int64_t> i = aHNs;
i *= aRate;
i /= HNS_PER_S;
NS_ENSURE_TRUE(i.isValid(), E_FAIL);
*aOutFrames = i.value();
return S_OK;
}
HRESULT
GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride)
{
// Try to get the default stride from the media type.
HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
if (SUCCEEDED(hr)) {
return S_OK;
}
// Stride attribute not set, calculate it.
GUID subtype = GUID_NULL;
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, aWidth, (LONG*)(aOutStride));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
return hr;
}
int32_t
MFOffsetToInt32(const MFOffset& aOffset)
{
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
}
media::TimeUnit
GetSampleDuration(IMFSample* aSample)
{
NS_ENSURE_TRUE(aSample, media::TimeUnit::Invalid());
int64_t duration = 0;
aSample->GetSampleDuration(&duration);
return media::TimeUnit::FromMicroseconds(HNsToUsecs(duration));
}
media::TimeUnit
GetSampleTime(IMFSample* aSample)
{
NS_ENSURE_TRUE(aSample, media::TimeUnit::Invalid());
LONGLONG timestampHns = 0;
HRESULT hr = aSample->GetSampleTime(&timestampHns);
NS_ENSURE_TRUE(SUCCEEDED(hr), media::TimeUnit::Invalid());
return media::TimeUnit::FromMicroseconds(HNsToUsecs(timestampHns));
}
// Gets the sub-region of the video frame that should be displayed.
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
HRESULT
GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion)
{
// Determine if "pan and scan" is enabled for this media. If it is, we
// only display a region of the video frame, not the entire frame.
BOOL panScan = MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
// If pan and scan mode is enabled. Try to get the display region.
HRESULT hr = E_FAIL;
MFVideoArea videoArea;
memset(&videoArea, 0, sizeof(MFVideoArea));
if (panScan) {
hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE,
(UINT8*)&videoArea,
sizeof(MFVideoArea),
nullptr);
}
// If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
// check for a minimimum display aperture.
if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
(UINT8*)&videoArea,
sizeof(MFVideoArea),
nullptr);
}
if (hr == MF_E_ATTRIBUTENOTFOUND) {
// Minimum display aperture is not set, for "backward compatibility with
// some components", check for a geometric aperture.
hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
(UINT8*)&videoArea,
sizeof(MFVideoArea),
nullptr);
}
if (SUCCEEDED(hr)) {
// The media specified a picture region, return it.
aOutPictureRegion = nsIntRect(MFOffsetToInt32(videoArea.OffsetX),
MFOffsetToInt32(videoArea.OffsetY),
videoArea.Area.cx,
videoArea.Area.cy);
return S_OK;
}
// No picture region defined, fall back to using the entire video area.
UINT32 width = 0, height = 0;
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
aOutPictureRegion = nsIntRect(0, 0, width, height);
return S_OK;
}
namespace wmf {
static const wchar_t* sDLLs[] = {
L"mfplat.dll",
L"mf.dll",
L"dxva2.dll",
L"evr.dll",
};
HRESULT
LoadDLLs()
{
static bool sDLLsLoaded = false;
static bool sFailedToLoadDlls = false;
if (sDLLsLoaded) {
return S_OK;
}
if (sFailedToLoadDlls) {
return E_FAIL;
}
// Try to load all the required DLLs. If we fail to load any dll,
// unload the dlls we succeeded in loading.
nsTArray<const wchar_t*> loadedDlls;
for (const wchar_t* dll : sDLLs) {
if (!LoadLibrarySystem32(dll)) {
NS_WARNING("Failed to load WMF DLLs");
for (const wchar_t* loadedDll : loadedDlls) {
FreeLibrary(GetModuleHandleW(loadedDll));
}
sFailedToLoadDlls = true;
return E_FAIL;
}
loadedDlls.AppendElement(dll);
}
sDLLsLoaded = true;
return S_OK;
}
#define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
static FunctionType FunctionName##Ptr = nullptr; \
if (!FunctionName##Ptr) { \
FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandleW(L ## #DLL), #FunctionName); \
if (!FunctionName##Ptr) { \
NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \
return E_FAIL; \
} \
}
#define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL) \
#define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \
ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \
#define DECL_FUNCTION_PTR(FunctionName, ...) \
typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__)
HRESULT
MFStartup()
{
HRESULT hr = LoadDLLs();
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION);
const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
// decltype is unusable for functions having default parameters
DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
if (!IsWin7OrLater())
return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
else
return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
}
HRESULT
MFShutdown()
{
ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
return (MFShutdownPtr)();
}
HRESULT
MFCreateMediaType(IMFMediaType **aOutMFType)
{
ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll)
return (MFCreateMediaTypePtr)(aOutMFType);
}
HRESULT
MFGetStrideForBitmapInfoHeader(DWORD aFormat,
DWORD aWidth,
LONG *aOutStride)
{
ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, evr.dll)
return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride);
}
HRESULT MFGetService(IUnknown *punkObject,
REFGUID guidService,
REFIID riid,
LPVOID *ppvObject)
{
ENSURE_FUNCTION_PTR(MFGetService, mf.dll)
return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject);
}
HRESULT
DXVA2CreateDirect3DDeviceManager9(UINT *pResetToken,
IDirect3DDeviceManager9 **ppDXVAManager)
{
ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll)
return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager);
}
HRESULT
MFCreateSample(IMFSample **ppIMFSample)
{
ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll)
return (MFCreateSamplePtr)(ppIMFSample);
}
HRESULT
MFCreateAlignedMemoryBuffer(DWORD cbMaxLength,
DWORD fAlignmentFlags,
IMFMediaBuffer **ppBuffer)
{
ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll)
return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags, ppBuffer);
}
HRESULT
MFCreateDXGIDeviceManager(UINT *pResetToken, IMFDXGIDeviceManager **ppDXVAManager)
{
ENSURE_FUNCTION_PTR(MFCreateDXGIDeviceManager, mfplat.dll)
return (MFCreateDXGIDeviceManagerPtr)(pResetToken, ppDXVAManager);
}
HRESULT
MFCreateDXGISurfaceBuffer(REFIID riid,
IUnknown *punkSurface,
UINT uSubresourceIndex,
BOOL fButtomUpWhenLinear,
IMFMediaBuffer **ppBuffer)
{
ENSURE_FUNCTION_PTR(MFCreateDXGISurfaceBuffer, mfplat.dll)
return (MFCreateDXGISurfaceBufferPtr)(riid, punkSurface, uSubresourceIndex, fButtomUpWhenLinear, ppBuffer);
}
} // end namespace wmf
} // end namespace mozilla