diff options
| -rw-r--r-- | include/media/IOMX.h | 19 | ||||
| -rw-r--r-- | include/media/stagefright/ACodec.h | 14 | ||||
| -rw-r--r-- | media/libmedia/IOMX.cpp | 32 | ||||
| -rw-r--r-- | media/libstagefright/ACodec.cpp | 165 | ||||
| -rw-r--r-- | media/libstagefright/OMXClient.cpp | 12 | ||||
| -rw-r--r-- | media/libstagefright/include/OMX.h | 8 | ||||
| -rw-r--r-- | media/libstagefright/include/OMXNodeInstance.h | 17 | ||||
| -rw-r--r-- | media/libstagefright/omx/GraphicBufferSource.cpp | 50 | ||||
| -rw-r--r-- | media/libstagefright/omx/GraphicBufferSource.h | 3 | ||||
| -rw-r--r-- | media/libstagefright/omx/OMX.cpp | 15 | ||||
| -rw-r--r-- | media/libstagefright/omx/OMXNodeInstance.cpp | 105 | ||||
| -rw-r--r-- | media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp | 10 | 
12 files changed, 352 insertions, 98 deletions
diff --git a/include/media/IOMX.h b/include/media/IOMX.h index 26cc73e..84fdf83 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -92,7 +92,7 @@ public:              node_id node, OMX_U32 portIndex, OMX_BOOL enable,              OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) = 0; -   virtual status_t configureVideoTunnelMode( +    virtual status_t configureVideoTunnelMode(              node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,              OMX_U32 audioHwSync, native_handle_t **sidebandHandle) = 0; @@ -152,13 +152,23 @@ public:      virtual status_t freeBuffer(              node_id node, OMX_U32 port_index, buffer_id buffer) = 0; -    virtual status_t fillBuffer(node_id node, buffer_id buffer) = 0; - +    enum { +        kFenceTimeoutMs = 1000 +    }; +    // Calls OMX_FillBuffer on buffer, and passes |fenceFd| to component if it supports +    // fences. Otherwise, it waits on |fenceFd| before calling OMX_FillBuffer. +    // Takes ownership of |fenceFd| even if this call fails. +    virtual status_t fillBuffer(node_id node, buffer_id buffer, int fenceFd = -1) = 0; + +    // Calls OMX_EmptyBuffer on buffer (after updating buffer header with |range_offset|, +    // |range_length|, |flags| and |timestamp|). Passes |fenceFd| to component if it +    // supports fences. Otherwise, it waits on |fenceFd| before calling OMX_EmptyBuffer. +    // Takes ownership of |fenceFd| even if this call fails.      virtual status_t emptyBuffer(              node_id node,              buffer_id buffer,              OMX_U32 range_offset, OMX_U32 range_length, -            OMX_U32 flags, OMX_TICKS timestamp) = 0; +            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd = -1) = 0;      virtual status_t getExtensionIndex(              node_id node, @@ -190,6 +200,7 @@ struct omx_message {      } type;      IOMX::node_id node; +    int fenceFd; // used for EMPTY_BUFFER_DONE and FILL_BUFFER_DONE; client must close this      union {          // if type == EVENT diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index bbecc80..f7a3df7 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -160,11 +160,25 @@ private:          sp<ABuffer> mData;          sp<GraphicBuffer> mGraphicBuffer; +        int mFenceFd; + +        // The following field and 4 methods are used for debugging only +        bool mIsReadFence; +        // Store |fenceFd| and set read/write flag. Log error, if there is already a fence stored. +        void setReadFence(int fenceFd, const char *dbg); +        void setWriteFence(int fenceFd, const char *dbg); +        // Log error, if the current fence is not a read/write fence. +        void checkReadFence(const char *dbg); +        void checkWriteFence(const char *dbg);      };      static const char *_asString(BufferInfo::Status s);      void dumpBuffers(OMX_U32 portIndex); +    // If |fd| is non-negative, waits for fence with |fd| and logs an error if it fails. Returns +    // the error code or OK on success. If |fd| is negative, it returns OK +    status_t waitForFence(int fd, const char *dbg); +  #if TRACK_BUFFER_TIMING      struct BufferStats {          int64_t mEmptyBufferTimeUs; diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index cac2f7f..ca1cdc7 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -511,11 +511,15 @@ public:          return reply.readInt32();      } -    virtual status_t fillBuffer(node_id node, buffer_id buffer) { +    virtual status_t fillBuffer(node_id node, buffer_id buffer, int fenceFd) {          Parcel data, reply;          data.writeInterfaceToken(IOMX::getInterfaceDescriptor());          data.writeInt32((int32_t)node);          data.writeInt32((int32_t)buffer); +        data.writeInt32(fenceFd >= 0); +        if (fenceFd >= 0) { +            data.writeFileDescriptor(fenceFd, true /* takeOwnership */); +        }          remote()->transact(FILL_BUFFER, data, &reply);          return reply.readInt32(); @@ -525,7 +529,7 @@ public:              node_id node,              buffer_id buffer,              OMX_U32 range_offset, OMX_U32 range_length, -            OMX_U32 flags, OMX_TICKS timestamp) { +            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {          Parcel data, reply;          data.writeInterfaceToken(IOMX::getInterfaceDescriptor());          data.writeInt32((int32_t)node); @@ -534,6 +538,10 @@ public:          data.writeInt32(range_length);          data.writeInt32(flags);          data.writeInt64(timestamp); +        data.writeInt32(fenceFd >= 0); +        if (fenceFd >= 0) { +            data.writeFileDescriptor(fenceFd, true /* takeOwnership */); +        }          remote()->transact(EMPTY_BUFFER, data, &reply);          return reply.readInt32(); @@ -1012,7 +1020,9 @@ status_t BnOMX::onTransact(              node_id node = (node_id)data.readInt32();              buffer_id buffer = (buffer_id)data.readInt32(); -            reply->writeInt32(fillBuffer(node, buffer)); +            bool haveFence = data.readInt32(); +            int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1; +            reply->writeInt32(fillBuffer(node, buffer, fenceFd));              return NO_ERROR;          } @@ -1027,11 +1037,10 @@ status_t BnOMX::onTransact(              OMX_U32 range_length = data.readInt32();              OMX_U32 flags = data.readInt32();              OMX_TICKS timestamp = data.readInt64(); - -            reply->writeInt32( -                    emptyBuffer( -                        node, buffer, range_offset, range_length, -                        flags, timestamp)); +            bool haveFence = data.readInt32(); +            int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1; +            reply->writeInt32(emptyBuffer( +                    node, buffer, range_offset, range_length, flags, timestamp, fenceFd));              return NO_ERROR;          } @@ -1072,7 +1081,9 @@ public:          Parcel data, reply;          data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());          data.write(&msg, sizeof(msg)); - +        if (msg.fenceFd >= 0) { +            data.writeFileDescriptor(msg.fenceFd, true /* takeOwnership */); +        }          ALOGV("onMessage writing message %d, size %zu", msg.type, sizeof(msg));          remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY); @@ -1090,6 +1101,9 @@ status_t BnOMXObserver::onTransact(              omx_message msg;              data.read(&msg, sizeof(msg)); +            if (msg.fenceFd >= 0) { +                msg.fenceFd = ::dup(data.readFileDescriptor()); +            }              ALOGV("onTransact reading message %d, size %zu", msg.type, sizeof(msg)); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 08045d1..a770746 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -132,6 +132,7 @@ struct CodecObserver : public BnOMXObserver {              case omx_message::EMPTY_BUFFER_DONE:              {                  msg->setInt32("buffer", omx_msg.u.buffer_data.buffer); +                msg->setInt32("fence_fd", omx_msg.fenceFd);                  break;              } @@ -151,6 +152,8 @@ struct CodecObserver : public BnOMXObserver {                  msg->setInt64(                          "timestamp",                          omx_msg.u.extended_buffer_data.timestamp); +                msg->setInt32( +                        "fence_fd", omx_msg.fenceFd);                  break;              } @@ -199,13 +202,14 @@ protected:  private:      bool onOMXMessage(const sp<AMessage> &msg); -    bool onOMXEmptyBufferDone(IOMX::buffer_id bufferID); +    bool onOMXEmptyBufferDone(IOMX::buffer_id bufferID, int fenceFd);      bool onOMXFillBufferDone(              IOMX::buffer_id bufferID,              size_t rangeOffset, size_t rangeLength,              OMX_U32 flags, -            int64_t timeUs); +            int64_t timeUs, +            int fenceFd);      void getMoreInputDataIfPossible(); @@ -407,6 +411,38 @@ private:  //////////////////////////////////////////////////////////////////////////////// +void ACodec::BufferInfo::setWriteFence(int fenceFd, const char *dbg) { +    if (mFenceFd >= 0) { +        ALOGW("OVERWRITE OF %s fence %d by write fence %d in %s", +                mIsReadFence ? "read" : "write", mFenceFd, fenceFd, dbg); +    } +    mFenceFd = fenceFd; +    mIsReadFence = false; +} + +void ACodec::BufferInfo::setReadFence(int fenceFd, const char *dbg) { +    if (mFenceFd >= 0) { +        ALOGW("OVERWRITE OF %s fence %d by read fence %d in %s", +                mIsReadFence ? "read" : "write", mFenceFd, fenceFd, dbg); +    } +    mFenceFd = fenceFd; +    mIsReadFence = true; +} + +void ACodec::BufferInfo::checkWriteFence(const char *dbg) { +    if (mFenceFd >= 0 && mIsReadFence) { +        ALOGD("REUSING read fence %d as write fence in %s", mFenceFd, dbg); +    } +} + +void ACodec::BufferInfo::checkReadFence(const char *dbg) { +    if (mFenceFd >= 0 && !mIsReadFence) { +        ALOGD("REUSING write fence %d as read fence in %s", mFenceFd, dbg); +    } +} + +//////////////////////////////////////////////////////////////////////////////// +  ACodec::ACodec()      : mQuirks(0),        mNode(0), @@ -640,11 +676,12 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) {      // cancel undequeued buffers to new surface      if (!storingMetadataInDecodedBuffers() || mLegacyAdaptiveExperiment) {          for (size_t i = 0; i < buffers.size(); ++i) { -            const BufferInfo &info = buffers[i]; +            BufferInfo &info = buffers.editItemAt(i);              if (info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {                  ALOGV("canceling buffer %p", info.mGraphicBuffer->getNativeBuffer());                  err = nativeWindow->cancelBuffer( -                        nativeWindow, info.mGraphicBuffer->getNativeBuffer(), -1); +                        nativeWindow, info.mGraphicBuffer->getNativeBuffer(), info.mFenceFd); +                info.mFenceFd = -1;                  if (err != OK) {                      ALOGE("failed to cancel buffer %p to the new surface: %s (%d)",                              info.mGraphicBuffer->getNativeBuffer(), @@ -721,6 +758,7 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {                  BufferInfo info;                  info.mStatus = BufferInfo::OWNED_BY_US; +                info.mFenceFd = -1;                  uint32_t requiresAllocateBufferBit =                      (portIndex == kPortIndexInput) @@ -925,7 +963,8 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() {      // Dequeue buffers and send them to OMX      for (OMX_U32 i = 0; i < bufferCount; i++) {          ANativeWindowBuffer *buf; -        err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf); +        int fenceFd; +        err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);          if (err != 0) {              ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);              break; @@ -934,6 +973,8 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() {          sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));          BufferInfo info;          info.mStatus = BufferInfo::OWNED_BY_US; +        info.mFenceFd = fenceFd; +        info.mIsReadFence = false;          info.mData = new ABuffer(NULL /* data */, bufferSize /* capacity */);          info.mGraphicBuffer = graphicBuffer;          mBuffers[kPortIndexOutput].push(info); @@ -1004,6 +1045,7 @@ status_t ACodec::allocateOutputMetadataBuffers() {      for (OMX_U32 i = 0; i < bufferCount; i++) {          BufferInfo info;          info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; +        info.mFenceFd = -1;          info.mGraphicBuffer = NULL;          info.mDequeuedAt = mDequeueCounter; @@ -1040,7 +1082,8 @@ status_t ACodec::allocateOutputMetadataBuffers() {              BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);              ANativeWindowBuffer *buf; -            err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf); +            int fenceFd; +            err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);              if (err != 0) {                  ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);                  break; @@ -1050,6 +1093,7 @@ status_t ACodec::allocateOutputMetadataBuffers() {              mOMX->updateGraphicBufferInMeta(                      mNode, kPortIndexOutput, graphicBuffer, info->mBufferID);              info->mStatus = BufferInfo::OWNED_BY_US; +            info->setWriteFence(fenceFd, "allocateOutputMetadataBuffers for legacy");              info->mGraphicBuffer = graphicBuffer;          } @@ -1083,7 +1127,9 @@ status_t ACodec::submitOutputMetadataBuffer() {            mComponentName.c_str(), info->mBufferID, info->mGraphicBuffer.get());      --mMetadataBuffersToSubmit; -    status_t err = mOMX->fillBuffer(mNode, info->mBufferID); +    info->checkWriteFence("submitOutputMetadataBuffer"); +    status_t err = mOMX->fillBuffer(mNode, info->mBufferID, info->mFenceFd); +    info->mFenceFd = -1;      if (err == OK) {          info->mStatus = BufferInfo::OWNED_BY_COMPONENT;      } @@ -1091,6 +1137,16 @@ status_t ACodec::submitOutputMetadataBuffer() {      return err;  } +status_t ACodec::waitForFence(int fd, const char *dbg ) { +    status_t res = OK; +    if (fd >= 0) { +        sp<Fence> fence = new Fence(fd); +        res = fence->wait(IOMX::kFenceTimeoutMs); +        ALOGW_IF(res != OK, "FENCE TIMEOUT for %d in %s", fd, dbg); +    } +    return res; +} +  // static  const char *ACodec::_asString(BufferInfo::Status s) {      switch (s) { @@ -1123,8 +1179,10 @@ status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) {      ALOGV("[%s] Calling cancelBuffer on buffer %u",           mComponentName.c_str(), info->mBufferID); +    info->checkWriteFence("cancelBufferToNativeWindow");      int err = mNativeWindow->cancelBuffer( -        mNativeWindow.get(), info->mGraphicBuffer.get(), -1); +        mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd); +    info->mFenceFd = -1;      ALOGW_IF(err != 0, "[%s] can not return buffer %u to native window",              mComponentName.c_str(), info->mBufferID); @@ -1144,9 +1202,11 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {          return NULL;      } +    int fenceFd = -1;      do { -        if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) { -            ALOGE("dequeueBuffer failed."); +        status_t err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd); +        if (err != 0) { +            ALOGE("dequeueBuffer failed: %s(%d).", asString(err), err);              return NULL;          } @@ -1170,7 +1230,7 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {                  }                  ALOGV("dequeued buffer %p", info->mGraphicBuffer->getNativeBuffer());                  info->mStatus = BufferInfo::OWNED_BY_US; - +                info->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow");                  return info;              }          } @@ -1213,6 +1273,7 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {      // discard buffer in LRU info and replace with new buffer      oldest->mGraphicBuffer = new GraphicBuffer(buf, false);      oldest->mStatus = BufferInfo::OWNED_BY_US; +    oldest->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow for oldest");      mOMX->updateGraphicBufferInMeta(              mNode, kPortIndexOutput, oldest->mGraphicBuffer, @@ -1277,6 +1338,18 @@ status_t ACodec::freeBuffer(OMX_U32 portIndex, size_t i) {      BufferInfo *info = &mBuffers[portIndex].editItemAt(i);      status_t err = OK; +    // there should not be any fences in the metadata +    MetadataBufferType type = +        portIndex == kPortIndexOutput ? mOutputMetadataType : mInputMetadataType; +    if (type == kMetadataBufferTypeANWBuffer && info->mData != NULL +            && info->mData->size() >= sizeof(VideoNativeMetadata)) { +        int fenceFd = ((VideoNativeMetadata *)info->mData->data())->nFenceFd; +        if (fenceFd >= 0) { +            ALOGW("unreleased fence (%d) in %s metadata buffer %zu", +                    fenceFd, portIndex == kPortIndexInput ? "input" : "output", i); +        } +    } +      switch (info->mStatus) {          case BufferInfo::OWNED_BY_US:              if (portIndex == kPortIndexOutput && mNativeWindow != NULL) { @@ -1294,6 +1367,10 @@ status_t ACodec::freeBuffer(OMX_U32 portIndex, size_t i) {              break;      } +    if (info->mFenceFd >= 0) { +        ::close(info->mFenceFd); +    } +      // remove buffer even if mOMX->freeBuffer fails      mBuffers[portIndex].removeAt(i); @@ -4433,9 +4510,12 @@ bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) {          case omx_message::EMPTY_BUFFER_DONE:          {              IOMX::buffer_id bufferID; +            int32_t fenceFd; +              CHECK(msg->findInt32("buffer", (int32_t*)&bufferID)); +            CHECK(msg->findInt32("fence_fd", &fenceFd)); -            return onOMXEmptyBufferDone(bufferID); +            return onOMXEmptyBufferDone(bufferID, fenceFd);          }          case omx_message::FILL_BUFFER_DONE: @@ -4443,19 +4523,21 @@ bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) {              IOMX::buffer_id bufferID;              CHECK(msg->findInt32("buffer", (int32_t*)&bufferID)); -            int32_t rangeOffset, rangeLength, flags; +            int32_t rangeOffset, rangeLength, flags, fenceFd;              int64_t timeUs;              CHECK(msg->findInt32("range_offset", &rangeOffset));              CHECK(msg->findInt32("range_length", &rangeLength));              CHECK(msg->findInt32("flags", &flags));              CHECK(msg->findInt64("timestamp", &timeUs)); +            CHECK(msg->findInt32("fence_fd", &fenceFd));              return onOMXFillBufferDone(                      bufferID,                      (size_t)rangeOffset, (size_t)rangeLength,                      (OMX_U32)flags, -                    timeUs); +                    timeUs, +                    fenceFd);          }          default: @@ -4486,7 +4568,7 @@ bool ACodec::BaseState::onOMXEvent(      return true;  } -bool ACodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID) { +bool ACodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID, int fenceFd) {      ALOGV("[%s] onOMXEmptyBufferDone %u",           mCodec->mComponentName.c_str(), bufferID); @@ -4495,10 +4577,20 @@ bool ACodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID) {      if (status != BufferInfo::OWNED_BY_COMPONENT) {          ALOGE("Wrong ownership in EBD: %s(%d) buffer #%u", _asString(status), status, bufferID);          mCodec->dumpBuffers(kPortIndexInput); +        if (fenceFd >= 0) { +            ::close(fenceFd); +        }          return false;      }      info->mStatus = BufferInfo::OWNED_BY_US; +    // input buffers cannot take fences, so wait for any fence now +    (void)mCodec->waitForFence(fenceFd, "onOMXEmptyBufferDone"); +    fenceFd = -1; + +    // still save fence for completeness +    info->setWriteFence(fenceFd, "onOMXEmptyBufferDone"); +      // We're in "store-metadata-in-buffers" mode, the underlying      // OMX component had access to data that's implicitly refcounted      // by this "MediaBuffer" object. Now that the OMX component has @@ -4670,13 +4762,16 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {                          mCodec->submitOutputMetadataBuffer();                      }                  } +                info->checkReadFence("onInputBufferFilled");                  status_t err2 = mCodec->mOMX->emptyBuffer(                      mCodec->mNode,                      bufferID,                      0,                      buffer->size(),                      flags, -                    timeUs); +                    timeUs, +                    info->mFenceFd); +                info->mFenceFd = -1;                  if (err2 != OK) {                      mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err2));                      return; @@ -4704,13 +4799,16 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {                  ALOGV("[%s] calling emptyBuffer %u signalling EOS",                       mCodec->mComponentName.c_str(), bufferID); +                info->checkReadFence("onInputBufferFilled");                  status_t err2 = mCodec->mOMX->emptyBuffer(                          mCodec->mNode,                          bufferID,                          0,                          0,                          OMX_BUFFERFLAG_EOS, -                        0); +                        0, +                        info->mFenceFd); +                info->mFenceFd = -1;                  if (err2 != OK) {                      mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err2));                      return; @@ -4765,7 +4863,8 @@ bool ACodec::BaseState::onOMXFillBufferDone(          IOMX::buffer_id bufferID,          size_t rangeOffset, size_t rangeLength,          OMX_U32 flags, -        int64_t timeUs) { +        int64_t timeUs, +        int fenceFd) {      ALOGV("[%s] onOMXFillBufferDone %u time %" PRId64 " us, flags = 0x%08x",           mCodec->mComponentName.c_str(), bufferID, timeUs, flags); @@ -4794,12 +4893,22 @@ bool ACodec::BaseState::onOMXFillBufferDone(          ALOGE("Wrong ownership in FBD: %s(%d) buffer #%u", _asString(status), status, bufferID);          mCodec->dumpBuffers(kPortIndexOutput);          mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION); +        if (fenceFd >= 0) { +            ::close(fenceFd); +        }          return true;      }      info->mDequeuedAt = ++mCodec->mDequeueCounter;      info->mStatus = BufferInfo::OWNED_BY_US; +    // byte buffers cannot take fences, so wait for any fence now +    if (mCodec->mNativeWindow == NULL) { +        (void)mCodec->waitForFence(fenceFd, "onOMXFillBufferDone"); +        fenceFd = -1; +    } +    info->setReadFence(fenceFd, "onOMXFillBufferDone"); +      PortMode mode = getPortMode(kPortIndexOutput);      switch (mode) { @@ -4813,7 +4922,8 @@ bool ACodec::BaseState::onOMXFillBufferDone(                  ALOGV("[%s] calling fillBuffer %u",                       mCodec->mComponentName.c_str(), info->mBufferID); -                err = mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID); +                err = mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID, info->mFenceFd); +                info->mFenceFd = -1;                  if (err != OK) {                      mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));                      return true; @@ -4946,17 +5056,23 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {          err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs);          ALOGW_IF(err != NO_ERROR, "failed to set buffer timestamp: %d", err); +        info->checkReadFence("onOutputBufferDrained before queueBuffer");          err = mCodec->mNativeWindow->queueBuffer( -                    mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), -1); +                    mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd); +        info->mFenceFd = -1;          if (err == OK) {              info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;          } else {              mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));              info->mStatus = BufferInfo::OWNED_BY_US; +            // keeping read fence as write fence to avoid clobbering +            info->mIsReadFence = false;          }      } else {          if (mCodec->mNativeWindow != NULL &&              (info->mData == NULL || info->mData->size() != 0)) { +            // move read fence into write fence to avoid clobbering +            info->mIsReadFence = false;              ATRACE_NAME("frame-drop");          }          info->mStatus = BufferInfo::OWNED_BY_US; @@ -4991,7 +5107,10 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {                  if (info != NULL) {                      ALOGV("[%s] calling fillBuffer %u",                           mCodec->mComponentName.c_str(), info->mBufferID); -                    status_t err = mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID); +                    info->checkWriteFence("onOutputBufferDrained::RESUBMIT_BUFFERS"); +                    status_t err = mCodec->mOMX->fillBuffer( +                            mCodec->mNode, info->mBufferID, info->mFenceFd); +                    info->mFenceFd = -1;                      if (err == OK) {                          info->mStatus = BufferInfo::OWNED_BY_COMPONENT;                      } else { @@ -5754,7 +5873,9 @@ void ACodec::ExecutingState::submitRegularOutputBuffers() {          ALOGV("[%s] calling fillBuffer %u", mCodec->mComponentName.c_str(), info->mBufferID); -        status_t err = mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID); +        info->checkWriteFence("submitRegularOutputBuffers"); +        status_t err = mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID, info->mFenceFd); +        info->mFenceFd = -1;          if (err != OK) {              failed = true;              break; diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 5d04628..e69890d 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -125,13 +125,13 @@ struct MuxOMX : public IOMX {      virtual status_t freeBuffer(              node_id node, OMX_U32 port_index, buffer_id buffer); -    virtual status_t fillBuffer(node_id node, buffer_id buffer); +    virtual status_t fillBuffer(node_id node, buffer_id buffer, int fenceFd);      virtual status_t emptyBuffer(              node_id node,              buffer_id buffer,              OMX_U32 range_offset, OMX_U32 range_length, -            OMX_U32 flags, OMX_TICKS timestamp); +            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);      virtual status_t getExtensionIndex(              node_id node, @@ -385,17 +385,17 @@ status_t MuxOMX::freeBuffer(      return getOMX(node)->freeBuffer(node, port_index, buffer);  } -status_t MuxOMX::fillBuffer(node_id node, buffer_id buffer) { -    return getOMX(node)->fillBuffer(node, buffer); +status_t MuxOMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) { +    return getOMX(node)->fillBuffer(node, buffer, fenceFd);  }  status_t MuxOMX::emptyBuffer(          node_id node,          buffer_id buffer,          OMX_U32 range_offset, OMX_U32 range_length, -        OMX_U32 flags, OMX_TICKS timestamp) { +        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {      return getOMX(node)->emptyBuffer( -            node, buffer, range_offset, range_length, flags, timestamp); +            node, buffer, range_offset, range_length, flags, timestamp, fenceFd);  }  status_t MuxOMX::getExtensionIndex( diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index c34954b..d468dfc 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -118,13 +118,13 @@ public:      virtual status_t freeBuffer(              node_id node, OMX_U32 port_index, buffer_id buffer); -    virtual status_t fillBuffer(node_id node, buffer_id buffer); +    virtual status_t fillBuffer(node_id node, buffer_id buffer, int fenceFd);      virtual status_t emptyBuffer(              node_id node,              buffer_id buffer,              OMX_U32 range_offset, OMX_U32 range_length, -            OMX_U32 flags, OMX_TICKS timestamp); +            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);      virtual status_t getExtensionIndex(              node_id node, @@ -148,10 +148,10 @@ public:              OMX_IN OMX_PTR pEventData);      OMX_ERRORTYPE OnEmptyBufferDone( -            node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); +            node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd);      OMX_ERRORTYPE OnFillBufferDone( -            node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); +            node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd);      void invalidateNodeID(node_id node); diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index fe6dccd..76df815 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -105,16 +105,16 @@ struct OMXNodeInstance {      status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer); -    status_t fillBuffer(OMX::buffer_id buffer); +    status_t fillBuffer(OMX::buffer_id buffer, int fenceFd);      status_t emptyBuffer(              OMX::buffer_id buffer,              OMX_U32 rangeOffset, OMX_U32 rangeLength, -            OMX_U32 flags, OMX_TICKS timestamp); +            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);      status_t emptyGraphicBuffer(              OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &buffer, -            OMX_U32 flags, OMX_TICKS timestamp); +            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);      status_t getExtensionIndex(              const char *parameterName, OMX_INDEXTYPE *index); @@ -208,9 +208,18 @@ private:      status_t storeMetaDataInBuffers_l(              OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type); +    // Stores fence into buffer if it is ANWBuffer type and has enough space. +    // otherwise, waits for the fence to signal.  Takes ownership of |fenceFd|. +    status_t storeFenceInMeta_l( +            OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex); + +    // Retrieves the fence from buffer if ANWBuffer type and has enough space. Otherwise, returns -1 +    int retrieveFenceFromMeta_l( +            OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex); +      status_t emptyBuffer_l(              OMX_BUFFERHEADERTYPE *header, -            OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr); +            OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr, int fenceFd);      status_t updateGraphicBufferInMeta_l(              OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer, diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index f797e63..be91510 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -64,6 +64,7 @@ GraphicBufferSource::GraphicBufferSource(      mLatestBufferId(-1),      mLatestBufferFrameNum(0),      mLatestBufferUseCount(0), +    mLatestBufferFence(Fence::NO_FENCE),      mRepeatBufferDeferred(false),      mTimePerCaptureUs(-1ll),      mTimePerFrameUs(-1ll), @@ -226,9 +227,8 @@ void GraphicBufferSource::addCodecBuffer(OMX_BUFFERHEADERTYPE* header) {      mCodecBuffers.add(codecBuffer);  } -void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { +void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header, int fenceFd) {      Mutex::Autolock autoLock(mMutex); -      if (!mExecuting) {          return;      } @@ -237,6 +237,9 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {      if (cbi < 0) {          // This should never happen.          ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header); +        if (fenceFd >= 0) { +            ::close(fenceFd); +        }          return;      } @@ -258,6 +261,9 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {          }          // No GraphicBuffer to deal with, no additional input or output is          // expected, so just return. +        if (fenceFd >= 0) { +            ::close(fenceFd); +        }          return;      } @@ -291,6 +297,7 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {      // If we find a match, release that slot.  If we don't, the BufferQueue      // has dropped that GraphicBuffer, and there's nothing for us to release.      int id = codecBuffer.mBuf; +    sp<Fence> fence = new Fence(fenceFd);      if (mBufferSlot[id] != NULL &&          mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {          ALOGV("cbi %d matches bq slot %d, handle=%p", @@ -304,15 +311,16 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {                  int outSlot;                  mConsumer->attachBuffer(&outSlot, mBufferSlot[id]);                  mConsumer->releaseBuffer(outSlot, 0, -                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);              } else {                  mConsumer->releaseBuffer(id, codecBuffer.mFrameNumber, -                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);              }          }      } else {          ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d",                  cbi); +        // we will not reuse codec buffer, so there is no need to wait for fence      }      // Mark the codec buffer as available by clearing the GraphicBuffer ref. @@ -394,7 +402,7 @@ void GraphicBufferSource::suspend(bool suspend) {                  mConsumer->detachBuffer(item.mBuf);                  mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer);                  mConsumer->releaseBuffer(item.mBuf, 0, -                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);              } else {                  mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,                          EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); @@ -447,13 +455,6 @@ bool GraphicBufferSource::fillCodecBuffer_l() {      mNumFramesAvailable--; -    // Wait for it to become available. -    err = item.mFence->waitForever("GraphicBufferSource::fillCodecBuffer_l"); -    if (err != OK) { -        ALOGW("failed to wait for buffer fence: %d", err); -        // keep going -    } -      // If this is the first time we're seeing this buffer, add it to our      // slot table.      if (item.mGraphicBuffer != NULL) { @@ -489,11 +490,12 @@ bool GraphicBufferSource::fillCodecBuffer_l() {              mConsumer->detachBuffer(item.mBuf);              mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer);              mConsumer->releaseBuffer(item.mBuf, 0, -                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);          } else {              mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, -                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);          } +        // item.mFence is released at the end of this method      } else {          ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);          setLatestBuffer_l(item, dropped); @@ -520,9 +522,10 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {                  mLatestBufferFrameNum,                  EGL_NO_DISPLAY,                  EGL_NO_SYNC_KHR, -                Fence::NO_FENCE); +                mLatestBufferFence);          mLatestBufferId = -1;          mLatestBufferFrameNum = 0; +        mLatestBufferFence = Fence::NO_FENCE;          return false;      } @@ -537,6 +540,7 @@ bool GraphicBufferSource::repeatLatestBuffer_l() {      item.mBuf = mLatestBufferId;      item.mFrameNumber = mLatestBufferFrameNum;      item.mTimestamp = mRepeatLastFrameTimestamp; +    item.mFence = mLatestBufferFence;      status_t err = submitBuffer_l(item, cbi); @@ -576,12 +580,13 @@ void GraphicBufferSource::setLatestBuffer_l(                  mConsumer->attachBuffer(&outSlot, mBufferSlot[mLatestBufferId]);                  mConsumer->releaseBuffer(outSlot, 0, -                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, mLatestBufferFence);              } else {                  mConsumer->releaseBuffer(                          mLatestBufferId, mLatestBufferFrameNum, -                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, mLatestBufferFence);              } +            // mLatestBufferFence will be set to new fence just below          }      } @@ -592,6 +597,7 @@ void GraphicBufferSource::setLatestBuffer_l(      mLatestBufferUseCount = dropped ? 0 : 1;      mRepeatBufferDeferred = false;      mRepeatLastFrameCount = kRepeatLastFrameCount; +    mLatestBufferFence = item.mFence;      if (mReflector != NULL) {          sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector); @@ -687,8 +693,7 @@ int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {      return timeUs;  } -status_t GraphicBufferSource::submitBuffer_l( -        const BufferItem &item, int cbi) { +status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {      ALOGV("submitBuffer_l cbi=%d", cbi);      int64_t timeUs = getTimestamp(item); @@ -704,7 +709,8 @@ status_t GraphicBufferSource::submitBuffer_l(      OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;      sp<GraphicBuffer> buffer = codecBuffer.mGraphicBuffer;      status_t err = mNodeInstance->emptyGraphicBuffer( -            header, buffer, OMX_BUFFERFLAG_ENDOFFRAME, timeUs); +            header, buffer, OMX_BUFFERFLAG_ENDOFFRAME, timeUs, +            item.mFence->isValid() ? item.mFence->dup() : -1);      if (err != OK) {          ALOGW("WARNING: emptyNativeWindowBuffer failed: 0x%x", err);          codecBuffer.mGraphicBuffer = NULL; @@ -737,7 +743,7 @@ void GraphicBufferSource::submitEndOfInputStream_l() {      OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;      status_t err = mNodeInstance->emptyGraphicBuffer(              header, NULL /* buffer */, OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS, -            0 /* timestamp */); +            0 /* timestamp */, -1 /* fenceFd */);      if (err != OK) {          ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);      } else { @@ -799,7 +805,7 @@ void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) {                  mConsumer->detachBuffer(item.mBuf);                  mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer);                  mConsumer->releaseBuffer(item.mBuf, 0, -                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); +                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);              } else {                  mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,                          EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 21ee96a..555bbec 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -93,7 +93,7 @@ public:      // Called from OnEmptyBufferDone.  If we have a BQ buffer available,      // fill it with a new frame of data; otherwise, just mark it as available. -    void codecBufferEmptied(OMX_BUFFERHEADERTYPE* header); +    void codecBufferEmptied(OMX_BUFFERHEADERTYPE* header, int fenceFd);      // Called when omx_message::FILL_BUFFER_DONE is received. (Currently the      // buffer source will fix timestamp in the header if needed.) @@ -274,6 +274,7 @@ private:      int mLatestBufferId;      uint64_t mLatestBufferFrameNum;      int32_t mLatestBufferUseCount; +    sp<Fence> mLatestBufferFence;      // The previous buffer should've been repeated but      // no codec buffer was available at the time. diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 4ca827c..76217ec 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -415,17 +415,17 @@ status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {              port_index, buffer);  } -status_t OMX::fillBuffer(node_id node, buffer_id buffer) { -    return findInstance(node)->fillBuffer(buffer); +status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) { +    return findInstance(node)->fillBuffer(buffer, fenceFd);  }  status_t OMX::emptyBuffer(          node_id node,          buffer_id buffer,          OMX_U32 range_offset, OMX_U32 range_length, -        OMX_U32 flags, OMX_TICKS timestamp) { +        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {      return findInstance(node)->emptyBuffer( -            buffer, range_offset, range_length, flags, timestamp); +            buffer, range_offset, range_length, flags, timestamp, fenceFd);  }  status_t OMX::getExtensionIndex( @@ -459,6 +459,7 @@ OMX_ERRORTYPE OMX::OnEvent(      omx_message msg;      msg.type = omx_message::EVENT;      msg.node = node; +    msg.fenceFd = -1;      msg.u.event_data.event = eEvent;      msg.u.event_data.data1 = nData1;      msg.u.event_data.data2 = nData2; @@ -469,12 +470,13 @@ OMX_ERRORTYPE OMX::OnEvent(  }  OMX_ERRORTYPE OMX::OnEmptyBufferDone( -        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { +        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) {      ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);      omx_message msg;      msg.type = omx_message::EMPTY_BUFFER_DONE;      msg.node = node; +    msg.fenceFd = fenceFd;      msg.u.buffer_data.buffer = buffer;      findDispatcher(node)->post(msg); @@ -483,12 +485,13 @@ OMX_ERRORTYPE OMX::OnEmptyBufferDone(  }  OMX_ERRORTYPE OMX::OnFillBufferDone( -        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { +        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer, int fenceFd) {      ALOGV("OnFillBufferDone buffer=%p", pBuffer);      omx_message msg;      msg.type = omx_message::FILL_BUFFER_DONE;      msg.node = node; +    msg.fenceFd = fenceFd;      msg.u.extended_buffer_data.buffer = buffer;      msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;      msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index e4b2de4..4ba4aeb 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -76,11 +76,11 @@ static const OMX_U32 kPortIndexOutput = 1;  #define SIMPLE_NEW_BUFFER(buffer_id, port, size, data) \      NEW_BUFFER_FMT(buffer_id, port, "%zu@%p", (size), (data)) -#define EMPTY_BUFFER(addr, header) "%#x [%u@%p]", \ -    (addr), (header)->nAllocLen, (header)->pBuffer -#define FULL_BUFFER(addr, header) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld]", \ +#define EMPTY_BUFFER(addr, header, fenceFd) "%#x [%u@%p fc=%d]", \ +    (addr), (header)->nAllocLen, (header)->pBuffer, (fenceFd) +#define FULL_BUFFER(addr, header, fenceFd) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld fc=%d]", \      (intptr_t)(addr), (header)->nAllocLen, (header)->pBuffer, \ -    (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp +    (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp, (fenceFd)  #define WITH_STATS_WRAPPER(fmt, ...) fmt " { IN=%zu/%zu OUT=%zu/%zu }", ##__VA_ARGS__, \      mInputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexInput], \ @@ -1050,7 +1050,7 @@ status_t OMXNodeInstance::freeBuffer(      return StatusFromOMXError(err);  } -status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) { +status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer, int fenceFd) {      Mutex::Autolock autoLock(mLock);      OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); @@ -1058,15 +1058,22 @@ status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {      header->nOffset = 0;      header->nFlags = 0; +    // meta now owns fenceFd +    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexOutput); +    if (res != OK) { +        CLOG_ERROR(fillBuffer::storeFenceInMeta, res, EMPTY_BUFFER(buffer, header, fenceFd)); +        return res; +    } +      {          Mutex::Autolock _l(mDebugLock);          mOutputBuffersWithCodec.add(header); -        CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header))); +        CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header, fenceFd)));      }      OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);      if (err != OMX_ErrorNone) { -        CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header)); +        CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header, fenceFd));          Mutex::Autolock _l(mDebugLock);          mOutputBuffersWithCodec.remove(header);      } @@ -1076,7 +1083,7 @@ status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {  status_t OMXNodeInstance::emptyBuffer(          OMX::buffer_id buffer,          OMX_U32 rangeOffset, OMX_U32 rangeLength, -        OMX_U32 flags, OMX_TICKS timestamp) { +        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {      Mutex::Autolock autoLock(mLock);      OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); @@ -1084,6 +1091,9 @@ status_t OMXNodeInstance::emptyBuffer(      // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.      if (rangeOffset > header->nAllocLen              || rangeLength > header->nAllocLen - rangeOffset) { +        if (fenceFd >= 0) { +            ::close(fenceFd); +        }          return BAD_VALUE;      }      header->nFilledLen = rangeLength; @@ -1110,7 +1120,7 @@ status_t OMXNodeInstance::emptyBuffer(          buffer_meta->CopyToOMX(header);      } -    return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer); +    return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd);  }  // log queued buffer activity for the next few input and/or output frames @@ -1137,11 +1147,62 @@ void OMXNodeInstance::unbumpDebugLevel_l(size_t portIndex) {      }  } +status_t OMXNodeInstance::storeFenceInMeta_l( +        OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex) { +    // propagate fence if component supports it; wait for it otherwise +    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nFilledLen : header->nAllocLen; +    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer +            && metaSize >= sizeof(VideoNativeMetadata)) { +        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer); +        if (nativeMeta.nFenceFd >= 0) { +            ALOGE("fence (%d) already exists in meta", nativeMeta.nFenceFd); +            if (fenceFd >= 0) { +                ::close(fenceFd); +            } +            return ALREADY_EXISTS; +        } +        nativeMeta.nFenceFd = fenceFd; +    } else if (fenceFd >= 0) { +        CLOG_BUFFER(storeFenceInMeta, "waiting for fence %d", fenceFd); +        sp<Fence> fence = new Fence(fenceFd); +        return fence->wait(IOMX::kFenceTimeoutMs); +    } +    return OK; +} + +int OMXNodeInstance::retrieveFenceFromMeta_l( +        OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex) { +    OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nAllocLen : header->nFilledLen; +    int fenceFd = -1; +    if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer +            && header->nAllocLen >= sizeof(VideoNativeMetadata)) { +        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer); +        if (nativeMeta.eType == kMetadataBufferTypeANWBuffer) { +            fenceFd = nativeMeta.nFenceFd; +            nativeMeta.nFenceFd = -1; +        } +        if (metaSize < sizeof(nativeMeta) && fenceFd >= 0) { +            CLOG_ERROR(foundFenceInEmptyMeta, BAD_VALUE, FULL_BUFFER( +                    NULL, header, nativeMeta.nFenceFd)); +            fenceFd = -1; +        } +    } +    return fenceFd; +} +  status_t OMXNodeInstance::emptyBuffer_l( -        OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr) { +        OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp, +        intptr_t debugAddr, int fenceFd) {      header->nFlags = flags;      header->nTimeStamp = timestamp; +    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexInput); +    if (res != OK) { +        CLOG_ERROR(emptyBuffer::storeFenceInMeta, res, WITH_STATS( +                FULL_BUFFER(debugAddr, header, fenceFd))); +        return res; +    } +      {          Mutex::Autolock _l(mDebugLock);          mInputBuffersWithCodec.add(header); @@ -1151,11 +1212,11 @@ status_t OMXNodeInstance::emptyBuffer_l(              bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */);          } -        CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header))); +        CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header, fenceFd)));      }      OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header); -    CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header)); +    CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header, fenceFd));      {          Mutex::Autolock _l(mDebugLock); @@ -1172,18 +1233,19 @@ status_t OMXNodeInstance::emptyBuffer_l(  // like emptyBuffer, but the data is already in header->pBuffer  status_t OMXNodeInstance::emptyGraphicBuffer(          OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer, -        OMX_U32 flags, OMX_TICKS timestamp) { +        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {      Mutex::Autolock autoLock(mLock);      OMX::buffer_id buffer = findBufferID(header);      status_t err = updateGraphicBufferInMeta_l(kPortIndexInput, graphicBuffer, buffer, header);      if (err != OK) { -        CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER((intptr_t)header->pBuffer, header)); +        CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER( +                (intptr_t)header->pBuffer, header, fenceFd));          return err;      }      header->nOffset = 0;      header->nFilledLen = graphicBuffer == NULL ? 0 : header->nAllocLen; -    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer); +    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);  }  status_t OMXNodeInstance::getExtensionIndex( @@ -1307,7 +1369,8 @@ void OMXNodeInstance::onMessage(const omx_message &msg) {              mOutputBuffersWithCodec.remove(buffer);              CLOG_BUMPED_BUFFER( -                    FBD, WITH_STATS(FULL_BUFFER(msg.u.extended_buffer_data.buffer, buffer))); +                    FBD, WITH_STATS(FULL_BUFFER( +                            msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd)));              unbumpDebugLevel_l(kPortIndexOutput);          } @@ -1335,7 +1398,7 @@ void OMXNodeInstance::onMessage(const omx_message &msg) {              mInputBuffersWithCodec.remove(buffer);              CLOG_BUMPED_BUFFER( -                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer))); +                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd)));          }          if (bufferSource != NULL) { @@ -1344,7 +1407,7 @@ void OMXNodeInstance::onMessage(const omx_message &msg) {              // Don't dispatch a message back to ACodec, since it doesn't              // know that anyone asked to have the buffer emptied and will              // be very confused. -            bufferSource->codecBufferEmptied(buffer); +            bufferSource->codecBufferEmptied(buffer, msg.fenceFd);              return;          }      } @@ -1439,8 +1502,9 @@ OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(      if (instance->mDying) {          return OMX_ErrorNone;      } +    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);      return instance->owner()->OnEmptyBufferDone(instance->nodeID(), -            instance->findBufferID(pBuffer), pBuffer); +            instance->findBufferID(pBuffer), pBuffer, fenceFd);  }  // static @@ -1452,8 +1516,9 @@ OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(      if (instance->mDying) {          return OMX_ErrorNone;      } +    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);      return instance->owner()->OnFillBufferDone(instance->nodeID(), -            instance->findBufferID(pBuffer), pBuffer); +            instance->findBufferID(pBuffer), pBuffer, fenceFd);  }  void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) { diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp index 5f80cbc..cd1ac36 100644 --- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp @@ -517,6 +517,16 @@ const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer(              // TODO do we need to support other formats?              srcStride *= 4;          } + +        if (nativeMeta.nFenceFd >= 0) { +            sp<Fence> fence = new Fence(nativeMeta.nFenceFd); +            nativeMeta.nFenceFd = -1; +            status_t err = fence->wait(IOMX::kFenceTimeoutMs); +            if (err != OK) { +                ALOGE("Timed out waiting on input fence"); +                return NULL; +            } +        }      } else {          // TODO: remove this part.  Check if anyone uses this.  | 
