From fb0816d02d6cbe6d8eb422811d5a61b2cbffda01 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Mon, 10 Jun 2013 08:22:05 -0400 Subject: [PATCH] Bug 871485 - Share hw codec between applications/tasks. r=mwu, r=doublec, r=roc --- content/html/content/src/HTMLMediaElement.cpp | 5 + content/media/MediaDecoder.cpp | 48 ++- content/media/MediaDecoder.h | 10 + content/media/MediaDecoderReader.h | 7 + content/media/MediaDecoderStateMachine.cpp | 90 +++++ content/media/MediaDecoderStateMachine.h | 11 + content/media/moz.build | 1 + content/media/omx/Makefile.in | 1 + content/media/omx/MediaOmxReader.cpp | 30 +- content/media/omx/MediaOmxReader.h | 5 + content/media/omx/OMXCodecProxy.cpp | 241 +++++++++++++ content/media/omx/OMXCodecProxy.h | 100 ++++++ content/media/omx/OmxDecoder.cpp | 322 ++++++++++-------- content/media/omx/OmxDecoder.h | 13 +- .../IMediaResourceManagerClient.cpp | 62 ++++ .../IMediaResourceManagerClient.h | 43 +++ .../IMediaResourceManagerDeathNotifier.cpp | 114 +++++++ .../IMediaResourceManagerDeathNotifier.h | 67 ++++ .../IMediaResourceManagerService.cpp | 86 +++++ .../IMediaResourceManagerService.h | 47 +++ .../omx/mediaresourcemanager/Makefile.in | 27 ++ .../MediaResourceManagerClient.cpp | 40 +++ .../MediaResourceManagerClient.h | 51 +++ .../MediaResourceManagerService.cpp | 179 ++++++++++ .../MediaResourceManagerService.h | 95 ++++++ .../media/omx/mediaresourcemanager/moz.build | 16 + content/media/omx/moz.build | 1 + layout/build/Makefile.in | 1 + widget/gonk/Makefile.in | 1 + widget/gonk/nsAppShell.cpp | 5 + 30 files changed, 1564 insertions(+), 155 deletions(-) create mode 100644 content/media/omx/OMXCodecProxy.cpp create mode 100644 content/media/omx/OMXCodecProxy.h create mode 100644 content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp create mode 100644 content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h create mode 100644 content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp create mode 100644 content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h create mode 100644 content/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp create mode 100644 content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h create mode 100644 content/media/omx/mediaresourcemanager/Makefile.in create mode 100644 content/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp create mode 100644 content/media/omx/mediaresourcemanager/MediaResourceManagerClient.h create mode 100644 content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp create mode 100644 content/media/omx/mediaresourcemanager/MediaResourceManagerService.h create mode 100644 content/media/omx/mediaresourcemanager/moz.build diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp index 517f552f134..8321e9234a9 100644 --- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -3244,6 +3244,11 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() { nsIDocument* ownerDoc = OwnerDoc(); + + if (mDecoder) { + mDecoder->SetDormantIfNecessary(ownerDoc->Hidden()); + } + // SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the // CanPlayChanged callback. if (UseAudioChannelService() && mPlayingThroughTheAudioChannel && diff --git a/content/media/MediaDecoder.cpp b/content/media/MediaDecoder.cpp index e3d0c802a02..c16dee4db48 100644 --- a/content/media/MediaDecoder.cpp +++ b/content/media/MediaDecoder.cpp @@ -112,11 +112,47 @@ public: NS_IMPL_THREADSAFE_ISUPPORTS1(MediaDecoder, nsIObserver) +void MediaDecoder::SetDormantIfNecessary(bool aDormant) +{ + MOZ_ASSERT(NS_IsMainThread()); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + + if (!mDecoderStateMachine || !mDecoderStateMachine->IsDormantNeeded() || (mPlayState == PLAY_STATE_SHUTDOWN)) { + return; + } + + if (mIsDormant == aDormant) { + // no change to dormant state + return; + } + + if(aDormant) { + // enter dormant state + StopProgress(); + DestroyDecodedStream(); + mDecoderStateMachine->SetDormant(true); + + mRequestedSeekTime = mCurrentTime; + if (mPlayState == PLAY_STATE_PLAYING){ + mNextState = PLAY_STATE_PLAYING; + } else { + mNextState = PLAY_STATE_PAUSED; + } + mNextState = mPlayState; + mIsDormant = aDormant; + ChangeState(PLAY_STATE_LOADING); + } else if ((aDormant != true) && (mPlayState == PLAY_STATE_LOADING)) { + // exit dormant state + // just trigger to state machine. + mDecoderStateMachine->SetDormant(false); + } +} + void MediaDecoder::Pause() { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - if (mPlayState == PLAY_STATE_SEEKING || mPlayState == PLAY_STATE_ENDED) { + if ((mPlayState == PLAY_STATE_LOADING && mIsDormant) || mPlayState == PLAY_STATE_SEEKING || mPlayState == PLAY_STATE_ENDED) { mNextState = PLAY_STATE_PAUSED; return; } @@ -333,6 +369,7 @@ MediaDecoder::MediaDecoder() : mTransportSeekable(true), mMediaSeekable(true), mReentrantMonitor("media.decoder"), + mIsDormant(false), mPlayState(PLAY_STATE_PAUSED), mNextState(PLAY_STATE_PAUSED), mCalledResourceLoaded(false), @@ -519,7 +556,7 @@ nsresult MediaDecoder::Play() NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine."); nsresult res = ScheduleStateMachineThread(); NS_ENSURE_SUCCESS(res,res); - if (mPlayState == PLAY_STATE_SEEKING) { + if ((mPlayState == PLAY_STATE_LOADING && mIsDormant) || mPlayState == PLAY_STATE_SEEKING) { mNextState = PLAY_STATE_PLAYING; return NS_OK; } @@ -619,7 +656,7 @@ nsresult MediaDecoder::Seek(double aTime) // If we are already in the seeking state, then setting mRequestedSeekTime // above will result in the new seek occurring when the current seek // completes. - if (mPlayState != PLAY_STATE_SEEKING) { + if ((mPlayState != PLAY_STATE_LOADING || !mIsDormant) && mPlayState != PLAY_STATE_SEEKING) { bool paused = false; if (mOwner) { paused = mOwner->GetPaused(); @@ -1160,6 +1197,11 @@ void MediaDecoder::ChangeState(PlayState aState) break; } } + + if (aState!= PLAY_STATE_LOADING) { + mIsDormant = false; + } + GetReentrantMonitor().NotifyAll(); } diff --git a/content/media/MediaDecoder.h b/content/media/MediaDecoder.h index eda871cfffb..a20dd328f99 100644 --- a/content/media/MediaDecoder.h +++ b/content/media/MediaDecoder.h @@ -332,6 +332,12 @@ public: // called. virtual nsresult Play(); + // Set/Unset dormant state if necessary. + // Dormant state is a state to free all scarce media resources + // (like hw video codec), did not decoding and stay dormant. + // It is used to share scarece media resources in system. + virtual void SetDormantIfNecessary(bool aDormant); + // Pause video playback. virtual void Pause(); // Adjust the speed of the playback, optionally with pitch correction, @@ -1000,6 +1006,10 @@ public: // without holding the monitor. nsAutoPtr mDecodedStream; + // True if this decoder is in dormant state. + // Should be true only when PlayState is PLAY_STATE_LOADING. + bool mIsDormant; + // Set to one of the valid play states. // This can only be changed on the main thread while holding the decoder // monitor. Thus, it can be safely read while holding the decoder monitor diff --git a/content/media/MediaDecoderReader.h b/content/media/MediaDecoderReader.h index e7cef26c2ee..47f128cf9ad 100644 --- a/content/media/MediaDecoderReader.h +++ b/content/media/MediaDecoderReader.h @@ -407,6 +407,13 @@ public: // on failure. virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0; + // True if this reader is waiting media resource allocation + virtual bool IsWaitingMediaResources() { return false; } + // True when this reader need to become dormant state + virtual bool IsDormantNeeded() { return false; } + // Release media resources they should be released in dormant state + virtual void ReleaseMediaResources() {}; + // Resets all state related to decoding, emptying all buffers etc. virtual nsresult ResetDecode(); diff --git a/content/media/MediaDecoderStateMachine.cpp b/content/media/MediaDecoderStateMachine.cpp index ef9b79577c4..48a6fa34511 100644 --- a/content/media/MediaDecoderStateMachine.cpp +++ b/content/media/MediaDecoderStateMachine.cpp @@ -503,12 +503,28 @@ void MediaDecoderStateMachine::DecodeThreadRun() while (mState != DECODER_STATE_SHUTDOWN && mState != DECODER_STATE_COMPLETED && + mState != DECODER_STATE_DORMANT && !mStopDecodeThread) { if (mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) { DecodeLoop(); } else if (mState == DECODER_STATE_SEEKING) { DecodeSeek(); + } else if (mState == DECODER_STATE_DECODING_METADATA) { + if (NS_FAILED(DecodeMetadata())) { + NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN, + "Should be in shutdown state if metadata loading fails."); + LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread")); + } + } else if (mState == DECODER_STATE_WAIT_FOR_RESOURCES) { + mDecoder->GetReentrantMonitor().Wait(); + + if (!mReader->IsWaitingMediaResources()) { + // change state to DECODER_STATE_WAIT_FOR_RESOURCES + StartDecodeMetadata(); + } + } else if (mState == DECODER_STATE_DORMANT) { + mDecoder->GetReentrantMonitor().Wait(); } } @@ -953,6 +969,7 @@ void MediaDecoderStateMachine::DecodeLoop() if (!mStopDecodeThread && mState != DECODER_STATE_SHUTDOWN && + mState != DECODER_STATE_DORMANT && mState != DECODER_STATE_SEEKING) { mState = DECODER_STATE_COMPLETED; @@ -1457,6 +1474,33 @@ void MediaDecoderStateMachine::SetMediaSeekable(bool aMediaSeekable) mMediaSeekable = aMediaSeekable; } +bool MediaDecoderStateMachine::IsDormantNeeded() +{ + return mReader->IsDormantNeeded(); +} + +void MediaDecoderStateMachine::SetDormant(bool aDormant) +{ + NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); + mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); + + if (!mReader) { + return; + } + + if (aDormant) { + ScheduleStateMachine(); + mState = DECODER_STATE_DORMANT; + mDecoder->GetReentrantMonitor().NotifyAll(); + } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) { + ScheduleStateMachine(); + mStartTime = 0; + mCurrentFrameTime = 0; + mState = DECODER_STATE_DECODING_METADATA; + mDecoder->GetReentrantMonitor().NotifyAll(); + } +} + void MediaDecoderStateMachine::Shutdown() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); @@ -1484,6 +1528,22 @@ void MediaDecoderStateMachine::StartDecoding() ScheduleStateMachine(); } +void MediaDecoderStateMachine::StartWaitForResources() +{ + NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(), + "Should be on state machine or decode thread."); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + mState = DECODER_STATE_WAIT_FOR_RESOURCES; +} + +void MediaDecoderStateMachine::StartDecodeMetadata() +{ + NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(), + "Should be on state machine or decode thread."); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + mState = DECODER_STATE_DECODING_METADATA; +} + void MediaDecoderStateMachine::Play() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); @@ -1815,6 +1875,12 @@ nsresult MediaDecoderStateMachine::DecodeMetadata() ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); res = mReader->ReadMetadata(&info, &tags); } + if (NS_SUCCEEDED(res) && (mState == DECODER_STATE_DECODING_METADATA) && (mReader->IsWaitingMediaResources())) { + // change state to DECODER_STATE_WAIT_FOR_RESOURCES + StartWaitForResources(); + return NS_OK; + } + mInfo = info; if (NS_FAILED(res) || (!info.mHasVideo && !info.mHasAudio)) { @@ -2081,6 +2147,10 @@ nsresult MediaDecoderStateMachine::RunStateMachine() // Now that those threads are stopped, there's no possibility of // mPendingWakeDecoder being needed again. Revoke it. mPendingWakeDecoder = nullptr; + { + ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); + mReader->ReleaseMediaResources(); + } NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN, "How did we escape from the shutdown state?"); // We must daisy-chain these events to destroy the decoder. We must @@ -2100,6 +2170,26 @@ nsresult MediaDecoderStateMachine::RunStateMachine() return NS_OK; } + case DECODER_STATE_DORMANT: { + if (IsPlaying()) { + StopPlayback(); + } + StopAudioThread(); + StopDecodeThread(); + // Now that those threads are stopped, there's no possibility of + // mPendingWakeDecoder being needed again. Revoke it. + mPendingWakeDecoder = nullptr; + { + ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); + mReader->ReleaseMediaResources(); + } + return NS_OK; + } + + case DECODER_STATE_WAIT_FOR_RESOURCES: { + return NS_OK; + } + case DECODER_STATE_DECODING_METADATA: { // Ensure we have a decode thread to decode metadata. return ScheduleDecodeThread(); diff --git a/content/media/MediaDecoderStateMachine.h b/content/media/MediaDecoderStateMachine.h index a4fcdbaa684..23179e4c517 100644 --- a/content/media/MediaDecoderStateMachine.h +++ b/content/media/MediaDecoderStateMachine.h @@ -116,6 +116,8 @@ public: // Enumeration for the valid decoding states enum State { DECODER_STATE_DECODING_METADATA, + DECODER_STATE_WAIT_FOR_RESOURCES, + DECODER_STATE_DORMANT, DECODER_STATE_DECODING, DECODER_STATE_SEEKING, DECODER_STATE_BUFFERING, @@ -132,6 +134,11 @@ public: // calling this. void SetVolume(double aVolume); void SetAudioCaptured(bool aCapture); + + // Check if the decoder needs to become dormant state. + bool IsDormantNeeded(); + // Set/Unset dormant state. + void SetDormant(bool aDormant); void Shutdown(); // Called from the main thread to get the duration. The decoder monitor @@ -493,6 +500,10 @@ private: // thread. The decoder monitor must be held. void StartDecoding(); + void StartWaitForResources(); + + void StartDecodeMetadata(); + // Returns true if we're currently playing. The decoder monitor must // be held. bool IsPlaying(); diff --git a/content/media/moz.build b/content/media/moz.build index 2e7596cd3a5..3eb82d0be57 100644 --- a/content/media/moz.build +++ b/content/media/moz.build @@ -34,6 +34,7 @@ PARALLEL_DIRS += ['webrtc'] if CONFIG['MOZ_OMX_DECODER']: PARALLEL_DIRS += ['omx'] + PARALLEL_DIRS += ['omx/mediaresourcemanager'] if CONFIG['MOZ_WEBSPEECH']: PARALLEL_DIRS += ['webspeech'] diff --git a/content/media/omx/Makefile.in b/content/media/omx/Makefile.in index 33f0310785f..9717543d344 100644 --- a/content/media/omx/Makefile.in +++ b/content/media/omx/Makefile.in @@ -18,6 +18,7 @@ include $(topsrcdir)/config/rules.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk INCLUDES += \ + -I$(srcdir)/mediaresourcemanager \ -I$(topsrcdir)/ipc/chromium/src \ -I$(srcdir)/../../base/src \ -I$(srcdir)/../../html/content/src \ diff --git a/content/media/omx/MediaOmxReader.cpp b/content/media/omx/MediaOmxReader.cpp index 1299f7c0c0f..0e3c81ea97a 100644 --- a/content/media/omx/MediaOmxReader.cpp +++ b/content/media/omx/MediaOmxReader.cpp @@ -35,6 +35,7 @@ MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder) : MediaOmxReader::~MediaOmxReader() { ResetDecode(); + mOmxDecoder.clear(); } nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor) @@ -42,6 +43,25 @@ nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor) return NS_OK; } +bool MediaOmxReader::IsWaitingMediaResources() +{ + return mOmxDecoder->IsWaitingMediaResources(); +} + +bool MediaOmxReader::IsDormantNeeded() +{ + if (!mOmxDecoder.get()) { + return false; + } + return mOmxDecoder->IsDormantNeeded(); +} + +void MediaOmxReader::ReleaseMediaResources() +{ + ResetDecode(); + mOmxDecoder->ReleaseMediaResources(); +} + nsresult MediaOmxReader::ReadMetadata(VideoInfo* aInfo, MetadataTags** aTags) { @@ -56,6 +76,14 @@ nsresult MediaOmxReader::ReadMetadata(VideoInfo* aInfo, } } + if (!mOmxDecoder->TryLoad()) { + return NS_ERROR_FAILURE; + } + + if (IsWaitingMediaResources()) { + return NS_OK; + } + // Set the total duration (the max of the audio and video track). int64_t durationUs; mOmxDecoder->GetDuration(&durationUs); @@ -112,8 +140,6 @@ nsresult MediaOmxReader::ResetDecode() if (container) { container->ClearCurrentFrame(); } - - mOmxDecoder.clear(); return NS_OK; } diff --git a/content/media/omx/MediaOmxReader.h b/content/media/omx/MediaOmxReader.h index 9165740cc87..13a36c595c6 100644 --- a/content/media/omx/MediaOmxReader.h +++ b/content/media/omx/MediaOmxReader.h @@ -54,6 +54,11 @@ public: return mHasVideo; } + virtual bool IsWaitingMediaResources(); + + virtual bool IsDormantNeeded(); + virtual void ReleaseMediaResources(); + virtual nsresult ReadMetadata(VideoInfo* aInfo, MetadataTags** aTags); virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); diff --git a/content/media/omx/OMXCodecProxy.cpp b/content/media/omx/OMXCodecProxy.cpp new file mode 100644 index 00000000000..253548dd0d7 --- /dev/null +++ b/content/media/omx/OMXCodecProxy.cpp @@ -0,0 +1,241 @@ +/* -*- 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/. */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "OMXCodecProxy" + +#include +#include +#include +#include +#include + +#include "nsDebug.h" + +#include "IMediaResourceManagerService.h" + +#include "OMXCodecProxy.h" + +namespace android { + +// static +sp OMXCodecProxy::Create( + const sp &omx, + const sp &meta, bool createEncoder, + const sp &source, + const char *matchComponentName, + uint32_t flags, + const sp &nativeWindow) +{ + sp proxy; + + const char *mime; + if (!meta->findCString(kKeyMIMEType, &mime)) { + return NULL; + } + + if (!strncasecmp(mime, "video/", 6)) { + proxy = new OMXCodecProxy(omx, meta, createEncoder, source, matchComponentName, flags, nativeWindow); + } + return proxy; +} + + +OMXCodecProxy::OMXCodecProxy( + const sp &omx, + const sp &meta, + bool createEncoder, + const sp &source, + const char *matchComponentName, + uint32_t flags, + const sp &nativeWindow) + : mOMX(omx), + mSrcMeta(meta), + mIsEncoder(createEncoder), + mSource(source), + mComponentName(NULL), + mFlags(flags), + mNativeWindow(nativeWindow), + mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE) +{ +} + +OMXCodecProxy::~OMXCodecProxy() +{ + if (mOMXCodec.get()) { + wp tmp = mOMXCodec; + mOMXCodec.clear(); + while (tmp.promote() != NULL) { + // this value come from stagefrigh's AwesomePlayer. + usleep(1000); + } + } + // Complete all pending Binder ipc transactions + IPCThreadState::self()->flushCommands(); + + if (mManagerService.get() && mClient.get()) { + mManagerService->cancelClient(mClient); + } + + mSource.clear(); + free(mComponentName); + mComponentName = NULL; +} + +MediaResourceManagerClient::State OMXCodecProxy::getState() +{ + Mutex::Autolock autoLock(mLock); + return mState; +} + +void OMXCodecProxy::setEventListener(const wp& listener) +{ + Mutex::Autolock autoLock(mLock); + mEventListener = listener; +} + +void OMXCodecProxy::notifyStatusChangedLocked() +{ + if (mEventListener != NULL) { + sp listener = mEventListener.promote(); + if (listener != NULL) { + listener->statusChanged(); + } + } +} + +void OMXCodecProxy::requestResource() +{ + Mutex::Autolock autoLock(mLock); + + if (mClient.get()) { + return; + } + sp listener = this; + mClient = new MediaResourceManagerClient(listener); + + mManagerService = mClient->getMediaResourceManagerService(); + if (!mManagerService.get()) { + mClient = NULL; + return; + } + + mManagerService->requestMediaResource(mClient, MediaResourceManagerClient::HW_VIDEO_DECODER); +} + +bool OMXCodecProxy::IsWaitingResources() +{ + Mutex::Autolock autoLock(mLock); + return mState == MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE; +} + +// called on Binder ipc thread +void OMXCodecProxy::statusChanged(int event) +{ + Mutex::Autolock autoLock(mLock); + + if (mState != MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE) { + return; + } + + mState = (MediaResourceManagerClient::State) event; + + const char *mime; + if (!mSrcMeta->findCString(kKeyMIMEType, &mime)) { + return; + } + + if (!strncasecmp(mime, "video/", 6)) { + sp codec; + mOMXCodec = OMXCodec::Create(mOMX, mSrcMeta, mIsEncoder, mSource, mComponentName, mFlags, mNativeWindow); + if (mOMXCodec == NULL) { + mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN; + notifyStatusChangedLocked(); + return; + } + // Check if this video is sized such that we're comfortable + // possibly using an OMX decoder. + int32_t maxWidth, maxHeight; + char propValue[PROPERTY_VALUE_MAX]; + property_get("ro.moz.omx.hw.max_width", propValue, "-1"); + maxWidth = atoi(propValue); + property_get("ro.moz.omx.hw.max_height", propValue, "-1"); + maxHeight = atoi(propValue); + + int32_t width = -1, height = -1; + if (maxWidth > 0 && maxHeight > 0 && + !(mOMXCodec->getFormat()->findInt32(kKeyWidth, &width) && + mOMXCodec->getFormat()->findInt32(kKeyHeight, &height) && + width * height <= maxWidth * maxHeight)) { + printf_stderr("Failed to get video size, or it was too large for HW decoder ( but )", + width, height, maxWidth, maxHeight); + mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN; + notifyStatusChangedLocked(); + return; + } + + if (mOMXCodec->start() != OK) { + NS_WARNING("Couldn't start OMX video source"); + mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN; + notifyStatusChangedLocked(); + return; + } + } + notifyStatusChangedLocked(); +} + +status_t OMXCodecProxy::start(MetaData *params) +{ + Mutex::Autolock autoLock(mLock); + + if (!mOMXCodec.get()) { + return NO_INIT; + } + return mOMXCodec->start(); +} + +status_t OMXCodecProxy::stop() +{ + Mutex::Autolock autoLock(mLock); + + if (!mOMXCodec.get()) { + return NO_INIT; + } + return mOMXCodec->stop(); +} + +sp OMXCodecProxy::getFormat() +{ + Mutex::Autolock autoLock(mLock); + + if (!mOMXCodec.get()) { + sp meta = new MetaData; + return meta; + } + return mOMXCodec->getFormat(); +} + +status_t OMXCodecProxy::read(MediaBuffer **buffer, const ReadOptions *options) +{ + Mutex::Autolock autoLock(mLock); + + if (!mOMXCodec.get()) { + return NO_INIT; + } + return mOMXCodec->read(buffer, options); +} + +status_t OMXCodecProxy::pause() +{ + Mutex::Autolock autoLock(mLock); + + if (!mOMXCodec.get()) { + return NO_INIT; + } + return mOMXCodec->pause(); +} + +} // namespace android diff --git a/content/media/omx/OMXCodecProxy.h b/content/media/omx/OMXCodecProxy.h new file mode 100644 index 00000000000..cd55d1b743c --- /dev/null +++ b/content/media/omx/OMXCodecProxy.h @@ -0,0 +1,100 @@ +/* -*- 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/. */ +#ifndef OMX_CODEC_PROXY_DECODER_H_ +#define OMX_CODEC_PROXY_DECODER_H_ + + +#include +#include +#include +#include +#include + +#include "MediaResourceManagerClient.h" + +namespace android { + +struct MediaBufferGroup; +struct MetaData; + +class OMXCodecProxy : public MediaSource, + public MediaResourceManagerClient::EventListener +{ +public: + struct EventListener : public virtual RefBase { + virtual void statusChanged() = 0; + }; + + static sp Create( + const sp &omx, + const sp &meta, bool createEncoder, + const sp &source, + const char *matchComponentName = NULL, + uint32_t flags = 0, + const sp &nativeWindow = NULL); + + MediaResourceManagerClient::State getState(); + + void setEventListener(const wp& listener); + + void requestResource(); + bool IsWaitingResources(); + + // MediaResourceManagerClient::EventListener + virtual void statusChanged(int event); + + // MediaSource + virtual status_t start(MetaData *params = NULL); + virtual status_t stop(); + + virtual sp getFormat(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options = NULL); + + virtual status_t pause(); + +protected: + OMXCodecProxy( + const sp &omx, + const sp &meta, + bool createEncoder, + const sp &source, + const char *matchComponentName, + uint32_t flags, + const sp &nativeWindow); + + virtual ~OMXCodecProxy(); + + void notifyStatusChangedLocked(); + +private: + OMXCodecProxy(const OMXCodecProxy &); + OMXCodecProxy &operator=(const OMXCodecProxy &); + + Mutex mLock; + + sp mOMX; + sp mSrcMeta; + char *mComponentName; + bool mIsEncoder; + // Flags specified in the creation of the codec. + uint32_t mFlags; + sp mNativeWindow; + + sp mSource; + + sp mOMXCodec; + sp mClient; + MediaResourceManagerClient::State mState; + + sp mManagerService; + wp mEventListener; +}; + +} // namespace android + +#endif // OMX_CODEC_PROXY_DECODER_H_ diff --git a/content/media/omx/OmxDecoder.cpp b/content/media/omx/OmxDecoder.cpp index b5382db4c19..4c6a2d7dc42 100644 --- a/content/media/omx/OmxDecoder.cpp +++ b/content/media/omx/OmxDecoder.cpp @@ -22,6 +22,7 @@ #include "GonkNativeWindow.h" #include "GonkNativeWindowClient.h" +#include "OMXCodecProxy.h" #include "OmxDecoder.h" #ifdef PR_LOGGING @@ -163,22 +164,7 @@ OmxDecoder::OmxDecoder(MediaResource *aResource, OmxDecoder::~OmxDecoder() { - { - // Free all pending video buffers. - Mutex::Autolock autoLock(mSeekLock); - ReleaseAllPendingVideoBuffersLocked(); - } - - ReleaseVideoBuffer(); - ReleaseAudioBuffer(); - - if (mVideoSource.get()) { - mVideoSource->stop(); - } - - if (mAudioSource.get()) { - mAudioSource->stop(); - } + ReleaseMediaResources(); // unregister AMessage handler from ALooper. mLooper->unregisterHandler(mReflector->id()); @@ -186,19 +172,15 @@ OmxDecoder::~OmxDecoder() mLooper->stop(); } -class AutoStopMediaSource { - sp mMediaSource; -public: - AutoStopMediaSource(const sp& aMediaSource) : mMediaSource(aMediaSource) { - } - - ~AutoStopMediaSource() { - mMediaSource->stop(); - } -}; +void OmxDecoder::statusChanged() +{ + mozilla::ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + mDecoder->GetReentrantMonitor().NotifyAll(); +} static sp sOMX = nullptr; -static sp GetOMX() { +static sp GetOMX() +{ if(sOMX.get() == nullptr) { sOMX = new OMX; } @@ -231,7 +213,6 @@ bool OmxDecoder::Init() { ssize_t audioTrackIndex = -1; ssize_t videoTrackIndex = -1; - const char *audioMime = nullptr; for (size_t i = 0; i < extractor->countTracks(); ++i) { sp meta = extractor->getTrackMetaData(i); @@ -249,7 +230,6 @@ bool OmxDecoder::Init() { videoTrackIndex = i; } else if (audioTrackIndex == -1 && !strncasecmp(mime, "audio/", 6)) { audioTrackIndex = i; - audioMime = mime; } } @@ -260,134 +240,52 @@ bool OmxDecoder::Init() { mResource->SetReadMode(MediaCacheStream::MODE_PLAYBACK); + if (videoTrackIndex != -1) { + mVideoTrack = extractor->getTrack(videoTrackIndex); + } + + if (audioTrackIndex != -1) { + mAudioTrack = extractor->getTrack(audioTrackIndex); + } + return true; +} + +bool OmxDecoder::TryLoad() { + + if (!AllocateMediaResources()) { + return false; + } + + //check if video is waiting resources + if (mVideoSource.get()) { + if (mVideoSource->IsWaitingResources()) { + return true; + } + } + + // calculate duration int64_t totalDurationUs = 0; - - mNativeWindow = new GonkNativeWindow(); - mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow); - - // OMXClient::connect() always returns OK and abort's fatally if - // it can't connect. - OMXClient client; - DebugOnly err = client.connect(); - NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver."); - sp omx = client.interface(); - - sp videoTrack; - sp videoSource; - if (videoTrackIndex != -1 && (videoTrack = extractor->getTrack(videoTrackIndex)) != nullptr) { - // Experience with OMX codecs is that only the HW decoders are - // worth bothering with, at least on the platforms where this code - // is currently used, and for formats this code is currently used - // for (h.264). So if we don't get a hardware decoder, just give - // up. - int flags = kHardwareCodecsOnly; - - char propQemu[PROPERTY_VALUE_MAX]; - property_get("ro.kernel.qemu", propQemu, ""); - if (!strncmp(propQemu, "1", 1)) { - // If we are in emulator, allow to fall back to software. - flags = 0; - } - videoSource = OMXCodec::Create(omx, - videoTrack->getFormat(), - false, // decoder - videoTrack, - nullptr, - flags, - mNativeWindowClient); - if (videoSource == nullptr) { - NS_WARNING("Couldn't create OMX video source"); - return false; - } - - // Check if this video is sized such that we're comfortable - // possibly using an OMX decoder. - int32_t maxWidth, maxHeight; - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.moz.omx.hw.max_width", propValue, "-1"); - maxWidth = atoi(propValue); - property_get("ro.moz.omx.hw.max_height", propValue, "-1"); - maxHeight = atoi(propValue); - - int32_t width = -1, height = -1; - if (maxWidth > 0 && maxHeight > 0 && - !(videoSource->getFormat()->findInt32(kKeyWidth, &width) && - videoSource->getFormat()->findInt32(kKeyHeight, &height) && - width * height <= maxWidth * maxHeight)) { - printf_stderr("Failed to get video size, or it was too large for HW decoder ( but )", - width, height, maxWidth, maxHeight); - return false; - } - - if (videoSource->start() != OK) { - NS_WARNING("Couldn't start OMX video source"); - return false; - } - - int64_t durationUs; - if (videoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { - if (durationUs > totalDurationUs) - totalDurationUs = durationUs; - } + int64_t durationUs = 0; + if (mVideoTrack.get() && mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (durationUs > totalDurationUs) + totalDurationUs = durationUs; } - - sp audioTrack; - sp audioSource; - if (audioTrackIndex != -1 && (audioTrack = extractor->getTrack(audioTrackIndex)) != nullptr) - { - if (!strcasecmp(audioMime, "audio/raw")) { - audioSource = audioTrack; - } else { - // try to load hardware codec in mediaserver process. - int flags = kHardwareCodecsOnly; - audioSource = OMXCodec::Create(omx, - audioTrack->getFormat(), - false, // decoder - audioTrack, - nullptr, - flags); - } - if (audioSource == nullptr) { - // try to load software codec in this process. - int flags = kSoftwareCodecsOnly; - audioSource = OMXCodec::Create(GetOMX(), - audioTrack->getFormat(), - false, // decoder - audioTrack, - nullptr, - flags); - if (audioSource == nullptr) { - NS_WARNING("Couldn't create OMX audio source"); - return false; - } - } - if (audioSource->start() != OK) { - NS_WARNING("Couldn't start OMX audio source"); - return false; - } - - int64_t durationUs; - if (audioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { - if (durationUs > totalDurationUs) - totalDurationUs = durationUs; - } + if (mAudioTrack.get() && mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (durationUs > totalDurationUs) + totalDurationUs = durationUs; } - - // set decoder state - mVideoTrack = videoTrack; - mVideoSource = videoSource; - mAudioTrack = audioTrack; - mAudioSource = audioSource; mDurationUs = totalDurationUs; + // read video metadata if (mVideoSource.get() && !SetVideoFormat()) { NS_WARNING("Couldn't set OMX video format"); return false; } - // To reliably get the channel and sample rate data we need to read from the - // audio source until we get a INFO_FORMAT_CHANGE status + // read audio metadata if (mAudioSource.get()) { + // To reliably get the channel and sample rate data we need to read from the + // audio source until we get a INFO_FORMAT_CHANGE status status_t err = mAudioSource->read(&mAudioBuffer); if (err != INFO_FORMAT_CHANGED) { if (err != OK) { @@ -411,6 +309,132 @@ bool OmxDecoder::Init() { return true; } +bool OmxDecoder::IsDormantNeeded() +{ + if (mVideoTrack.get()) { + return true; + } + return false; +} + +bool OmxDecoder::IsWaitingMediaResources() +{ + if (mVideoSource.get()) { + return mVideoSource->IsWaitingResources(); + } + return false; +} + +bool OmxDecoder::AllocateMediaResources() +{ + // OMXClient::connect() always returns OK and abort's fatally if + // it can't connect. + OMXClient client; + DebugOnly err = client.connect(); + NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver."); + sp omx = client.interface(); + + if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) { + mNativeWindow = new GonkNativeWindow(); + mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow); + + // Experience with OMX codecs is that only the HW decoders are + // worth bothering with, at least on the platforms where this code + // is currently used, and for formats this code is currently used + // for (h.264). So if we don't get a hardware decoder, just give + // up. + int flags = kHardwareCodecsOnly; + + char propQemu[PROPERTY_VALUE_MAX]; + property_get("ro.kernel.qemu", propQemu, ""); + if (!strncmp(propQemu, "1", 1)) { + // If we are in emulator, allow to fall back to software. + flags = 0; + } + mVideoSource = + OMXCodecProxy::Create(omx, + mVideoTrack->getFormat(), + false, // decoder + mVideoTrack, + nullptr, + flags, + mNativeWindowClient); + if (mVideoSource == nullptr) { + NS_WARNING("Couldn't create OMX video source"); + return false; + } else { + sp listener = this; + mVideoSource->setEventListener(listener); + mVideoSource->requestResource(); + } + } + + if ((mAudioTrack != nullptr) && (mAudioSource == nullptr)) { + const char *audioMime = nullptr; + sp meta = mAudioTrack->getFormat(); + if (!meta->findCString(kKeyMIMEType, &audioMime)) { + return false; + } + if (!strcasecmp(audioMime, "audio/raw")) { + mAudioSource = mAudioTrack; + } else { + // try to load hardware codec in mediaserver process. + int flags = kHardwareCodecsOnly; + mAudioSource = OMXCodec::Create(omx, + mAudioTrack->getFormat(), + false, // decoder + mAudioTrack, + nullptr, + flags); + } + + if (mAudioSource == nullptr) { + // try to load software codec in this process. + int flags = kSoftwareCodecsOnly; + mAudioSource = OMXCodec::Create(GetOMX(), + mAudioTrack->getFormat(), + false, // decoder + mAudioTrack, + nullptr, + flags); + if (mAudioSource == nullptr) { + NS_WARNING("Couldn't create OMX audio source"); + return false; + } + } + if (mAudioSource->start() != OK) { + NS_WARNING("Couldn't start OMX audio source"); + return false; + } + } + return true; +} + + +void OmxDecoder::ReleaseMediaResources() { + { + // Free all pending video buffers. + Mutex::Autolock autoLock(mSeekLock); + ReleaseAllPendingVideoBuffersLocked(); + } + + ReleaseVideoBuffer(); + ReleaseAudioBuffer(); + + if (mVideoSource.get()) { + mVideoSource->stop(); + mVideoSource.clear(); + } + + if (mAudioSource.get()) { + mAudioSource->stop(); + mAudioSource.clear(); + } + + mNativeWindowClient.clear(); + mNativeWindow.clear(); +} + bool OmxDecoder::SetVideoFormat() { const char *componentName; @@ -707,7 +731,8 @@ bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs) return true; } -nsresult OmxDecoder::Play() { +nsresult OmxDecoder::Play() +{ if (!mPaused) { return NS_OK; } @@ -722,7 +747,8 @@ nsresult OmxDecoder::Play() { return NS_OK; } -void OmxDecoder::Pause() { +void OmxDecoder::Pause() +{ if (mPaused) { return; } diff --git a/content/media/omx/OmxDecoder.h b/content/media/omx/OmxDecoder.h index 79f4733b6b9..6a0b29eeaa4 100644 --- a/content/media/omx/OmxDecoder.h +++ b/content/media/omx/OmxDecoder.h @@ -12,6 +12,7 @@ #include "MPAPI.h" #include "MediaResource.h" #include "AbstractMediaDecoder.h" +#include "OMXCodecProxy.h" namespace android { class OmxDecoder; @@ -72,7 +73,7 @@ private: MediaStreamSource &operator=(const MediaStreamSource &); }; -class OmxDecoder : public RefBase { +class OmxDecoder : public OMXCodecProxy::EventListener { typedef MPAPI::AudioFrame AudioFrame; typedef MPAPI::VideoFrame VideoFrame; typedef mozilla::MediaResource MediaResource; @@ -93,7 +94,7 @@ class OmxDecoder : public RefBase { sp mNativeWindow; sp mNativeWindowClient; sp mVideoTrack; - sp mVideoSource; + sp mVideoSource; sp mAudioTrack; sp mAudioSource; int32_t mVideoWidth; @@ -162,7 +163,15 @@ public: OmxDecoder(MediaResource *aResource, AbstractMediaDecoder *aDecoder); ~OmxDecoder(); + // MediaResourceManagerClient::EventListener + virtual void statusChanged(); + bool Init(); + bool TryLoad(); + bool IsDormantNeeded(); + bool IsWaitingMediaResources(); + bool AllocateMediaResources(); + void ReleaseMediaResources(); bool SetVideoFormat(); bool SetAudioFormat(); diff --git a/content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp b/content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp new file mode 100644 index 00000000000..ae5dc2983a0 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp @@ -0,0 +1,62 @@ +/* -*- 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/. */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IMediaResourceManagerClient" +#include + +#include +#include + +#include + +#include "IMediaResourceManagerClient.h" + +namespace android { + +enum { + STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION +}; + +class BpMediaResourceManagerClient : public BpInterface +{ +public: + BpMediaResourceManagerClient(const sp& impl) + : BpInterface(impl) + { + } + + void statusChanged(int event) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaResourceManagerClient::getInterfaceDescriptor()); + data.writeInt32(event); + remote()->transact(STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(MediaResourceManagerClient, "android.media.IMediaResourceManagerClient"); + +// ---------------------------------------------------------------------- + +status_t BnMediaResourceManagerClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case STATUS_CHANGED: { + CHECK_INTERFACE(IMediaResourceManagerClient, data, reply); + int event = data.readInt32(); + statusChanged(event); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h b/content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h new file mode 100644 index 00000000000..fdb0e5cc201 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h @@ -0,0 +1,43 @@ +/* -*- 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/. */ + +#ifndef ANDROID_IMEDIARESOURCEMANAGERCLIENT_H +#define ANDROID_IMEDIARESOURCEMANAGERCLIENT_H + +#include +#include + +namespace android { + +// ---------------------------------------------------------------------------- + +class IMediaResourceManagerClient : public IInterface +{ +public: + DECLARE_META_INTERFACE(MediaResourceManagerClient); + + // Notifies a change of media resource request status. + virtual void statusChanged(int event) = 0; + +}; + + +// ---------------------------------------------------------------------------- + +class BnMediaResourceManagerClient : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H diff --git a/content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp b/content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp new file mode 100644 index 00000000000..832a7f395f9 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp @@ -0,0 +1,114 @@ +/* +** Copyright 2010, The Android Open Source Project +** Copyright 2013, Mozilla Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IMediaResourceManagerDeathNotifier" +#include + +#include +#include + +#include "IMediaResourceManagerDeathNotifier.h" + +namespace android { + +// client singleton for binder interface to services +Mutex IMediaResourceManagerDeathNotifier::sServiceLock; +sp IMediaResourceManagerDeathNotifier::sMediaResourceManagerService; +sp IMediaResourceManagerDeathNotifier::sDeathNotifier; +SortedVector< wp > IMediaResourceManagerDeathNotifier::sObitRecipients; + +// establish binder interface to MediaResourceManagerService +/*static*/const sp& +IMediaResourceManagerDeathNotifier::getMediaResourceManagerService() +{ + LOGV("getMediaResourceManagerService"); + Mutex::Autolock _l(sServiceLock); + if (sMediaResourceManagerService.get() == 0) { + sp sm = defaultServiceManager(); + sp binder; + do { + binder = sm->getService(String16("media.resource_manager")); + if (binder != 0) { + break; + } + LOGW("Media resource manager service not published, waiting..."); + usleep(500000); // 0.5 s + } while(true); + + if (sDeathNotifier == NULL) { + sDeathNotifier = new DeathNotifier(); + } + binder->linkToDeath(sDeathNotifier); + sMediaResourceManagerService = interface_cast(binder); + } + LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?"); + return sMediaResourceManagerService; +} + +/*static*/ void +IMediaResourceManagerDeathNotifier::addObitRecipient(const wp& recipient) +{ + LOGV("addObitRecipient"); + Mutex::Autolock _l(sServiceLock); + sObitRecipients.add(recipient); +} + +/*static*/ void +IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp& recipient) +{ + LOGV("removeObitRecipient"); + Mutex::Autolock _l(sServiceLock); + sObitRecipients.remove(recipient); +} + +void +IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp& who) +{ + LOGW("media server died"); + + // Need to do this with the lock held + SortedVector< wp > list; + { + Mutex::Autolock _l(sServiceLock); + sMediaResourceManagerService.clear(); + list = sObitRecipients; + } + + // Notify application when media server dies. + // Don't hold the static lock during callback in case app + // makes a call that needs the lock. + size_t count = list.size(); + for (size_t iter = 0; iter < count; ++iter) { + sp notifier = list[iter].promote(); + if (notifier != 0) { + notifier->died(); + } + } +} + +IMediaResourceManagerDeathNotifier::DeathNotifier::~DeathNotifier() +{ + LOGV("DeathNotifier::~DeathNotifier"); + Mutex::Autolock _l(sServiceLock); + sObitRecipients.clear(); + if (sMediaResourceManagerService != 0) { + sMediaResourceManagerService->asBinder()->unlinkToDeath(this); + } +} + +}; // namespace android diff --git a/content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h b/content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h new file mode 100644 index 00000000000..e61377d7fbf --- /dev/null +++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h @@ -0,0 +1,67 @@ +/* +** Copyright 2010, The Android Open Source Project +** Copyright 2013, Mozilla Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H +#define ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H + +#include +#include + +#include "IMediaResourceManagerService.h" + +namespace android { + +/** + * Handle MediaResourceManagerService's death notification. + * Made from android's IMediaDeathNotifier class. + */ +class IMediaResourceManagerDeathNotifier: virtual public RefBase +{ +public: + IMediaResourceManagerDeathNotifier() { addObitRecipient(this); } + virtual ~IMediaResourceManagerDeathNotifier() { removeObitRecipient(this); } + + virtual void died() = 0; + static const sp& getMediaResourceManagerService(); + +private: + IMediaResourceManagerDeathNotifier &operator=(const IMediaResourceManagerDeathNotifier &); + IMediaResourceManagerDeathNotifier(const IMediaResourceManagerDeathNotifier &); + + static void addObitRecipient(const wp& recipient); + static void removeObitRecipient(const wp& recipient); + + class DeathNotifier: public IBinder::DeathRecipient + { + public: + DeathNotifier() {} + virtual ~DeathNotifier(); + + virtual void binderDied(const wp& who); + }; + + friend class DeathNotifier; + + static Mutex sServiceLock; + static sp sMediaResourceManagerService; + static sp sDeathNotifier; + static SortedVector< wp > sObitRecipients; +}; + +}; // namespace android + +#endif // ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H diff --git a/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp new file mode 100644 index 00000000000..5a6e7da6fce --- /dev/null +++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp @@ -0,0 +1,86 @@ +/* -*- 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/. */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IMediaResourceManagerService" + +#include +#include + +#include +#include + +#include "IMediaResourceManagerService.h" + +namespace android { + +/** + * Function ID used between BpMediaResourceManagerService and + * BnMediaResourceManagerService by using Binder ipc. + */ +enum { + REQUEST_MEDIA_RESOURCE = IBinder::FIRST_CALL_TRANSACTION, + DEREGISTER_CLIENT +}; + +class BpMediaResourceManagerService : public BpInterface +{ +public: + BpMediaResourceManagerService(const sp& impl) + : BpInterface(impl) + { + } + + virtual void requestMediaResource(const sp& client, int resourceType) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor()); + data.writeStrongBinder(client->asBinder()); + data.writeInt32(resourceType); + remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply); + } + + virtual status_t cancelClient(const sp& client) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor()); + data.writeStrongBinder(client->asBinder()); + remote()->transact(DEREGISTER_CLIENT, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(MediaResourceManagerService, "android.media.IMediaResourceManagerService"); + +// ---------------------------------------------------------------------- + +status_t BnMediaResourceManagerService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + + case REQUEST_MEDIA_RESOURCE: { + CHECK_INTERFACE(IMediaResourceManagerService, data, reply); + sp client = interface_cast(data.readStrongBinder()); + int resourceType = data.readInt32(); + requestMediaResource(client, resourceType); + return NO_ERROR; + } break; + case DEREGISTER_CLIENT: { + CHECK_INTERFACE(IMediaResourceManagerService, data, reply); + sp client = interface_cast(data.readStrongBinder()); + cancelClient(client); + reply->writeInt32(NO_ERROR); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h new file mode 100644 index 00000000000..4ce31e9e7f0 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h @@ -0,0 +1,47 @@ +/* -*- 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/. */ + +#ifndef ANDROID_IMEDIARESOURCEMANAGERSERVICE_H +#define ANDROID_IMEDIARESOURCEMANAGERSERVICE_H + +#include +#include + +#include "IMediaResourceManagerClient.h" + + +namespace android { + +// ---------------------------------------------------------------------------- + +class IMediaResourceManagerService : public IInterface +{ +public: + DECLARE_META_INTERFACE(MediaResourceManagerService); + + // Request a media resource for IMediaResourceManagerClient. + virtual void requestMediaResource(const sp& client, int resourceType) = 0; + // Cancel a media resource request and a resource allocated to IMediaResourceManagerClient. + virtual status_t cancelClient(const sp& client) = 0; +}; + + +// ---------------------------------------------------------------------------- + +class BnMediaResourceManagerService : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_IMEDIARESOURCEMANAGERSERVICE_H diff --git a/content/media/omx/mediaresourcemanager/Makefile.in b/content/media/omx/mediaresourcemanager/Makefile.in new file mode 100644 index 00000000000..fc56f8d6078 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/Makefile.in @@ -0,0 +1,27 @@ +# 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/. + +DEPTH = @DEPTH@ +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +LIBRARY_NAME = mediaresourcemanager + +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk +include $(topsrcdir)/ipc/chromium/chromium-config.mk + +INCLUDES += \ + -I$(srcdir)/ \ + -I$(ANDROID_SOURCE)/frameworks/base/include/ \ + -I$(ANDROID_SOURCE)/frameworks/base/include/binder/ \ + -I$(ANDROID_SOURCE)/frameworks/base/include/utils/ \ + -I$(ANDROID_SOURCE)/frameworks/base/include/media/ \ + -I$(ANDROID_SOURCE)/frameworks/base/include/media/stagefright/openmax \ + -I$(ANDROID_SOURCE)/frameworks/base/media/libstagefright/include/ \ + $(NULL) diff --git a/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp b/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp new file mode 100644 index 00000000000..d39816c6956 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp @@ -0,0 +1,40 @@ +/* -*- 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/. */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaResourceManagerClient" + +#include + +#include "MediaResourceManagerClient.h" + +namespace android { + +MediaResourceManagerClient::MediaResourceManagerClient(const wp& listener) + : mEventListener(listener) +{ +} + +void MediaResourceManagerClient::statusChanged(int event) +{ + if (mEventListener != NULL) { + sp listener = mEventListener.promote(); + if (listener != NULL) { + listener->statusChanged(event); + } + } +} + +void MediaResourceManagerClient::died() +{ + sp listener = mEventListener.promote(); + if (listener != NULL) { + listener->statusChanged(CLIENT_STATE_SHUTDOWN); + } +} + +}; // namespace android + diff --git a/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.h b/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.h new file mode 100644 index 00000000000..94748963574 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.h @@ -0,0 +1,51 @@ +/* -*- 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/. */ + +#ifndef ANDROID_MEDIARESOURCEMANAGERCLIENT_H +#define ANDROID_MEDIARESOURCEMANAGERCLIENT_H + +#include "IMediaResourceManagerClient.h" +#include "IMediaResourceManagerDeathNotifier.h" + +namespace android { + +class MediaResourceManagerClient: public BnMediaResourceManagerClient, + public virtual IMediaResourceManagerDeathNotifier +{ +public: + // Enumeration for the valid decoding states + enum State { + CLIENT_STATE_WAIT_FOR_RESOURCE, + CLIENT_STATE_RESOURCE_ASSIGNED, + CLIENT_STATE_SHUTDOWN + }; + // Enumeration for the resource types + enum ResourceType { + HW_VIDEO_DECODER, + HW_AUDIO_DECODER, + HW_CAMERA + }; + + struct EventListener : public virtual RefBase { + // Notifies a change of media resource request status. + virtual void statusChanged(int event) = 0; + }; + + MediaResourceManagerClient(const wp& listener); + + // DeathRecipient + void died(); + + // IMediaResourceManagerClient + virtual void statusChanged(int event); + +private: + wp mEventListener; +}; + +}; // namespace android + +#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H diff --git a/content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp b/content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp new file mode 100644 index 00000000000..13e13cb8577 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp @@ -0,0 +1,179 @@ +/* -*- 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/. */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaResourceManagerService" + +#include +#include +#include + +#include "MediaResourceManagerClient.h" +#include "MediaResourceManagerService.h" + +namespace android { + +int waitBeforeAdding(const android::String16& serviceName) +{ + android::sp sm = android::defaultServiceManager(); + for ( int i = 0 ; i < 5; i++ ) { + if ( sm->checkService ( serviceName ) != NULL ) { + sleep(1); + } + else { + //good to go; + return 0; + } + } + // time out failure + return -1; +} + +// Wait until service manager is started +void +waitServiceManager() +{ + android::sp sm; + do { + sm = android::defaultServiceManager(); + if (sm.get()) { + break; + } + usleep(50000); // 0.05 s + } while(true); +} + +/* static */ +void MediaResourceManagerService::instantiate() { + waitServiceManager(); + waitBeforeAdding( android::String16("media.resource_manager") ); + + defaultServiceManager()->addService( + String16("media.resource_manager"), new MediaResourceManagerService()); +} + +MediaResourceManagerService::MediaResourceManagerService() + : mVideoDecoderCount(VIDEO_DECODER_COUNT) +{ + mLooper = new ALooper; + mLooper->setName("MediaResourceManagerService"); + + mReflector = new AHandlerReflector(this); + // Register AMessage handler to ALooper. + mLooper->registerHandler(mReflector); + // Start ALooper thread. + mLooper->start(); +} + +MediaResourceManagerService::~MediaResourceManagerService() +{ + // Unregister AMessage handler from ALooper. + mLooper->unregisterHandler(mReflector->id()); + // Stop ALooper thread. + mLooper->stop(); +} + +void MediaResourceManagerService::binderDied(const wp& who) +{ + if (who != NULL) { + sp binder = who.promote(); + if (binder != NULL) { + cancelClientLocked(binder); + } + } +} + +void MediaResourceManagerService::requestMediaResource(const sp& client, int resourceType) +{ + if (resourceType != MediaResourceManagerClient::HW_VIDEO_DECODER) { + // Support only HW_VIDEO_DECODER + return; + } + + { + Mutex::Autolock autoLock(mLock); + sp binder = client->asBinder(); + mVideoCodecRequestQueue.push_back(binder); + binder->linkToDeath(this); + } + + sp notify = + new AMessage(kNotifyRequest, mReflector->id()); + // Post AMessage to MediaResourceManagerService via ALooper. + notify->post(); +} + +status_t MediaResourceManagerService::cancelClient(const sp& client) +{ + { + Mutex::Autolock autoLock(mLock); + sp binder = client->asBinder(); + cancelClientLocked(binder); + } + + sp notify = + new AMessage(kNotifyRequest, mReflector->id()); + // Post AMessage to MediaResourceManagerService via ALooper. + notify->post(); + + return NO_ERROR; +} + +// Called on ALooper thread. +void MediaResourceManagerService::onMessageReceived(const sp &msg) +{ + Mutex::Autolock autoLock(mLock); + + // Exit if no request. + if (mVideoCodecRequestQueue.empty()) { + return; + } + + // Check if resource is available + int found = -1; + for (int i=0 ; i client = interface_cast(mVideoDecoderSlots[found].mClient); + client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED); +} + +void MediaResourceManagerService::cancelClientLocked(const sp& binder) +{ + // Clear the request from request queue. + Fifo::iterator it(mVideoCodecRequestQueue.begin()); + while (it != mVideoCodecRequestQueue.end()) { + if (*it == binder) { + *it = NULL; + continue; + } + it++; + } + + // Clear the client from the resource + for (int i=0 ; iunlinkToDeath(this); +} + +}; // namespace android + diff --git a/content/media/omx/mediaresourcemanager/MediaResourceManagerService.h b/content/media/omx/mediaresourcemanager/MediaResourceManagerService.h new file mode 100644 index 00000000000..af4755030e4 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerService.h @@ -0,0 +1,95 @@ +/* -*- 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/. */ + +#ifndef ANDROID_MEDIARESOURCEMANAGERSERVICE_H +#define ANDROID_MEDIARESOURCEMANAGERSERVICE_H + +#include +#include +#include +#include +#include + +#include "IMediaResourceManagerClient.h" +#include "IMediaResourceManagerService.h" + +namespace android { + +/** + * Manage permissions of using media resources(hw decoder, hw encoder, camera) + * XXX Current implementaion support only one hw video decoder. + * Need to extend to support multiple instance and other resources. + */ +class MediaResourceManagerService: public BnMediaResourceManagerService, + public IBinder::DeathRecipient +{ +public: + // The maximum number of hardware decoders available. + enum { VIDEO_DECODER_COUNT = 1 }; + + enum { + kNotifyRequest = 'noti' + }; + + // Instantiate MediaResourceManagerService and register to service manager. + // If service manager is not present, wait until service manager becomes present. + static void instantiate(); + + // DeathRecipient + virtual void binderDied(const wp& who); + + // derived from IMediaResourceManagerService + virtual void requestMediaResource(const sp& client, int resourceType); + virtual status_t cancelClient(const sp& client); + + // Receive a message from AHandlerReflector. + // Called on ALooper thread. + void onMessageReceived(const sp &msg); + +protected: + MediaResourceManagerService(); + virtual ~MediaResourceManagerService(); + +protected: + // Represent a media resouce. + // Hold a IMediaResourceManagerClient that got a media resource as IBinder. + struct ResourceSlot { + ResourceSlot () + { + } + sp mClient; + }; + + void cancelClientLocked(const sp& binder); + + // mVideoDecoderSlots is the array of slots that represent a media resource. + ResourceSlot mVideoDecoderSlots[VIDEO_DECODER_COUNT]; + // The maximum number of hardware decoders available on the device. + int mVideoDecoderCount; + + // The lock protects mVideoDecoderSlots and mVideoCodecRequestQueue called + // from multiple threads. + Mutex mLock; + typedef Vector > Fifo; + // Queue of media resource requests. + // Hold IMediaResourceManagerClient that requesting a media resource as IBinder. + Fifo mVideoCodecRequestQueue; + + // ALooper is a message loop used in stagefright. + // It creates a thread for messages and handles messages in the thread. + // ALooper is a clone of Looper in android Java. + // http://developer.android.com/reference/android/os/Looper.html + sp mLooper; + // deliver a message to a wrapped object(OmxDecoder). + // AHandlerReflector is similar to Handler in android Java. + // http://developer.android.com/reference/android/os/Handler.html + sp > mReflector; + +}; + +}; // namespace android + +#endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H diff --git a/content/media/omx/mediaresourcemanager/moz.build b/content/media/omx/mediaresourcemanager/moz.build new file mode 100644 index 00000000000..e759be0a577 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/moz.build @@ -0,0 +1,16 @@ +# -*- 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/. + +MODULE = 'content' + +CPP_SOURCES += [ + 'IMediaResourceManagerClient.cpp', + 'IMediaResourceManagerDeathNotifier.cpp', + 'IMediaResourceManagerService.cpp', + 'MediaResourceManagerClient.cpp', + 'MediaResourceManagerService.cpp', +] + diff --git a/content/media/omx/moz.build b/content/media/omx/moz.build index 57aa713dcf1..4ad2d79a184 100644 --- a/content/media/omx/moz.build +++ b/content/media/omx/moz.build @@ -15,5 +15,6 @@ CPP_SOURCES += [ 'MediaOmxDecoder.cpp', 'MediaOmxReader.cpp', 'OmxDecoder.cpp', + 'OMXCodecProxy.cpp', ] diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index b3feaf93a87..9d7a855a8bc 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -115,6 +115,7 @@ ifdef MOZ_OMX_DECODER #{ # include OMX decoder SHARED_LIBRARY_LIBS += \ $(DEPTH)/content/media/omx/$(LIB_PREFIX)gkconomx_s.$(LIB_SUFFIX) \ + $(DEPTH)/content/media/omx/mediaresourcemanager/$(LIB_PREFIX)mediaresourcemanager.$(LIB_SUFFIX) \ $(NULL) endif #} diff --git a/widget/gonk/Makefile.in b/widget/gonk/Makefile.in index 2e18994c53f..71f3246bffb 100644 --- a/widget/gonk/Makefile.in +++ b/widget/gonk/Makefile.in @@ -43,6 +43,7 @@ LOCAL_INCLUDES += \ -I$(topsrcdir)/content/events/src \ -I$(topsrcdir)/gfx/skia/include/core \ -I$(topsrcdir)/gfx/skia/include/config \ + -I$(topsrcdir)/content/media/omx/mediaresourcemanager \ -I$(srcdir) \ $(NULL) diff --git a/widget/gonk/nsAppShell.cpp b/widget/gonk/nsAppShell.cpp index a42bd6c8432..454c7debf0e 100644 --- a/widget/gonk/nsAppShell.cpp +++ b/widget/gonk/nsAppShell.cpp @@ -30,6 +30,7 @@ #include "base/basictypes.h" #include "nscore.h" +#include "MediaResourceManagerService.h" #include "mozilla/FileUtils.h" #include "mozilla/Hal.h" #include "mozilla/Mutex.h" @@ -639,6 +640,10 @@ nsAppShell::Init() InitGonkMemoryPressureMonitoring(); + if (XRE_GetProcessType() == GeckoProcessType_Default) { + android::MediaResourceManagerService::instantiate(); + } + nsCOMPtr obsServ = GetObserverService(); if (obsServ) { obsServ->AddObserver(this, "browser-ui-startup-complete", false);