import changes from `dev' branch of rmottola/Arctic-Fox:

- fix misspatch and apply Bug 1097803: Report succesful Direct2D 1.1 usage. r=jrmuizel (adc553e15)
- Refactor graphics device initialization on Windows. (bug 1183910 part 1, r=mattwoodrow,bas) (af396b2aa)
- Add a pref to force TDRs for graphics testing. (bug 1183910 part 2, r=mattwoodrow) (c35e7131c)
- Bug 1157476 - Remove synchronous dispatch in AndroidMediaResourceServer::Start. r=cajbir (39033ed48)
- Bug 1174055 - Remove WMFReader. r=jya (2890dc625)
- Bug 1144638. Retry getting an active display link. r=mstange (c786816cf)
- Bug 1154322 - Allow using skia for content rendering. r=jrmuizel (26413363e)
- Bug 1161731: Remove newline characters from the ends of NS_WARNING messages in /gfx and /layout. r=mstange (820583f0f)
- Bug 1147297. Fix assert vsync adjustment time on windows to be >=. r=jrmuizel (c65917a4a)
- Bug 1147953. Fix vsync adjustment time to allow negative timestamps. r=jrmuizel (10a725baa)
- Bug 1160157: Part 1. Uninitialized statics aren't really uninitialized, but it doesn't read well. r=jmuizelaar (e9e214c52)
- minor tweaks (17a5ae1e4)
- Remove D3D11Status flag in favor of FeatureStatus. (bug 1183910 part 3, r=mattwoodrow) (734eaec03)
This commit is contained in:
2021-06-18 12:23:11 +08:00
parent 14c77e53f5
commit c0c874b64a
39 changed files with 558 additions and 2757 deletions
+10
View File
@@ -190,6 +190,7 @@
#include "mozilla/widget/PuppetBidiKeyboard.h"
#include "mozilla/RemoteSpellCheckEngineChild.h"
#include "GMPServiceChild.h"
#include "gfxPlatform.h"
using namespace mozilla;
using namespace mozilla::docshell;
@@ -2806,6 +2807,15 @@ ContentChild::RecvEndDragSession(const bool& aDoneDrag,
return true;
}
bool
ContentChild::RecvTestGraphicsDeviceReset(const uint32_t& aResetReason)
{
#if defined(XP_WIN)
gfxPlatform::GetPlatform()->TestDeviceReset(DeviceResetReason(aResetReason));
#endif
return true;
}
} // namespace dom
} // namespace mozilla
+2
View File
@@ -463,6 +463,8 @@ public:
virtual bool RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) override;
virtual bool RecvTestGraphicsDeviceReset(const uint32_t& aResetReason) override;
private:
virtual void ActorDestroy(ActorDestroyReason why) override;
+7
View File
@@ -646,6 +646,13 @@ child:
*/
GamepadUpdate(GamepadChangeEvent aGamepadEvent);
/**
* Tell the child that for testing purposes, a graphics device reset has
* occurred.
*/
async TestGraphicsDeviceReset(uint32_t aReason);
/**
* Notify the child that presentation receiver has been launched with the
* correspondent iframe.
+7 -41
View File
@@ -56,10 +56,6 @@
#include "RtspOmxDecoder.h"
#include "RtspOmxReader.h"
#endif
#ifdef MOZ_WMF
#include "WMFDecoder.h"
#include "WMFReader.h"
#endif
#ifdef MOZ_DIRECTSHOW
#include "DirectShowDecoder.h"
#include "DirectShowReader.h"
@@ -318,14 +314,6 @@ IsAndroidMediaType(const nsACString& aType)
}
#endif
#ifdef MOZ_WMF
static bool
IsWMFSupportedType(const nsACString& aType)
{
return WMFDecoder::CanPlayType(aType, NS_LITERAL_STRING(""));
}
#endif
#ifdef MOZ_DIRECTSHOW
static bool
IsDirectShowSupportedType(const nsACString& aType)
@@ -426,6 +414,7 @@ CanPlayStatus
DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
const nsAString& aRequestedCodecs)
{
MOZ_ASSERT(NS_IsMainThread());
char const* const* codecList = nullptr;
#ifdef MOZ_RAW
if (IsRawType(nsDependentCString(aMIMEType))) {
@@ -481,7 +470,7 @@ DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaEnabled()) {
GetAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList);
EnsureAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList))
}
#endif
if (!codecList) {
@@ -557,16 +546,6 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
return CANPLAY_MAYBE;
}
#endif
#ifdef MOZ_WMF
if (IsWMFSupportedType(nsDependentCString(aMIMEType))) {
if (!aHaveRequestedCodecs) {
return CANPLAY_MAYBE;
}
return WMFDecoder::CanPlayType(nsDependentCString(aMIMEType),
aRequestedCodecs)
? CANPLAY_YES : CANPLAY_NO;
}
#endif
#ifdef MOZ_APPLEMEDIA
if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), nullptr)) {
return CANPLAY_MAYBE;
@@ -591,6 +570,7 @@ static
already_AddRefed<MediaDecoder>
InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<MediaDecoder> decoder;
#ifdef MOZ_FMP4
@@ -664,7 +644,7 @@ if (IsAACSupportedType(aType)) {
#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaEnabled() &&
GetAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
decoder = new AndroidMediaDecoder(aType);
return decoder.forget();
}
@@ -681,12 +661,6 @@ if (IsAACSupportedType(aType)) {
return decoder.forget();
}
#endif
#ifdef MOZ_WMF
if (IsWMFSupportedType(aType)) {
decoder = new WMFDecoder();
return decoder.forget();
}
#endif
#ifdef MOZ_APPLEMEDIA
if (IsAppleMediaSupportedType(aType)) {
decoder = new AppleDecoder();
@@ -703,6 +677,7 @@ if (IsAACSupportedType(aType)) {
already_AddRefed<MediaDecoder>
DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<MediaDecoder> decoder(InstantiateDecoder(aType, aOwner));
NS_ENSURE_TRUE(decoder != nullptr, nullptr);
NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
@@ -713,6 +688,7 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
/* static */
MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, AbstractMediaDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
MediaDecoderReader* decoderReader = nullptr;
if (!aDecoder) {
@@ -757,7 +733,7 @@ if (IsAACSupportedType(aType)) {
#endif
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaEnabled() &&
GetAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
decoderReader = new AndroidMediaReader(aDecoder, aType);
} else
#endif
@@ -765,17 +741,10 @@ if (IsAACSupportedType(aType)) {
decoderReader = new WebMReader(aDecoder);
} else
#ifdef MOZ_DIRECTSHOW
// Note: DirectShowReader is preferred for MP3, but if it's disabled we
// fallback to the WMFReader.
if (IsDirectShowSupportedType(aType)) {
decoderReader = new DirectShowReader(aDecoder);
} else
#endif
#ifdef MOZ_WMF
if (IsWMFSupportedType(aType)) {
decoderReader = new WMFReader(aDecoder);
} else
#endif
#ifdef MOZ_APPLEMEDIA
if (IsAppleMediaSupportedType(aType)) {
decoderReader = new AppleMP3Reader(aDecoder);
@@ -814,9 +783,6 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
IsMP4SupportedType(aType) ||
#endif
IsMP3SupportedType(aType) ||
#ifdef MOZ_WMF
IsWMFSupportedType(aType) ||
#endif
#ifdef MOZ_DIRECTSHOW
IsDirectShowSupportedType(aType) ||
#endif
-12
View File
@@ -28,10 +28,6 @@
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackList.h"
#ifdef MOZ_WMF
#include "WMFDecoder.h"
#endif
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::media;
@@ -1482,14 +1478,6 @@ MediaDecoder::IsAndroidMediaEnabled()
}
#endif
#ifdef MOZ_WMF
bool
MediaDecoder::IsWMFEnabled()
{
return WMFDecoder::IsEnabled();
}
#endif
#ifdef MOZ_APPLEMEDIA
bool
MediaDecoder::IsAppleMP3Enabled()
+9 -1
View File
@@ -207,6 +207,7 @@ static const char* GetOmxLibraryName()
AndroidMediaPluginHost::AndroidMediaPluginHost() {
MOZ_COUNT_CTOR(AndroidMediaPluginHost);
MOZ_ASSERT(NS_IsMainThread());
mResourceServer = AndroidMediaResourceServer::Start();
@@ -305,14 +306,21 @@ void AndroidMediaPluginHost::DestroyDecoder(Decoder *aDecoder)
}
AndroidMediaPluginHost *sAndroidMediaPluginHost = nullptr;
AndroidMediaPluginHost *GetAndroidMediaPluginHost()
AndroidMediaPluginHost *EnsureAndroidMediaPluginHost()
{
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (!sAndroidMediaPluginHost) {
sAndroidMediaPluginHost = new AndroidMediaPluginHost();
}
return sAndroidMediaPluginHost;
}
AndroidMediaPluginHost *GetAndroidMediaPluginHost()
{
MOZ_ASSERT(sAndroidMediaPluginHost);
return sAndroidMediaPluginHost;
}
void AndroidMediaPluginHost::Shutdown()
{
delete sAndroidMediaPluginHost;
@@ -29,6 +29,11 @@ public:
void DestroyDecoder(MPAPI::Decoder *aDecoder);
};
// Must be called on the main thread. Creates the plugin host if it doesn't
// already exist.
AndroidMediaPluginHost *EnsureAndroidMediaPluginHost();
// May be called on any thread after EnsureAndroidMediaPluginHost has been called.
AndroidMediaPluginHost *GetAndroidMediaPluginHost();
} // namespace mozilla
@@ -398,6 +398,7 @@ AndroidMediaResourceServer::AndroidMediaResourceServer() :
NS_IMETHODIMP
AndroidMediaResourceServer::Run()
{
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
nsresult rv;
@@ -420,13 +421,9 @@ AndroidMediaResourceServer::Run()
already_AddRefed<AndroidMediaResourceServer>
AndroidMediaResourceServer::Start()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<AndroidMediaResourceServer> server = new AndroidMediaResourceServer();
// We should fix this up - see bug 1157476.
if (NS_IsMainThread()) {
server->Run();
} else {
NS_DispatchToMainThread(server, NS_DISPATCH_SYNC);
}
server->Run();
return server.forget();
}
-3
View File
@@ -51,9 +51,6 @@ if CONFIG['MOZ_DIRECTSHOW']:
if CONFIG['MOZ_ANDROID_OMX']:
DIRS += ['android']
if CONFIG['MOZ_WMF']:
DIRS += ['wmf']
if CONFIG['MOZ_FMP4']:
DIRS += ['fmp4']
+13
View File
@@ -5,13 +5,17 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS += [
'DXVA2Manager.h',
'MFTDecoder.h',
'WMF.h',
'WMFAudioMFTManager.h',
'WMFDecoderModule.h',
'WMFMediaDataDecoder.h',
'WMFUtils.h',
'WMFVideoMFTManager.h',
]
UNIFIED_SOURCES += [
'DXVA2Manager.cpp',
'MFTDecoder.cpp',
'WMFAudioMFTManager.cpp',
'WMFDecoderModule.cpp',
@@ -19,8 +23,17 @@ UNIFIED_SOURCES += [
'WMFVideoMFTManager.cpp',
]
SOURCES += [
'WMFUtils.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
if CONFIG['OS_ARCH'] == 'WINNT':
DEFINES['NOMINMAX'] = True
FAIL_ON_WARNINGS = True
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
-680
View File
@@ -1,680 +0,0 @@
/* -*- 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 "WMF.h"
#include <unknwn.h>
#include <ole2.h>
#include "WMFByteStream.h"
#include "WMFSourceReaderCallback.h"
#include "WMFUtils.h"
#include "MediaResource.h"
#include "nsISeekableStream.h"
#include "mozilla/RefPtr.h"
#include "nsIThreadPool.h"
#include "nsXPCOMCIDInternal.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/DebugOnly.h"
#include "SharedThreadPool.h"
#include <algorithm>
#include <cassert>
namespace mozilla {
PRLogModuleInfo* gWMFByteStreamLog = nullptr;
#define WMF_BS_LOG(...) MOZ_LOG(gWMFByteStreamLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
WMFByteStream::WMFByteStream(MediaResource* aResource,
WMFSourceReaderCallback* aSourceReaderCallback)
: mSourceReaderCallback(aSourceReaderCallback),
mResource(aResource),
mReentrantMonitor("WMFByteStream.Data"),
mOffset(0),
mIsShutdown(false)
{
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
NS_ASSERTION(mSourceReaderCallback, "Must have a source reader callback.");
if (!gWMFByteStreamLog) {
gWMFByteStreamLog = PR_NewLogModule("WMFByteStream");
}
WMF_BS_LOG("[%p] WMFByteStream CTOR", this);
MOZ_COUNT_CTOR(WMFByteStream);
}
WMFByteStream::~WMFByteStream()
{
MOZ_COUNT_DTOR(WMFByteStream);
WMF_BS_LOG("[%p] WMFByteStream DTOR", this);
}
nsresult
WMFByteStream::Init()
{
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"), 4);
NS_ENSURE_TRUE(mThreadPool, NS_ERROR_FAILURE);
NS_ConvertUTF8toUTF16 contentTypeUTF16(mResource->GetContentType());
if (!contentTypeUTF16.IsEmpty()) {
HRESULT hr = wmf::MFCreateAttributes(byRef(mAttributes), 1);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
hr = mAttributes->SetString(MF_BYTESTREAM_CONTENT_TYPE,
contentTypeUTF16.get());
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
WMF_BS_LOG("[%p] WMFByteStream has Content-Type=%s", this, mResource->GetContentType().get());
}
return NS_OK;
}
nsresult
WMFByteStream::Shutdown()
{
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mIsShutdown = true;
}
mSourceReaderCallback->Cancel();
return NS_OK;
}
// IUnknown Methods
STDMETHODIMP
WMFByteStream::QueryInterface(REFIID aIId, void **aInterface)
{
WMF_BS_LOG("[%p] WMFByteStream::QueryInterface %s", this, GetGUIDName(aIId).get());
if (aIId == IID_IMFByteStream) {
return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
}
if (aIId == IID_IUnknown) {
return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
}
if (aIId == IID_IMFAttributes) {
return DoGetInterface(static_cast<IMFAttributes*>(this), aInterface);
}
*aInterface = nullptr;
return E_NOINTERFACE;
}
NS_IMPL_ADDREF(WMFByteStream)
NS_IMPL_RELEASE(WMFByteStream)
// Stores data regarding an async read opreation.
class ReadRequest final : public IUnknown {
~ReadRequest() {}
public:
ReadRequest(int64_t aOffset, BYTE* aBuffer, ULONG aLength)
: mOffset(aOffset),
mBuffer(aBuffer),
mBufferLength(aLength),
mBytesRead(0)
{}
// IUnknown Methods
STDMETHODIMP QueryInterface(REFIID aRIID, LPVOID *aOutObject);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
int64_t mOffset;
BYTE* mBuffer;
ULONG mBufferLength;
ULONG mBytesRead;
// IUnknown ref counting.
ThreadSafeAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
};
NS_IMPL_ADDREF(ReadRequest)
NS_IMPL_RELEASE(ReadRequest)
// IUnknown Methods
STDMETHODIMP
ReadRequest::QueryInterface(REFIID aIId, void **aInterface)
{
WMF_BS_LOG("ReadRequest::QueryInterface %s", GetGUIDName(aIId).get());
if (aIId == IID_IUnknown) {
return DoGetInterface(static_cast<IUnknown*>(this), aInterface);
}
*aInterface = nullptr;
return E_NOINTERFACE;
}
class ProcessReadRequestEvent final : public nsRunnable {
public:
ProcessReadRequestEvent(WMFByteStream* aStream,
IMFAsyncResult* aResult,
ReadRequest* aRequestState)
: mStream(aStream),
mResult(aResult),
mRequestState(aRequestState) {}
NS_IMETHOD Run() {
mStream->ProcessReadRequest(mResult, mRequestState);
return NS_OK;
}
private:
RefPtr<WMFByteStream> mStream;
RefPtr<IMFAsyncResult> mResult;
RefPtr<ReadRequest> mRequestState;
};
// IMFByteStream Methods
STDMETHODIMP
WMFByteStream::BeginRead(BYTE *aBuffer,
ULONG aLength,
IMFAsyncCallback *aCallback,
IUnknown *aCallerState)
{
NS_ENSURE_TRUE(aBuffer, E_POINTER);
NS_ENSURE_TRUE(aCallback, E_POINTER);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
WMF_BS_LOG("[%p] WMFByteStream::BeginRead() mOffset=%lld tell=%lld length=%lu mIsShutdown=%d",
this, mOffset, mResource->Tell(), aLength, mIsShutdown);
if (mIsShutdown || mOffset < 0) {
return E_INVALIDARG;
}
// Create an object to store our state.
RefPtr<ReadRequest> requestState = new ReadRequest(mOffset, aBuffer, aLength);
// Create an IMFAsyncResult, this is passed back to the caller as a token to
// retrieve the number of bytes read.
RefPtr<IMFAsyncResult> callersResult;
HRESULT hr = wmf::MFCreateAsyncResult(requestState,
aCallback,
aCallerState,
byRef(callersResult));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Dispatch an event to perform the read in the thread pool.
nsCOMPtr<nsIRunnable> r = new ProcessReadRequestEvent(this,
callersResult,
requestState);
nsresult rv = mThreadPool->Dispatch(r, NS_DISPATCH_NORMAL);
if (mResource->GetLength() > -1) {
mOffset = std::min<int64_t>(mOffset + aLength, mResource->GetLength());
} else {
mOffset += aLength;
}
return NS_SUCCEEDED(rv) ? S_OK : E_FAIL;
}
nsresult
WMFByteStream::Read(ReadRequest* aRequestState)
{
// Read in a loop to ensure we fill the buffer, when possible.
ULONG totalBytesRead = 0;
nsresult rv = NS_OK;
while (totalBytesRead < aRequestState->mBufferLength) {
BYTE* buffer = aRequestState->mBuffer + totalBytesRead;
ULONG bytesRead = 0;
ULONG length = aRequestState->mBufferLength - totalBytesRead;
rv = mResource->ReadAt(aRequestState->mOffset + totalBytesRead,
reinterpret_cast<char*>(buffer),
length,
reinterpret_cast<uint32_t*>(&bytesRead));
NS_ENSURE_SUCCESS(rv, rv);
totalBytesRead += bytesRead;
if (bytesRead == 0) {
break;
}
}
aRequestState->mBytesRead = totalBytesRead;
return NS_OK;
}
// Note: This is called on one of the thread pool's threads.
void
WMFByteStream::ProcessReadRequest(IMFAsyncResult* aResult,
ReadRequest* aRequestState)
{
if (mResource->GetLength() > -1 &&
aRequestState->mOffset > mResource->GetLength()) {
aResult->SetStatus(S_OK);
wmf::MFInvokeCallback(aResult);
WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read offset greater than length, soft-failing read", this);
return;
}
nsresult rv = Read(aRequestState);
if (NS_FAILED(rv)) {
Shutdown();
aResult->SetStatus(E_ABORT);
} else {
aResult->SetStatus(S_OK);
}
WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read %d at %lld finished rv=%x",
this, aRequestState->mBytesRead, aRequestState->mOffset, rv);
// Let caller know read is complete.
DebugOnly<HRESULT> hr = wmf::MFInvokeCallback(aResult);
NS_ASSERTION(SUCCEEDED(hr), "Failed to invoke callback!");
}
STDMETHODIMP
WMFByteStream::BeginWrite(const BYTE *, ULONG ,
IMFAsyncCallback *,
IUnknown *)
{
WMF_BS_LOG("[%p] WMFByteStream::BeginWrite()", this);
return E_NOTIMPL;
}
STDMETHODIMP
WMFByteStream::Close()
{
WMF_BS_LOG("[%p] WMFByteStream::Close()", this);
return S_OK;
}
STDMETHODIMP
WMFByteStream::EndRead(IMFAsyncResult* aResult, ULONG *aBytesRead)
{
NS_ENSURE_TRUE(aResult, E_POINTER);
NS_ENSURE_TRUE(aBytesRead, E_POINTER);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// Extract our state object.
RefPtr<IUnknown> unknown;
HRESULT hr = aResult->GetObject(byRef(unknown));
if (FAILED(hr) || !unknown) {
return E_INVALIDARG;
}
ReadRequest* requestState =
static_cast<ReadRequest*>(unknown.get());
// Report result.
*aBytesRead = requestState->mBytesRead;
WMF_BS_LOG("[%p] WMFByteStream::EndRead() offset=%lld *aBytesRead=%u mOffset=%lld status=0x%x hr=0x%x eof=%d",
this, requestState->mOffset, *aBytesRead, mOffset, aResult->GetStatus(), hr, IsEOS());
return aResult->GetStatus();
}
STDMETHODIMP
WMFByteStream::EndWrite(IMFAsyncResult *, ULONG *)
{
WMF_BS_LOG("[%p] WMFByteStream::EndWrite()", this);
return E_NOTIMPL;
}
STDMETHODIMP
WMFByteStream::Flush()
{
WMF_BS_LOG("[%p] WMFByteStream::Flush()", this);
return S_OK;
}
STDMETHODIMP
WMFByteStream::GetCapabilities(DWORD *aCapabilities)
{
WMF_BS_LOG("[%p] WMFByteStream::GetCapabilities()", this);
NS_ENSURE_TRUE(aCapabilities, E_POINTER);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
bool seekable = mResource->IsTransportSeekable();
bool cached = mResource->IsDataCachedToEndOfResource(0);
*aCapabilities = MFBYTESTREAM_IS_READABLE |
MFBYTESTREAM_IS_SEEKABLE |
(!cached ? MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED : 0) |
(!seekable ? MFBYTESTREAM_HAS_SLOW_SEEK : 0);
return S_OK;
}
STDMETHODIMP
WMFByteStream::GetCurrentPosition(QWORD *aPosition)
{
NS_ENSURE_TRUE(aPosition, E_POINTER);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// Note: Returning the length of stream as position when read
// cursor is < 0 seems to be the behaviour expected by WMF, but
// also note it doesn't seem to expect that the position is an
// unsigned value since if you seek to > length and read WMF
// expects the read to succeed after reading 0 bytes, but if you
// seek to < 0 and read, the read is expected to fails... So
// go figure...
*aPosition = mOffset < 0 ? mResource->GetLength() : mOffset;
WMF_BS_LOG("[%p] WMFByteStream::GetCurrentPosition() %lld", this, mOffset);
return S_OK;
}
STDMETHODIMP
WMFByteStream::GetLength(QWORD *aLength)
{
NS_ENSURE_TRUE(aLength, E_POINTER);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
*aLength = mResource->GetLength();
WMF_BS_LOG("[%p] WMFByteStream::GetLength() %lld", this, *aLength);
return S_OK;
}
bool
WMFByteStream::IsEOS()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mResource->GetLength() > -1 &&
(mOffset < 0 ||
mOffset >= mResource->GetLength());
}
STDMETHODIMP
WMFByteStream::IsEndOfStream(BOOL *aEndOfStream)
{
NS_ENSURE_TRUE(aEndOfStream, E_POINTER);
*aEndOfStream = IsEOS();
WMF_BS_LOG("[%p] WMFByteStream::IsEndOfStream() %d", this, *aEndOfStream);
return S_OK;
}
STDMETHODIMP
WMFByteStream::Read(BYTE* aBuffer, ULONG aBufferLength, ULONG* aOutBytesRead)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsRefPtr<ReadRequest> request = new ReadRequest(mOffset, aBuffer, aBufferLength);
if (NS_FAILED(Read(request))) {
WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld failed!", this, mOffset);
return E_FAIL;
}
if (aOutBytesRead) {
*aOutBytesRead = request->mBytesRead;
}
WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld length=%u bytesRead=%u",
this, mOffset, aBufferLength, request->mBytesRead);
mOffset += request->mBytesRead;
return S_OK;
}
STDMETHODIMP
WMFByteStream::Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin,
LONGLONG aSeekOffset,
DWORD aSeekFlags,
QWORD *aCurrentPosition)
{
WMF_BS_LOG("[%p] WMFByteStream::Seek(%d, %lld)", this, aSeekOrigin, aSeekOffset);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
int64_t offset = mOffset;
if (aSeekOrigin == msoBegin) {
offset = aSeekOffset;
} else {
offset += aSeekOffset;
}
int64_t length = mResource->GetLength();
if (length > -1) {
mOffset = std::min<int64_t>(offset, length);
} else {
mOffset = offset;
}
if (aCurrentPosition) {
*aCurrentPosition = mOffset;
}
return S_OK;
}
STDMETHODIMP
WMFByteStream::SetCurrentPosition(QWORD aPosition)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
WMF_BS_LOG("[%p] WMFByteStream::SetCurrentPosition(%lld)",
this, aPosition);
int64_t length = mResource->GetLength();
if (length > -1) {
mOffset = std::min<int64_t>(aPosition, length);
} else {
mOffset = aPosition;
}
return S_OK;
}
STDMETHODIMP
WMFByteStream::SetLength(QWORD)
{
WMF_BS_LOG("[%p] WMFByteStream::SetLength()", this);
return E_NOTIMPL;
}
STDMETHODIMP
WMFByteStream::Write(const BYTE *, ULONG, ULONG *)
{
WMF_BS_LOG("[%p] WMFByteStream::Write()", this);
return E_NOTIMPL;
}
// IMFAttributes methods
STDMETHODIMP
WMFByteStream::GetItem(REFGUID guidKey, PROPVARIANT* pValue)
{
MOZ_ASSERT(mAttributes);
return mAttributes->GetItem(guidKey, pValue);
}
STDMETHODIMP
WMFByteStream::GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType)
{
assert(mAttributes);
return mAttributes->GetItemType(guidKey, pType);
}
STDMETHODIMP
WMFByteStream::CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult)
{
assert(mAttributes);
return mAttributes->CompareItem(guidKey, Value, pbResult);
}
STDMETHODIMP
WMFByteStream::Compare(IMFAttributes* pTheirs,
MF_ATTRIBUTES_MATCH_TYPE MatchType,
BOOL* pbResult)
{
assert(mAttributes);
return mAttributes->Compare(pTheirs, MatchType, pbResult);
}
STDMETHODIMP
WMFByteStream::GetUINT32(REFGUID guidKey, UINT32* punValue)
{
assert(mAttributes);
return mAttributes->GetUINT32(guidKey, punValue);
}
STDMETHODIMP
WMFByteStream::GetUINT64(REFGUID guidKey, UINT64* punValue)
{
assert(mAttributes);
return mAttributes->GetUINT64(guidKey, punValue);
}
STDMETHODIMP
WMFByteStream::GetDouble(REFGUID guidKey, double* pfValue)
{
assert(mAttributes);
return mAttributes->GetDouble(guidKey, pfValue);
}
STDMETHODIMP
WMFByteStream::GetGUID(REFGUID guidKey, GUID* pguidValue)
{
assert(mAttributes);
return mAttributes->GetGUID(guidKey, pguidValue);
}
STDMETHODIMP
WMFByteStream::GetStringLength(REFGUID guidKey, UINT32* pcchLength)
{
assert(mAttributes);
return mAttributes->GetStringLength(guidKey, pcchLength);
}
STDMETHODIMP
WMFByteStream::GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength)
{
assert(mAttributes);
return mAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
}
STDMETHODIMP
WMFByteStream::GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength)
{
assert(mAttributes);
return mAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
}
STDMETHODIMP
WMFByteStream::GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize)
{
assert(mAttributes);
return mAttributes->GetBlobSize(guidKey, pcbBlobSize);
}
STDMETHODIMP
WMFByteStream::GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize)
{
assert(mAttributes);
return mAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
}
STDMETHODIMP
WMFByteStream::GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize)
{
assert(mAttributes);
return mAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
}
STDMETHODIMP
WMFByteStream::GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv)
{
assert(mAttributes);
return mAttributes->GetUnknown(guidKey, riid, ppv);
}
STDMETHODIMP
WMFByteStream::SetItem(REFGUID guidKey, REFPROPVARIANT Value)
{
assert(mAttributes);
return mAttributes->SetItem(guidKey, Value);
}
STDMETHODIMP
WMFByteStream::DeleteItem(REFGUID guidKey)
{
assert(mAttributes);
return mAttributes->DeleteItem(guidKey);
}
STDMETHODIMP
WMFByteStream::DeleteAllItems()
{
assert(mAttributes);
return mAttributes->DeleteAllItems();
}
STDMETHODIMP
WMFByteStream::SetUINT32(REFGUID guidKey, UINT32 unValue)
{
assert(mAttributes);
return mAttributes->SetUINT32(guidKey, unValue);
}
STDMETHODIMP
WMFByteStream::SetUINT64(REFGUID guidKey,UINT64 unValue)
{
assert(mAttributes);
return mAttributes->SetUINT64(guidKey, unValue);
}
STDMETHODIMP
WMFByteStream::SetDouble(REFGUID guidKey, double fValue)
{
assert(mAttributes);
return mAttributes->SetDouble(guidKey, fValue);
}
STDMETHODIMP
WMFByteStream::SetGUID(REFGUID guidKey, REFGUID guidValue)
{
assert(mAttributes);
return mAttributes->SetGUID(guidKey, guidValue);
}
STDMETHODIMP
WMFByteStream::SetString(REFGUID guidKey, LPCWSTR wszValue)
{
assert(mAttributes);
return mAttributes->SetString(guidKey, wszValue);
}
STDMETHODIMP
WMFByteStream::SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize)
{
assert(mAttributes);
return mAttributes->SetBlob(guidKey, pBuf, cbBufSize);
}
STDMETHODIMP
WMFByteStream::SetUnknown(REFGUID guidKey, IUnknown* pUnknown)
{
assert(mAttributes);
return mAttributes->SetUnknown(guidKey, pUnknown);
}
STDMETHODIMP
WMFByteStream::LockStore()
{
assert(mAttributes);
return mAttributes->LockStore();
}
STDMETHODIMP
WMFByteStream::UnlockStore()
{
assert(mAttributes);
return mAttributes->UnlockStore();
}
STDMETHODIMP
WMFByteStream::GetCount(UINT32* pcItems)
{
assert(mAttributes);
return mAttributes->GetCount(pcItems);
}
STDMETHODIMP
WMFByteStream::GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue)
{
assert(mAttributes);
return mAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
}
STDMETHODIMP
WMFByteStream::CopyAllItems(IMFAttributes* pDest)
{
assert(mAttributes);
return mAttributes->CopyAllItems(pDest);
}
} // namespace mozilla
-162
View File
@@ -1,162 +0,0 @@
/* -*- 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/. */
#if !defined(WMFByteStream_h_)
#define WMFByteStream_h_
#include "WMF.h"
#include "nsISupportsImpl.h"
#include "nsCOMPtr.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Attributes.h"
#include "nsAutoPtr.h"
#include "mozilla/RefPtr.h"
namespace mozilla {
class MediaResource;
class ReadRequest;
class WMFSourceReaderCallback;
class SharedThreadPool;
// Wraps a MediaResource around an IMFByteStream interface, so that it can
// be used by the IMFSourceReader. Each WMFByteStream creates a WMF Work Queue
// on which blocking I/O is performed. The SourceReader requests reads
// asynchronously using {Begin,End}Read(), and more rarely synchronously
// using Read().
//
// Note: This implementation attempts to be bug-compatible with Windows Media
// Foundation's implementation of IMFByteStream. The behaviour of WMF's
// IMFByteStream was determined by creating it and testing the edge cases.
// For details see the test code at:
// https://github.com/cpearce/IMFByteStreamBehaviour/
class WMFByteStream final : public IMFByteStream
, public IMFAttributes
{
~WMFByteStream();
public:
WMFByteStream(MediaResource* aResource, WMFSourceReaderCallback* aCallback);
nsresult Init();
nsresult Shutdown();
// IUnknown Methods.
STDMETHODIMP QueryInterface(REFIID aIId, LPVOID *aInterface);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IMFByteStream Methods.
STDMETHODIMP BeginRead(BYTE *aBuffer,
ULONG aLength,
IMFAsyncCallback *aCallback,
IUnknown *aCallerState);
STDMETHODIMP BeginWrite(const BYTE *, ULONG ,
IMFAsyncCallback *,
IUnknown *);
STDMETHODIMP Close();
STDMETHODIMP EndRead(IMFAsyncResult* aResult, ULONG *aBytesRead);
STDMETHODIMP EndWrite(IMFAsyncResult *, ULONG *);
STDMETHODIMP Flush();
STDMETHODIMP GetCapabilities(DWORD *aCapabilities);
STDMETHODIMP GetCurrentPosition(QWORD *aPosition);
STDMETHODIMP GetLength(QWORD *pqwLength);
STDMETHODIMP IsEndOfStream(BOOL *aIsEndOfStream);
STDMETHODIMP Read(BYTE *, ULONG, ULONG *);
STDMETHODIMP Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin,
LONGLONG aSeekOffset,
DWORD aSeekFlags,
QWORD *aCurrentPosition);
STDMETHODIMP SetCurrentPosition(QWORD aPosition);
STDMETHODIMP SetLength(QWORD);
STDMETHODIMP Write(const BYTE *, ULONG, ULONG *);
// IMFAttributes methods
STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue);
STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType);
STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult);
STDMETHODIMP Compare(IMFAttributes* pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, BOOL* pbResult);
STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue);
STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue);
STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue);
STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue);
STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength);
STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength);
STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength);
STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize);
STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize);
STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize);
STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv);
STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value);
STDMETHODIMP DeleteItem(REFGUID guidKey);
STDMETHODIMP DeleteAllItems();
STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue);
STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue);
STDMETHODIMP SetDouble(REFGUID guidKey, double fValue);
STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue);
STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue);
STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize);
STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown);
STDMETHODIMP LockStore();
STDMETHODIMP UnlockStore();
STDMETHODIMP GetCount(UINT32* pcItems);
STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue);
STDMETHODIMP CopyAllItems(IMFAttributes* pDest);
// We perform an async read operation in this callback implementation.
// Processes an async read request, storing the result in aResult, and
// notifying the caller when the read operation is complete.
void ProcessReadRequest(IMFAsyncResult* aResult,
ReadRequest* aRequestState);
private:
// Locks the MediaResource and performs the read. The other read methods
// call this function.
nsresult Read(ReadRequest* aRequestState);
// Returns true if the current position of the stream is at end of stream.
bool IsEOS();
// Reference to the thread pool in which we perform the reads asynchronously.
// Note this is pool is shared amongst all active WMFByteStreams.
RefPtr<SharedThreadPool> mThreadPool;
// Reference to the source reader's callback. We use this reference to
// notify threads waiting on a ReadSample() callback to stop waiting
// if the stream is closed, which happens when the media element is
// shutdown.
RefPtr<WMFSourceReaderCallback> mSourceReaderCallback;
// Resource we're wrapping.
nsRefPtr<MediaResource> mResource;
// Protects mOffset, which is accessed by the SourceReaders thread(s), and
// on the work queue thread.
ReentrantMonitor mReentrantMonitor;
// Current offset of the logical read cursor. We maintain this separately
// from the media resource's offset since a partially complete read (in Invoke())
// would leave the resource's offset at a value unexpected by the caller,
// since the read hadn't yet completed.
int64_t mOffset;
// We implement IMFAttributes by forwarding all calls to an instance of the
// standard IMFAttributes class, which we store a reference to here.
RefPtr<IMFAttributes> mAttributes;
// True if the resource has been shutdown, either because the WMFReader is
// shutting down, or because the underlying MediaResource has closed.
bool mIsShutdown;
// IUnknown ref counting.
ThreadSafeAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
};
} // namespace mozilla
#endif
-142
View File
@@ -1,142 +0,0 @@
/* -*- 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 "WMF.h"
#include "WMFDecoder.h"
#include "WMFReader.h"
#include "WMFUtils.h"
#include "MediaDecoderStateMachine.h"
#include "mozilla/Preferences.h"
#include "mozilla/WindowsVersion.h"
#include "nsCharSeparatedTokenizer.h"
#ifdef MOZ_DIRECTSHOW
#include "DirectShowDecoder.h"
#endif
namespace mozilla {
MediaDecoderStateMachine* WMFDecoder::CreateStateMachine()
{
return new MediaDecoderStateMachine(this, new WMFReader(this));
}
/* static */
bool
WMFDecoder::IsMP3Supported()
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
if (!MediaDecoder::IsWMFEnabled()) {
return false;
}
// MP3 works fine in WMF on Windows Vista and Windows 8.
if (!IsWin7OrLater()) {
return true;
}
// MP3 support is disabled if we're on Windows 7 and no service packs are
// installed, since it's crashy. Win7 with service packs is not so crashy,
// so we enable it there. Note we prefer DirectShow for MP3 playback, but
// we still support MP3 in MP4 via WMF, or MP3 in WMF if DirectShow is
// disabled.
return IsWin7SP1OrLater();
}
static bool
IsSupportedH264Codec(const nsAString& aCodec)
{
// According to the WMF documentation:
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx
// "The Media Foundation H.264 video decoder is a Media Foundation Transform
// that supports decoding of Baseline, Main, and High profiles, up to level
// 5.1.". We also report that we can play Extended profile, as there are
// bitstreams that are Extended compliant that are also Baseline compliant.
int16_t profile = 0, level = 0;
if (!ExtractH264CodecDetails(aCodec, profile, level)) {
return false;
}
return level >= H264_LEVEL_1 &&
level <= H264_LEVEL_5_1 &&
(profile == H264_PROFILE_BASE ||
profile == H264_PROFILE_MAIN ||
profile == H264_PROFILE_EXTENDED ||
profile == H264_PROFILE_HIGH);
}
bool
WMFDecoder::CanPlayType(const nsACString& aType,
const nsAString& aCodecs)
{
if (!MediaDecoder::IsWMFEnabled() ||
NS_FAILED(LoadDLLs())) {
return false;
}
// Assume that if LoadDLLs() didn't fail, we can playback the types that
// we know should be supported by Windows Media Foundation.
if ((aType.EqualsASCII("audio/mpeg") || aType.EqualsASCII("audio/mp3")) &&
IsMP3Supported()) {
// Note: We block MP3 playback on Window 7 SP0 since it seems to crash
// in some circumstances.
return !aCodecs.Length() || aCodecs.EqualsASCII("mp3");
}
// AAC-LC or MP3 in M4A.
if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) {
return !aCodecs.Length() ||
aCodecs.EqualsASCII("mp4a.40.2") ||
aCodecs.EqualsASCII("mp3");
}
if (!aType.EqualsASCII("video/mp4")) {
return false;
}
// H.264 + AAC in MP4. Verify that all the codecs specifed are ones that
// we expect that we can play.
nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
bool expectMoreTokens = false;
while (tokenizer.hasMoreTokens()) {
const nsSubstring& token = tokenizer.nextToken();
expectMoreTokens = tokenizer.separatorAfterCurrentToken();
if (token.EqualsASCII("mp4a.40.2") || // AAC-LC
token.EqualsASCII("mp3") ||
IsSupportedH264Codec(token)) {
continue;
}
return false;
}
if (expectMoreTokens) {
// Last codec name was empty
return false;
}
return true;
}
nsresult
WMFDecoder::LoadDLLs()
{
return NS_OK; // Removed in next patch in series.
}
void
WMFDecoder::UnloadDLLs()
{
// Removed in next patch in series.
}
/* static */
bool
WMFDecoder::IsEnabled()
{
// We only use WMF on Windows Vista and up
return IsVistaOrLater() &&
Preferences::GetBool("media.windows-media-foundation.enabled");
}
} // namespace mozilla
-51
View File
@@ -1,51 +0,0 @@
/* -*- 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/. */
#if !defined(WMFDecoder_h_)
#define WMFDecoder_h_
#include "MediaDecoder.h"
namespace mozilla {
// Decoder that uses Windows Media Foundation to playback H.264/AAC in MP4
// and M4A files, and MP3 files if the DirectShow backend is disabled.
// Playback is strictly limited to only those codecs.
class WMFDecoder : public MediaDecoder
{
public:
virtual MediaDecoder* Clone() {
if (!IsWMFEnabled()) {
return nullptr;
}
return new WMFDecoder();
}
virtual MediaDecoderStateMachine* CreateStateMachine();
// Loads the DLLs required by Windows Media Foundation. If this returns
// failure, you can assume that WMF is not available on the user's system.
static nsresult LoadDLLs();
static void UnloadDLLs();
// Returns true if the WMF backend is preffed on, and we're running on a
// version of Windows which is likely to support WMF.
static bool IsEnabled();
// Returns true if MP3 decoding is enabled on this system. We block
// MP3 playback on Windows 7 SP0, since it's crashy on that platform.
static bool IsMP3Supported();
// Returns the HTMLMediaElement.canPlayType() result for the mime type
// and codecs parameter. aCodecs can be empty.
static bool CanPlayType(const nsACString& aType,
const nsAString& aCodecs);
};
} // namespace mozilla
#endif
-929
View File
@@ -1,929 +0,0 @@
/* -*- 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 "WMFReader.h"
#include "WMFDecoder.h"
#include "WMFUtils.h"
#include "WMFByteStream.h"
#include "WMFSourceReaderCallback.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/Preferences.h"
#include "DXVA2Manager.h"
#include "ImageContainer.h"
#include "Layers.h"
#include "mozilla/layers/LayersTypes.h"
#include "gfxWindowsPlatform.h"
#ifndef MOZ_SAMPLE_TYPE_FLOAT32
#error We expect 32bit float audio samples on desktop for the Windows Media Foundation media backend.
#endif
#include "MediaDecoder.h"
#include "VideoUtils.h"
#include "gfx2DGlue.h"
using namespace mozilla::gfx;
using namespace mozilla::media;
using mozilla::layers::Image;
using mozilla::layers::LayerManager;
using mozilla::layers::LayersBackend;
namespace mozilla {
extern PRLogModuleInfo* gMediaDecoderLog;
#define DECODER_LOG(...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
// Uncomment to enable verbose per-sample logging.
//#define LOG_SAMPLE_DECODE 1
WMFReader::WMFReader(AbstractMediaDecoder* aDecoder)
: MediaDecoderReader(aDecoder),
mSourceReader(nullptr),
mAudioChannels(0),
mAudioBytesPerSample(0),
mAudioRate(0),
mVideoWidth(0),
mVideoHeight(0),
mVideoStride(0),
mAudioFrameSum(0),
mAudioFrameOffset(0),
mHasAudio(false),
mHasVideo(false),
mUseHwAccel(false),
mMustRecaptureAudioPosition(true),
mIsMP3Enabled(WMFDecoder::IsMP3Supported()),
mCOMInitialized(false)
{
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
MOZ_COUNT_CTOR(WMFReader);
}
WMFReader::~WMFReader()
{
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
// Note: We must shutdown the byte stream before calling MFShutdown, else we
// get assertion failures when unlocking the byte stream's work queue.
if (mByteStream) {
DebugOnly<nsresult> rv = mByteStream->Shutdown();
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to shutdown WMFByteStream");
}
DebugOnly<HRESULT> hr = wmf::MFShutdown();
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
MOZ_COUNT_DTOR(WMFReader);
}
bool
WMFReader::InitializeDXVA()
{
if (gfxWindowsPlatform::GetPlatform()->IsWARP() ||
!gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding()) {
return false;
}
MOZ_ASSERT(mDecoder->GetImageContainer());
// Extract the layer manager backend type so that we can determine
// whether it's worthwhile using DXVA. If we're not running with a D3D
// layer manager then the readback of decoded video frames from GPU to
// CPU memory grinds painting to a halt, and makes playback performance
// *worse*.
MediaDecoderOwner* owner = mDecoder->GetOwner();
NS_ENSURE_TRUE(owner, false);
dom::HTMLMediaElement* element = owner->GetMediaElement();
NS_ENSURE_TRUE(element, false);
nsRefPtr<LayerManager> layerManager =
nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
NS_ENSURE_TRUE(layerManager, false);
LayersBackend backend = layerManager->GetCompositorBackendType();
if (backend != LayersBackend::LAYERS_D3D9 &&
backend != LayersBackend::LAYERS_D3D11) {
return false;
}
mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA();
return mDXVA2Manager != nullptr;
}
nsresult
WMFReader::Init(MediaDecoderReader* aCloneDonor)
{
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
nsresult rv = WMFDecoder::LoadDLLs();
NS_ENSURE_SUCCESS(rv, rv);
if (FAILED(wmf::MFStartup())) {
NS_WARNING("Failed to initialize Windows Media Foundation");
return NS_ERROR_FAILURE;
}
mSourceReaderCallback = new WMFSourceReaderCallback();
// Must be created on main thread.
mByteStream = new WMFByteStream(mDecoder->GetResource(), mSourceReaderCallback);
rv = mByteStream->Init();
NS_ENSURE_SUCCESS(rv, rv);
if (mDecoder->GetImageContainer() != nullptr &&
IsVideoContentType(mDecoder->GetResource()->GetContentType())) {
mUseHwAccel = InitializeDXVA();
} else {
mUseHwAccel = false;
}
return NS_OK;
}
bool
WMFReader::HasAudio()
{
MOZ_ASSERT(OnTaskQueue());
return mHasAudio;
}
bool
WMFReader::HasVideo()
{
MOZ_ASSERT(OnTaskQueue());
return mHasVideo;
}
static HRESULT
ConfigureSourceReaderStream(IMFSourceReader *aReader,
const DWORD aStreamIndex,
const GUID& aOutputSubType,
const GUID* aAllowedInSubTypes,
const uint32_t aNumAllowedInSubTypes)
{
NS_ENSURE_TRUE(aReader, E_POINTER);
NS_ENSURE_TRUE(aAllowedInSubTypes, E_POINTER);
RefPtr<IMFMediaType> nativeType;
RefPtr<IMFMediaType> type;
HRESULT hr;
// Find the native format of the stream.
hr = aReader->GetNativeMediaType(aStreamIndex, 0, byRef(nativeType));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Get the native output subtype of the stream. This denotes the uncompressed
// type.
GUID subType;
hr = nativeType->GetGUID(MF_MT_SUBTYPE, &subType);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Ensure the input type of the media is in the allowed formats list.
bool isSubTypeAllowed = false;
for (uint32_t i = 0; i < aNumAllowedInSubTypes; i++) {
if (aAllowedInSubTypes[i] == subType) {
isSubTypeAllowed = true;
break;
}
}
if (!isSubTypeAllowed) {
nsCString name = GetGUIDName(subType);
DECODER_LOG("ConfigureSourceReaderStream subType=%s is not allowed to be decoded", name.get());
return E_FAIL;
}
// Find the major type.
GUID majorType;
hr = nativeType->GetGUID(MF_MT_MAJOR_TYPE, &majorType);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Define the output type.
hr = wmf::MFCreateMediaType(byRef(type));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = type->SetGUID(MF_MT_MAJOR_TYPE, majorType);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = type->SetGUID(MF_MT_SUBTYPE, aOutputSubType);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Set the uncompressed format. This can fail if the decoder can't produce
// that type.
return aReader->SetCurrentMediaType(aStreamIndex, nullptr, type);
}
// Returns the duration of the resource, in microseconds.
HRESULT
GetSourceReaderDuration(IMFSourceReader *aReader,
int64_t& aOutDuration)
{
AutoPropVar var;
HRESULT hr = aReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE,
MF_PD_DURATION,
&var);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// WMF stores duration in hundred nanosecond units.
int64_t duration_hns = 0;
hr = wmf::PropVariantToInt64(var, &duration_hns);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
aOutDuration = HNsToUsecs(duration_hns);
return S_OK;
}
HRESULT
GetSourceReaderCanSeek(IMFSourceReader* aReader, bool& aOutCanSeek)
{
NS_ENSURE_TRUE(aReader, E_FAIL);
HRESULT hr;
AutoPropVar var;
hr = aReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE,
MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS,
&var);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
ULONG flags = 0;
hr = wmf::PropVariantToUInt32(var, &flags);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
aOutCanSeek = ((flags & MFMEDIASOURCE_CAN_SEEK) == MFMEDIASOURCE_CAN_SEEK);
return S_OK;
}
HRESULT
WMFReader::ConfigureVideoFrameGeometry(IMFMediaType* aMediaType)
{
NS_ENSURE_TRUE(aMediaType != nullptr, E_POINTER);
HRESULT hr;
// Verify that the video subtype is what we expect it to be.
// When using hardware acceleration/DXVA2 the video format should
// be NV12, which is DXVA2's preferred format. For software decoding
// we use YV12, as that's easier for us to stick into our rendering
// pipeline than NV12. NV12 has interleaved UV samples, whereas YV12
// is a planar format.
GUID videoFormat;
hr = aMediaType->GetGUID(MF_MT_SUBTYPE, &videoFormat);
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_NV12 || !mUseHwAccel, E_FAIL);
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_YV12 || mUseHwAccel, E_FAIL);
nsIntRect pictureRegion;
hr = GetPictureRegion(aMediaType, pictureRegion);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
UINT32 width = 0, height = 0;
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
uint32_t aspectNum = 0, aspectDenom = 0;
hr = MFGetAttributeRatio(aMediaType,
MF_MT_PIXEL_ASPECT_RATIO,
&aspectNum,
&aspectDenom);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Calculate and validate the picture region and frame dimensions after
// scaling by the pixel aspect ratio.
nsIntSize frameSize = nsIntSize(width, height);
nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) {
// Video track's frame sizes will overflow. Ignore the video track.
return E_FAIL;
}
// Success! Save state.
mInfo.mVideo.mDisplay = displaySize;
GetDefaultStride(aMediaType, &mVideoStride);
mVideoWidth = width;
mVideoHeight = height;
mPictureRegion = pictureRegion;
DECODER_LOG("WMFReader frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d) PAR=%d:%d",
width, height,
mVideoStride,
mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height,
displaySize.width, displaySize.height,
aspectNum, aspectDenom);
return S_OK;
}
HRESULT
WMFReader::ConfigureVideoDecoder()
{
NS_ASSERTION(mSourceReader, "Must have a SourceReader before configuring decoders!");
// Determine if we have video.
if (!mSourceReader ||
!SourceReaderHasStream(mSourceReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM)) {
// No stream, no error.
return S_OK;
}
if (!mDecoder->GetImageContainer()) {
// We can't display the video, so don't bother to decode; disable the stream.
return mSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_VIDEO_STREAM, FALSE);
}
static const GUID MP4VideoTypes[] = {
MFVideoFormat_H264
};
HRESULT hr = ConfigureSourceReaderStream(mSourceReader,
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
mUseHwAccel ? MFVideoFormat_NV12 : MFVideoFormat_YV12,
MP4VideoTypes,
ArrayLength(MP4VideoTypes));
if (FAILED(hr)) {
DECODER_LOG("Failed to configured video output");
return hr;
}
RefPtr<IMFMediaType> mediaType;
hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
byRef(mediaType));
if (FAILED(hr)) {
NS_WARNING("Failed to get configured video media type");
return hr;
}
if (FAILED(ConfigureVideoFrameGeometry(mediaType))) {
NS_WARNING("Failed configured video frame dimensions");
return hr;
}
DECODER_LOG("Successfully configured video stream");
mHasVideo = true;
return S_OK;
}
void
WMFReader::GetSupportedAudioCodecs(const GUID** aCodecs, uint32_t* aNumCodecs)
{
MOZ_ASSERT(aCodecs);
MOZ_ASSERT(aNumCodecs);
if (mIsMP3Enabled) {
GUID aacOrMp3 = MFMPEG4Format_Base;
aacOrMp3.Data1 = 0x6D703461;// FOURCC('m','p','4','a');
static const GUID codecs[] = {
MFAudioFormat_AAC,
MFAudioFormat_MP3,
aacOrMp3
};
*aCodecs = codecs;
*aNumCodecs = ArrayLength(codecs);
} else {
static const GUID codecs[] = {
MFAudioFormat_AAC
};
*aCodecs = codecs;
*aNumCodecs = ArrayLength(codecs);
}
}
HRESULT
WMFReader::ConfigureAudioDecoder()
{
NS_ASSERTION(mSourceReader, "Must have a SourceReader before configuring decoders!");
if (!mSourceReader ||
!SourceReaderHasStream(mSourceReader, MF_SOURCE_READER_FIRST_AUDIO_STREAM)) {
// No stream, no error.
return S_OK;
}
const GUID* codecs;
uint32_t numCodecs = 0;
GetSupportedAudioCodecs(&codecs, &numCodecs);
HRESULT hr = ConfigureSourceReaderStream(mSourceReader,
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
MFAudioFormat_Float,
codecs,
numCodecs);
if (FAILED(hr)) {
NS_WARNING("Failed to configure WMF Audio decoder for PCM output");
return hr;
}
RefPtr<IMFMediaType> mediaType;
hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
byRef(mediaType));
if (FAILED(hr)) {
NS_WARNING("Failed to get configured audio media type");
return hr;
}
mAudioRate = MFGetAttributeUINT32(mediaType, MF_MT_AUDIO_SAMPLES_PER_SECOND, 0);
mAudioChannels = MFGetAttributeUINT32(mediaType, MF_MT_AUDIO_NUM_CHANNELS, 0);
mAudioBytesPerSample = MFGetAttributeUINT32(mediaType, MF_MT_AUDIO_BITS_PER_SAMPLE, 16) / 8;
mInfo.mAudio.mChannels = mAudioChannels;
mInfo.mAudio.mRate = mAudioRate;
mHasAudio = true;
DECODER_LOG("Successfully configured audio stream. rate=%u channels=%u bitsPerSample=%u",
mAudioRate, mAudioChannels, mAudioBytesPerSample);
return S_OK;
}
HRESULT
WMFReader::CreateSourceReader()
{
HRESULT hr;
RefPtr<IMFAttributes> attr;
hr = wmf::MFCreateAttributes(byRef(attr), 1);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, mSourceReaderCallback);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
if (mUseHwAccel) {
hr = attr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER,
mDXVA2Manager->GetDXVADeviceManager());
if (FAILED(hr)) {
DECODER_LOG("Failed to set DXVA2 D3D Device manager on source reader attributes");
mUseHwAccel = false;
}
}
hr = wmf::MFCreateSourceReaderFromByteStream(mByteStream, attr, byRef(mSourceReader));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = ConfigureVideoDecoder();
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = ConfigureAudioDecoder();
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
if (mUseHwAccel && mInfo.HasVideo()) {
RefPtr<IMFTransform> videoDecoder;
hr = mSourceReader->GetServiceForStream(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
GUID_NULL,
IID_IMFTransform,
(void**)(IMFTransform**)(byRef(videoDecoder)));
if (SUCCEEDED(hr)) {
ULONG_PTR manager = ULONG_PTR(mDXVA2Manager->GetDXVADeviceManager());
hr = videoDecoder->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER,
manager);
if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
// Ignore MF_E_TRANSFORM_TYPE_NOT_SET. Vista returns this here
// on some, perhaps all, video cards. This may be because activating
// DXVA changes the available output types. It seems to be safe to
// ignore this error.
hr = S_OK;
}
}
if (FAILED(hr)) {
DECODER_LOG("Failed to set DXVA2 D3D Device manager on decoder hr=0x%x", hr);
mUseHwAccel = false;
}
}
return hr;
}
nsresult
WMFReader::ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags)
{
MOZ_ASSERT(OnTaskQueue());
DECODER_LOG("WMFReader::ReadMetadata()");
HRESULT hr;
const bool triedToInitDXVA = mUseHwAccel;
if (FAILED(CreateSourceReader())) {
mSourceReader = nullptr;
if (triedToInitDXVA && !mUseHwAccel) {
// We tried to initialize DXVA and failed. Try again to create the
// IMFSourceReader but this time we won't use DXVA. Note that we
// must recreate the IMFSourceReader from scratch, as on some systems
// (AMD Radeon 3000) we cannot successfully reconfigure an existing
// reader to not use DXVA after we've failed to configure DXVA.
// See bug 987127.
if (FAILED(CreateSourceReader())) {
mSourceReader = nullptr;
}
}
}
if (!mSourceReader) {
NS_WARNING("Failed to create IMFSourceReader");
return NS_ERROR_FAILURE;
}
if (mInfo.HasVideo()) {
DECODER_LOG("Using DXVA: %s", (mUseHwAccel ? "Yes" : "No"));
}
// Abort if both video and audio failed to initialize.
NS_ENSURE_TRUE(mInfo.HasValidMedia(), NS_ERROR_FAILURE);
// Get the duration, and report it to the decoder if we have it.
int64_t duration = 0;
hr = GetSourceReaderDuration(mSourceReader, duration);
if (SUCCEEDED(hr)) {
mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
}
*aInfo = mInfo;
*aTags = nullptr;
// aTags can be retrieved using techniques like used here:
// http://blogs.msdn.com/b/mf/archive/2010/01/12/mfmediapropdump.aspx
return NS_OK;
}
bool
WMFReader::IsMediaSeekable()
{
// Get the duration
int64_t duration = 0;
HRESULT hr = GetSourceReaderDuration(mSourceReader, duration);
// We can seek if we get a duration *and* the reader reports that it's
// seekable.
bool canSeek = false;
if (FAILED(hr) || FAILED(GetSourceReaderCanSeek(mSourceReader, canSeek)) ||
!canSeek) {
return false;
}
return true;
}
bool
WMFReader::DecodeAudioData()
{
MOZ_ASSERT(OnTaskQueue());
HRESULT hr;
hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
0, // control flags
0, // read stream index
nullptr,
nullptr,
nullptr);
if (FAILED(hr)) {
DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr);
// End the stream.
return false;
}
DWORD flags = 0;
LONGLONG timestampHns = 0;
RefPtr<IMFSample> sample;
hr = mSourceReaderCallback->Wait(&flags, &timestampHns, byRef(sample));
if (FAILED(hr) ||
(flags & MF_SOURCE_READERF_ERROR) ||
(flags & MF_SOURCE_READERF_ENDOFSTREAM) ||
(flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x",
hr, flags);
// End the stream.
return false;
}
if (!sample) {
// Not enough data? Try again...
return true;
}
RefPtr<IMFMediaBuffer> buffer;
hr = sample->ConvertToContiguousBuffer(byRef(buffer));
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it.
DWORD maxLength = 0, currentLength = 0;
hr = buffer->Lock(&data, &maxLength, &currentLength);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
uint32_t numFrames = currentLength / mAudioBytesPerSample / mAudioChannels;
NS_ASSERTION(sizeof(AudioDataValue) == mAudioBytesPerSample, "Size calculation is wrong");
nsAutoArrayPtr<AudioDataValue> pcmSamples(new AudioDataValue[numFrames * mAudioChannels]);
memcpy(pcmSamples.get(), data, currentLength);
buffer->Unlock();
// We calculate the timestamp and the duration based on the number of audio
// frames we've already played. We don't trust the timestamp stored on the
// IMFSample, as sometimes it's wrong, possibly due to buggy encoders?
// If this sample block comes after a discontinuity (i.e. a gap or seek)
// reset the frame counters, and capture the timestamp. Future timestamps
// will be offset from this block's timestamp.
UINT32 discontinuity = false;
sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
if (mMustRecaptureAudioPosition || discontinuity) {
mAudioFrameSum = 0;
hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
mMustRecaptureAudioPosition = false;
}
int64_t timestamp;
hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, &timestamp);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
mAudioFrameSum += numFrames;
int64_t duration;
hr = FramesToUsecs(numFrames, mAudioRate, &duration);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
timestamp,
duration,
numFrames,
pcmSamples.forget(),
mAudioChannels,
mAudioRate));
#ifdef LOG_SAMPLE_DECODE
DECODER_LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
timestamp, duration, currentLength);
#endif
return true;
}
HRESULT
WMFReader::CreateBasicVideoFrame(IMFSample* aSample,
int64_t aTimestampUsecs,
int64_t aDurationUsecs,
int64_t aOffsetBytes,
VideoData** aOutVideoData)
{
NS_ENSURE_TRUE(aSample, E_POINTER);
NS_ENSURE_TRUE(aOutVideoData, E_POINTER);
*aOutVideoData = nullptr;
HRESULT hr;
RefPtr<IMFMediaBuffer> buffer;
// Must convert to contiguous buffer to use IMD2DBuffer interface.
hr = aSample->ConvertToContiguousBuffer(byRef(buffer));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Try and use the IMF2DBuffer interface if available, otherwise fallback
// to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient,
// but only some systems (Windows 8?) support it.
BYTE* data = nullptr;
LONG stride = 0;
RefPtr<IMF2DBuffer> twoDBuffer;
hr = buffer->QueryInterface(static_cast<IMF2DBuffer**>(byRef(twoDBuffer)));
if (SUCCEEDED(hr)) {
hr = twoDBuffer->Lock2D(&data, &stride);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
} else {
hr = buffer->Lock(&data, nullptr, nullptr);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
stride = mVideoStride;
}
// YV12, planar format: [YYYY....][VVVV....][UUUU....]
// i.e., Y, then V, then U.
VideoData::YCbCrBuffer b;
// Y (Y') plane
b.mPlanes[0].mData = data;
b.mPlanes[0].mStride = stride;
b.mPlanes[0].mHeight = mVideoHeight;
b.mPlanes[0].mWidth = mVideoWidth;
b.mPlanes[0].mOffset = 0;
b.mPlanes[0].mSkip = 0;
// The V and U planes are stored 16-row-aligned, so we need to add padding
// to the row heights to ensure the Y'CbCr planes are referenced properly.
uint32_t padding = 0;
if (mVideoHeight % 16 != 0) {
padding = 16 - (mVideoHeight % 16);
}
uint32_t y_size = stride * (mVideoHeight + padding);
uint32_t v_size = stride * (mVideoHeight + padding) / 4;
uint32_t halfStride = (stride + 1) / 2;
uint32_t halfHeight = (mVideoHeight + 1) / 2;
uint32_t halfWidth = (mVideoWidth + 1) / 2;
// U plane (Cb)
b.mPlanes[1].mData = data + y_size + v_size;
b.mPlanes[1].mStride = halfStride;
b.mPlanes[1].mHeight = halfHeight;
b.mPlanes[1].mWidth = halfWidth;
b.mPlanes[1].mOffset = 0;
b.mPlanes[1].mSkip = 0;
// V plane (Cr)
b.mPlanes[2].mData = data + y_size;
b.mPlanes[2].mStride = halfStride;
b.mPlanes[2].mHeight = halfHeight;
b.mPlanes[2].mWidth = halfWidth;
b.mPlanes[2].mOffset = 0;
b.mPlanes[2].mSkip = 0;
nsRefPtr<VideoData> v = VideoData::Create(mInfo.mVideo,
mDecoder->GetImageContainer(),
aOffsetBytes,
aTimestampUsecs,
aDurationUsecs,
b,
false,
-1,
mPictureRegion);
if (twoDBuffer) {
twoDBuffer->Unlock2D();
} else {
buffer->Unlock();
}
v.forget(aOutVideoData);
return S_OK;
}
HRESULT
WMFReader::CreateD3DVideoFrame(IMFSample* aSample,
int64_t aTimestampUsecs,
int64_t aDurationUsecs,
int64_t aOffsetBytes,
VideoData** aOutVideoData)
{
NS_ENSURE_TRUE(aSample, E_POINTER);
NS_ENSURE_TRUE(aOutVideoData, E_POINTER);
NS_ENSURE_TRUE(mDXVA2Manager, E_ABORT);
NS_ENSURE_TRUE(mUseHwAccel, E_ABORT);
*aOutVideoData = nullptr;
HRESULT hr;
nsRefPtr<Image> image;
hr = mDXVA2Manager->CopyToImage(aSample,
mPictureRegion,
mDecoder->GetImageContainer(),
getter_AddRefs(image));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
NS_ENSURE_TRUE(image, E_FAIL);
nsRefPtr<VideoData> v = VideoData::CreateFromImage(mInfo.mVideo,
mDecoder->GetImageContainer(),
aOffsetBytes,
aTimestampUsecs,
aDurationUsecs,
image.forget(),
false,
-1,
mPictureRegion);
NS_ENSURE_TRUE(v, E_FAIL);
v.forget(aOutVideoData);
return S_OK;
}
bool
WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold)
{
MOZ_ASSERT(OnTaskQueue());
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
HRESULT hr;
hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0, // control flags
0, // read stream index
nullptr,
nullptr,
nullptr);
if (FAILED(hr)) {
DECODER_LOG("WMFReader::DecodeVideoData() ReadSample failed with hr=0x%x", hr);
return false;
}
DWORD flags = 0;
LONGLONG timestampHns = 0;
RefPtr<IMFSample> sample;
hr = mSourceReaderCallback->Wait(&flags, &timestampHns, byRef(sample));
if (flags & MF_SOURCE_READERF_ERROR) {
NS_WARNING("WMFReader: Catastrophic failure reading video sample");
// Future ReadSample() calls will fail, so give up and report end of stream.
return false;
}
if (FAILED(hr)) {
// Unknown failure, ask caller to try again?
return true;
}
if (!sample) {
if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
DECODER_LOG("WMFReader; Null sample after video decode, at end of stream");
return false;
}
DECODER_LOG("WMFReader; Null sample after video decode. Maybe insufficient data...");
return true;
}
if ((flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
DECODER_LOG("WMFReader: Video media type changed!");
RefPtr<IMFMediaType> mediaType;
hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
byRef(mediaType));
if (FAILED(hr) ||
FAILED(ConfigureVideoFrameGeometry(mediaType))) {
NS_WARNING("Failed to reconfigure video media type");
return false;
}
}
int64_t timestamp = HNsToUsecs(timestampHns);
if (timestamp < aTimeThreshold) {
return true;
}
int64_t offset = mDecoder->GetResource()->Tell();
int64_t duration = GetSampleDuration(sample);
VideoData* v = nullptr;
if (mUseHwAccel) {
hr = CreateD3DVideoFrame(sample, timestamp, duration, offset, &v);
} else {
hr = CreateBasicVideoFrame(sample, timestamp, duration, offset, &v);
}
NS_ENSURE_TRUE(SUCCEEDED(hr) && v, false);
a.mParsed++;
a.mDecoded++;
mVideoQueue.Push(v);
#ifdef LOG_SAMPLE_DECODE
DECODER_LOG("Decoded video sample timestamp=%lld duration=%lld stride=%d height=%u flags=%u",
timestamp, duration, mVideoStride, mVideoHeight, flags);
#endif
if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
// End of stream.
DECODER_LOG("End of video stream");
return false;
}
return true;
}
nsRefPtr<MediaDecoderReader::SeekPromise>
WMFReader::Seek(int64_t aTargetUs, int64_t aEndTime)
{
nsresult res = SeekInternal(aTargetUs);
if (NS_FAILED(res)) {
return SeekPromise::CreateAndReject(res, __func__);
} else {
return SeekPromise::CreateAndResolve(aTargetUs, __func__);
}
}
nsresult
WMFReader::SeekInternal(int64_t aTargetUs)
{
DECODER_LOG("WMFReader::Seek() %lld", aTargetUs);
MOZ_ASSERT(OnTaskQueue());
#ifdef DEBUG
bool canSeek = false;
GetSourceReaderCanSeek(mSourceReader, canSeek);
NS_ASSERTION(canSeek, "WMFReader::Seek() should only be called if we can seek!");
#endif
nsresult rv = ResetDecode();
NS_ENSURE_SUCCESS(rv, rv);
// Mark that we must recapture the audio frame count from the next sample.
// WMF doesn't set a discontinuity marker when we seek to time 0, so we
// must remember to recapture the audio frame offset and reset the frame
// sum on the next audio packet we decode.
mMustRecaptureAudioPosition = true;
AutoPropVar var;
HRESULT hr = InitPropVariantFromInt64(UsecsToHNs(aTargetUs), &var);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
hr = mSourceReader->SetCurrentPosition(GUID_NULL, var);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
return NS_OK;
}
} // namespace mozilla
-114
View File
@@ -1,114 +0,0 @@
/* -*- 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/. */
#if !defined(WMFReader_h_)
#define WMFReader_h_
#include "WMF.h"
#include "MediaDecoderReader.h"
#include "nsAutoPtr.h"
#include "mozilla/RefPtr.h"
#include "nsRect.h"
namespace mozilla {
class WMFByteStream;
class WMFSourceReaderCallback;
class DXVA2Manager;
// Decoder backend for reading H.264/AAC in MP4/M4A, and MP3 files using
// Windows Media Foundation.
class WMFReader : public MediaDecoderReader
{
public:
WMFReader(AbstractMediaDecoder* aDecoder);
virtual ~WMFReader();
nsresult Init(MediaDecoderReader* aCloneDonor) override;
bool DecodeAudioData() override;
bool DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold) override;
bool HasAudio() override;
bool HasVideo() override;
nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) override;
nsRefPtr<SeekPromise>
Seek(int64_t aTime, int64_t aEndTime) override;
bool IsMediaSeekable() override;
private:
HRESULT CreateSourceReader();
HRESULT ConfigureAudioDecoder();
HRESULT ConfigureVideoDecoder();
HRESULT ConfigureVideoFrameGeometry(IMFMediaType* aMediaType);
void GetSupportedAudioCodecs(const GUID** aCodecs, uint32_t* aNumCodecs);
HRESULT CreateBasicVideoFrame(IMFSample* aSample,
int64_t aTimestampUsecs,
int64_t aDurationUsecs,
int64_t aOffsetBytes,
VideoData** aOutVideoData);
HRESULT CreateD3DVideoFrame(IMFSample* aSample,
int64_t aTimestampUsecs,
int64_t aDurationUsecs,
int64_t aOffsetBytes,
VideoData** aOutVideoData);
// Attempt to initialize DXVA. Returns true on success.
bool InitializeDXVA();
nsresult SeekInternal(int64_t aTime);
RefPtr<IMFSourceReader> mSourceReader;
RefPtr<WMFByteStream> mByteStream;
RefPtr<WMFSourceReaderCallback> mSourceReaderCallback;
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
// Region inside the video frame that makes up the picture. Pixels outside
// of this region should not be rendered.
nsIntRect mPictureRegion;
uint32_t mAudioChannels;
uint32_t mAudioBytesPerSample;
uint32_t mAudioRate;
uint32_t mVideoWidth;
uint32_t mVideoHeight;
uint32_t mVideoStride;
// The offset, in audio frames, at which playback started since the
// last discontinuity.
int64_t mAudioFrameOffset;
// The number of audio frames that we've played since the last
// discontinuity.
int64_t mAudioFrameSum;
// True if we need to re-initialize mAudioFrameOffset and mAudioFrameSum
// from the next audio packet we decode. This happens after a seek, since
// WMF doesn't mark a stream as having a discontinuity after a seek(0).
bool mMustRecaptureAudioPosition;
bool mHasAudio;
bool mHasVideo;
bool mUseHwAccel;
// We can't call WMFDecoder::IsMP3Supported() on non-main threads, since it
// checks a pref, so we cache its value in mIsMP3Enabled and use that on
// the decode thread.
const bool mIsMP3Enabled;
bool mCOMInitialized;
};
} // namespace mozilla
#endif
-151
View File
@@ -1,151 +0,0 @@
/* -*- 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 "WMFSourceReaderCallback.h"
#include "WMFUtils.h"
namespace mozilla {
static PRLogModuleInfo* gWMFSourceReaderCallbackLog = nullptr;
#define WMF_CB_LOG(...) MOZ_LOG(gWMFSourceReaderCallbackLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
// IUnknown Methods
STDMETHODIMP
WMFSourceReaderCallback::QueryInterface(REFIID aIId, void **aInterface)
{
WMF_CB_LOG("WMFSourceReaderCallback::QueryInterface %s", GetGUIDName(aIId).get());
if (aIId == IID_IMFSourceReaderCallback) {
return DoGetInterface(static_cast<WMFSourceReaderCallback*>(this), aInterface);
}
if (aIId == IID_IUnknown) {
return DoGetInterface(static_cast<WMFSourceReaderCallback*>(this), aInterface);
}
*aInterface = nullptr;
return E_NOINTERFACE;
}
NS_IMPL_ADDREF(WMFSourceReaderCallback)
NS_IMPL_RELEASE(WMFSourceReaderCallback)
WMFSourceReaderCallback::WMFSourceReaderCallback()
: mMonitor("WMFSourceReaderCallback")
, mResultStatus(S_OK)
, mStreamFlags(0)
, mTimestamp(0)
, mSample(nullptr)
, mReadFinished(false)
{
if (!gWMFSourceReaderCallbackLog) {
gWMFSourceReaderCallbackLog = PR_NewLogModule("WMFSourceReaderCallback");
}
}
HRESULT
WMFSourceReaderCallback::NotifyReadComplete(HRESULT aReadStatus,
DWORD aStreamIndex,
DWORD aStreamFlags,
LONGLONG aTimestamp,
IMFSample *aSample)
{
// Note: aSample can be nullptr on success if more data is required!
ReentrantMonitorAutoEnter mon(mMonitor);
if (mSample) {
// The WMFReader should have called Wait() to retrieve the last
// sample returned by the last ReadSample() call, but if we're
// aborting the read before Wait() is called the sample ref
// can be non-null.
mSample->Release();
mSample = nullptr;
}
if (SUCCEEDED(aReadStatus)) {
if (aSample) {
mTimestamp = aTimestamp;
mSample = aSample;
mSample->AddRef();
}
}
mResultStatus = aReadStatus;
mStreamFlags = aStreamFlags;
// Set the sentinal value and notify the monitor, so that threads waiting
// in Wait() are awoken.
mReadFinished = true;
mon.NotifyAll();
return S_OK;
}
STDMETHODIMP
WMFSourceReaderCallback::OnReadSample(HRESULT aReadStatus,
DWORD aStreamIndex,
DWORD aStreamFlags,
LONGLONG aTimestamp,
IMFSample *aSample)
{
WMF_CB_LOG("WMFSourceReaderCallback::OnReadSample() hr=0x%x flags=0x%x time=%lld sample=%p",
aReadStatus, aStreamFlags, aTimestamp, aSample);
return NotifyReadComplete(aReadStatus,
aStreamIndex,
aStreamFlags,
aTimestamp,
aSample);
}
HRESULT
WMFSourceReaderCallback::Cancel()
{
WMF_CB_LOG("WMFSourceReaderCallback::Cancel()");
return NotifyReadComplete(E_ABORT,
0,
0,
0,
nullptr);
}
STDMETHODIMP
WMFSourceReaderCallback::OnEvent(DWORD, IMFMediaEvent *)
{
return S_OK;
}
STDMETHODIMP
WMFSourceReaderCallback::OnFlush(DWORD)
{
return S_OK;
}
HRESULT
WMFSourceReaderCallback::Wait(DWORD* aStreamFlags,
LONGLONG* aTimeStamp,
IMFSample** aSample)
{
ReentrantMonitorAutoEnter mon(mMonitor);
WMF_CB_LOG("WMFSourceReaderCallback::Wait() starting wait");
while (!mReadFinished) {
mon.Wait();
}
mReadFinished = false;
WMF_CB_LOG("WMFSourceReaderCallback::Wait() done waiting");
*aStreamFlags = mStreamFlags;
*aTimeStamp = mTimestamp;
*aSample = mSample;
HRESULT hr = mResultStatus;
mSample = nullptr;
mTimestamp = 0;
mStreamFlags = 0;
mResultStatus = S_OK;
return hr;
}
} // namespace mozilla
-85
View File
@@ -1,85 +0,0 @@
/* -*- 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/. */
#if !defined(WMFSourceReaderCallback_h_)
#define WMFSourceReaderCallback_h_
#include "WMF.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/RefPtr.h"
#include "nsISupportsImpl.h"
namespace mozilla {
// A listener which we pass into the IMFSourceReader upon creation which is
// notified when an asynchronous call to IMFSourceReader::ReadSample()
// completes. This allows us to abort ReadSample() operations when the
// WMFByteStream's underlying MediaResource is closed. This ensures that
// the decode threads don't get stuck in a synchronous ReadSample() call
// when the MediaResource is unexpectedly shutdown.
class WMFSourceReaderCallback final : public IMFSourceReaderCallback
{
~WMFSourceReaderCallback() {}
public:
WMFSourceReaderCallback();
// IUnknown Methods.
STDMETHODIMP QueryInterface(REFIID aIId, LPVOID *aInterface);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IMFSourceReaderCallback methods
STDMETHODIMP OnReadSample(HRESULT hrStatus,
DWORD dwStreamIndex,
DWORD dwStreamFlags,
LONGLONG llTimestamp,
IMFSample *pSample);
STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *);
STDMETHODIMP OnFlush(DWORD);
// Causes the calling thread to block waiting for the
// IMFSourceReader::ReadSample() result callback to occur, or for the
// WMFByteStream to be closed.
HRESULT Wait(DWORD* aStreamFlags,
LONGLONG* aTimeStamp,
IMFSample** aSample);
// Cancels Wait() calls.
HRESULT Cancel();
private:
// Sets state to record the result of a read, and awake threads
// waiting in Wait().
HRESULT NotifyReadComplete(HRESULT aReadStatus,
DWORD aStreamIndex,
DWORD aStreamFlags,
LONGLONG aTimestamp,
IMFSample *aSample);
// Synchronizes all member data in this class, and Wait() blocks on
// and NotifyReadComplete() notifies this monitor.
ReentrantMonitor mMonitor;
// Read result data.
HRESULT mResultStatus;
DWORD mStreamFlags;
LONGLONG mTimestamp;
IMFSample* mSample;
// Sentinal. Set to true when a read result is returned. Wait() won't exit
// until this is set to true.
bool mReadFinished;
// IUnknown ref counting.
ThreadSafeAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
};
} // namespace mozilla
#endif // WMFSourceReaderCallback_h_
-36
View File
@@ -1,36 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'DXVA2Manager.h',
'WMF.h',
'WMFDecoder.h',
'WMFReader.h',
'WMFUtils.h',
]
UNIFIED_SOURCES += [
'DXVA2Manager.cpp',
'WMFByteStream.cpp',
'WMFDecoder.cpp',
'WMFReader.cpp',
'WMFSourceReaderCallback.cpp',
]
SOURCES += [
'WMFUtils.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FAIL_ON_WARNINGS = True
FINAL_LIBRARY = 'xul'
if CONFIG['OS_ARCH'] == 'WINNT':
DEFINES['NOMINMAX'] = True
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
+3 -1
View File
@@ -669,7 +669,9 @@ Factory::SetDirect3D10Device(ID3D10Device1 *aDevice)
// do not throw on failure; return error codes and disconnect the device
// On Windows 8 error codes are the default, but on Windows 7 the
// default is to throw (or perhaps only with some drivers?)
aDevice->SetExceptionMode(0);
if (aDevice) {
aDevice->SetExceptionMode(0);
}
mD3D10Device = aDevice;
}
+4 -4
View File
@@ -346,11 +346,11 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
#ifdef XP_WIN
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
gfxWindowsPlatform::GetPlatform()->GetD3D10Device() &&
((aMoz2DBackend == gfx::BackendType::DIRECT2D && Factory::GetDirect3D10Device()) ||
(aMoz2DBackend == gfx::BackendType::DIRECT2D1_1 && Factory::GetDirect3D11Device())) &&
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize) {
aSize.height <= maxTextureSize)
{
texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags);
}
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
+1 -1
View File
@@ -206,7 +206,7 @@ DeviceManagerD3D9::Init()
if (!mNv3DVUtils) {
mNv3DVUtils = new Nv3DVUtils();
if (!mNv3DVUtils) {
NS_WARNING("Could not create a new instance of Nv3DVUtils.\n");
NS_WARNING("Could not create a new instance of Nv3DVUtils.");
}
}
+1 -1
View File
@@ -673,7 +673,7 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
}
if (UseVsyncComposition()) {
NS_WARNING("Enabling vsync compositor\n");
NS_WARNING("Enabling vsync compositor");
mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
} else {
mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);
+7
View File
@@ -32,5 +32,12 @@ FeatureStatusToString(FeatureStatus aStatus)
}
}
bool
IsFeatureStatusFailure(FeatureStatus aStatus)
{
return aStatus != FeatureStatus::Unused &&
aStatus != FeatureStatus::Available;
}
} // namespace gfx
} // namespace mozilla
+1
View File
@@ -39,6 +39,7 @@ enum class FeatureStatus
};
const char* FeatureStatusToString(FeatureStatus aStatus);
bool IsFeatureStatusFailure(FeatureStatus aStatus);
} // namespace gfx
} // namespace mozilla
+1 -1
View File
@@ -492,7 +492,7 @@ gfxAndroidPlatform::CreateHardwareVsyncSource()
VsyncSource::Display& display = vsyncSource->GetGlobalDisplay();
display.EnableVsync();
if (!display.IsVsyncEnabled()) {
NS_WARNING("Error enabling gonk vsync. Falling back to software vsync\n");
NS_WARNING("Error enabling gonk vsync. Falling back to software vsync");
return gfxPlatform::CreateHardwareVsyncSource();
}
display.DisableVsync();
+2 -2
View File
@@ -2350,7 +2350,7 @@ gfxPlatform::ShouldUseLayersAcceleration()
if (gfxPrefs::LayersAccelerationForceEnabled()) {
return true;
}
if (gfxPlatform::GetPlatform()->AccelerateLayersByDefault()) {
if (AccelerateLayersByDefault()) {
return true;
}
if (acceleratedEnv && *acceleratedEnv != '0') {
@@ -2426,7 +2426,7 @@ gfxPlatform::UsesOffMainThreadCompositing()
already_AddRefed<mozilla::gfx::VsyncSource>
gfxPlatform::CreateHardwareVsyncSource()
{
NS_WARNING("Hardware Vsync support not yet implemented. Falling back to software timers\n");
NS_WARNING("Hardware Vsync support not yet implemented. Falling back to software timers");
nsRefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
return softwareVsync.forget();
}
+4
View File
@@ -673,6 +673,10 @@ public:
return mCompositorBackend;
}
// Trigger a test-driven graphics device reset.
virtual void TestDeviceReset(DeviceResetReason aReason)
{}
protected:
gfxPlatform();
virtual ~gfxPlatform();
+33 -11
View File
@@ -78,7 +78,8 @@ gfxPlatformMac::gfxPlatformMac()
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) |
BackendTypeBit(BackendType::SKIA) |
BackendTypeBit(BackendType::COREGRAPHICS);
uint32_t contentMask = BackendTypeBit(BackendType::COREGRAPHICS);
uint32_t contentMask = BackendTypeBit(BackendType::COREGRAPHICS) |
BackendTypeBit(BackendType::SKIA);
InitBackendPrefs(canvasMask, BackendType::COREGRAPHICS,
contentMask, BackendType::COREGRAPHICS);
@@ -460,13 +461,26 @@ public:
OSXDisplay()
: mDisplayLink(nullptr)
{
MOZ_ASSERT(NS_IsMainThread());
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
}
~OSXDisplay()
{
MOZ_ASSERT(NS_IsMainThread());
mTimer->Cancel();
mTimer = nullptr;
DisableVsync();
}
static void RetryEnableVsync(nsITimer* aTimer, void* aOsxDisplay)
{
MOZ_ASSERT(NS_IsMainThread());
OSXDisplay* osxDisplay = static_cast<OSXDisplay*>(aOsxDisplay);
MOZ_ASSERT(osxDisplay);
osxDisplay->EnableVsync();
}
virtual void EnableVsync() override
{
MOZ_ASSERT(NS_IsMainThread());
@@ -479,18 +493,25 @@ public:
// situations. According to the docs, it is compatible with all displays running on the computer
// But if we have different monitors at different display rates, we may hit issues.
if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not create a display link with all active displays. Falling back to main display\n");
NS_WARNING("Could not create a display link with all active displays. Retrying");
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
// bug 1142708 - When coming back from sleep, there may be no active displays ready yet,
// even if listening for the kIOMessageSystemHasPoweredOn event from OS X sleep notifications.
// bug 1142708 - When coming back from sleep,
// or when changing displays, active displays may not be ready yet,
// even if listening for the kIOMessageSystemHasPoweredOn event
// from OS X sleep notifications.
// Active displays are those that are drawable.
// In these cases, default back to the main display to try to get a vsync event.
// The alternative would be to keep polling the CGActiveDisplayList for the displays to be ready.
if (CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &mDisplayLink) != kCVReturnSuccess) {
MOZ_CRASH("Could not create a CVDisplayLink with either active displays or the main display");
}
NS_WARNING("Using the CVDisplayLink from the main display\n");
// bug 1144638 - When changing display configurations and getting
// notifications from CGDisplayReconfigurationCallBack, the
// callback gets called twice for each active display
// so it's difficult to know when all displays are active.
// Instead, try again soon. The delay is arbitrary. 100ms chosen
// because on a late 2013 15" retina, it takes about that
// long to come back up from sleep.
uint32_t delay = 100;
mTimer->InitWithFuncCallback(RetryEnableVsync, this, delay, nsITimer::TYPE_ONE_SHOT);
return;
}
if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
@@ -538,6 +559,7 @@ public:
private:
// Manages the display link render thread
CVDisplayLinkRef mDisplayLink;
nsRefPtr<nsITimer> mTimer;
}; // OSXDisplay
private:
@@ -575,7 +597,7 @@ gfxPlatformMac::CreateHardwareVsyncSource()
VsyncSource::Display& primaryDisplay = osxVsyncSource->GetGlobalDisplay();
primaryDisplay.EnableVsync();
if (!primaryDisplay.IsVsyncEnabled()) {
NS_WARNING("OS X Vsync source not enabled. Falling back to software vsync.\n");
NS_WARNING("OS X Vsync source not enabled. Falling back to software vsync.");
return gfxPlatform::CreateHardwareVsyncSource();
}
+1
View File
@@ -241,6 +241,7 @@ private:
DECL_GFX_PREF(Once, "gfx.max-alloc-size", MaxAllocSize, int32_t, (int32_t)500000000);
DECL_GFX_PREF(Once, "gfx.max-texture-size", MaxTextureSize, int32_t, (int32_t)32767);
DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled", PerfWarnings, bool, false);
DECL_GFX_PREF(Live, "gfx.testing.device-reset", DeviceResetForTesting, int32_t, 0);
DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false);
// These times should be in milliseconds
+1 -1
View File
@@ -1320,7 +1320,7 @@ gfxUtils::WriteAsPNG(SourceSurface* aSurface, const char* aFile)
}
}
if (!file) {
NS_WARNING("Failed to open file to create PNG!\n");
NS_WARNING("Failed to open file to create PNG!");
return;
}
}
File diff suppressed because it is too large Load Diff
+29 -31
View File
@@ -229,9 +229,8 @@ public:
#ifdef CAIRO_HAS_DWRITE_FONT
IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
inline bool DWriteEnabled() { return mUseDirectWrite; }
inline bool DWriteEnabled() { return !!mDWriteFactory; }
inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
IDWriteTextAnalyzer *GetDWriteAnalyzer() { return mDWriteAnalyzer; }
IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
{ return mRenderingParams[aRenderMode]; }
@@ -263,17 +262,20 @@ public:
}
bool SupportsApzTouchInput() const override;
// Recreate devices as needed for a device reset. Returns true if a device
// reset occurred.
bool HandleDeviceReset();
void UpdateBackendPrefs();
// Return the diagnostic status of DirectX initialization. If
// initialization has not been attempted, this returns
// FeatureStatus::Unused.
mozilla::gfx::FeatureStatus GetD3D11Status() const {
return mD3D11Status;
}
mozilla::gfx::FeatureStatus GetD2DStatus() const {
return mD2DStatus;
}
mozilla::gfx::FeatureStatus GetD3D11Status() const;
mozilla::gfx::FeatureStatus GetD2DStatus() const;
mozilla::gfx::FeatureStatus GetD2D1Status() const;
unsigned GetD3D11Version();
mozilla::gfx::FeatureStatus GetD2D1Status();
void TestDeviceReset(DeviceResetReason aReason) override;
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
static mozilla::Atomic<size_t> sD3D11MemoryUsed;
@@ -286,6 +288,7 @@ protected:
return true;
}
void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
protected:
RenderMode mRenderMode;
@@ -296,34 +299,25 @@ protected:
private:
void Init();
void InitD3D11Devices();
void InitializeDevices();
void InitializeD3D11();
void InitializeD2D();
bool InitializeD2D1();
bool InitDWriteSupport();
// Used by InitD3D11Devices().
enum class D3D11Status {
Ok,
TryWARP,
ForceWARP,
Blocked
};
D3D11Status CheckD3D11Support();
bool AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
bool AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
bool AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
bool AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
void DisableD2D();
// Used by UpdateRenderMode().
mozilla::gfx::FeatureStatus InitD2DSupport();
void InitDWriteSupport();
mozilla::gfx::FeatureStatus CheckD3D11Support(bool* aCanUseHardware);
void AttemptD3D11DeviceCreation();
void AttemptWARPDeviceCreation();
void AttemptD3D11ImageBridgeDeviceCreation();
bool AttemptD3D11ContentDeviceCreation();
IDXGIAdapter1 *GetDXGIAdapter();
bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
bool mUseDirectWrite;
bool mUsingGDIFonts;
#ifdef CAIRO_HAS_DWRITE_FONT
nsRefPtr<IDWriteFactory> mDWriteFactory;
nsRefPtr<IDWriteTextAnalyzer> mDWriteAnalyzer;
nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
DWRITE_MEASURING_MODE mMeasuringMode;
#endif
@@ -333,17 +327,21 @@ private:
mozilla::RefPtr<ID3D11Device> mD3D11Device;
mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
mozilla::RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
bool mD3D11DeviceInitialized;
mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
bool mIsWARP;
bool mHasDeviceReset;
bool mHasFakeDeviceReset;
bool mDoesD3D11TextureSharingWork;
DeviceResetReason mDeviceResetReason;
// These should not be accessed directly. Use the Get[Feature]Status
// accessors instead.
mozilla::gfx::FeatureStatus mAcceleration;
mozilla::gfx::FeatureStatus mD3D11Status;
mozilla::gfx::FeatureStatus mD2DStatus;
mozilla::gfx::FeatureStatus mD2D1Status;
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
};
#endif /* GFX_WINDOWS_PLATFORM_H */
+1 -1
View File
@@ -859,7 +859,7 @@ CreateVsyncRefreshTimer()
return;
}
NS_WARNING("Enabling vsync refresh driver\n");
NS_WARNING("Enabling vsync refresh driver");
if (XRE_IsParentProcess()) {
// Make sure all vsync systems are ready.