Loading media/codec2/sfplugin/CCodec.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ #include <media/stagefright/BufferProducerWrapper.h> #include <media/stagefright/MediaCodecConstants.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/RenderedFrameInfo.h> #include <utils/NativeHandle.h> #include "C2OMXNode.h" Loading Loading @@ -672,8 +673,7 @@ public: } void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override { mCodec->mCallback->onOutputFramesRendered( {RenderedFrameInfo(mediaTimeUs, renderTimeNs)}); mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, renderTimeNs)}); } void onOutputBuffersChanged() override { Loading media/codec2/vndk/platform/C2SurfaceSyncObj.cpp +45 −11 Original line number Diff line number Diff line Loading @@ -114,8 +114,8 @@ C2SyncVariables *C2SurfaceSyncMemory::mem() { } namespace { constexpr int kSpinNumForLock = 100; constexpr int kSpinNumForUnlock = 200; constexpr int kSpinNumForLock = 0; constexpr int kSpinNumForUnlock = 0; enum : uint32_t { FUTEX_UNLOCKED = 0, Loading @@ -125,32 +125,65 @@ namespace { } int C2SyncVariables::lock() { uint32_t old; for (int i = 0; i < kSpinNumForLock; i++) { old = 0; uint32_t old = FUTEX_UNLOCKED; // see if we can lock uncontended immediately (if previously unlocked) if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) { return 0; } // spin to see if we can get it with a short wait without involving kernel for (int i = 0; i < kSpinNumForLock; i++) { sched_yield(); old = FUTEX_UNLOCKED; if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) { return 0; } } if (old == FUTEX_LOCKED_UNCONTENDED) // still locked, if other side thinks it was uncontended, now it is contended, so let them // know that they need to wake us up. if (old == FUTEX_LOCKED_UNCONTENDED) { old = mLock.exchange(FUTEX_LOCKED_CONTENDED); // It is possible that the other holder released the lock at this very moment (and old // becomes UNLOCKED), If so, we will not involve the kernel to wait for the lock to be // released, but are still marking our lock contended (even though we are the only // holders.) } while (old) { // while the futex is still locked by someone else while (old != FUTEX_UNLOCKED) { // wait until other side releases the lock (and still contented) (void)syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0); // try to relock old = mLock.exchange(FUTEX_LOCKED_CONTENDED); } return 0; } int C2SyncVariables::unlock() { if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) return 0; // TRICKY: here we assume that we are holding this lock // unlock the lock immediately (since we were holding it) // If it is (still) locked uncontested, we are done (no need to involve the kernel) if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) { return 0; } // We don't need to spin for unlock as here we know already we have a waiter who we need to // wake up. This code was here in case someone just happened to lock this lock (uncontested) // before we would wake up other waiters to avoid a syscall. It is unsure if this ever gets // exercised or if this is the behavior we want. (Note that if this code is removed, the same // situation is still handled in lock() by the woken up waiter that realizes that the lock is // now taken.) for (int i = 0; i < kSpinNumForUnlock; i++) { if (mLock.load()) { // here we seem to check if someone relocked this lock, and if they relocked uncontested, // we up it to contested (since there are other waiters.) if (mLock.load() != FUTEX_UNLOCKED) { uint32_t old = FUTEX_LOCKED_UNCONTENDED; mLock.compare_exchange_strong(old, FUTEX_LOCKED_CONTENDED); // this is always true here so we return immediately if (old) { return 0; } Loading @@ -158,6 +191,7 @@ int C2SyncVariables::unlock() { sched_yield(); } // wake up one waiter (void)syscall(__NR_futex, &mLock, FUTEX_WAKE, 1, NULL, NULL, 0); return 0; } Loading media/libstagefright/ACodec.cpp +115 −92 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include <media/stagefright/MediaDefs.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/RenderedFrameInfo.h> #include <media/stagefright/SurfaceUtils.h> #include <media/hardware/HardwareAPI.h> #include <media/MediaBufferHolder.h> Loading Loading @@ -632,7 +633,8 @@ std::shared_ptr<BufferChannelBase> ACodec::getBufferChannel() { if (!mBufferChannel) { mBufferChannel = std::make_shared<ACodecBufferChannel>( new AMessage(kWhatInputBufferFilled, this), new AMessage(kWhatOutputBufferDrained, this)); new AMessage(kWhatOutputBufferDrained, this), new AMessage(kWhatPollForRenderedBuffers, this)); } return mBufferChannel; } Loading Loading @@ -742,6 +744,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { // if we have not yet started the codec, we can simply set the native window if (mBuffers[kPortIndexInput].size() == 0) { mNativeWindow = surface; initializeFrameTracking(); return OK; } Loading Loading @@ -850,6 +853,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { mNativeWindow = nativeWindow; mNativeWindowUsageBits = usageBits; initializeFrameTracking(); return OK; } Loading Loading @@ -960,7 +964,6 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { BufferInfo info; info.mStatus = BufferInfo::OWNED_BY_US; info.mFenceFd = -1; info.mRenderInfo = NULL; info.mGraphicBuffer = NULL; info.mNewGraphicBuffer = false; Loading Loading @@ -1228,6 +1231,7 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( *bufferCount = def.nBufferCountActual; *bufferSize = def.nBufferSize; initializeFrameTracking(); return err; } Loading Loading @@ -1266,7 +1270,6 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { info.mStatus = BufferInfo::OWNED_BY_US; info.mFenceFd = fenceFd; info.mIsReadFence = false; info.mRenderInfo = NULL; info.mGraphicBuffer = graphicBuffer; info.mNewGraphicBuffer = false; info.mDequeuedAt = mDequeueCounter; Loading Loading @@ -1343,7 +1346,6 @@ status_t ACodec::allocateOutputMetadataBuffers() { BufferInfo info; info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; info.mFenceFd = -1; info.mRenderInfo = NULL; info.mGraphicBuffer = NULL; info.mNewGraphicBuffer = false; info.mDequeuedAt = mDequeueCounter; Loading Loading @@ -1439,42 +1441,6 @@ status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) { return err; } void ACodec::updateRenderInfoForDequeuedBuffer( ANativeWindowBuffer *buf, int fenceFd, BufferInfo *info) { info->mRenderInfo = mRenderTracker.updateInfoForDequeuedBuffer( buf, fenceFd, info - &mBuffers[kPortIndexOutput][0]); // check for any fences already signaled notifyOfRenderedFrames(false /* dropIncomplete */, info->mRenderInfo); } void ACodec::onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) { if (mRenderTracker.onFrameRendered(mediaTimeUs, systemNano) != OK) { mRenderTracker.dumpRenderQueue(); } } void ACodec::notifyOfRenderedFrames(bool dropIncomplete, FrameRenderTracker::Info *until) { std::list<FrameRenderTracker::Info> done = mRenderTracker.checkFencesAndGetRenderedFrames(until, dropIncomplete); // unlink untracked frames for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin(); it != done.cend(); ++it) { ssize_t index = it->getIndex(); if (index >= 0 && (size_t)index < mBuffers[kPortIndexOutput].size()) { mBuffers[kPortIndexOutput][index].mRenderInfo = NULL; } else if (index >= 0) { // THIS SHOULD NEVER HAPPEN ALOGE("invalid index %zd in %zu", index, mBuffers[kPortIndexOutput].size()); } } mCallback->onOutputFramesRendered(done); } void ACodec::onFirstTunnelFrameReady() { mCallback->onFirstTunnelFrameReady(); } Loading Loading @@ -1529,7 +1495,6 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { info->mStatus = BufferInfo::OWNED_BY_US; info->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow"); updateRenderInfoForDequeuedBuffer(buf, fenceFd, info); return info; } } Loading Loading @@ -1574,18 +1539,96 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { oldest->mNewGraphicBuffer = true; oldest->mStatus = BufferInfo::OWNED_BY_US; oldest->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow for oldest"); mRenderTracker.untrackFrame(oldest->mRenderInfo); oldest->mRenderInfo = NULL; ALOGV("replaced oldest buffer #%u with age %u, graphicBuffer %p", (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]), mDequeueCounter - oldest->mDequeuedAt, oldest->mGraphicBuffer->handle); updateRenderInfoForDequeuedBuffer(buf, fenceFd, oldest); return oldest; } void ACodec::initializeFrameTracking() { mTrackedFrames.clear(); int isWindowToDisplay = 0; mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &isWindowToDisplay); mIsWindowToDisplay = isWindowToDisplay == 1; // No frame tracking is needed if we're not sending frames to the display if (!mIsWindowToDisplay) { // Return early so we don't call into SurfaceFlinger (requiring permissions) return; } int hasPresentFenceTimes = 0; mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &hasPresentFenceTimes); mHasPresentFenceTimes = hasPresentFenceTimes == 1; if (!mHasPresentFenceTimes) { ALOGI("Using latch times for frame rendered signals - present fences not supported"); } status_t err = native_window_enable_frame_timestamps(mNativeWindow.get(), true); if (err) { ALOGE("Failed to enable frame timestamps (%d)", err); } } void ACodec::trackReleasedFrame(int64_t frameId, int64_t mediaTimeUs, int64_t desiredRenderTimeNs) { // If the render time is earlier than now, then we're suggesting it should be rendered ASAP, // so track the frame as if the desired render time is now. int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC); if (desiredRenderTimeNs < nowNs) { desiredRenderTimeNs = nowNs; } // We've just queued a frame to the surface, so keep track of it and later check to see if it is // actually rendered. TrackedFrame frame; frame.id = frameId; frame.mediaTimeUs = mediaTimeUs; frame.desiredRenderTimeNs = desiredRenderTimeNs; mTrackedFrames.push_back(frame); } void ACodec::pollForRenderedFrames() { std::list<RenderedFrameInfo> renderedFrameInfos; // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have, // in fact, been rendered. int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC); while (!mTrackedFrames.empty()) { TrackedFrame & frame = mTrackedFrames.front(); // Frames that should have been rendered at least 100ms in the past are checked if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) { break; } status_t err; nsecs_t latchOrPresentTimeNs = NATIVE_WINDOW_TIMESTAMP_INVALID; err = native_window_get_frame_timestamps(mNativeWindow.get(), frame.id, /* outRequestedPresentTime */ nullptr, /* outAcquireTime */ nullptr, mHasPresentFenceTimes ? nullptr : &latchOrPresentTimeNs, // latch time /* outFirstRefreshStartTime */ nullptr, /* outLastRefreshStartTime */ nullptr, /* outGpuCompositionDoneTime */ nullptr, mHasPresentFenceTimes ? &latchOrPresentTimeNs : nullptr, // display present time, /* outDequeueReadyTime */ nullptr, /* outReleaseTime */ nullptr); if (err) { ALOGE("Failed to get frame timestamps for %lld: %d", (long long) frame.id, err); } // If we don't have a render time by now, then consider the frame as dropped if (latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_PENDING && latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_INVALID) { renderedFrameInfos.push_back(RenderedFrameInfo(frame.mediaTimeUs, latchOrPresentTimeNs)); } mTrackedFrames.pop_front(); } if (!renderedFrameInfos.empty()) { mCallback->onOutputFramesRendered(renderedFrameInfos); } } status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) { if (portIndex == kPortIndexInput) { mBufferChannel->setInputBufferArray({}); Loading Loading @@ -1661,11 +1704,6 @@ status_t ACodec::freeBuffer(OMX_U32 portIndex, size_t i) { ::close(info->mFenceFd); } if (portIndex == kPortIndexOutput) { mRenderTracker.untrackFrame(info->mRenderInfo, i); info->mRenderInfo = NULL; } // remove buffer even if mOMXNode->freeBuffer fails mBuffers[portIndex].erase(mBuffers[portIndex].begin() + i); return err; Loading Loading @@ -6030,22 +6068,10 @@ bool ACodec::BaseState::onOMXMessageList(const sp<AMessage> &msg) { sp<RefBase> obj; CHECK(msg->findObject("messages", &obj)); sp<MessageList> msgList = static_cast<MessageList *>(obj.get()); bool receivedRenderedEvents = false; for (std::list<sp<AMessage>>::const_iterator it = msgList->getList().cbegin(); it != msgList->getList().cend(); ++it) { (*it)->setWhat(ACodec::kWhatOMXMessageItem); mCodec->handleMessage(*it); int32_t type; CHECK((*it)->findInt32("type", &type)); if (type == omx_message::FRAME_RENDERED) { receivedRenderedEvents = true; } } if (receivedRenderedEvents) { // NOTE: all buffers are rendered in this case mCodec->notifyOfRenderedFrames(); } return true; } Loading Loading @@ -6554,15 +6580,6 @@ bool ACodec::BaseState::onOMXFillBufferDone( info->mDequeuedAt = ++mCodec->mDequeueCounter; info->mStatus = BufferInfo::OWNED_BY_US; if (info->mRenderInfo != NULL) { // The fence for an emptied buffer must have signaled, but there still could be queued // or out-of-order dequeued buffers in the render queue prior to this buffer. Drop these, // as we will soon requeue this buffer to the surface. While in theory we could still keep // track of buffers that are requeued to the surface, it is better to add support to the // buffer-queue to notify us of released buffers and their fences (in the future). mCodec->notifyOfRenderedFrames(true /* dropIncomplete */); } // byte buffers cannot take fences, so wait for any fence now if (mCodec->mNativeWindow == NULL) { (void)mCodec->waitForFence(fenceFd, "onOMXFillBufferDone"); Loading Loading @@ -6769,14 +6786,6 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) { mCodec->mLastHdr10PlusBuffer = hdr10PlusInfo; } // save buffers sent to the surface so we can get render time when they return int64_t mediaTimeUs = -1; buffer->meta()->findInt64("timeUs", &mediaTimeUs); if (mediaTimeUs >= 0) { mCodec->mRenderTracker.onFrameQueued( mediaTimeUs, info->mGraphicBuffer, new Fence(::dup(info->mFenceFd))); } int64_t timestampNs = 0; if (!msg->findInt64("timestampNs", ×tampNs)) { // use media timestamp if client did not request a specific render timestamp Loading @@ -6790,11 +6799,25 @@ 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); uint64_t frameId; err = native_window_get_next_frame_id(mCodec->mNativeWindow.get(), &frameId); info->checkReadFence("onOutputBufferDrained before queueBuffer"); err = mCodec->mNativeWindow->queueBuffer( mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd); // TODO(b/266211548): Poll the native window for rendered buffers, since when queueing // buffers, the frame event history delta is retrieved. int64_t mediaTimeUs = -1; buffer->meta()->findInt64("timeUs", &mediaTimeUs); if (mCodec->mIsWindowToDisplay) { mCodec->trackReleasedFrame(frameId, mediaTimeUs, timestampNs); mCodec->pollForRenderedFrames(); } else { // When the surface is an intermediate surface, onFrameRendered is triggered immediately // when the frame is queued to the non-display surface mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, timestampNs)}); } info->mFenceFd = -1; if (err == OK) { info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; Loading Loading @@ -7021,7 +7044,6 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { ++mCodec->mNodeGeneration; mCodec->mComponentName = componentName; mCodec->mRenderTracker.setComponentName(componentName); mCodec->mFlags = 0; if (componentName.endsWith(".secure")) { Loading Loading @@ -7644,7 +7666,6 @@ void ACodec::ExecutingState::resume() { void ACodec::ExecutingState::stateEntered() { ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str()); mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC)); mCodec->processDeferredMessages(); } Loading Loading @@ -7755,7 +7776,15 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) { mCodec->signalSubmitOutputMetadataBufferIfEOS_workaround(); } } return true; handled = true; break; } case kWhatPollForRenderedBuffers: { mCodec->pollForRenderedFrames(); handled = true; break; } default: Loading Loading @@ -8439,7 +8468,7 @@ void ACodec::forceStateTransition(int generation) { } bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) { mCodec->onFrameRendered(mediaTimeUs, systemNano); mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)}); return true; } Loading Loading @@ -8613,7 +8642,7 @@ void ACodec::OutputPortSettingsChangedState::stateEntered() { bool ACodec::OutputPortSettingsChangedState::onOMXFrameRendered( int64_t mediaTimeUs, nsecs_t systemNano) { mCodec->onFrameRendered(mediaTimeUs, systemNano); mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)}); return true; } Loading Loading @@ -8644,10 +8673,6 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent( OMX_CommandPortEnable, kPortIndexOutput); } // Clear the RenderQueue in which queued GraphicBuffers hold the // actual buffer references in order to free them early. mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC)); if (err == OK) { err = mCodec->allocateBuffersOnPort(kPortIndexOutput); ALOGE_IF(err != OK, "Failed to allocate output port buffers after port " Loading Loading @@ -9031,8 +9056,6 @@ void ACodec::FlushingState::changeStateIfWeOwnAllBuffers() { // the native window for rendering. Let's get those back as well. mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs(); mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC)); mCodec->mCallback->onFlushCompleted(); mCodec->mPortEOS[kPortIndexInput] = Loading media/libstagefright/ACodecBufferChannel.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/AUtils.h> #include <media/stagefright/ACodec.h> #include <media/stagefright/MediaCodec.h> #include <media/MediaCodecBuffer.h> #include <system/window.h> Loading Loading @@ -87,9 +88,11 @@ ACodecBufferChannel::BufferInfo::BufferInfo( } ACodecBufferChannel::ACodecBufferChannel( const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained) const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained, const sp<AMessage> &pollForRenderedBuffers) : mInputBufferFilled(inputBufferFilled), mOutputBufferDrained(outputBufferDrained), mPollForRenderedBuffers(pollForRenderedBuffers), mHeapSeqNum(-1) { } Loading Loading @@ -488,7 +491,7 @@ status_t ACodecBufferChannel::renderOutputBuffer( } void ACodecBufferChannel::pollForRenderedBuffers() { // TODO(b/266211548): Poll the native window for rendered buffers. mPollForRenderedBuffers->post(); } status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) { Loading media/libstagefright/MediaCodec.cpp +18 −7 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ #include <media/stagefright/MediaErrors.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/RenderedFrameInfo.h> #include <media/stagefright/SurfaceUtils.h> #include <nativeloader/dlext_namespaces.h> #include <private/android_filesystem_config.h> Loading Loading @@ -750,7 +751,7 @@ public: const sp<AMessage> &outputFormat) override; virtual void onInputSurfaceDeclined(status_t err) override; virtual void onSignaledInputEOS(status_t err) override; virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override; virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) override; virtual void onOutputBuffersChanged() override; virtual void onFirstTunnelFrameReady() override; private: Loading Loading @@ -859,7 +860,7 @@ void CodecCallback::onSignaledInputEOS(status_t err) { notify->post(); } void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) { void CodecCallback::onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) { sp<AMessage> notify(mNotify->dup()); notify->setInt32("what", kWhatOutputFramesRendered); if (MediaCodec::CreateFramesRenderedMessage(done, notify)) { Loading Loading @@ -5953,12 +5954,10 @@ status_t MediaCodec::handleLeftover(size_t index) { return onQueueInputBuffer(msg); } //static size_t MediaCodec::CreateFramesRenderedMessage( const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) { template<typename T> static size_t CreateFramesRenderedMessageInternal(const std::list<T> &done, sp<AMessage> &msg) { size_t index = 0; for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin(); it != done.cend(); ++it) { for (typename std::list<T>::const_iterator it = done.cbegin(); it != done.cend(); ++it) { if (it->getRenderTimeNs() < 0) { continue; // dropped frame from tracking } Loading @@ -5969,6 +5968,18 @@ size_t MediaCodec::CreateFramesRenderedMessage( return index; } //static size_t MediaCodec::CreateFramesRenderedMessage( const std::list<RenderedFrameInfo> &done, sp<AMessage> &msg) { return CreateFramesRenderedMessageInternal(done, msg); } //static size_t MediaCodec::CreateFramesRenderedMessage( const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) { return CreateFramesRenderedMessageInternal(done, msg); } status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) { size_t index; CHECK(msg->findSize("index", &index)); Loading Loading
media/codec2/sfplugin/CCodec.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ #include <media/stagefright/BufferProducerWrapper.h> #include <media/stagefright/MediaCodecConstants.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/RenderedFrameInfo.h> #include <utils/NativeHandle.h> #include "C2OMXNode.h" Loading Loading @@ -672,8 +673,7 @@ public: } void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override { mCodec->mCallback->onOutputFramesRendered( {RenderedFrameInfo(mediaTimeUs, renderTimeNs)}); mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, renderTimeNs)}); } void onOutputBuffersChanged() override { Loading
media/codec2/vndk/platform/C2SurfaceSyncObj.cpp +45 −11 Original line number Diff line number Diff line Loading @@ -114,8 +114,8 @@ C2SyncVariables *C2SurfaceSyncMemory::mem() { } namespace { constexpr int kSpinNumForLock = 100; constexpr int kSpinNumForUnlock = 200; constexpr int kSpinNumForLock = 0; constexpr int kSpinNumForUnlock = 0; enum : uint32_t { FUTEX_UNLOCKED = 0, Loading @@ -125,32 +125,65 @@ namespace { } int C2SyncVariables::lock() { uint32_t old; for (int i = 0; i < kSpinNumForLock; i++) { old = 0; uint32_t old = FUTEX_UNLOCKED; // see if we can lock uncontended immediately (if previously unlocked) if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) { return 0; } // spin to see if we can get it with a short wait without involving kernel for (int i = 0; i < kSpinNumForLock; i++) { sched_yield(); old = FUTEX_UNLOCKED; if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) { return 0; } } if (old == FUTEX_LOCKED_UNCONTENDED) // still locked, if other side thinks it was uncontended, now it is contended, so let them // know that they need to wake us up. if (old == FUTEX_LOCKED_UNCONTENDED) { old = mLock.exchange(FUTEX_LOCKED_CONTENDED); // It is possible that the other holder released the lock at this very moment (and old // becomes UNLOCKED), If so, we will not involve the kernel to wait for the lock to be // released, but are still marking our lock contended (even though we are the only // holders.) } while (old) { // while the futex is still locked by someone else while (old != FUTEX_UNLOCKED) { // wait until other side releases the lock (and still contented) (void)syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, NULL, NULL, 0); // try to relock old = mLock.exchange(FUTEX_LOCKED_CONTENDED); } return 0; } int C2SyncVariables::unlock() { if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) return 0; // TRICKY: here we assume that we are holding this lock // unlock the lock immediately (since we were holding it) // If it is (still) locked uncontested, we are done (no need to involve the kernel) if (mLock.exchange(FUTEX_UNLOCKED) == FUTEX_LOCKED_UNCONTENDED) { return 0; } // We don't need to spin for unlock as here we know already we have a waiter who we need to // wake up. This code was here in case someone just happened to lock this lock (uncontested) // before we would wake up other waiters to avoid a syscall. It is unsure if this ever gets // exercised or if this is the behavior we want. (Note that if this code is removed, the same // situation is still handled in lock() by the woken up waiter that realizes that the lock is // now taken.) for (int i = 0; i < kSpinNumForUnlock; i++) { if (mLock.load()) { // here we seem to check if someone relocked this lock, and if they relocked uncontested, // we up it to contested (since there are other waiters.) if (mLock.load() != FUTEX_UNLOCKED) { uint32_t old = FUTEX_LOCKED_UNCONTENDED; mLock.compare_exchange_strong(old, FUTEX_LOCKED_CONTENDED); // this is always true here so we return immediately if (old) { return 0; } Loading @@ -158,6 +191,7 @@ int C2SyncVariables::unlock() { sched_yield(); } // wake up one waiter (void)syscall(__NR_futex, &mLock, FUTEX_WAKE, 1, NULL, NULL, 0); return 0; } Loading
media/libstagefright/ACodec.cpp +115 −92 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include <media/stagefright/MediaDefs.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/RenderedFrameInfo.h> #include <media/stagefright/SurfaceUtils.h> #include <media/hardware/HardwareAPI.h> #include <media/MediaBufferHolder.h> Loading Loading @@ -632,7 +633,8 @@ std::shared_ptr<BufferChannelBase> ACodec::getBufferChannel() { if (!mBufferChannel) { mBufferChannel = std::make_shared<ACodecBufferChannel>( new AMessage(kWhatInputBufferFilled, this), new AMessage(kWhatOutputBufferDrained, this)); new AMessage(kWhatOutputBufferDrained, this), new AMessage(kWhatPollForRenderedBuffers, this)); } return mBufferChannel; } Loading Loading @@ -742,6 +744,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { // if we have not yet started the codec, we can simply set the native window if (mBuffers[kPortIndexInput].size() == 0) { mNativeWindow = surface; initializeFrameTracking(); return OK; } Loading Loading @@ -850,6 +853,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { mNativeWindow = nativeWindow; mNativeWindowUsageBits = usageBits; initializeFrameTracking(); return OK; } Loading Loading @@ -960,7 +964,6 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { BufferInfo info; info.mStatus = BufferInfo::OWNED_BY_US; info.mFenceFd = -1; info.mRenderInfo = NULL; info.mGraphicBuffer = NULL; info.mNewGraphicBuffer = false; Loading Loading @@ -1228,6 +1231,7 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( *bufferCount = def.nBufferCountActual; *bufferSize = def.nBufferSize; initializeFrameTracking(); return err; } Loading Loading @@ -1266,7 +1270,6 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { info.mStatus = BufferInfo::OWNED_BY_US; info.mFenceFd = fenceFd; info.mIsReadFence = false; info.mRenderInfo = NULL; info.mGraphicBuffer = graphicBuffer; info.mNewGraphicBuffer = false; info.mDequeuedAt = mDequeueCounter; Loading Loading @@ -1343,7 +1346,6 @@ status_t ACodec::allocateOutputMetadataBuffers() { BufferInfo info; info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; info.mFenceFd = -1; info.mRenderInfo = NULL; info.mGraphicBuffer = NULL; info.mNewGraphicBuffer = false; info.mDequeuedAt = mDequeueCounter; Loading Loading @@ -1439,42 +1441,6 @@ status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) { return err; } void ACodec::updateRenderInfoForDequeuedBuffer( ANativeWindowBuffer *buf, int fenceFd, BufferInfo *info) { info->mRenderInfo = mRenderTracker.updateInfoForDequeuedBuffer( buf, fenceFd, info - &mBuffers[kPortIndexOutput][0]); // check for any fences already signaled notifyOfRenderedFrames(false /* dropIncomplete */, info->mRenderInfo); } void ACodec::onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) { if (mRenderTracker.onFrameRendered(mediaTimeUs, systemNano) != OK) { mRenderTracker.dumpRenderQueue(); } } void ACodec::notifyOfRenderedFrames(bool dropIncomplete, FrameRenderTracker::Info *until) { std::list<FrameRenderTracker::Info> done = mRenderTracker.checkFencesAndGetRenderedFrames(until, dropIncomplete); // unlink untracked frames for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin(); it != done.cend(); ++it) { ssize_t index = it->getIndex(); if (index >= 0 && (size_t)index < mBuffers[kPortIndexOutput].size()) { mBuffers[kPortIndexOutput][index].mRenderInfo = NULL; } else if (index >= 0) { // THIS SHOULD NEVER HAPPEN ALOGE("invalid index %zd in %zu", index, mBuffers[kPortIndexOutput].size()); } } mCallback->onOutputFramesRendered(done); } void ACodec::onFirstTunnelFrameReady() { mCallback->onFirstTunnelFrameReady(); } Loading Loading @@ -1529,7 +1495,6 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { info->mStatus = BufferInfo::OWNED_BY_US; info->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow"); updateRenderInfoForDequeuedBuffer(buf, fenceFd, info); return info; } } Loading Loading @@ -1574,18 +1539,96 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { oldest->mNewGraphicBuffer = true; oldest->mStatus = BufferInfo::OWNED_BY_US; oldest->setWriteFence(fenceFd, "dequeueBufferFromNativeWindow for oldest"); mRenderTracker.untrackFrame(oldest->mRenderInfo); oldest->mRenderInfo = NULL; ALOGV("replaced oldest buffer #%u with age %u, graphicBuffer %p", (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]), mDequeueCounter - oldest->mDequeuedAt, oldest->mGraphicBuffer->handle); updateRenderInfoForDequeuedBuffer(buf, fenceFd, oldest); return oldest; } void ACodec::initializeFrameTracking() { mTrackedFrames.clear(); int isWindowToDisplay = 0; mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &isWindowToDisplay); mIsWindowToDisplay = isWindowToDisplay == 1; // No frame tracking is needed if we're not sending frames to the display if (!mIsWindowToDisplay) { // Return early so we don't call into SurfaceFlinger (requiring permissions) return; } int hasPresentFenceTimes = 0; mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &hasPresentFenceTimes); mHasPresentFenceTimes = hasPresentFenceTimes == 1; if (!mHasPresentFenceTimes) { ALOGI("Using latch times for frame rendered signals - present fences not supported"); } status_t err = native_window_enable_frame_timestamps(mNativeWindow.get(), true); if (err) { ALOGE("Failed to enable frame timestamps (%d)", err); } } void ACodec::trackReleasedFrame(int64_t frameId, int64_t mediaTimeUs, int64_t desiredRenderTimeNs) { // If the render time is earlier than now, then we're suggesting it should be rendered ASAP, // so track the frame as if the desired render time is now. int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC); if (desiredRenderTimeNs < nowNs) { desiredRenderTimeNs = nowNs; } // We've just queued a frame to the surface, so keep track of it and later check to see if it is // actually rendered. TrackedFrame frame; frame.id = frameId; frame.mediaTimeUs = mediaTimeUs; frame.desiredRenderTimeNs = desiredRenderTimeNs; mTrackedFrames.push_back(frame); } void ACodec::pollForRenderedFrames() { std::list<RenderedFrameInfo> renderedFrameInfos; // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have, // in fact, been rendered. int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC); while (!mTrackedFrames.empty()) { TrackedFrame & frame = mTrackedFrames.front(); // Frames that should have been rendered at least 100ms in the past are checked if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) { break; } status_t err; nsecs_t latchOrPresentTimeNs = NATIVE_WINDOW_TIMESTAMP_INVALID; err = native_window_get_frame_timestamps(mNativeWindow.get(), frame.id, /* outRequestedPresentTime */ nullptr, /* outAcquireTime */ nullptr, mHasPresentFenceTimes ? nullptr : &latchOrPresentTimeNs, // latch time /* outFirstRefreshStartTime */ nullptr, /* outLastRefreshStartTime */ nullptr, /* outGpuCompositionDoneTime */ nullptr, mHasPresentFenceTimes ? &latchOrPresentTimeNs : nullptr, // display present time, /* outDequeueReadyTime */ nullptr, /* outReleaseTime */ nullptr); if (err) { ALOGE("Failed to get frame timestamps for %lld: %d", (long long) frame.id, err); } // If we don't have a render time by now, then consider the frame as dropped if (latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_PENDING && latchOrPresentTimeNs != NATIVE_WINDOW_TIMESTAMP_INVALID) { renderedFrameInfos.push_back(RenderedFrameInfo(frame.mediaTimeUs, latchOrPresentTimeNs)); } mTrackedFrames.pop_front(); } if (!renderedFrameInfos.empty()) { mCallback->onOutputFramesRendered(renderedFrameInfos); } } status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) { if (portIndex == kPortIndexInput) { mBufferChannel->setInputBufferArray({}); Loading Loading @@ -1661,11 +1704,6 @@ status_t ACodec::freeBuffer(OMX_U32 portIndex, size_t i) { ::close(info->mFenceFd); } if (portIndex == kPortIndexOutput) { mRenderTracker.untrackFrame(info->mRenderInfo, i); info->mRenderInfo = NULL; } // remove buffer even if mOMXNode->freeBuffer fails mBuffers[portIndex].erase(mBuffers[portIndex].begin() + i); return err; Loading Loading @@ -6030,22 +6068,10 @@ bool ACodec::BaseState::onOMXMessageList(const sp<AMessage> &msg) { sp<RefBase> obj; CHECK(msg->findObject("messages", &obj)); sp<MessageList> msgList = static_cast<MessageList *>(obj.get()); bool receivedRenderedEvents = false; for (std::list<sp<AMessage>>::const_iterator it = msgList->getList().cbegin(); it != msgList->getList().cend(); ++it) { (*it)->setWhat(ACodec::kWhatOMXMessageItem); mCodec->handleMessage(*it); int32_t type; CHECK((*it)->findInt32("type", &type)); if (type == omx_message::FRAME_RENDERED) { receivedRenderedEvents = true; } } if (receivedRenderedEvents) { // NOTE: all buffers are rendered in this case mCodec->notifyOfRenderedFrames(); } return true; } Loading Loading @@ -6554,15 +6580,6 @@ bool ACodec::BaseState::onOMXFillBufferDone( info->mDequeuedAt = ++mCodec->mDequeueCounter; info->mStatus = BufferInfo::OWNED_BY_US; if (info->mRenderInfo != NULL) { // The fence for an emptied buffer must have signaled, but there still could be queued // or out-of-order dequeued buffers in the render queue prior to this buffer. Drop these, // as we will soon requeue this buffer to the surface. While in theory we could still keep // track of buffers that are requeued to the surface, it is better to add support to the // buffer-queue to notify us of released buffers and their fences (in the future). mCodec->notifyOfRenderedFrames(true /* dropIncomplete */); } // byte buffers cannot take fences, so wait for any fence now if (mCodec->mNativeWindow == NULL) { (void)mCodec->waitForFence(fenceFd, "onOMXFillBufferDone"); Loading Loading @@ -6769,14 +6786,6 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) { mCodec->mLastHdr10PlusBuffer = hdr10PlusInfo; } // save buffers sent to the surface so we can get render time when they return int64_t mediaTimeUs = -1; buffer->meta()->findInt64("timeUs", &mediaTimeUs); if (mediaTimeUs >= 0) { mCodec->mRenderTracker.onFrameQueued( mediaTimeUs, info->mGraphicBuffer, new Fence(::dup(info->mFenceFd))); } int64_t timestampNs = 0; if (!msg->findInt64("timestampNs", ×tampNs)) { // use media timestamp if client did not request a specific render timestamp Loading @@ -6790,11 +6799,25 @@ 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); uint64_t frameId; err = native_window_get_next_frame_id(mCodec->mNativeWindow.get(), &frameId); info->checkReadFence("onOutputBufferDrained before queueBuffer"); err = mCodec->mNativeWindow->queueBuffer( mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd); // TODO(b/266211548): Poll the native window for rendered buffers, since when queueing // buffers, the frame event history delta is retrieved. int64_t mediaTimeUs = -1; buffer->meta()->findInt64("timeUs", &mediaTimeUs); if (mCodec->mIsWindowToDisplay) { mCodec->trackReleasedFrame(frameId, mediaTimeUs, timestampNs); mCodec->pollForRenderedFrames(); } else { // When the surface is an intermediate surface, onFrameRendered is triggered immediately // when the frame is queued to the non-display surface mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, timestampNs)}); } info->mFenceFd = -1; if (err == OK) { info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; Loading Loading @@ -7021,7 +7044,6 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { ++mCodec->mNodeGeneration; mCodec->mComponentName = componentName; mCodec->mRenderTracker.setComponentName(componentName); mCodec->mFlags = 0; if (componentName.endsWith(".secure")) { Loading Loading @@ -7644,7 +7666,6 @@ void ACodec::ExecutingState::resume() { void ACodec::ExecutingState::stateEntered() { ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str()); mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC)); mCodec->processDeferredMessages(); } Loading Loading @@ -7755,7 +7776,15 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) { mCodec->signalSubmitOutputMetadataBufferIfEOS_workaround(); } } return true; handled = true; break; } case kWhatPollForRenderedBuffers: { mCodec->pollForRenderedFrames(); handled = true; break; } default: Loading Loading @@ -8439,7 +8468,7 @@ void ACodec::forceStateTransition(int generation) { } bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) { mCodec->onFrameRendered(mediaTimeUs, systemNano); mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)}); return true; } Loading Loading @@ -8613,7 +8642,7 @@ void ACodec::OutputPortSettingsChangedState::stateEntered() { bool ACodec::OutputPortSettingsChangedState::onOMXFrameRendered( int64_t mediaTimeUs, nsecs_t systemNano) { mCodec->onFrameRendered(mediaTimeUs, systemNano); mCodec->mCallback->onOutputFramesRendered({RenderedFrameInfo(mediaTimeUs, systemNano)}); return true; } Loading Loading @@ -8644,10 +8673,6 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent( OMX_CommandPortEnable, kPortIndexOutput); } // Clear the RenderQueue in which queued GraphicBuffers hold the // actual buffer references in order to free them early. mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC)); if (err == OK) { err = mCodec->allocateBuffersOnPort(kPortIndexOutput); ALOGE_IF(err != OK, "Failed to allocate output port buffers after port " Loading Loading @@ -9031,8 +9056,6 @@ void ACodec::FlushingState::changeStateIfWeOwnAllBuffers() { // the native window for rendering. Let's get those back as well. mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs(); mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC)); mCodec->mCallback->onFlushCompleted(); mCodec->mPortEOS[kPortIndexInput] = Loading
media/libstagefright/ACodecBufferChannel.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/AUtils.h> #include <media/stagefright/ACodec.h> #include <media/stagefright/MediaCodec.h> #include <media/MediaCodecBuffer.h> #include <system/window.h> Loading Loading @@ -87,9 +88,11 @@ ACodecBufferChannel::BufferInfo::BufferInfo( } ACodecBufferChannel::ACodecBufferChannel( const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained) const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained, const sp<AMessage> &pollForRenderedBuffers) : mInputBufferFilled(inputBufferFilled), mOutputBufferDrained(outputBufferDrained), mPollForRenderedBuffers(pollForRenderedBuffers), mHeapSeqNum(-1) { } Loading Loading @@ -488,7 +491,7 @@ status_t ACodecBufferChannel::renderOutputBuffer( } void ACodecBufferChannel::pollForRenderedBuffers() { // TODO(b/266211548): Poll the native window for rendered buffers. mPollForRenderedBuffers->post(); } status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) { Loading
media/libstagefright/MediaCodec.cpp +18 −7 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ #include <media/stagefright/MediaErrors.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/RenderedFrameInfo.h> #include <media/stagefright/SurfaceUtils.h> #include <nativeloader/dlext_namespaces.h> #include <private/android_filesystem_config.h> Loading Loading @@ -750,7 +751,7 @@ public: const sp<AMessage> &outputFormat) override; virtual void onInputSurfaceDeclined(status_t err) override; virtual void onSignaledInputEOS(status_t err) override; virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override; virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) override; virtual void onOutputBuffersChanged() override; virtual void onFirstTunnelFrameReady() override; private: Loading Loading @@ -859,7 +860,7 @@ void CodecCallback::onSignaledInputEOS(status_t err) { notify->post(); } void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) { void CodecCallback::onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) { sp<AMessage> notify(mNotify->dup()); notify->setInt32("what", kWhatOutputFramesRendered); if (MediaCodec::CreateFramesRenderedMessage(done, notify)) { Loading Loading @@ -5953,12 +5954,10 @@ status_t MediaCodec::handleLeftover(size_t index) { return onQueueInputBuffer(msg); } //static size_t MediaCodec::CreateFramesRenderedMessage( const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) { template<typename T> static size_t CreateFramesRenderedMessageInternal(const std::list<T> &done, sp<AMessage> &msg) { size_t index = 0; for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin(); it != done.cend(); ++it) { for (typename std::list<T>::const_iterator it = done.cbegin(); it != done.cend(); ++it) { if (it->getRenderTimeNs() < 0) { continue; // dropped frame from tracking } Loading @@ -5969,6 +5968,18 @@ size_t MediaCodec::CreateFramesRenderedMessage( return index; } //static size_t MediaCodec::CreateFramesRenderedMessage( const std::list<RenderedFrameInfo> &done, sp<AMessage> &msg) { return CreateFramesRenderedMessageInternal(done, msg); } //static size_t MediaCodec::CreateFramesRenderedMessage( const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) { return CreateFramesRenderedMessageInternal(done, msg); } status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) { size_t index; CHECK(msg->findSize("index", &index)); Loading