mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 871485 - Share hw codec between applications/tasks. r=mwu, r=doublec, r=roc
This commit is contained in:
parent
235fd18774
commit
357c151486
@ -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 &&
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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<DecodedStreamData> 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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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']
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
241
content/media/omx/OMXCodecProxy.cpp
Normal file
241
content/media/omx/OMXCodecProxy.cpp
Normal file
@ -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 <binder/IPCThreadState.h>
|
||||
#include <cutils/properties.h>
|
||||
#include <stagefright/MetaData.h>
|
||||
#include <stagefright/OMXCodec.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "nsDebug.h"
|
||||
|
||||
#include "IMediaResourceManagerService.h"
|
||||
|
||||
#include "OMXCodecProxy.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// static
|
||||
sp<OMXCodecProxy> OMXCodecProxy::Create(
|
||||
const sp<IOMX> &omx,
|
||||
const sp<MetaData> &meta, bool createEncoder,
|
||||
const sp<MediaSource> &source,
|
||||
const char *matchComponentName,
|
||||
uint32_t flags,
|
||||
const sp<ANativeWindow> &nativeWindow)
|
||||
{
|
||||
sp<OMXCodecProxy> 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<IOMX> &omx,
|
||||
const sp<MetaData> &meta,
|
||||
bool createEncoder,
|
||||
const sp<MediaSource> &source,
|
||||
const char *matchComponentName,
|
||||
uint32_t flags,
|
||||
const sp<ANativeWindow> &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<MediaSource> 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<OMXCodecProxy::EventListener>& listener)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
mEventListener = listener;
|
||||
}
|
||||
|
||||
void OMXCodecProxy::notifyStatusChangedLocked()
|
||||
{
|
||||
if (mEventListener != NULL) {
|
||||
sp<EventListener> listener = mEventListener.promote();
|
||||
if (listener != NULL) {
|
||||
listener->statusChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OMXCodecProxy::requestResource()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mClient.get()) {
|
||||
return;
|
||||
}
|
||||
sp<MediaResourceManagerClient::EventListener> 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<MediaSource> 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 (<w=%d, h=%d> but <maxW=%d, maxH=%d>)",
|
||||
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<MetaData> OMXCodecProxy::getFormat()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (!mOMXCodec.get()) {
|
||||
sp<MetaData> 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
|
100
content/media/omx/OMXCodecProxy.h
Normal file
100
content/media/omx/OMXCodecProxy.h
Normal file
@ -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 <android/native_window.h>
|
||||
#include <IOMX.h>
|
||||
#include <stagefright/MediaBuffer.h>
|
||||
#include <stagefright/MediaSource.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#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<OMXCodecProxy> Create(
|
||||
const sp<IOMX> &omx,
|
||||
const sp<MetaData> &meta, bool createEncoder,
|
||||
const sp<MediaSource> &source,
|
||||
const char *matchComponentName = NULL,
|
||||
uint32_t flags = 0,
|
||||
const sp<ANativeWindow> &nativeWindow = NULL);
|
||||
|
||||
MediaResourceManagerClient::State getState();
|
||||
|
||||
void setEventListener(const wp<EventListener>& 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<MetaData> getFormat();
|
||||
|
||||
virtual status_t read(
|
||||
MediaBuffer **buffer, const ReadOptions *options = NULL);
|
||||
|
||||
virtual status_t pause();
|
||||
|
||||
protected:
|
||||
OMXCodecProxy(
|
||||
const sp<IOMX> &omx,
|
||||
const sp<MetaData> &meta,
|
||||
bool createEncoder,
|
||||
const sp<MediaSource> &source,
|
||||
const char *matchComponentName,
|
||||
uint32_t flags,
|
||||
const sp<ANativeWindow> &nativeWindow);
|
||||
|
||||
virtual ~OMXCodecProxy();
|
||||
|
||||
void notifyStatusChangedLocked();
|
||||
|
||||
private:
|
||||
OMXCodecProxy(const OMXCodecProxy &);
|
||||
OMXCodecProxy &operator=(const OMXCodecProxy &);
|
||||
|
||||
Mutex mLock;
|
||||
|
||||
sp<IOMX> mOMX;
|
||||
sp<MetaData> mSrcMeta;
|
||||
char *mComponentName;
|
||||
bool mIsEncoder;
|
||||
// Flags specified in the creation of the codec.
|
||||
uint32_t mFlags;
|
||||
sp<ANativeWindow> mNativeWindow;
|
||||
|
||||
sp<MediaSource> mSource;
|
||||
|
||||
sp<MediaSource> mOMXCodec;
|
||||
sp<MediaResourceManagerClient> mClient;
|
||||
MediaResourceManagerClient::State mState;
|
||||
|
||||
sp<IMediaResourceManagerService> mManagerService;
|
||||
wp<OMXCodecProxy::EventListener> mEventListener;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // OMX_CODEC_PROXY_DECODER_H_
|
@ -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<MediaSource> mMediaSource;
|
||||
public:
|
||||
AutoStopMediaSource(const sp<MediaSource>& aMediaSource) : mMediaSource(aMediaSource) {
|
||||
}
|
||||
|
||||
~AutoStopMediaSource() {
|
||||
mMediaSource->stop();
|
||||
}
|
||||
};
|
||||
void OmxDecoder::statusChanged()
|
||||
{
|
||||
mozilla::ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
static sp<IOMX> sOMX = nullptr;
|
||||
static sp<IOMX> GetOMX() {
|
||||
static sp<IOMX> 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<MetaData> 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<status_t> err = client.connect();
|
||||
NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
|
||||
sp<IOMX> omx = client.interface();
|
||||
|
||||
sp<MediaSource> videoTrack;
|
||||
sp<MediaSource> 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 (<w=%d, h=%d> but <maxW=%d, maxH=%d>)",
|
||||
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<MediaSource> audioTrack;
|
||||
sp<MediaSource> 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<status_t> err = client.connect();
|
||||
NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
|
||||
sp<IOMX> 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<OMXCodecProxy::EventListener> listener = this;
|
||||
mVideoSource->setEventListener(listener);
|
||||
mVideoSource->requestResource();
|
||||
}
|
||||
}
|
||||
|
||||
if ((mAudioTrack != nullptr) && (mAudioSource == nullptr)) {
|
||||
const char *audioMime = nullptr;
|
||||
sp<MetaData> 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;
|
||||
}
|
||||
|
@ -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<GonkNativeWindow> mNativeWindow;
|
||||
sp<GonkNativeWindowClient> mNativeWindowClient;
|
||||
sp<MediaSource> mVideoTrack;
|
||||
sp<MediaSource> mVideoSource;
|
||||
sp<OMXCodecProxy> mVideoSource;
|
||||
sp<MediaSource> mAudioTrack;
|
||||
sp<MediaSource> 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();
|
||||
|
||||
|
@ -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 <utils/Log.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <binder/Parcel.h>
|
||||
|
||||
#include "IMediaResourceManagerClient.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
enum {
|
||||
STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION
|
||||
};
|
||||
|
||||
class BpMediaResourceManagerClient : public BpInterface<IMediaResourceManagerClient>
|
||||
{
|
||||
public:
|
||||
BpMediaResourceManagerClient(const sp<IBinder>& impl)
|
||||
: BpInterface<IMediaResourceManagerClient>(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
|
@ -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 <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
|
||||
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<IMediaResourceManagerClient>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
|
@ -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 <utils/Log.h>
|
||||
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <binder/IPCThreadState.h>
|
||||
|
||||
#include "IMediaResourceManagerDeathNotifier.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// client singleton for binder interface to services
|
||||
Mutex IMediaResourceManagerDeathNotifier::sServiceLock;
|
||||
sp<IMediaResourceManagerService> IMediaResourceManagerDeathNotifier::sMediaResourceManagerService;
|
||||
sp<IMediaResourceManagerDeathNotifier::DeathNotifier> IMediaResourceManagerDeathNotifier::sDeathNotifier;
|
||||
SortedVector< wp<IMediaResourceManagerDeathNotifier> > IMediaResourceManagerDeathNotifier::sObitRecipients;
|
||||
|
||||
// establish binder interface to MediaResourceManagerService
|
||||
/*static*/const sp<IMediaResourceManagerService>&
|
||||
IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
|
||||
{
|
||||
LOGV("getMediaResourceManagerService");
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
if (sMediaResourceManagerService.get() == 0) {
|
||||
sp<IServiceManager> sm = defaultServiceManager();
|
||||
sp<IBinder> 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<IMediaResourceManagerService>(binder);
|
||||
}
|
||||
LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?");
|
||||
return sMediaResourceManagerService;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
IMediaResourceManagerDeathNotifier::addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
|
||||
{
|
||||
LOGV("addObitRecipient");
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
sObitRecipients.add(recipient);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
|
||||
{
|
||||
LOGV("removeObitRecipient");
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
sObitRecipients.remove(recipient);
|
||||
}
|
||||
|
||||
void
|
||||
IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who)
|
||||
{
|
||||
LOGW("media server died");
|
||||
|
||||
// Need to do this with the lock held
|
||||
SortedVector< wp<IMediaResourceManagerDeathNotifier> > 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<IMediaResourceManagerDeathNotifier> 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
|
@ -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 <utils/threads.h>
|
||||
#include <utils/SortedVector.h>
|
||||
|
||||
#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<IMediaResourceManagerService>& getMediaResourceManagerService();
|
||||
|
||||
private:
|
||||
IMediaResourceManagerDeathNotifier &operator=(const IMediaResourceManagerDeathNotifier &);
|
||||
IMediaResourceManagerDeathNotifier(const IMediaResourceManagerDeathNotifier &);
|
||||
|
||||
static void addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
|
||||
static void removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
|
||||
|
||||
class DeathNotifier: public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
DeathNotifier() {}
|
||||
virtual ~DeathNotifier();
|
||||
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
};
|
||||
|
||||
friend class DeathNotifier;
|
||||
|
||||
static Mutex sServiceLock;
|
||||
static sp<IMediaResourceManagerService> sMediaResourceManagerService;
|
||||
static sp<DeathNotifier> sDeathNotifier;
|
||||
static SortedVector< wp<IMediaResourceManagerDeathNotifier> > sObitRecipients;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
|
@ -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 <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <binder/Parcel.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#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<IMediaResourceManagerService>
|
||||
{
|
||||
public:
|
||||
BpMediaResourceManagerService(const sp<IBinder>& impl)
|
||||
: BpInterface<IMediaResourceManagerService>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& 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<IMediaResourceManagerClient>& 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<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
int resourceType = data.readInt32();
|
||||
requestMediaResource(client, resourceType);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case DEREGISTER_CLIENT: {
|
||||
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
cancelClient(client);
|
||||
reply->writeInt32(NO_ERROR);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
@ -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 <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
|
||||
#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<IMediaResourceManagerClient>& client, int resourceType) = 0;
|
||||
// Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client) = 0;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnMediaResourceManagerService : public BnInterface<IMediaResourceManagerService>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
|
27
content/media/omx/mediaresourcemanager/Makefile.in
Normal file
27
content/media/omx/mediaresourcemanager/Makefile.in
Normal file
@ -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)
|
@ -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 <utils/Log.h>
|
||||
|
||||
#include "MediaResourceManagerClient.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
MediaResourceManagerClient::MediaResourceManagerClient(const wp<EventListener>& listener)
|
||||
: mEventListener(listener)
|
||||
{
|
||||
}
|
||||
|
||||
void MediaResourceManagerClient::statusChanged(int event)
|
||||
{
|
||||
if (mEventListener != NULL) {
|
||||
sp<EventListener> listener = mEventListener.promote();
|
||||
if (listener != NULL) {
|
||||
listener->statusChanged(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaResourceManagerClient::died()
|
||||
{
|
||||
sp<EventListener> listener = mEventListener.promote();
|
||||
if (listener != NULL) {
|
||||
listener->statusChanged(CLIENT_STATE_SHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
@ -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<EventListener>& listener);
|
||||
|
||||
// DeathRecipient
|
||||
void died();
|
||||
|
||||
// IMediaResourceManagerClient
|
||||
virtual void statusChanged(int event);
|
||||
|
||||
private:
|
||||
wp<EventListener> mEventListener;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
|
@ -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 <binder/IServiceManager.h>
|
||||
#include <media/stagefright/foundation/AMessage.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "MediaResourceManagerClient.h"
|
||||
#include "MediaResourceManagerService.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
int waitBeforeAdding(const android::String16& serviceName)
|
||||
{
|
||||
android::sp<android::IServiceManager> 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<android::IServiceManager> 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<MediaResourceManagerService>(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<IBinder>& who)
|
||||
{
|
||||
if (who != NULL) {
|
||||
sp<IBinder> binder = who.promote();
|
||||
if (binder != NULL) {
|
||||
cancelClientLocked(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
{
|
||||
if (resourceType != MediaResourceManagerClient::HW_VIDEO_DECODER) {
|
||||
// Support only HW_VIDEO_DECODER
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
mVideoCodecRequestQueue.push_back(binder);
|
||||
binder->linkToDeath(this);
|
||||
}
|
||||
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyRequest, mReflector->id());
|
||||
// Post AMessage to MediaResourceManagerService via ALooper.
|
||||
notify->post();
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client)
|
||||
{
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
cancelClientLocked(binder);
|
||||
}
|
||||
|
||||
sp<AMessage> 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<AMessage> &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<mVideoDecoderCount ; i++) {
|
||||
if (!mVideoDecoderSlots[i].mClient.get()) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Exit if no resource is available.
|
||||
if (found == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign resource to IMediaResourceManagerClient
|
||||
Fifo::iterator front(mVideoCodecRequestQueue.begin());
|
||||
mVideoDecoderSlots[found].mClient = *front;
|
||||
mVideoCodecRequestQueue.erase(front);
|
||||
// Notify resource assignment to the client.
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(mVideoDecoderSlots[found].mClient);
|
||||
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& 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 ; i<mVideoDecoderCount ; i++) {
|
||||
if (mVideoDecoderSlots[i].mClient == binder) {
|
||||
mVideoDecoderSlots[i].mClient = NULL;
|
||||
}
|
||||
}
|
||||
binder->unlinkToDeath(this);
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
@ -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 <media/stagefright/foundation/ABase.h>
|
||||
#include <media/stagefright/foundation/AHandlerReflector.h>
|
||||
#include <media/stagefright/foundation/ALooper.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#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<IBinder>& who);
|
||||
|
||||
// derived from IMediaResourceManagerService
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType);
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client);
|
||||
|
||||
// Receive a message from AHandlerReflector.
|
||||
// Called on ALooper thread.
|
||||
void onMessageReceived(const sp<AMessage> &msg);
|
||||
|
||||
protected:
|
||||
MediaResourceManagerService();
|
||||
virtual ~MediaResourceManagerService();
|
||||
|
||||
protected:
|
||||
// Represent a media resouce.
|
||||
// Hold a IMediaResourceManagerClient that got a media resource as IBinder.
|
||||
struct ResourceSlot {
|
||||
ResourceSlot ()
|
||||
{
|
||||
}
|
||||
sp<IBinder> mClient;
|
||||
};
|
||||
|
||||
void cancelClientLocked(const sp<IBinder>& 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<sp<IBinder> > 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<ALooper> 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<AHandlerReflector<MediaResourceManagerService> > mReflector;
|
||||
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H
|
16
content/media/omx/mediaresourcemanager/moz.build
Normal file
16
content/media/omx/mediaresourcemanager/moz.build
Normal file
@ -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',
|
||||
]
|
||||
|
@ -15,5 +15,6 @@ CPP_SOURCES += [
|
||||
'MediaOmxDecoder.cpp',
|
||||
'MediaOmxReader.cpp',
|
||||
'OmxDecoder.cpp',
|
||||
'OMXCodecProxy.cpp',
|
||||
]
|
||||
|
||||
|
@ -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 #}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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<nsIObserverService> obsServ = GetObserverService();
|
||||
if (obsServ) {
|
||||
obsServ->AddObserver(this, "browser-ui-startup-complete", false);
|
||||
|
Loading…
Reference in New Issue
Block a user