diff options
| author | Wei Jia <wjia@google.com> | 2015-05-12 23:46:53 +0000 | 
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-05-12 23:46:53 +0000 | 
| commit | 94183482a089690278fbe2346fa6946c9c7d97ef (patch) | |
| tree | 8127c65f4280eca22817c9ecf71457308ca7796f | |
| parent | 9586592ed94478af8ab2feb921459aa63a402970 (diff) | |
| parent | b6ea1292f8adae45d95c6f37d50c96534219b6d2 (diff) | |
| download | frameworks_av-94183482a089690278fbe2346fa6946c9c7d97ef.zip frameworks_av-94183482a089690278fbe2346fa6946c9c7d97ef.tar.gz frameworks_av-94183482a089690278fbe2346fa6946c9c7d97ef.tar.bz2  | |
Merge "MediaSync: support changing surface on the fly." into mnc-dev
| -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 */) {  | 
