Bug 1132832 - Remove media resource API from PlatformDecoderModule. r=jya

This commit is contained in:
Alfredo Yang 2015-04-10 02:16:00 -04:00
parent 563d53c18a
commit c156487302
18 changed files with 106 additions and 279 deletions

View File

@ -157,7 +157,6 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mDemuxerInitialized(false)
, mFoundSPSForTelemetry(false)
, mIsEncrypted(false)
, mAreDecodersSetup(false)
, mIndexReady(false)
, mLastSeenEnd(-1)
, mDemuxerMonitor("MP4 Demuxer")
@ -294,12 +293,6 @@ private:
};
#endif // MOZ_EME
void MP4Reader::RequestCodecResource() {
if (mVideo.mDecoder) {
mVideo.mDecoder->AllocateMediaResources();
}
}
bool MP4Reader::IsWaitingMediaResources() {
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
}
@ -357,14 +350,6 @@ MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType)
mPlatform->SupportsMimeType(aMimeType);
}
void
MP4Reader::PreReadMetadata()
{
if (mPlatform) {
RequestCodecResource();
}
}
bool
MP4Reader::InitDemuxer()
{
@ -408,7 +393,6 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
} else if (mPlatform && !IsWaitingMediaResources()) {
*aInfo = mInfo;
*aTags = nullptr;
return NS_OK;
}
if (HasAudio()) {
@ -461,7 +445,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
*aInfo = mInfo;
*aTags = nullptr;
if (!IsWaitingMediaResources() && !IsWaitingOnCDMResource()) {
if (!IsWaitingOnCDMResource()) {
NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE);
}
@ -471,11 +455,28 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
return NS_OK;
}
bool MP4Reader::CheckIfDecoderSetup()
{
if (!mDemuxerInitialized) {
return false;
}
if (HasAudio() && !mAudio.mDecoder) {
return false;
}
if (HasVideo() && !mVideo.mDecoder) {
return false;
}
return true;
}
bool
MP4Reader::EnsureDecodersSetup()
{
if (mAreDecodersSetup) {
return !!mPlatform;
if (CheckIfDecoderSetup()) {
return true;
}
if (mIsEncrypted) {
@ -507,8 +508,11 @@ MP4Reader::EnsureDecodersSetup()
return false;
#endif
} else {
mPlatform = PlatformDecoderModule::Create();
NS_ENSURE_TRUE(mPlatform, false);
// mPlatform doesn't need to be recreated when resuming from dormant.
if (!mPlatform) {
mPlatform = PlatformDecoderModule::Create();
NS_ENSURE_TRUE(mPlatform, false);
}
}
if (HasAudio()) {
@ -549,7 +553,6 @@ MP4Reader::EnsureDecodersSetup()
NS_ENSURE_SUCCESS(rv, false);
}
mAreDecodersSetup = true;
return true;
}
@ -1125,13 +1128,8 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
bool MP4Reader::IsDormantNeeded()
{
#if defined(MP4_READER_DORMANT)
return
#if defined(MP4_READER_DORMANT_HEURISTIC)
mDormantEnabled &&
#endif
mVideo.mDecoder &&
mVideo.mDecoder->IsDormantNeeded();
return mDormantEnabled;
#else
return false;
#endif
@ -1146,7 +1144,8 @@ void MP4Reader::ReleaseMediaResources()
container->ClearCurrentFrame();
}
if (mVideo.mDecoder) {
mVideo.mDecoder->ReleaseMediaResources();
mVideo.mDecoder->Shutdown();
mVideo.mDecoder = nullptr;
}
}

View File

@ -28,12 +28,6 @@ typedef std::deque<nsRefPtr<MediaRawData>> MediaSampleQueue;
class MP4Stream;
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
#define MP4_READER_DORMANT
#else
#undef MP4_READER_DORMANT
#endif
#if defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG)
#define MP4_READER_DORMANT_HEURISTIC
#else
#undef MP4_READER_DORMANT_HEURISTIC
@ -61,11 +55,6 @@ public:
virtual bool HasAudio() override;
virtual bool HasVideo() override;
// PreReadMetadata() is called by MediaDecoderStateMachine::DecodeMetadata()
// before checking hardware resource. In Gonk, it requests hardware codec so
// MediaDecoderStateMachine could go to DORMANT state if the hardware codec is
// not available.
virtual void PreReadMetadata() override;
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) override;
@ -106,6 +95,8 @@ private:
bool EnsureDecodersSetup();
bool CheckIfDecoderSetup();
// Sends input to decoder for aTrack, and output to the state machine,
// if necessary.
void Update(TrackType aTrack);
@ -137,7 +128,6 @@ private:
bool IsSupportedAudioMimeType(const nsACString& aMimeType);
bool IsSupportedVideoMimeType(const nsACString& aMimeType);
void NotifyResourcesStatusChanged();
void RequestCodecResource();
virtual bool IsWaitingOnCDMResource() override;
Microseconds GetNextKeyframeTime();
@ -289,8 +279,6 @@ private:
// Synchronized by decoder monitor.
bool mIsEncrypted;
bool mAreDecodersSetup;
bool mIndexReady;
int64_t mLastSeenEnd;
Monitor mDemuxerMonitor;

View File

@ -256,11 +256,6 @@ public:
virtual bool IsWaitingMediaResources() {
return false;
};
virtual bool IsDormantNeeded() {
return false;
};
virtual void AllocateMediaResources() {}
virtual void ReleaseMediaResources() {}
virtual bool IsHardwareAccelerated() const { return false; }
// ConfigurationChanged will be called to inform the video or audio decoder

View File

@ -142,11 +142,6 @@ SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
mActiveProxy = aProxy;
mActiveCallback = aProxy->mCallback;
if (mDecoderReleasedResources) {
mDecoder->AllocateMediaResources();
mDecoderReleasedResources = false;
}
}
void
@ -176,14 +171,6 @@ SharedDecoderManager::DrainComplete()
}
}
void
SharedDecoderManager::ReleaseMediaResources()
{
mDecoderReleasedResources = true;
mDecoder->ReleaseMediaResources();
mActiveProxy = nullptr;
}
void
SharedDecoderManager::Shutdown()
{
@ -262,20 +249,6 @@ SharedDecoderProxy::IsWaitingMediaResources()
return mManager->mActiveProxy != nullptr;
}
bool
SharedDecoderProxy::IsDormantNeeded()
{
return mManager->mDecoder->IsDormantNeeded();
}
void
SharedDecoderProxy::ReleaseMediaResources()
{
if (mManager->mActiveProxy == this) {
mManager->ReleaseMediaResources();
}
}
bool
SharedDecoderProxy::IsHardwareAccelerated() const
{

View File

@ -74,8 +74,6 @@ public:
virtual nsresult Drain() override;
virtual nsresult Shutdown() override;
virtual bool IsWaitingMediaResources() override;
virtual bool IsDormantNeeded() override;
virtual void ReleaseMediaResources() override;
virtual bool IsHardwareAccelerated() const override;
friend class SharedDecoderManager;

View File

@ -73,10 +73,15 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
mLooper->setName("GonkAudioDecoderManager");
mLooper->start();
mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, false, nullptr);
mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, nullptr);
if (!mDecoder.get()) {
return nullptr;
}
if (!mDecoder->AskMediaCodecAndWait())
{
mDecoder = nullptr;
return nullptr;
}
sp<AMessage> format = new AMessage;
// Fixed values
GADM_LOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate);

View File

@ -137,15 +137,23 @@ GonkMediaDataDecoder::~GonkMediaDataDecoder()
nsresult
GonkMediaDataDecoder::Init()
{
mDecoder = mManager->Init(mCallback);
sp<MediaCodecProxy> decoder;
decoder = mManager->Init(mCallback);
mDecoder = decoder;
mDrainComplete = false;
return mDecoder.get() ? NS_OK : NS_ERROR_UNEXPECTED;
return NS_OK;
}
nsresult
GonkMediaDataDecoder::Shutdown()
{
if (!mDecoder.get()) {
return NS_OK;
}
mDecoder->stop();
mDecoder->ReleaseMediaResources();
mDecoder = nullptr;
return NS_OK;
}
@ -256,19 +264,10 @@ GonkMediaDataDecoder::Drain()
bool
GonkMediaDataDecoder::IsWaitingMediaResources() {
return mDecoder->IsWaitingResources();
}
void
GonkMediaDataDecoder::AllocateMediaResources()
{
mManager->AllocateMediaResources();
}
void
GonkMediaDataDecoder::ReleaseMediaResources()
{
mManager->ReleaseMediaResources();
if (!mDecoder.get()) {
return true;
}
return false;
}
} // namespace mozilla

View File

@ -44,10 +44,6 @@ public:
// in the overrided function.
virtual nsresult Flush();
virtual void AllocateMediaResources() {}
virtual void ReleaseMediaResources() {}
// It should be called in MediaTash thread.
bool HasQueuedSample() {
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
@ -100,12 +96,6 @@ public:
virtual bool IsWaitingMediaResources() override;
virtual bool IsDormantNeeded() { return true;}
virtual void AllocateMediaResources() override;
virtual void ReleaseMediaResources() override;
private:
// Called on the task queue. Inserts the sample into the decoder, and

View File

@ -43,10 +43,6 @@ using namespace android;
typedef android::MediaCodecProxy MediaCodecProxy;
namespace mozilla {
enum {
kNotifyCodecReserved = 'core',
kNotifyCodecCanceled = 'coca',
};
GonkVideoDecoderManager::GonkVideoDecoderManager(
MediaTaskQueue* aTaskQueue,
@ -112,13 +108,17 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
if (mLooper->start() != OK || mManagerLooper->start() != OK ) {
return nullptr;
}
mDecoder = MediaCodecProxy::CreateByType(mLooper, "video/avc", false, true, mVideoListener);
mDecoder = MediaCodecProxy::CreateByType(mLooper, "video/avc", false, mVideoListener);
mDecoder->AskMediaCodecAndWait();
uint32_t capability = MediaCodecProxy::kEmptyCapability;
if (mDecoder->getCapability(&capability) == OK && (capability &
MediaCodecProxy::kCanExposeGraphicBuffer)) {
mNativeWindow = new GonkNativeWindow();
}
mReaderCallback->NotifyResourcesStatusChanged();
return mDecoder;
}
@ -488,15 +488,10 @@ GonkVideoDecoderManager::Flush()
return NS_OK;
}
void
GonkVideoDecoderManager::AllocateMediaResources()
{
mDecoder->RequestMediaResources();
}
void
GonkVideoDecoderManager::codecReserved()
{
GVDM_LOG("codecReserved");
sp<AMessage> format = new AMessage;
sp<Surface> surface;
@ -509,24 +504,12 @@ GonkVideoDecoderManager::codecReserved()
}
mDecoder->configure(format, surface, nullptr, 0);
mDecoder->Prepare();
if (mHandler != nullptr) {
// post kNotifyCodecReserved to Looper thread.
sp<AMessage> notify = new AMessage(kNotifyCodecReserved, mHandler->id());
notify->post();
}
}
void
GonkVideoDecoderManager::codecCanceled()
{
mDecoder = nullptr;
if (mHandler != nullptr) {
// post kNotifyCodecCanceled to Looper thread.
sp<AMessage> notify = new AMessage(kNotifyCodecCanceled, mHandler->id());
notify->post();
}
}
// Called on GonkVideoDecoderManager::mManagerLooper thread.
@ -534,21 +517,6 @@ void
GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
{
switch (aMessage->what()) {
case kNotifyCodecReserved:
{
// Our decode may have acquired the hardware resource that it needs
// to start. Notify the state machine to resume loading metadata.
GVDM_LOG("CodecReserved!");
mReaderCallback->NotifyResourcesStatusChanged();
break;
}
case kNotifyCodecCanceled:
{
mReaderCallback->ReleaseMediaResources();
break;
}
case kNotifyPostReleaseBuffer:
{
ReleaseAllPendingVideoBuffers();

View File

@ -51,8 +51,6 @@ public:
virtual nsresult Flush() override;
virtual void AllocateMediaResources();
virtual void ReleaseMediaResources();
static void RecycleCallback(TextureClient* aClient, void* aClosure);
@ -146,7 +144,6 @@ private:
android::sp<MediaCodecProxy> mDecoder;
nsRefPtr<layers::ImageContainer> mImageContainer;
MediaDataDecoderCallback* mCallback;
android::MediaBuffer* mVideoBuffer;
@ -179,7 +176,6 @@ private:
Vector<android::MediaBuffer*> mPendingVideoBuffers;
// The lock protects mPendingVideoBuffers.
Mutex mPendingVideoBuffersLock;
};
} // namespace mozilla

View File

@ -66,13 +66,6 @@ WMFMediaDataDecoder::ProcessShutdown()
mDecoder = nullptr;
}
void
WMFMediaDataDecoder::ProcessReleaseDecoder()
{
mMFTManager->Shutdown();
mDecoder = nullptr;
}
// Inserts data into the decoder's pipeline.
nsresult
WMFMediaDataDecoder::Input(MediaRawData* aSample)
@ -157,24 +150,6 @@ WMFMediaDataDecoder::Drain()
return NS_OK;
}
void
WMFMediaDataDecoder::AllocateMediaResources()
{
mDecoder = mMFTManager->Init();
}
void
WMFMediaDataDecoder::ReleaseMediaResources()
{
DebugOnly<nsresult> rv = mTaskQueue->FlushAndDispatch(
NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessReleaseDecoder));
#ifdef DEBUG
if (NS_FAILED(rv)) {
NS_WARNING("WMFMediaDataDecoder::ReleaseMediaResources() dispatch of task failed!");
}
#endif
}
bool
WMFMediaDataDecoder::IsHardwareAccelerated() const {
return mMFTManager && mMFTManager->IsHardwareAccelerated();

View File

@ -70,9 +70,6 @@ public:
virtual nsresult Shutdown() override;
virtual bool IsWaitingMediaResources() { return false; };
virtual bool IsDormantNeeded() { return true; };
virtual void AllocateMediaResources() override;
virtual void ReleaseMediaResources() override;
virtual bool IsHardwareAccelerated() const override;
private:
@ -90,7 +87,6 @@ private:
void ProcessDrain();
void ProcessShutdown();
void ProcessReleaseDecoder();
RefPtr<FlushableMediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;

View File

@ -122,40 +122,6 @@ H264Converter::IsWaitingMediaResources()
return MediaDataDecoder::IsWaitingMediaResources();
}
bool
H264Converter::IsDormantNeeded()
{
if (mNeedAVCC) {
return true;
}
return mDecoder ?
mDecoder->IsDormantNeeded() : MediaDataDecoder::IsDormantNeeded();
}
void
H264Converter::AllocateMediaResources()
{
if (mNeedAVCC) {
// Nothing to do, decoder will be allocated on the fly when required.
return;
}
if (mDecoder) {
mDecoder->AllocateMediaResources();
}
}
void
H264Converter::ReleaseMediaResources()
{
if (mNeedAVCC) {
Shutdown();
return;
}
if (mDecoder) {
mDecoder->ReleaseMediaResources();
}
}
bool
H264Converter::IsHardwareAccelerated() const
{
@ -219,7 +185,7 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
// The SPS has changed, signal to flush the current decoder and create a
// new one.
mDecoder->Flush();
ReleaseMediaResources();
Shutdown();
return CreateDecoderAndInit(aSample);
}

View File

@ -35,9 +35,6 @@ public:
virtual nsresult Drain() override;
virtual nsresult Shutdown() override;
virtual bool IsWaitingMediaResources() override;
virtual bool IsDormantNeeded() override;
virtual void AllocateMediaResources() override;
virtual void ReleaseMediaResources() override;
virtual bool IsHardwareAccelerated() const override;
// Return true if mimetype is H.264.

View File

@ -78,42 +78,38 @@ sp<MediaCodecProxy>
MediaCodecProxy::CreateByType(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync,
wp<CodecResourceListener> aListener)
{
sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper, aMime, aEncoder, aAsync, aListener);
if ((!aAsync && codec->allocated()) || codec->requestResource()) {
return codec;
}
return nullptr;
sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper,
aMime,
aEncoder,
aListener);
return codec;
}
MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync,
wp<CodecResourceListener> aListener)
: mCodecLooper(aLooper)
, mCodecMime(aMime)
, mCodecEncoder(aEncoder)
, mListener(aListener)
, mMediaCodecLock("MediaCodecProxy::mMediaCodecLock")
, mPendingRequestMediaResource(false)
{
MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
if (aAsync) {
mResourceHandler = new MediaResourceHandler(this);
} else {
allocateCodec();
}
mResourceHandler = new MediaResourceHandler(this);
}
MediaCodecProxy::~MediaCodecProxy()
{
releaseCodec();
cancelResource();
SetMediaCodecFree();
}
bool
MediaCodecProxy::requestResource()
MediaCodecProxy::AskMediaCodecAndWait()
{
if (mResourceHandler == nullptr) {
return false;
@ -124,30 +120,39 @@ MediaCodecProxy::requestResource()
? IMediaResourceManagerService::HW_VIDEO_ENCODER
: IMediaResourceManagerService::HW_VIDEO_DECODER);
} else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
mResourceHandler->requestResource(mCodecEncoder
? IMediaResourceManagerService::HW_AUDIO_ENCODER
: IMediaResourceManagerService::HW_AUDIO_DECODER);
if (allocateCodec()) {
return true;
}
} else {
return false;
}
mozilla::MonitorAutoLock mon(mMediaCodecLock);
mPendingRequestMediaResource = true;
while (mPendingRequestMediaResource) {
mMediaCodecLock.Wait();
}
MCP_LOG("AskMediaCodecAndWait complete");
return true;
}
void
MediaCodecProxy::RequestMediaResources()
{
requestResource();
}
void
MediaCodecProxy::cancelResource()
MediaCodecProxy::SetMediaCodecFree()
{
if (mResourceHandler == nullptr) {
return;
}
mozilla::MonitorAutoLock mon(mMediaCodecLock);
if (mPendingRequestMediaResource) {
mPendingRequestMediaResource = false;
mon.NotifyAll();
}
mResourceHandler->cancelResource();
mResourceHandler = nullptr;
}
bool
@ -462,13 +467,19 @@ MediaCodecProxy::getCapability(uint32_t *aCapability)
void
MediaCodecProxy::resourceReserved()
{
MCP_LOG("resourceReserved");
// Create MediaCodec
releaseCodec();
if (!allocateCodec()) {
cancelResource();
SetMediaCodecFree();
return;
}
// Notify initialization waiting.
mozilla::MonitorAutoLock mon(mMediaCodecLock);
mPendingRequestMediaResource = false;
mon.NotifyAll();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
@ -476,20 +487,6 @@ MediaCodecProxy::resourceReserved()
}
}
// Called on a Binder thread
void
MediaCodecProxy::resourceCanceled()
{
// Release MediaCodec
releaseCodec();
// Notification
sp<CodecResourceListener> listener = mListener.promote();
if (listener != nullptr) {
listener->codecCanceled();
}
}
bool MediaCodecProxy::Prepare()
{
@ -611,23 +608,10 @@ status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
return err;
}
bool MediaCodecProxy::IsWaitingResources()
{
if (mResourceHandler.get()) {
return mResourceHandler->IsWaitingResource();
}
return false;
}
bool MediaCodecProxy::IsDormantNeeded()
{
return mCodecLooper.get() ? true : false;
}
void MediaCodecProxy::ReleaseMediaResources()
{
releaseCodec();
cancelResource();
SetMediaCodecFree();
}
void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {

View File

@ -12,6 +12,7 @@
#include <stagefright/MediaBuffer.h>
#include <utils/threads.h>
#include "MediaResourceHandler.h"
#include "mozilla/Monitor.h"
namespace android {
// This class is intended to be a proxy for MediaCodec with codec resource
@ -55,7 +56,6 @@ public:
static sp<MediaCodecProxy> CreateByType(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync=false,
wp<CodecResourceListener> aListener=nullptr);
// MediaCodec methods
@ -129,22 +129,26 @@ public:
int64_t aTimestampUsecs, uint64_t flags);
status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs);
bool Prepare();
bool IsWaitingResources();
bool IsDormantNeeded();
void RequestMediaResources();
void ReleaseMediaResources();
// This updates mOutputBuffer when receiving INFO_OUTPUT_BUFFERS_CHANGED event.
bool UpdateOutputBuffers();
void ReleaseMediaBuffer(MediaBuffer* abuffer);
// It asks for the OMX codec and blocked until the resource is grant to be
// allocated.
bool AskMediaCodecAndWait();
// Free the OMX codec so others can allocate it.
void SetMediaCodecFree();
protected:
virtual ~MediaCodecProxy();
// MediaResourceHandler::EventListener::resourceReserved()
virtual void resourceReserved();
// MediaResourceHandler::EventListener::resourceCanceled()
virtual void resourceCanceled();
virtual void resourceCanceled() {}
private:
// Forbidden
@ -156,14 +160,8 @@ private:
MediaCodecProxy(sp<ALooper> aLooper,
const char *aMime,
bool aEncoder,
bool aAsync,
wp<CodecResourceListener> aListener);
// Request Resource
bool requestResource();
// Cancel Resource
void cancelResource();
// Allocate Codec Resource
bool allocateCodec();
// Release Codec Resource
@ -188,6 +186,8 @@ private:
Vector<sp<ABuffer> > mInputBuffers;
Vector<sp<ABuffer> > mOutputBuffers;
mozilla::Monitor mMediaCodecLock;
bool mPendingRequestMediaResource;
};
} // namespace android

View File

@ -1322,7 +1322,7 @@ MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
const char* mime;
if (sourceFormat->findCString(kKeyMIMEType, &mime)) {
aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aAsync, aListener);
aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aListener);
}
if (aTrack.mCodec == nullptr) {

View File

@ -270,10 +270,8 @@ pref("media.play-stand-alone", true);
pref("media.hardware-video-decoding.enabled", true);
#if defined(XP_WIN)
pref("media.decoder.heuristic.dormant.enabled", true);
pref("media.decoder.heuristic.dormant.timeout", 60000);
#endif
#ifdef MOZ_WMF
pref("media.windows-media-foundation.enabled", true);