Bug 871485 - Share hw codec between applications/tasks. r=mwu, r=doublec, r=roc
This commit is contained in:
@@ -3244,6 +3244,11 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
|
|||||||
void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
|
void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
|
||||||
{
|
{
|
||||||
nsIDocument* ownerDoc = OwnerDoc();
|
nsIDocument* ownerDoc = OwnerDoc();
|
||||||
|
|
||||||
|
if (mDecoder) {
|
||||||
|
mDecoder->SetDormantIfNecessary(ownerDoc->Hidden());
|
||||||
|
}
|
||||||
|
|
||||||
// SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
|
// SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
|
||||||
// CanPlayChanged callback.
|
// CanPlayChanged callback.
|
||||||
if (UseAudioChannelService() && mPlayingThroughTheAudioChannel &&
|
if (UseAudioChannelService() && mPlayingThroughTheAudioChannel &&
|
||||||
|
|||||||
@@ -112,11 +112,47 @@ public:
|
|||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS1(MediaDecoder, nsIObserver)
|
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()
|
void MediaDecoder::Pause()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
if (mPlayState == PLAY_STATE_SEEKING || mPlayState == PLAY_STATE_ENDED) {
|
if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING || mPlayState == PLAY_STATE_ENDED) {
|
||||||
mNextState = PLAY_STATE_PAUSED;
|
mNextState = PLAY_STATE_PAUSED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -333,6 +369,8 @@ MediaDecoder::MediaDecoder() :
|
|||||||
mTransportSeekable(true),
|
mTransportSeekable(true),
|
||||||
mMediaSeekable(true),
|
mMediaSeekable(true),
|
||||||
mReentrantMonitor("media.decoder"),
|
mReentrantMonitor("media.decoder"),
|
||||||
|
mIsMetadataLoaded(false),
|
||||||
|
mIsDormant(false),
|
||||||
mPlayState(PLAY_STATE_PAUSED),
|
mPlayState(PLAY_STATE_PAUSED),
|
||||||
mNextState(PLAY_STATE_PAUSED),
|
mNextState(PLAY_STATE_PAUSED),
|
||||||
mCalledResourceLoaded(false),
|
mCalledResourceLoaded(false),
|
||||||
@@ -519,7 +557,7 @@ nsresult MediaDecoder::Play()
|
|||||||
NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
|
NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
|
||||||
nsresult res = ScheduleStateMachineThread();
|
nsresult res = ScheduleStateMachineThread();
|
||||||
NS_ENSURE_SUCCESS(res,res);
|
NS_ENSURE_SUCCESS(res,res);
|
||||||
if (mPlayState == PLAY_STATE_SEEKING) {
|
if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) {
|
||||||
mNextState = PLAY_STATE_PLAYING;
|
mNextState = PLAY_STATE_PLAYING;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@@ -619,7 +657,7 @@ nsresult MediaDecoder::Seek(double aTime)
|
|||||||
// If we are already in the seeking state, then setting mRequestedSeekTime
|
// If we are already in the seeking state, then setting mRequestedSeekTime
|
||||||
// above will result in the new seek occurring when the current seek
|
// above will result in the new seek occurring when the current seek
|
||||||
// completes.
|
// completes.
|
||||||
if (mPlayState != PLAY_STATE_SEEKING) {
|
if (mPlayState != PLAY_STATE_LOADING && mPlayState != PLAY_STATE_SEEKING) {
|
||||||
bool paused = false;
|
bool paused = false;
|
||||||
if (mOwner) {
|
if (mOwner) {
|
||||||
paused = mOwner->GetPaused();
|
paused = mOwner->GetPaused();
|
||||||
@@ -703,7 +741,9 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
|
|||||||
// Make sure the element and the frame (if any) are told about
|
// Make sure the element and the frame (if any) are told about
|
||||||
// our new size.
|
// our new size.
|
||||||
Invalidate();
|
Invalidate();
|
||||||
mOwner->MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags);
|
if (!mIsMetadataLoaded) {
|
||||||
|
mOwner->MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mCalledResourceLoaded) {
|
if (!mCalledResourceLoaded) {
|
||||||
@@ -720,7 +760,9 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
|
|||||||
bool notifyResourceIsLoaded = !mCalledResourceLoaded &&
|
bool notifyResourceIsLoaded = !mCalledResourceLoaded &&
|
||||||
IsDataCachedToEndOfResource();
|
IsDataCachedToEndOfResource();
|
||||||
if (mOwner) {
|
if (mOwner) {
|
||||||
mOwner->FirstFrameLoaded(notifyResourceIsLoaded);
|
if (!mIsMetadataLoaded) {
|
||||||
|
mOwner->FirstFrameLoaded(notifyResourceIsLoaded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can run cache callbacks.
|
// This can run cache callbacks.
|
||||||
@@ -746,6 +788,8 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
|
|||||||
// Run NotifySuspendedStatusChanged now to give us a chance to notice
|
// Run NotifySuspendedStatusChanged now to give us a chance to notice
|
||||||
// that autoplay should run.
|
// that autoplay should run.
|
||||||
NotifySuspendedStatusChanged();
|
NotifySuspendedStatusChanged();
|
||||||
|
|
||||||
|
mIsMetadataLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaDecoder::ResourceLoaded()
|
void MediaDecoder::ResourceLoaded()
|
||||||
@@ -1160,6 +1204,11 @@ void MediaDecoder::ChangeState(PlayState aState)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aState!= PLAY_STATE_LOADING) {
|
||||||
|
mIsDormant = false;
|
||||||
|
}
|
||||||
|
|
||||||
GetReentrantMonitor().NotifyAll();
|
GetReentrantMonitor().NotifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -332,6 +332,12 @@ public:
|
|||||||
// called.
|
// called.
|
||||||
virtual nsresult Play();
|
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.
|
// Pause video playback.
|
||||||
virtual void Pause();
|
virtual void Pause();
|
||||||
// Adjust the speed of the playback, optionally with pitch correction,
|
// Adjust the speed of the playback, optionally with pitch correction,
|
||||||
@@ -1000,6 +1006,13 @@ public:
|
|||||||
// without holding the monitor.
|
// without holding the monitor.
|
||||||
nsAutoPtr<DecodedStreamData> mDecodedStream;
|
nsAutoPtr<DecodedStreamData> mDecodedStream;
|
||||||
|
|
||||||
|
// True if metadata is already loaded in the past.
|
||||||
|
bool mIsMetadataLoaded;
|
||||||
|
|
||||||
|
// 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.
|
// Set to one of the valid play states.
|
||||||
// This can only be changed on the main thread while holding the decoder
|
// 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
|
// monitor. Thus, it can be safely read while holding the decoder monitor
|
||||||
|
|||||||
@@ -407,6 +407,13 @@ public:
|
|||||||
// on failure.
|
// on failure.
|
||||||
virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0;
|
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.
|
// Resets all state related to decoding, emptying all buffers etc.
|
||||||
virtual nsresult ResetDecode();
|
virtual nsresult ResetDecode();
|
||||||
|
|
||||||
|
|||||||
@@ -503,12 +503,28 @@ void MediaDecoderStateMachine::DecodeThreadRun()
|
|||||||
|
|
||||||
while (mState != DECODER_STATE_SHUTDOWN &&
|
while (mState != DECODER_STATE_SHUTDOWN &&
|
||||||
mState != DECODER_STATE_COMPLETED &&
|
mState != DECODER_STATE_COMPLETED &&
|
||||||
|
mState != DECODER_STATE_DORMANT &&
|
||||||
!mStopDecodeThread)
|
!mStopDecodeThread)
|
||||||
{
|
{
|
||||||
if (mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) {
|
if (mState == DECODER_STATE_DECODING || mState == DECODER_STATE_BUFFERING) {
|
||||||
DecodeLoop();
|
DecodeLoop();
|
||||||
} else if (mState == DECODER_STATE_SEEKING) {
|
} else if (mState == DECODER_STATE_SEEKING) {
|
||||||
DecodeSeek();
|
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 &&
|
if (!mStopDecodeThread &&
|
||||||
mState != DECODER_STATE_SHUTDOWN &&
|
mState != DECODER_STATE_SHUTDOWN &&
|
||||||
|
mState != DECODER_STATE_DORMANT &&
|
||||||
mState != DECODER_STATE_SEEKING)
|
mState != DECODER_STATE_SEEKING)
|
||||||
{
|
{
|
||||||
mState = DECODER_STATE_COMPLETED;
|
mState = DECODER_STATE_COMPLETED;
|
||||||
@@ -1457,6 +1474,33 @@ void MediaDecoderStateMachine::SetMediaSeekable(bool aMediaSeekable)
|
|||||||
mMediaSeekable = 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()
|
void MediaDecoderStateMachine::Shutdown()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||||
@@ -1484,6 +1528,22 @@ void MediaDecoderStateMachine::StartDecoding()
|
|||||||
ScheduleStateMachine();
|
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()
|
void MediaDecoderStateMachine::Play()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||||
@@ -1815,6 +1875,12 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
|||||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||||
res = mReader->ReadMetadata(&info, &tags);
|
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;
|
mInfo = info;
|
||||||
|
|
||||||
if (NS_FAILED(res) || (!info.mHasVideo && !info.mHasAudio)) {
|
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
|
// Now that those threads are stopped, there's no possibility of
|
||||||
// mPendingWakeDecoder being needed again. Revoke it.
|
// mPendingWakeDecoder being needed again. Revoke it.
|
||||||
mPendingWakeDecoder = nullptr;
|
mPendingWakeDecoder = nullptr;
|
||||||
|
{
|
||||||
|
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||||
|
mReader->ReleaseMediaResources();
|
||||||
|
}
|
||||||
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
|
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
|
||||||
"How did we escape from the shutdown state?");
|
"How did we escape from the shutdown state?");
|
||||||
// We must daisy-chain these events to destroy the decoder. We must
|
// We must daisy-chain these events to destroy the decoder. We must
|
||||||
@@ -2100,6 +2170,26 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||||||
return NS_OK;
|
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: {
|
case DECODER_STATE_DECODING_METADATA: {
|
||||||
// Ensure we have a decode thread to decode metadata.
|
// Ensure we have a decode thread to decode metadata.
|
||||||
return ScheduleDecodeThread();
|
return ScheduleDecodeThread();
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ public:
|
|||||||
// Enumeration for the valid decoding states
|
// Enumeration for the valid decoding states
|
||||||
enum State {
|
enum State {
|
||||||
DECODER_STATE_DECODING_METADATA,
|
DECODER_STATE_DECODING_METADATA,
|
||||||
|
DECODER_STATE_WAIT_FOR_RESOURCES,
|
||||||
|
DECODER_STATE_DORMANT,
|
||||||
DECODER_STATE_DECODING,
|
DECODER_STATE_DECODING,
|
||||||
DECODER_STATE_SEEKING,
|
DECODER_STATE_SEEKING,
|
||||||
DECODER_STATE_BUFFERING,
|
DECODER_STATE_BUFFERING,
|
||||||
@@ -132,6 +134,11 @@ public:
|
|||||||
// calling this.
|
// calling this.
|
||||||
void SetVolume(double aVolume);
|
void SetVolume(double aVolume);
|
||||||
void SetAudioCaptured(bool aCapture);
|
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();
|
void Shutdown();
|
||||||
|
|
||||||
// Called from the main thread to get the duration. The decoder monitor
|
// Called from the main thread to get the duration. The decoder monitor
|
||||||
@@ -493,6 +500,10 @@ private:
|
|||||||
// thread. The decoder monitor must be held.
|
// thread. The decoder monitor must be held.
|
||||||
void StartDecoding();
|
void StartDecoding();
|
||||||
|
|
||||||
|
void StartWaitForResources();
|
||||||
|
|
||||||
|
void StartDecodeMetadata();
|
||||||
|
|
||||||
// Returns true if we're currently playing. The decoder monitor must
|
// Returns true if we're currently playing. The decoder monitor must
|
||||||
// be held.
|
// be held.
|
||||||
bool IsPlaying();
|
bool IsPlaying();
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ PARALLEL_DIRS += ['webrtc']
|
|||||||
|
|
||||||
if CONFIG['MOZ_OMX_DECODER']:
|
if CONFIG['MOZ_OMX_DECODER']:
|
||||||
PARALLEL_DIRS += ['omx']
|
PARALLEL_DIRS += ['omx']
|
||||||
|
PARALLEL_DIRS += ['omx/mediaresourcemanager']
|
||||||
|
|
||||||
if CONFIG['MOZ_WEBSPEECH']:
|
if CONFIG['MOZ_WEBSPEECH']:
|
||||||
PARALLEL_DIRS += ['webspeech']
|
PARALLEL_DIRS += ['webspeech']
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ include $(topsrcdir)/config/rules.mk
|
|||||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||||
|
|
||||||
INCLUDES += \
|
INCLUDES += \
|
||||||
|
-I$(srcdir)/mediaresourcemanager \
|
||||||
-I$(topsrcdir)/ipc/chromium/src \
|
-I$(topsrcdir)/ipc/chromium/src \
|
||||||
-I$(srcdir)/../../base/src \
|
-I$(srcdir)/../../base/src \
|
||||||
-I$(srcdir)/../../html/content/src \
|
-I$(srcdir)/../../html/content/src \
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder) :
|
|||||||
MediaOmxReader::~MediaOmxReader()
|
MediaOmxReader::~MediaOmxReader()
|
||||||
{
|
{
|
||||||
ResetDecode();
|
ResetDecode();
|
||||||
|
mOmxDecoder.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
|
nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
|
||||||
@@ -42,6 +43,25 @@ nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
|
|||||||
return NS_OK;
|
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,
|
nsresult MediaOmxReader::ReadMetadata(VideoInfo* aInfo,
|
||||||
MetadataTags** aTags)
|
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).
|
// Set the total duration (the max of the audio and video track).
|
||||||
int64_t durationUs;
|
int64_t durationUs;
|
||||||
mOmxDecoder->GetDuration(&durationUs);
|
mOmxDecoder->GetDuration(&durationUs);
|
||||||
@@ -112,8 +140,6 @@ nsresult MediaOmxReader::ResetDecode()
|
|||||||
if (container) {
|
if (container) {
|
||||||
container->ClearCurrentFrame();
|
container->ClearCurrentFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
mOmxDecoder.clear();
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ public:
|
|||||||
return mHasVideo;
|
return mHasVideo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool IsWaitingMediaResources();
|
||||||
|
|
||||||
|
virtual bool IsDormantNeeded();
|
||||||
|
virtual void ReleaseMediaResources();
|
||||||
|
|
||||||
virtual nsresult ReadMetadata(VideoInfo* aInfo,
|
virtual nsresult ReadMetadata(VideoInfo* aInfo,
|
||||||
MetadataTags** aTags);
|
MetadataTags** aTags);
|
||||||
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
|
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 "GonkNativeWindow.h"
|
||||||
#include "GonkNativeWindowClient.h"
|
#include "GonkNativeWindowClient.h"
|
||||||
|
#include "OMXCodecProxy.h"
|
||||||
#include "OmxDecoder.h"
|
#include "OmxDecoder.h"
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
@@ -163,22 +164,7 @@ OmxDecoder::OmxDecoder(MediaResource *aResource,
|
|||||||
|
|
||||||
OmxDecoder::~OmxDecoder()
|
OmxDecoder::~OmxDecoder()
|
||||||
{
|
{
|
||||||
{
|
ReleaseMediaResources();
|
||||||
// Free all pending video buffers.
|
|
||||||
Mutex::Autolock autoLock(mSeekLock);
|
|
||||||
ReleaseAllPendingVideoBuffersLocked();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseVideoBuffer();
|
|
||||||
ReleaseAudioBuffer();
|
|
||||||
|
|
||||||
if (mVideoSource.get()) {
|
|
||||||
mVideoSource->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mAudioSource.get()) {
|
|
||||||
mAudioSource->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// unregister AMessage handler from ALooper.
|
// unregister AMessage handler from ALooper.
|
||||||
mLooper->unregisterHandler(mReflector->id());
|
mLooper->unregisterHandler(mReflector->id());
|
||||||
@@ -186,19 +172,15 @@ OmxDecoder::~OmxDecoder()
|
|||||||
mLooper->stop();
|
mLooper->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AutoStopMediaSource {
|
void OmxDecoder::statusChanged()
|
||||||
sp<MediaSource> mMediaSource;
|
{
|
||||||
public:
|
mozilla::ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||||
AutoStopMediaSource(const sp<MediaSource>& aMediaSource) : mMediaSource(aMediaSource) {
|
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
~AutoStopMediaSource() {
|
|
||||||
mMediaSource->stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static sp<IOMX> sOMX = nullptr;
|
static sp<IOMX> sOMX = nullptr;
|
||||||
static sp<IOMX> GetOMX() {
|
static sp<IOMX> GetOMX()
|
||||||
|
{
|
||||||
if(sOMX.get() == nullptr) {
|
if(sOMX.get() == nullptr) {
|
||||||
sOMX = new OMX;
|
sOMX = new OMX;
|
||||||
}
|
}
|
||||||
@@ -231,7 +213,6 @@ bool OmxDecoder::Init() {
|
|||||||
|
|
||||||
ssize_t audioTrackIndex = -1;
|
ssize_t audioTrackIndex = -1;
|
||||||
ssize_t videoTrackIndex = -1;
|
ssize_t videoTrackIndex = -1;
|
||||||
const char *audioMime = nullptr;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < extractor->countTracks(); ++i) {
|
for (size_t i = 0; i < extractor->countTracks(); ++i) {
|
||||||
sp<MetaData> meta = extractor->getTrackMetaData(i);
|
sp<MetaData> meta = extractor->getTrackMetaData(i);
|
||||||
@@ -249,7 +230,6 @@ bool OmxDecoder::Init() {
|
|||||||
videoTrackIndex = i;
|
videoTrackIndex = i;
|
||||||
} else if (audioTrackIndex == -1 && !strncasecmp(mime, "audio/", 6)) {
|
} else if (audioTrackIndex == -1 && !strncasecmp(mime, "audio/", 6)) {
|
||||||
audioTrackIndex = i;
|
audioTrackIndex = i;
|
||||||
audioMime = mime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,134 +240,52 @@ bool OmxDecoder::Init() {
|
|||||||
|
|
||||||
mResource->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
|
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;
|
int64_t totalDurationUs = 0;
|
||||||
|
int64_t durationUs = 0;
|
||||||
mNativeWindow = new GonkNativeWindow();
|
if (mVideoTrack.get() && mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
|
||||||
mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow);
|
if (durationUs > totalDurationUs)
|
||||||
|
totalDurationUs = durationUs;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (mAudioTrack.get() && mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
|
||||||
sp<MediaSource> audioTrack;
|
if (durationUs > totalDurationUs)
|
||||||
sp<MediaSource> audioSource;
|
totalDurationUs = durationUs;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set decoder state
|
|
||||||
mVideoTrack = videoTrack;
|
|
||||||
mVideoSource = videoSource;
|
|
||||||
mAudioTrack = audioTrack;
|
|
||||||
mAudioSource = audioSource;
|
|
||||||
mDurationUs = totalDurationUs;
|
mDurationUs = totalDurationUs;
|
||||||
|
|
||||||
|
// read video metadata
|
||||||
if (mVideoSource.get() && !SetVideoFormat()) {
|
if (mVideoSource.get() && !SetVideoFormat()) {
|
||||||
NS_WARNING("Couldn't set OMX video format");
|
NS_WARNING("Couldn't set OMX video format");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// To reliably get the channel and sample rate data we need to read from the
|
// read audio metadata
|
||||||
// audio source until we get a INFO_FORMAT_CHANGE status
|
|
||||||
if (mAudioSource.get()) {
|
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);
|
status_t err = mAudioSource->read(&mAudioBuffer);
|
||||||
if (err != INFO_FORMAT_CHANGED) {
|
if (err != INFO_FORMAT_CHANGED) {
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
@@ -411,6 +309,132 @@ bool OmxDecoder::Init() {
|
|||||||
return true;
|
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() {
|
bool OmxDecoder::SetVideoFormat() {
|
||||||
const char *componentName;
|
const char *componentName;
|
||||||
|
|
||||||
@@ -699,7 +723,8 @@ bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult OmxDecoder::Play() {
|
nsresult OmxDecoder::Play()
|
||||||
|
{
|
||||||
if (!mPaused) {
|
if (!mPaused) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@@ -714,7 +739,8 @@ nsresult OmxDecoder::Play() {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmxDecoder::Pause() {
|
void OmxDecoder::Pause()
|
||||||
|
{
|
||||||
if (mPaused) {
|
if (mPaused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "MPAPI.h"
|
#include "MPAPI.h"
|
||||||
#include "MediaResource.h"
|
#include "MediaResource.h"
|
||||||
#include "AbstractMediaDecoder.h"
|
#include "AbstractMediaDecoder.h"
|
||||||
|
#include "OMXCodecProxy.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
class OmxDecoder;
|
class OmxDecoder;
|
||||||
@@ -72,7 +73,7 @@ private:
|
|||||||
MediaStreamSource &operator=(const MediaStreamSource &);
|
MediaStreamSource &operator=(const MediaStreamSource &);
|
||||||
};
|
};
|
||||||
|
|
||||||
class OmxDecoder : public RefBase {
|
class OmxDecoder : public OMXCodecProxy::EventListener {
|
||||||
typedef MPAPI::AudioFrame AudioFrame;
|
typedef MPAPI::AudioFrame AudioFrame;
|
||||||
typedef MPAPI::VideoFrame VideoFrame;
|
typedef MPAPI::VideoFrame VideoFrame;
|
||||||
typedef mozilla::MediaResource MediaResource;
|
typedef mozilla::MediaResource MediaResource;
|
||||||
@@ -93,7 +94,7 @@ class OmxDecoder : public RefBase {
|
|||||||
sp<GonkNativeWindow> mNativeWindow;
|
sp<GonkNativeWindow> mNativeWindow;
|
||||||
sp<GonkNativeWindowClient> mNativeWindowClient;
|
sp<GonkNativeWindowClient> mNativeWindowClient;
|
||||||
sp<MediaSource> mVideoTrack;
|
sp<MediaSource> mVideoTrack;
|
||||||
sp<MediaSource> mVideoSource;
|
sp<OMXCodecProxy> mVideoSource;
|
||||||
sp<MediaSource> mAudioTrack;
|
sp<MediaSource> mAudioTrack;
|
||||||
sp<MediaSource> mAudioSource;
|
sp<MediaSource> mAudioSource;
|
||||||
int32_t mVideoWidth;
|
int32_t mVideoWidth;
|
||||||
@@ -162,7 +163,15 @@ public:
|
|||||||
OmxDecoder(MediaResource *aResource, AbstractMediaDecoder *aDecoder);
|
OmxDecoder(MediaResource *aResource, AbstractMediaDecoder *aDecoder);
|
||||||
~OmxDecoder();
|
~OmxDecoder();
|
||||||
|
|
||||||
|
// MediaResourceManagerClient::EventListener
|
||||||
|
virtual void statusChanged();
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
|
bool TryLoad();
|
||||||
|
bool IsDormantNeeded();
|
||||||
|
bool IsWaitingMediaResources();
|
||||||
|
bool AllocateMediaResources();
|
||||||
|
void ReleaseMediaResources();
|
||||||
bool SetVideoFormat();
|
bool SetVideoFormat();
|
||||||
bool SetAudioFormat();
|
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',
|
'MediaOmxDecoder.cpp',
|
||||||
'MediaOmxReader.cpp',
|
'MediaOmxReader.cpp',
|
||||||
'OmxDecoder.cpp',
|
'OmxDecoder.cpp',
|
||||||
|
'OMXCodecProxy.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ ifdef MOZ_OMX_DECODER #{
|
|||||||
# include OMX decoder
|
# include OMX decoder
|
||||||
SHARED_LIBRARY_LIBS += \
|
SHARED_LIBRARY_LIBS += \
|
||||||
$(DEPTH)/content/media/omx/$(LIB_PREFIX)gkconomx_s.$(LIB_SUFFIX) \
|
$(DEPTH)/content/media/omx/$(LIB_PREFIX)gkconomx_s.$(LIB_SUFFIX) \
|
||||||
|
$(DEPTH)/content/media/omx/mediaresourcemanager/$(LIB_PREFIX)mediaresourcemanager.$(LIB_SUFFIX) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
endif #}
|
endif #}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ LOCAL_INCLUDES += \
|
|||||||
-I$(topsrcdir)/content/events/src \
|
-I$(topsrcdir)/content/events/src \
|
||||||
-I$(topsrcdir)/gfx/skia/include/core \
|
-I$(topsrcdir)/gfx/skia/include/core \
|
||||||
-I$(topsrcdir)/gfx/skia/include/config \
|
-I$(topsrcdir)/gfx/skia/include/config \
|
||||||
|
-I$(topsrcdir)/content/media/omx/mediaresourcemanager \
|
||||||
-I$(srcdir) \
|
-I$(srcdir) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
|
#include "MediaResourceManagerService.h"
|
||||||
#include "mozilla/FileUtils.h"
|
#include "mozilla/FileUtils.h"
|
||||||
#include "mozilla/Hal.h"
|
#include "mozilla/Hal.h"
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
@@ -639,6 +640,10 @@ nsAppShell::Init()
|
|||||||
|
|
||||||
InitGonkMemoryPressureMonitoring();
|
InitGonkMemoryPressureMonitoring();
|
||||||
|
|
||||||
|
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||||
|
android::MediaResourceManagerService::instantiate();
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
|
nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
|
||||||
if (obsServ) {
|
if (obsServ) {
|
||||||
obsServ->AddObserver(this, "browser-ui-startup-complete", false);
|
obsServ->AddObserver(this, "browser-ui-startup-complete", false);
|
||||||
|
|||||||
Reference in New Issue
Block a user