mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-29 18:18:27 +00:00
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:
@@ -190,6 +190,7 @@
|
|||||||
#include "mozilla/widget/PuppetBidiKeyboard.h"
|
#include "mozilla/widget/PuppetBidiKeyboard.h"
|
||||||
#include "mozilla/RemoteSpellCheckEngineChild.h"
|
#include "mozilla/RemoteSpellCheckEngineChild.h"
|
||||||
#include "GMPServiceChild.h"
|
#include "GMPServiceChild.h"
|
||||||
|
#include "gfxPlatform.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::docshell;
|
using namespace mozilla::docshell;
|
||||||
@@ -2806,6 +2807,15 @@ ContentChild::RecvEndDragSession(const bool& aDoneDrag,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ContentChild::RecvTestGraphicsDeviceReset(const uint32_t& aResetReason)
|
||||||
|
{
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
gfxPlatform::GetPlatform()->TestDeviceReset(DeviceResetReason(aResetReason));
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|||||||
@@ -463,6 +463,8 @@ public:
|
|||||||
|
|
||||||
virtual bool RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) override;
|
virtual bool RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) override;
|
||||||
|
|
||||||
|
virtual bool RecvTestGraphicsDeviceReset(const uint32_t& aResetReason) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||||
|
|
||||||
|
|||||||
@@ -646,6 +646,13 @@ child:
|
|||||||
*/
|
*/
|
||||||
GamepadUpdate(GamepadChangeEvent aGamepadEvent);
|
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
|
* Notify the child that presentation receiver has been launched with the
|
||||||
* correspondent iframe.
|
* correspondent iframe.
|
||||||
|
|||||||
@@ -56,10 +56,6 @@
|
|||||||
#include "RtspOmxDecoder.h"
|
#include "RtspOmxDecoder.h"
|
||||||
#include "RtspOmxReader.h"
|
#include "RtspOmxReader.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_WMF
|
|
||||||
#include "WMFDecoder.h"
|
|
||||||
#include "WMFReader.h"
|
|
||||||
#endif
|
|
||||||
#ifdef MOZ_DIRECTSHOW
|
#ifdef MOZ_DIRECTSHOW
|
||||||
#include "DirectShowDecoder.h"
|
#include "DirectShowDecoder.h"
|
||||||
#include "DirectShowReader.h"
|
#include "DirectShowReader.h"
|
||||||
@@ -318,14 +314,6 @@ IsAndroidMediaType(const nsACString& aType)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_WMF
|
|
||||||
static bool
|
|
||||||
IsWMFSupportedType(const nsACString& aType)
|
|
||||||
{
|
|
||||||
return WMFDecoder::CanPlayType(aType, NS_LITERAL_STRING(""));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_DIRECTSHOW
|
#ifdef MOZ_DIRECTSHOW
|
||||||
static bool
|
static bool
|
||||||
IsDirectShowSupportedType(const nsACString& aType)
|
IsDirectShowSupportedType(const nsACString& aType)
|
||||||
@@ -426,6 +414,7 @@ CanPlayStatus
|
|||||||
DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
|
DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
|
||||||
const nsAString& aRequestedCodecs)
|
const nsAString& aRequestedCodecs)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
char const* const* codecList = nullptr;
|
char const* const* codecList = nullptr;
|
||||||
#ifdef MOZ_RAW
|
#ifdef MOZ_RAW
|
||||||
if (IsRawType(nsDependentCString(aMIMEType))) {
|
if (IsRawType(nsDependentCString(aMIMEType))) {
|
||||||
@@ -481,7 +470,7 @@ DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
|
|||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_ANDROID_OMX
|
#ifdef MOZ_ANDROID_OMX
|
||||||
if (MediaDecoder::IsAndroidMediaEnabled()) {
|
if (MediaDecoder::IsAndroidMediaEnabled()) {
|
||||||
GetAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList);
|
EnsureAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!codecList) {
|
if (!codecList) {
|
||||||
@@ -557,16 +546,6 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
|||||||
return CANPLAY_MAYBE;
|
return CANPLAY_MAYBE;
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef MOZ_APPLEMEDIA
|
||||||
if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), nullptr)) {
|
if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), nullptr)) {
|
||||||
return CANPLAY_MAYBE;
|
return CANPLAY_MAYBE;
|
||||||
@@ -591,6 +570,7 @@ static
|
|||||||
already_AddRefed<MediaDecoder>
|
already_AddRefed<MediaDecoder>
|
||||||
InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
nsRefPtr<MediaDecoder> decoder;
|
nsRefPtr<MediaDecoder> decoder;
|
||||||
|
|
||||||
#ifdef MOZ_FMP4
|
#ifdef MOZ_FMP4
|
||||||
@@ -664,7 +644,7 @@ if (IsAACSupportedType(aType)) {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_ANDROID_OMX
|
#ifdef MOZ_ANDROID_OMX
|
||||||
if (MediaDecoder::IsAndroidMediaEnabled() &&
|
if (MediaDecoder::IsAndroidMediaEnabled() &&
|
||||||
GetAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
|
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
|
||||||
decoder = new AndroidMediaDecoder(aType);
|
decoder = new AndroidMediaDecoder(aType);
|
||||||
return decoder.forget();
|
return decoder.forget();
|
||||||
}
|
}
|
||||||
@@ -681,12 +661,6 @@ if (IsAACSupportedType(aType)) {
|
|||||||
return decoder.forget();
|
return decoder.forget();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_WMF
|
|
||||||
if (IsWMFSupportedType(aType)) {
|
|
||||||
decoder = new WMFDecoder();
|
|
||||||
return decoder.forget();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef MOZ_APPLEMEDIA
|
#ifdef MOZ_APPLEMEDIA
|
||||||
if (IsAppleMediaSupportedType(aType)) {
|
if (IsAppleMediaSupportedType(aType)) {
|
||||||
decoder = new AppleDecoder();
|
decoder = new AppleDecoder();
|
||||||
@@ -703,6 +677,7 @@ if (IsAACSupportedType(aType)) {
|
|||||||
already_AddRefed<MediaDecoder>
|
already_AddRefed<MediaDecoder>
|
||||||
DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
nsRefPtr<MediaDecoder> decoder(InstantiateDecoder(aType, aOwner));
|
nsRefPtr<MediaDecoder> decoder(InstantiateDecoder(aType, aOwner));
|
||||||
NS_ENSURE_TRUE(decoder != nullptr, nullptr);
|
NS_ENSURE_TRUE(decoder != nullptr, nullptr);
|
||||||
NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
|
NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
|
||||||
@@ -713,6 +688,7 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
|||||||
/* static */
|
/* static */
|
||||||
MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, AbstractMediaDecoder* aDecoder)
|
MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, AbstractMediaDecoder* aDecoder)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MediaDecoderReader* decoderReader = nullptr;
|
MediaDecoderReader* decoderReader = nullptr;
|
||||||
|
|
||||||
if (!aDecoder) {
|
if (!aDecoder) {
|
||||||
@@ -757,7 +733,7 @@ if (IsAACSupportedType(aType)) {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_ANDROID_OMX
|
#ifdef MOZ_ANDROID_OMX
|
||||||
if (MediaDecoder::IsAndroidMediaEnabled() &&
|
if (MediaDecoder::IsAndroidMediaEnabled() &&
|
||||||
GetAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
|
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
|
||||||
decoderReader = new AndroidMediaReader(aDecoder, aType);
|
decoderReader = new AndroidMediaReader(aDecoder, aType);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
@@ -765,17 +741,10 @@ if (IsAACSupportedType(aType)) {
|
|||||||
decoderReader = new WebMReader(aDecoder);
|
decoderReader = new WebMReader(aDecoder);
|
||||||
} else
|
} else
|
||||||
#ifdef MOZ_DIRECTSHOW
|
#ifdef MOZ_DIRECTSHOW
|
||||||
// Note: DirectShowReader is preferred for MP3, but if it's disabled we
|
|
||||||
// fallback to the WMFReader.
|
|
||||||
if (IsDirectShowSupportedType(aType)) {
|
if (IsDirectShowSupportedType(aType)) {
|
||||||
decoderReader = new DirectShowReader(aDecoder);
|
decoderReader = new DirectShowReader(aDecoder);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_WMF
|
|
||||||
if (IsWMFSupportedType(aType)) {
|
|
||||||
decoderReader = new WMFReader(aDecoder);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
#ifdef MOZ_APPLEMEDIA
|
#ifdef MOZ_APPLEMEDIA
|
||||||
if (IsAppleMediaSupportedType(aType)) {
|
if (IsAppleMediaSupportedType(aType)) {
|
||||||
decoderReader = new AppleMP3Reader(aDecoder);
|
decoderReader = new AppleMP3Reader(aDecoder);
|
||||||
@@ -814,9 +783,6 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
|||||||
IsMP4SupportedType(aType) ||
|
IsMP4SupportedType(aType) ||
|
||||||
#endif
|
#endif
|
||||||
IsMP3SupportedType(aType) ||
|
IsMP3SupportedType(aType) ||
|
||||||
#ifdef MOZ_WMF
|
|
||||||
IsWMFSupportedType(aType) ||
|
|
||||||
#endif
|
|
||||||
#ifdef MOZ_DIRECTSHOW
|
#ifdef MOZ_DIRECTSHOW
|
||||||
IsDirectShowSupportedType(aType) ||
|
IsDirectShowSupportedType(aType) ||
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,10 +28,6 @@
|
|||||||
#include "mozilla/dom/VideoTrack.h"
|
#include "mozilla/dom/VideoTrack.h"
|
||||||
#include "mozilla/dom/VideoTrackList.h"
|
#include "mozilla/dom/VideoTrackList.h"
|
||||||
|
|
||||||
#ifdef MOZ_WMF
|
|
||||||
#include "WMFDecoder.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
using namespace mozilla::layers;
|
using namespace mozilla::layers;
|
||||||
using namespace mozilla::media;
|
using namespace mozilla::media;
|
||||||
@@ -1482,14 +1478,6 @@ MediaDecoder::IsAndroidMediaEnabled()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_WMF
|
|
||||||
bool
|
|
||||||
MediaDecoder::IsWMFEnabled()
|
|
||||||
{
|
|
||||||
return WMFDecoder::IsEnabled();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_APPLEMEDIA
|
#ifdef MOZ_APPLEMEDIA
|
||||||
bool
|
bool
|
||||||
MediaDecoder::IsAppleMP3Enabled()
|
MediaDecoder::IsAppleMP3Enabled()
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ static const char* GetOmxLibraryName()
|
|||||||
|
|
||||||
AndroidMediaPluginHost::AndroidMediaPluginHost() {
|
AndroidMediaPluginHost::AndroidMediaPluginHost() {
|
||||||
MOZ_COUNT_CTOR(AndroidMediaPluginHost);
|
MOZ_COUNT_CTOR(AndroidMediaPluginHost);
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
mResourceServer = AndroidMediaResourceServer::Start();
|
mResourceServer = AndroidMediaResourceServer::Start();
|
||||||
|
|
||||||
@@ -305,14 +306,21 @@ void AndroidMediaPluginHost::DestroyDecoder(Decoder *aDecoder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AndroidMediaPluginHost *sAndroidMediaPluginHost = nullptr;
|
AndroidMediaPluginHost *sAndroidMediaPluginHost = nullptr;
|
||||||
AndroidMediaPluginHost *GetAndroidMediaPluginHost()
|
AndroidMediaPluginHost *EnsureAndroidMediaPluginHost()
|
||||||
{
|
{
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
|
||||||
if (!sAndroidMediaPluginHost) {
|
if (!sAndroidMediaPluginHost) {
|
||||||
sAndroidMediaPluginHost = new AndroidMediaPluginHost();
|
sAndroidMediaPluginHost = new AndroidMediaPluginHost();
|
||||||
}
|
}
|
||||||
return sAndroidMediaPluginHost;
|
return sAndroidMediaPluginHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AndroidMediaPluginHost *GetAndroidMediaPluginHost()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(sAndroidMediaPluginHost);
|
||||||
|
return sAndroidMediaPluginHost;
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidMediaPluginHost::Shutdown()
|
void AndroidMediaPluginHost::Shutdown()
|
||||||
{
|
{
|
||||||
delete sAndroidMediaPluginHost;
|
delete sAndroidMediaPluginHost;
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ public:
|
|||||||
void DestroyDecoder(MPAPI::Decoder *aDecoder);
|
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();
|
AndroidMediaPluginHost *GetAndroidMediaPluginHost();
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ AndroidMediaResourceServer::AndroidMediaResourceServer() :
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
AndroidMediaResourceServer::Run()
|
AndroidMediaResourceServer::Run()
|
||||||
{
|
{
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
@@ -420,13 +421,9 @@ AndroidMediaResourceServer::Run()
|
|||||||
already_AddRefed<AndroidMediaResourceServer>
|
already_AddRefed<AndroidMediaResourceServer>
|
||||||
AndroidMediaResourceServer::Start()
|
AndroidMediaResourceServer::Start()
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
nsRefPtr<AndroidMediaResourceServer> server = new AndroidMediaResourceServer();
|
nsRefPtr<AndroidMediaResourceServer> server = new AndroidMediaResourceServer();
|
||||||
// We should fix this up - see bug 1157476.
|
server->Run();
|
||||||
if (NS_IsMainThread()) {
|
|
||||||
server->Run();
|
|
||||||
} else {
|
|
||||||
NS_DispatchToMainThread(server, NS_DISPATCH_SYNC);
|
|
||||||
}
|
|
||||||
return server.forget();
|
return server.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,9 +51,6 @@ if CONFIG['MOZ_DIRECTSHOW']:
|
|||||||
if CONFIG['MOZ_ANDROID_OMX']:
|
if CONFIG['MOZ_ANDROID_OMX']:
|
||||||
DIRS += ['android']
|
DIRS += ['android']
|
||||||
|
|
||||||
if CONFIG['MOZ_WMF']:
|
|
||||||
DIRS += ['wmf']
|
|
||||||
|
|
||||||
if CONFIG['MOZ_FMP4']:
|
if CONFIG['MOZ_FMP4']:
|
||||||
DIRS += ['fmp4']
|
DIRS += ['fmp4']
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,17 @@
|
|||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
|
'DXVA2Manager.h',
|
||||||
'MFTDecoder.h',
|
'MFTDecoder.h',
|
||||||
|
'WMF.h',
|
||||||
'WMFAudioMFTManager.h',
|
'WMFAudioMFTManager.h',
|
||||||
'WMFDecoderModule.h',
|
'WMFDecoderModule.h',
|
||||||
'WMFMediaDataDecoder.h',
|
'WMFMediaDataDecoder.h',
|
||||||
|
'WMFUtils.h',
|
||||||
'WMFVideoMFTManager.h',
|
'WMFVideoMFTManager.h',
|
||||||
]
|
]
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
|
'DXVA2Manager.cpp',
|
||||||
'MFTDecoder.cpp',
|
'MFTDecoder.cpp',
|
||||||
'WMFAudioMFTManager.cpp',
|
'WMFAudioMFTManager.cpp',
|
||||||
'WMFDecoderModule.cpp',
|
'WMFDecoderModule.cpp',
|
||||||
@@ -19,8 +23,17 @@ UNIFIED_SOURCES += [
|
|||||||
'WMFVideoMFTManager.cpp',
|
'WMFVideoMFTManager.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SOURCES += [
|
||||||
|
'WMFUtils.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
|
|
||||||
|
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||||
|
DEFINES['NOMINMAX'] = True
|
||||||
|
|
||||||
FAIL_ON_WARNINGS = True
|
FAIL_ON_WARNINGS = True
|
||||||
|
|
||||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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, ×tampHns, 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, ¤tLength);
|
|
||||||
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, ×tamp);
|
|
||||||
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, ×tampHns, 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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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_
|
|
||||||
@@ -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
@@ -669,7 +669,9 @@ Factory::SetDirect3D10Device(ID3D10Device1 *aDevice)
|
|||||||
// do not throw on failure; return error codes and disconnect the device
|
// 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
|
// On Windows 8 error codes are the default, but on Windows 7 the
|
||||||
// default is to throw (or perhaps only with some drivers?)
|
// default is to throw (or perhaps only with some drivers?)
|
||||||
aDevice->SetExceptionMode(0);
|
if (aDevice) {
|
||||||
|
aDevice->SetExceptionMode(0);
|
||||||
|
}
|
||||||
mD3D10Device = aDevice;
|
mD3D10Device = aDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -346,11 +346,11 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
|
|||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
|
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
|
||||||
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
|
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
|
||||||
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
|
((aMoz2DBackend == gfx::BackendType::DIRECT2D && Factory::GetDirect3D10Device()) ||
|
||||||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
|
(aMoz2DBackend == gfx::BackendType::DIRECT2D1_1 && Factory::GetDirect3D11Device())) &&
|
||||||
gfxWindowsPlatform::GetPlatform()->GetD3D10Device() &&
|
|
||||||
aSize.width <= maxTextureSize &&
|
aSize.width <= maxTextureSize &&
|
||||||
aSize.height <= maxTextureSize) {
|
aSize.height <= maxTextureSize)
|
||||||
|
{
|
||||||
texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags);
|
texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags);
|
||||||
}
|
}
|
||||||
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ DeviceManagerD3D9::Init()
|
|||||||
if (!mNv3DVUtils) {
|
if (!mNv3DVUtils) {
|
||||||
mNv3DVUtils = new Nv3DVUtils();
|
mNv3DVUtils = new Nv3DVUtils();
|
||||||
if (!mNv3DVUtils) {
|
if (!mNv3DVUtils) {
|
||||||
NS_WARNING("Could not create a new instance of Nv3DVUtils.\n");
|
NS_WARNING("Could not create a new instance of Nv3DVUtils.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -673,7 +673,7 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (UseVsyncComposition()) {
|
if (UseVsyncComposition()) {
|
||||||
NS_WARNING("Enabling vsync compositor\n");
|
NS_WARNING("Enabling vsync compositor");
|
||||||
mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
|
mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
|
||||||
} else {
|
} else {
|
||||||
mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);
|
mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);
|
||||||
|
|||||||
@@ -32,5 +32,12 @@ FeatureStatusToString(FeatureStatus aStatus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsFeatureStatusFailure(FeatureStatus aStatus)
|
||||||
|
{
|
||||||
|
return aStatus != FeatureStatus::Unused &&
|
||||||
|
aStatus != FeatureStatus::Available;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ enum class FeatureStatus
|
|||||||
};
|
};
|
||||||
|
|
||||||
const char* FeatureStatusToString(FeatureStatus aStatus);
|
const char* FeatureStatusToString(FeatureStatus aStatus);
|
||||||
|
bool IsFeatureStatusFailure(FeatureStatus aStatus);
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ gfxAndroidPlatform::CreateHardwareVsyncSource()
|
|||||||
VsyncSource::Display& display = vsyncSource->GetGlobalDisplay();
|
VsyncSource::Display& display = vsyncSource->GetGlobalDisplay();
|
||||||
display.EnableVsync();
|
display.EnableVsync();
|
||||||
if (!display.IsVsyncEnabled()) {
|
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();
|
return gfxPlatform::CreateHardwareVsyncSource();
|
||||||
}
|
}
|
||||||
display.DisableVsync();
|
display.DisableVsync();
|
||||||
|
|||||||
@@ -2350,7 +2350,7 @@ gfxPlatform::ShouldUseLayersAcceleration()
|
|||||||
if (gfxPrefs::LayersAccelerationForceEnabled()) {
|
if (gfxPrefs::LayersAccelerationForceEnabled()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (gfxPlatform::GetPlatform()->AccelerateLayersByDefault()) {
|
if (AccelerateLayersByDefault()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (acceleratedEnv && *acceleratedEnv != '0') {
|
if (acceleratedEnv && *acceleratedEnv != '0') {
|
||||||
@@ -2426,7 +2426,7 @@ gfxPlatform::UsesOffMainThreadCompositing()
|
|||||||
already_AddRefed<mozilla::gfx::VsyncSource>
|
already_AddRefed<mozilla::gfx::VsyncSource>
|
||||||
gfxPlatform::CreateHardwareVsyncSource()
|
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();
|
nsRefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
|
||||||
return softwareVsync.forget();
|
return softwareVsync.forget();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -673,6 +673,10 @@ public:
|
|||||||
return mCompositorBackend;
|
return mCompositorBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger a test-driven graphics device reset.
|
||||||
|
virtual void TestDeviceReset(DeviceResetReason aReason)
|
||||||
|
{}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
gfxPlatform();
|
gfxPlatform();
|
||||||
virtual ~gfxPlatform();
|
virtual ~gfxPlatform();
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ gfxPlatformMac::gfxPlatformMac()
|
|||||||
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) |
|
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) |
|
||||||
BackendTypeBit(BackendType::SKIA) |
|
BackendTypeBit(BackendType::SKIA) |
|
||||||
BackendTypeBit(BackendType::COREGRAPHICS);
|
BackendTypeBit(BackendType::COREGRAPHICS);
|
||||||
uint32_t contentMask = BackendTypeBit(BackendType::COREGRAPHICS);
|
uint32_t contentMask = BackendTypeBit(BackendType::COREGRAPHICS) |
|
||||||
|
BackendTypeBit(BackendType::SKIA);
|
||||||
InitBackendPrefs(canvasMask, BackendType::COREGRAPHICS,
|
InitBackendPrefs(canvasMask, BackendType::COREGRAPHICS,
|
||||||
contentMask, BackendType::COREGRAPHICS);
|
contentMask, BackendType::COREGRAPHICS);
|
||||||
|
|
||||||
@@ -460,13 +461,26 @@ public:
|
|||||||
OSXDisplay()
|
OSXDisplay()
|
||||||
: mDisplayLink(nullptr)
|
: mDisplayLink(nullptr)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||||
}
|
}
|
||||||
|
|
||||||
~OSXDisplay()
|
~OSXDisplay()
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
mTimer->Cancel();
|
||||||
|
mTimer = nullptr;
|
||||||
DisableVsync();
|
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
|
virtual void EnableVsync() override
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
@@ -479,18 +493,25 @@ public:
|
|||||||
// situations. According to the docs, it is compatible with all displays running on the computer
|
// 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.
|
// But if we have different monitors at different display rates, we may hit issues.
|
||||||
if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
|
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);
|
CVDisplayLinkRelease(mDisplayLink);
|
||||||
|
mDisplayLink = nullptr;
|
||||||
|
|
||||||
// bug 1142708 - When coming back from sleep, there may be no active displays ready yet,
|
// bug 1142708 - When coming back from sleep,
|
||||||
// even if listening for the kIOMessageSystemHasPoweredOn event from OS X sleep notifications.
|
// 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.
|
// Active displays are those that are drawable.
|
||||||
// In these cases, default back to the main display to try to get a vsync event.
|
// bug 1144638 - When changing display configurations and getting
|
||||||
// The alternative would be to keep polling the CGActiveDisplayList for the displays to be ready.
|
// notifications from CGDisplayReconfigurationCallBack, the
|
||||||
if (CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &mDisplayLink) != kCVReturnSuccess) {
|
// callback gets called twice for each active display
|
||||||
MOZ_CRASH("Could not create a CVDisplayLink with either active displays or the main display");
|
// so it's difficult to know when all displays are active.
|
||||||
}
|
// Instead, try again soon. The delay is arbitrary. 100ms chosen
|
||||||
NS_WARNING("Using the CVDisplayLink from the main display\n");
|
// 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) {
|
if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
|
||||||
@@ -538,6 +559,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// Manages the display link render thread
|
// Manages the display link render thread
|
||||||
CVDisplayLinkRef mDisplayLink;
|
CVDisplayLinkRef mDisplayLink;
|
||||||
|
nsRefPtr<nsITimer> mTimer;
|
||||||
}; // OSXDisplay
|
}; // OSXDisplay
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -575,7 +597,7 @@ gfxPlatformMac::CreateHardwareVsyncSource()
|
|||||||
VsyncSource::Display& primaryDisplay = osxVsyncSource->GetGlobalDisplay();
|
VsyncSource::Display& primaryDisplay = osxVsyncSource->GetGlobalDisplay();
|
||||||
primaryDisplay.EnableVsync();
|
primaryDisplay.EnableVsync();
|
||||||
if (!primaryDisplay.IsVsyncEnabled()) {
|
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();
|
return gfxPlatform::CreateHardwareVsyncSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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-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(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.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);
|
DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false);
|
||||||
|
|
||||||
// These times should be in milliseconds
|
// These times should be in milliseconds
|
||||||
|
|||||||
@@ -1320,7 +1320,7 @@ gfxUtils::WriteAsPNG(SourceSurface* aSurface, const char* aFile)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!file) {
|
if (!file) {
|
||||||
NS_WARNING("Failed to open file to create PNG!\n");
|
NS_WARNING("Failed to open file to create PNG!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+413
-290
File diff suppressed because it is too large
Load Diff
@@ -229,9 +229,8 @@ public:
|
|||||||
|
|
||||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||||
IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
|
IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
|
||||||
inline bool DWriteEnabled() { return mUseDirectWrite; }
|
inline bool DWriteEnabled() { return !!mDWriteFactory; }
|
||||||
inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
|
inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
|
||||||
IDWriteTextAnalyzer *GetDWriteAnalyzer() { return mDWriteAnalyzer; }
|
|
||||||
|
|
||||||
IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
|
IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
|
||||||
{ return mRenderingParams[aRenderMode]; }
|
{ return mRenderingParams[aRenderMode]; }
|
||||||
@@ -263,17 +262,20 @@ public:
|
|||||||
}
|
}
|
||||||
bool SupportsApzTouchInput() const override;
|
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
|
// Return the diagnostic status of DirectX initialization. If
|
||||||
// initialization has not been attempted, this returns
|
// initialization has not been attempted, this returns
|
||||||
// FeatureStatus::Unused.
|
// FeatureStatus::Unused.
|
||||||
mozilla::gfx::FeatureStatus GetD3D11Status() const {
|
mozilla::gfx::FeatureStatus GetD3D11Status() const;
|
||||||
return mD3D11Status;
|
mozilla::gfx::FeatureStatus GetD2DStatus() const;
|
||||||
}
|
mozilla::gfx::FeatureStatus GetD2D1Status() const;
|
||||||
mozilla::gfx::FeatureStatus GetD2DStatus() const {
|
|
||||||
return mD2DStatus;
|
|
||||||
}
|
|
||||||
unsigned GetD3D11Version();
|
unsigned GetD3D11Version();
|
||||||
mozilla::gfx::FeatureStatus GetD2D1Status();
|
|
||||||
|
void TestDeviceReset(DeviceResetReason aReason) override;
|
||||||
|
|
||||||
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
|
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
|
||||||
static mozilla::Atomic<size_t> sD3D11MemoryUsed;
|
static mozilla::Atomic<size_t> sD3D11MemoryUsed;
|
||||||
@@ -286,6 +288,7 @@ protected:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
|
void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
|
||||||
|
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RenderMode mRenderMode;
|
RenderMode mRenderMode;
|
||||||
@@ -296,34 +299,25 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
void InitD3D11Devices();
|
void InitializeDevices();
|
||||||
|
void InitializeD3D11();
|
||||||
|
void InitializeD2D();
|
||||||
|
bool InitializeD2D1();
|
||||||
|
bool InitDWriteSupport();
|
||||||
|
|
||||||
// Used by InitD3D11Devices().
|
void DisableD2D();
|
||||||
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);
|
|
||||||
|
|
||||||
// Used by UpdateRenderMode().
|
mozilla::gfx::FeatureStatus CheckD3D11Support(bool* aCanUseHardware);
|
||||||
mozilla::gfx::FeatureStatus InitD2DSupport();
|
void AttemptD3D11DeviceCreation();
|
||||||
void InitDWriteSupport();
|
void AttemptWARPDeviceCreation();
|
||||||
|
void AttemptD3D11ImageBridgeDeviceCreation();
|
||||||
|
bool AttemptD3D11ContentDeviceCreation();
|
||||||
|
|
||||||
IDXGIAdapter1 *GetDXGIAdapter();
|
IDXGIAdapter1 *GetDXGIAdapter();
|
||||||
bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
|
bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
|
||||||
|
|
||||||
bool mUseDirectWrite;
|
|
||||||
bool mUsingGDIFonts;
|
|
||||||
|
|
||||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||||
nsRefPtr<IDWriteFactory> mDWriteFactory;
|
nsRefPtr<IDWriteFactory> mDWriteFactory;
|
||||||
nsRefPtr<IDWriteTextAnalyzer> mDWriteAnalyzer;
|
|
||||||
nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
|
nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
|
||||||
DWRITE_MEASURING_MODE mMeasuringMode;
|
DWRITE_MEASURING_MODE mMeasuringMode;
|
||||||
#endif
|
#endif
|
||||||
@@ -333,17 +327,21 @@ private:
|
|||||||
mozilla::RefPtr<ID3D11Device> mD3D11Device;
|
mozilla::RefPtr<ID3D11Device> mD3D11Device;
|
||||||
mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
|
mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
|
||||||
mozilla::RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
|
mozilla::RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
|
||||||
bool mD3D11DeviceInitialized;
|
|
||||||
mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
|
mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
|
||||||
bool mIsWARP;
|
bool mIsWARP;
|
||||||
bool mHasDeviceReset;
|
bool mHasDeviceReset;
|
||||||
|
bool mHasFakeDeviceReset;
|
||||||
bool mDoesD3D11TextureSharingWork;
|
bool mDoesD3D11TextureSharingWork;
|
||||||
DeviceResetReason mDeviceResetReason;
|
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 mD3D11Status;
|
||||||
mozilla::gfx::FeatureStatus mD2DStatus;
|
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 */
|
#endif /* GFX_WINDOWS_PLATFORM_H */
|
||||||
|
|||||||
@@ -859,7 +859,7 @@ CreateVsyncRefreshTimer()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_WARNING("Enabling vsync refresh driver\n");
|
NS_WARNING("Enabling vsync refresh driver");
|
||||||
|
|
||||||
if (XRE_IsParentProcess()) {
|
if (XRE_IsParentProcess()) {
|
||||||
// Make sure all vsync systems are ready.
|
// Make sure all vsync systems are ready.
|
||||||
|
|||||||
Reference in New Issue
Block a user