diff options
-rw-r--r-- | include/media/stagefright/MediaSync.h | 12 | ||||
-rw-r--r-- | media/libstagefright/MediaSync.cpp | 70 |
2 files changed, 67 insertions, 15 deletions
diff --git a/include/media/stagefright/MediaSync.h b/include/media/stagefright/MediaSync.h index d1d634d..1eef211 100644 --- a/include/media/stagefright/MediaSync.h +++ b/include/media/stagefright/MediaSync.h @@ -169,7 +169,7 @@ private: class OutputListener : public BnProducerListener, public IBinder::DeathRecipient { public: - OutputListener(const sp<MediaSync> &sync); + OutputListener(const sp<MediaSync> &sync, const sp<IGraphicBufferProducer> &output); virtual ~OutputListener(); // From IProducerListener @@ -180,6 +180,7 @@ private: private: sp<MediaSync> mSync; + sp<IGraphicBufferProducer> mOutput; }; // mIsAbandoned is set to true when the input or output dies. @@ -192,6 +193,7 @@ private: size_t mNumOutstandingBuffers; sp<IGraphicBufferConsumer> mInput; sp<IGraphicBufferProducer> mOutput; + int mUsageFlagsFromOutput; sp<AudioTrack> mAudioTrack; uint32_t mNativeSampleRateInHz; @@ -207,6 +209,12 @@ private: // and that could cause problem if the producer of |mInput| only // supports pre-registered buffers. KeyedVector<uint64_t, sp<GraphicBuffer> > mBuffersFromInput; + + // Keep track of buffers sent to |mOutput|. When a new output surface comes + // in, those buffers will be returned to input and old output surface will + // be disconnected immediately. + KeyedVector<uint64_t, sp<GraphicBuffer> > mBuffersSentToOutput; + sp<ALooper> mLooper; float mPlaybackRate; @@ -241,7 +249,7 @@ private: // It gets called from an OutputListener. // During this callback, we detach the buffer from the output, and release // it to the input. A blocked onFrameAvailable call will be allowed to proceed. - void onBufferReleasedByOutput(); + void onBufferReleasedByOutput(sp<IGraphicBufferProducer> &output); // Return |buffer| back to the input. void returnBufferToInput_l(const sp<GraphicBuffer> &buffer, const sp<Fence> &fence); diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp index 97264fb..b402e48 100644 --- a/media/libstagefright/MediaSync.cpp +++ b/media/libstagefright/MediaSync.cpp @@ -49,6 +49,7 @@ MediaSync::MediaSync() mMutex(), mReleaseCondition(), mNumOutstandingBuffers(0), + mUsageFlagsFromOutput(0), mNativeSampleRateInHz(0), mNumFramesWritten(0), mHasAudio(false), @@ -82,10 +83,8 @@ MediaSync::~MediaSync() { status_t MediaSync::setSurface(const sp<IGraphicBufferProducer> &output) { Mutex::Autolock lock(mMutex); - // TODO: support suface change. - if (mOutput != NULL) { - ALOGE("setSurface: output surface has already been configured."); - return INVALID_OPERATION; + if (output == mOutput) { + return NO_ERROR; // same output surface. } if (output == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_VSYNC) { @@ -94,8 +93,24 @@ status_t MediaSync::setSurface(const sp<IGraphicBufferProducer> &output) { } if (output != NULL) { + int newUsage = 0; + output->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &newUsage); + + // Check usage flags only when current output surface has been used to create input surface. + if (mOutput != NULL && mInput != NULL) { + int ignoredFlags = (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER + | GRALLOC_USAGE_EXTERNAL_DISP); + // New output surface is not allowed to add new usage flag except ignored ones. + if ((newUsage & ~(mUsageFlagsFromOutput | ignoredFlags)) != 0) { + ALOGE("setSurface: new output surface has new usage flag not used by current one."); + return BAD_VALUE; + } + } + + // Try to connect to new output surface. If failed, current output surface will not + // be changed. IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; - sp<OutputListener> listener(new OutputListener(this)); + sp<OutputListener> listener(new OutputListener(this, output)); IInterface::asBinder(output)->linkToDeath(listener); status_t status = output->connect(listener, @@ -106,10 +121,18 @@ status_t MediaSync::setSurface(const sp<IGraphicBufferProducer> &output) { ALOGE("setSurface: failed to connect (%d)", status); return status; } + } - mOutput = output; + if (mOutput != NULL) { + mOutput->disconnect(NATIVE_WINDOW_API_MEDIA); + while (!mBuffersSentToOutput.isEmpty()) { + returnBufferToInput_l(mBuffersSentToOutput.valueAt(0), Fence::NO_FENCE); + mBuffersSentToOutput.removeItemsAt(0); + } } + mOutput = output; + return NO_ERROR; } @@ -181,9 +204,9 @@ status_t MediaSync::createInputSurface( if (status == NO_ERROR) { bufferConsumer->setConsumerName(String8("MediaSync")); // propagate usage bits from output surface - int usage = 0; - mOutput->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage); - bufferConsumer->setConsumerUsageBits(usage); + mUsageFlagsFromOutput = 0; + mOutput->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &mUsageFlagsFromOutput); + bufferConsumer->setConsumerUsageBits(mUsageFlagsFromOutput); *outBufferProducer = bufferProducer; mInput = bufferConsumer; } @@ -602,12 +625,24 @@ void MediaSync::renderOneBufferItem_l( const BufferItem &bufferItem) { return; } + if (mBuffersSentToOutput.indexOfKey(bufferItem.mGraphicBuffer->getId()) >= 0) { + // Something is wrong since this buffer should be held by output now, bail. + mInput->consumerDisconnect(); + onAbandoned_l(true /* isInput */); + return; + } + mBuffersSentToOutput.add(bufferItem.mGraphicBuffer->getId(), bufferItem.mGraphicBuffer); + ALOGV("queued buffer %#llx to output", (long long)bufferItem.mGraphicBuffer->getId()); } -void MediaSync::onBufferReleasedByOutput() { +void MediaSync::onBufferReleasedByOutput(sp<IGraphicBufferProducer> &output) { Mutex::Autolock lock(mMutex); + if (output != mOutput) { + return; // This is not the current output, ignore. + } + sp<GraphicBuffer> buffer; sp<Fence> fence; status_t status = mOutput->detachNextBuffer(&buffer, &fence); @@ -628,6 +663,13 @@ void MediaSync::onBufferReleasedByOutput() { return; } + ssize_t ix = mBuffersSentToOutput.indexOfKey(buffer->getId()); + if (ix < 0) { + // The buffer is unknown, maybe leftover, ignore. + return; + } + mBuffersSentToOutput.removeItemsAt(ix); + returnBufferToInput_l(buffer, fence); } @@ -727,13 +769,15 @@ void MediaSync::InputListener::binderDied(const wp<IBinder> &/* who */) { mSync->onAbandoned_l(true /* isInput */); } -MediaSync::OutputListener::OutputListener(const sp<MediaSync> &sync) - : mSync(sync) {} +MediaSync::OutputListener::OutputListener(const sp<MediaSync> &sync, + const sp<IGraphicBufferProducer> &output) + : mSync(sync), + mOutput(output) {} MediaSync::OutputListener::~OutputListener() {} void MediaSync::OutputListener::onBufferReleased() { - mSync->onBufferReleasedByOutput(); + mSync->onBufferReleasedByOutput(mOutput); } void MediaSync::OutputListener::binderDied(const wp<IBinder> &/* who */) { |