author | Sotaro Ikeda <sikeda@mozilla.com> |
Thu, 28 May 2015 07:23:57 -0700 | |
changeset 246033 | 343ccb3b257684de2e39ec5b04081b7f530ce9f4 |
parent 246032 | 8225a3b75df6ec1fecc43ab66855320c6fd924e9 |
child 246034 | db3d40e8b4de09f3775b637d42428f39922c80ed |
push id | 60334 |
push user | sikeda@mozilla.com |
push date | Thu, 28 May 2015 14:24:07 +0000 |
treeherder | mozilla-inbound@343ccb3b2576 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bwu |
bugs | 1168531 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/media/omx/MediaCodecProxy.cpp +++ b/dom/media/omx/MediaCodecProxy.cpp @@ -133,16 +133,30 @@ MediaCodecProxy::AskMediaCodecAndWait() while (mPendingRequestMediaResource) { mMediaCodecLock.Wait(); } MCP_LOG("AskMediaCodecAndWait complete"); return true; } +bool +MediaCodecProxy::AsyncAskMediaCodec() +{ + if ((strncasecmp(mCodecMime.get(), "video/", 6) != 0) || + (mResourceHandler == nullptr)) { + return false; + } + // request video codec + mResourceHandler->requestResource(mCodecEncoder + ? IMediaResourceManagerService::HW_VIDEO_ENCODER + : IMediaResourceManagerService::HW_VIDEO_DECODER); + return true; +} + void MediaCodecProxy::SetMediaCodecFree() { if (mResourceHandler == nullptr) { return; } mozilla::MonitorAutoLock mon(mMediaCodecLock);
--- a/dom/media/omx/MediaCodecProxy.h +++ b/dom/media/omx/MediaCodecProxy.h @@ -134,16 +134,20 @@ public: bool UpdateOutputBuffers(); void ReleaseMediaBuffer(MediaBuffer* abuffer); // It asks for the OMX codec and blocked until the resource is grant to be // allocated. bool AskMediaCodecAndWait(); + // It asks for the OMX codec asynchronously. + // Only video codec is supported. + bool AsyncAskMediaCodec(); + // Free the OMX codec so others can allocate it. void SetMediaCodecFree(); protected: virtual ~MediaCodecProxy(); // MediaResourceHandler::EventListener::resourceReserved() virtual void resourceReserved();
--- a/dom/media/omx/MediaCodecReader.cpp +++ b/dom/media/omx/MediaCodecReader.cpp @@ -62,16 +62,43 @@ IsValidDurationUs(int64_t aDuration) } inline bool IsValidTimestampUs(int64_t aTimestamp) { return aTimestamp >= INT64_C(0); } +MediaCodecReader::VideoResourceListener::VideoResourceListener( + MediaCodecReader* aReader) + : mReader(aReader) +{ +} + +MediaCodecReader::VideoResourceListener::~VideoResourceListener() +{ + mReader = nullptr; +} + +void +MediaCodecReader::VideoResourceListener::codecReserved() +{ + if (mReader) { + mReader->VideoCodecReserved(); + } +} + +void +MediaCodecReader::VideoResourceListener::codecCanceled() +{ + if (mReader) { + mReader->VideoCodecCanceled(); + } +} + MediaCodecReader::TrackInputCopier::~TrackInputCopier() { } bool MediaCodecReader::TrackInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer) { @@ -244,16 +271,17 @@ MediaCodecReader::MediaCodecReader(Abstr , mIsWaitingResources(false) , mTextureClientIndexesLock("MediaCodecReader::mTextureClientIndexesLock") , mColorConverterBufferSize(0) , mParserMonitor("MediaCodecReader::mParserMonitor") , mParseDataFromCache(true) , mNextParserPosition(INT64_C(0)) , mParsedDataLength(INT64_C(0)) { + mVideoListener = new VideoResourceListener(this); } MediaCodecReader::~MediaCodecReader() { } nsresult MediaCodecReader::Init(MediaDecoderReader* aCloneDonor) @@ -643,16 +671,24 @@ MediaCodecReader::ReadMetadata(MediaInfo // relies on IsWaitingMediaResources() function. And the waiting state will be // changed by binder thread, so we store the waiting state in a cache value to // make them in the same waiting state. UpdateIsWaitingMediaResources(); if (IsWaitingMediaResources()) { return NS_OK; } + // Configure video codec after the codecReserved. + if (mVideoTrack.mSource != nullptr) { + if (!ConfigureMediaCodec(mVideoTrack)) { + DestroyMediaCodec(mVideoTrack); + return NS_ERROR_FAILURE; + } + } + // TODO: start streaming if (!UpdateDuration()) { return NS_ERROR_FAILURE; } if (!UpdateAudioInfo()) { return NS_ERROR_FAILURE; @@ -1254,45 +1290,42 @@ MediaCodecReader::CreateTaskQueues() } return true; } bool MediaCodecReader::CreateMediaCodecs() { - if (CreateMediaCodec(mLooper, mAudioTrack, nullptr) && - CreateMediaCodec(mLooper, mVideoTrack, nullptr)) { + if (CreateMediaCodec(mLooper, mAudioTrack, false, nullptr) && + CreateMediaCodec(mLooper, mVideoTrack, true, mVideoListener)) { return true; } return false; } bool MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper, Track& aTrack, + bool aAsync, wp<MediaCodecProxy::CodecResourceListener> aListener) { if (aTrack.mSource != nullptr && aTrack.mCodec == nullptr) { sp<MetaData> sourceFormat = aTrack.mSource->getFormat(); const char* mime; if (sourceFormat->findCString(kKeyMIMEType, &mime)) { aTrack.mCodec = MediaCodecProxy::CreateByType(aLooper, mime, false, aListener); } if (aTrack.mCodec == nullptr) { NS_WARNING("Couldn't create MediaCodecProxy"); return false; } - if (!aTrack.mCodec->AskMediaCodecAndWait()) { - NS_WARNING("AskMediaCodecAndWait fail"); - return false; - } if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { aTrack.mInputCopier = new VorbisInputCopier; } else { aTrack.mInputCopier = new TrackInputCopier; } uint32_t capability = MediaCodecProxy::kEmptyCapability; @@ -1305,18 +1338,26 @@ MediaCodecReader::CreateMediaCodec(sp<AL GonkBufferQueue::createBufferQueue(&producer, &consumer); aTrack.mNativeWindow = new GonkNativeWindow(consumer); aTrack.mGraphicBufferProducer = producer; #else aTrack.mNativeWindow = new GonkNativeWindow(); #endif } - if (!aTrack.mCodec->allocated() || !ConfigureMediaCodec(aTrack)) { - NS_WARNING("Couldn't create and configure MediaCodec synchronously"); + if (!aAsync && aTrack.mCodec->AskMediaCodecAndWait()) { + // Pending configure() and start() to codecReserved() if the creation + // should be asynchronous. + if (!aTrack.mCodec->allocated() || !ConfigureMediaCodec(aTrack)){ + NS_WARNING("Couldn't create and configure MediaCodec synchronously"); + DestroyMediaCodec(aTrack); + return false; + } + } else if (aAsync && !aTrack.mCodec->AsyncAskMediaCodec()) { + NS_WARNING("Couldn't request MediaCodec asynchronously"); DestroyMediaCodec(aTrack); return false; } } return true; } @@ -1838,18 +1879,17 @@ MediaCodecReader::EnsureCodecFormatParse if (status == OK) { aTrack.mCodec->releaseOutputBuffer(index); } else if (status == INFO_OUTPUT_BUFFERS_CHANGED) { // Update output buffers of MediaCodec. if (aTrack.mCodec->getOutputBuffers(&aTrack.mOutputBuffers) != OK) { NS_WARNING("Couldn't get output buffers from MediaCodec"); return false; } - } else if (status != -EAGAIN && status != INVALID_OPERATION) { - // FIXME: let INVALID_OPERATION pass? + } else if (status != -EAGAIN) { return false; // something wrong!!! } FillCodecInputData(aTrack); } return aTrack.mCodec->getOutputFormat(&format) == OK; } uint8_t* @@ -1870,9 +1910,27 @@ MediaCodecReader::GetColorConverterBuffe void MediaCodecReader::ClearColorConverterBuffer() { mColorConverterBuffer = nullptr; mColorConverterBufferSize = 0; } +// Called on Binder thread. +void +MediaCodecReader::VideoCodecReserved() +{ + mDecoder->NotifyWaitingForResourcesStatusChanged(); +} + +// Called on Binder thread. +void +MediaCodecReader::VideoCodecCanceled() +{ + if (mVideoTrack.mTaskQueue) { + RefPtr<nsIRunnable> task = + NS_NewRunnableMethod(this, &MediaCodecReader::ReleaseCriticalResources); + mVideoTrack.mTaskQueue->Dispatch(task.forget()); + } +} + } // namespace mozilla
--- a/dom/media/omx/MediaCodecReader.h +++ b/dom/media/omx/MediaCodecReader.h @@ -172,28 +172,55 @@ protected: Track(const Track &rhs) = delete; const Track &operator=(const Track&) = delete; }; // Receive a message from MessageHandler. // Called on MediaCodecReader::mLooper thread. void onMessageReceived(const android::sp<android::AMessage>& aMessage); + // Receive a notify from ResourceListener. + // Called on Binder thread. + virtual void VideoCodecReserved(); + virtual void VideoCodecCanceled(); + virtual bool CreateExtractor(); // Check the underlying HW resource is available and store the result in // mIsWaitingResources. void UpdateIsWaitingMediaResources(); android::sp<android::MediaExtractor> mExtractor; // A cache value updated by UpdateIsWaitingMediaResources(), makes the // "waiting resources state" is synchronous to StateMachine. bool mIsWaitingResources; private: + + // An intermediary class that can be managed by android::sp<T>. + // Redirect codecReserved() and codecCanceled() to MediaCodecReader. + class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener + { + public: + VideoResourceListener(MediaCodecReader* aReader); + ~VideoResourceListener(); + + virtual void codecReserved(); + virtual void codecCanceled(); + + private: + // Forbidden + VideoResourceListener() = delete; + VideoResourceListener(const VideoResourceListener& rhs) = delete; + const VideoResourceListener& operator=(const VideoResourceListener& rhs) = delete; + + MediaCodecReader* mReader; + }; + friend class VideoResourceListener; + class VorbisInputCopier : public TrackInputCopier { virtual bool Copy(android::MediaBuffer* aSourceBuffer, android::sp<android::ABuffer> aCodecBuffer); }; struct AudioTrack : public Track { @@ -322,16 +349,17 @@ private: void DestroyExtractor(); bool CreateMediaSources(); void DestroyMediaSources(); bool CreateMediaCodecs(); static bool CreateMediaCodec(android::sp<android::ALooper>& aLooper, Track& aTrack, + bool aAsync, android::wp<android::MediaCodecProxy::CodecResourceListener> aListener); static bool ConfigureMediaCodec(Track& aTrack); void DestroyMediaCodecs(); static void DestroyMediaCodec(Track& aTrack); bool CreateTaskQueues(); void ShutdownTaskQueues(); void DecodeVideoFrameTask(int64_t aTimeThreshold); @@ -382,16 +410,18 @@ private: static PLDHashOperator ReleaseTextureClient(TextureClient* aClient, size_t& aIndex, void* aUserArg); PLDHashOperator ReleaseTextureClient(TextureClient* aClient, size_t& aIndex); void ReleaseAllTextureClients(); + android::sp<VideoResourceListener> mVideoListener; + android::sp<android::ALooper> mLooper; android::sp<android::MetaData> mMetaData; Mutex mTextureClientIndexesLock; nsDataHashtable<nsPtrHashKey<TextureClient>, size_t> mTextureClientIndexes; // media tracks AudioTrack mAudioTrack;