Loading media/libstagefright/MediaCodec.cpp +41 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <C2Buffer.h> #include "include/SoftwareRenderer.h" #include "PlaybackDurationAccumulator.h" #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h> Loading Loading @@ -152,6 +153,8 @@ static const char *kCodecRecentLatencyMin = "android.media.mediacodec.recent.min static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg"; /* in us */ static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n"; static const char *kCodecRecentLatencyHist = "android.media.mediacodec.recent.hist"; /* in us */ static const char *kCodecPlaybackDuration = "android.media.mediacodec.playback-duration"; /* in sec */ static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped"; /* 0/1 */ Loading Loading @@ -740,6 +743,8 @@ MediaCodec::MediaCodec( mHaveInputSurface(false), mHavePendingInputBuffers(false), mCpuBoostRequested(false), mPlaybackDurationAccumulator(new PlaybackDurationAccumulator()), mIsSurfaceToScreen(false), mLatencyUnknown(0), mBytesEncoded(0), mEarliestEncodedPtsUs(INT64_MAX), Loading Loading @@ -846,6 +851,10 @@ void MediaCodec::updateMediametrics() { if (mLatencyUnknown > 0) { mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown); } int64_t playbackDuration = mPlaybackDurationAccumulator->getDurationInSeconds(); if (playbackDuration > 0) { mediametrics_setInt64(mMetricsHandle, kCodecPlaybackDuration, playbackDuration); } if (mLifetimeStartNs > 0) { nsecs_t lifetime = systemTime(SYSTEM_TIME_MONOTONIC) - mLifetimeStartNs; lifetime = lifetime / (1000 * 1000); // emitted in ms, truncated not rounded Loading Loading @@ -985,6 +994,28 @@ void MediaCodec::updateTunnelPeek(const sp<AMessage> &msg) { ALOGV("Ignoring tunnel-peek=%d for %s", tunnelPeek, asString(mTunnelPeekState)); } void MediaCodec::updatePlaybackDuration(const sp<AMessage> &msg) { int what = 0; msg->findInt32("what", &what); if (msg->what() != kWhatCodecNotify && what != kWhatOutputFramesRendered) { static bool logged = false; if (!logged) { logged = true; ALOGE("updatePlaybackDuration: expected kWhatOuputFramesRendered (%d)", msg->what()); } return; } // Playback duration only counts if the buffers are going to the screen. if (!mIsSurfaceToScreen) { return; } int64_t renderTimeNs; size_t index = 0; while (msg->findInt64(AStringPrintf("%zu-system-nano", index++).c_str(), &renderTimeNs)) { mPlaybackDurationAccumulator->processRenderTime(renderTimeNs); } } bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor) { if (nbuckets <= 0 || width <= 0) { Loading Loading @@ -3199,6 +3230,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { ALOGV("TunnelPeekState: %s -> %s", asString(previousState), asString(TunnelPeekState::kBufferRendered)); updatePlaybackDuration(msg); // check that we have a notification set if (mOnFrameRenderedNotification != NULL) { sp<AMessage> notify = mOnFrameRenderedNotification->dup(); Loading Loading @@ -4905,6 +4937,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { return ALREADY_EXISTS; } // in case we don't connect, ensure that we don't signal the surface is // connected to the screen mIsSurfaceToScreen = false; err = nativeWindowConnect(surface.get(), "connectToSurface"); if (err == OK) { // Require a fresh set of buffers after each connect by using a unique generation Loading @@ -4930,6 +4966,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { if (!mAllowFrameDroppingBySurface) { disableLegacyBufferDropPostQ(surface); } // keep track whether or not the buffers of the connected surface go to the screen int result = 0; surface->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &result); mIsSurfaceToScreen = result != 0; } } // do not return ALREADY_EXISTS unless surfaces are the same Loading @@ -4947,6 +4987,7 @@ status_t MediaCodec::disconnectFromSurface() { } // assume disconnected even on error mSurface.clear(); mIsSurfaceToScreen = false; } return err; } Loading media/libstagefright/PlaybackDurationAccumulator.h 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PLAYBACK_DURATION_ACCUMULATOR_H_ namespace android { // Accumulates playback duration by processing render times of individual frames and by ignoring // frames rendered during inactive playbacks such as seeking, pausing, or re-buffering. class PlaybackDurationAccumulator { private: // Controls the maximum delta between render times before considering the playback is not // active and has stalled. static const int64_t MAX_PRESENTATION_DURATION_NS = 500 * 1000 * 1000; public: PlaybackDurationAccumulator() { mPlaybackDurationNs = 0; mPreviousRenderTimeNs = 0; } // Process a render time expressed in nanoseconds. void processRenderTime(int64_t newRenderTimeNs) { // If we detect wrap-around or out of order frames, just ignore the duration for this // and the next frame. if (newRenderTimeNs < mPreviousRenderTimeNs) { mPreviousRenderTimeNs = 0; } if (mPreviousRenderTimeNs > 0) { int64_t presentationDurationNs = newRenderTimeNs - mPreviousRenderTimeNs; if (presentationDurationNs < MAX_PRESENTATION_DURATION_NS) { mPlaybackDurationNs += presentationDurationNs; } } mPreviousRenderTimeNs = newRenderTimeNs; } int64_t getDurationInSeconds() { return mPlaybackDurationNs / 1000 / 1000 / 1000; // Nanoseconds to seconds. } private: // The playback duration accumulated so far. int64_t mPlaybackDurationNs; // The previous render time used to compute the next presentation duration. int64_t mPreviousRenderTimeNs; }; } #endif media/libstagefright/include/media/stagefright/MediaCodec.h +5 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ class IMemory; struct PersistentSurface; class SoftwareRenderer; class Surface; class PlaybackDurationAccumulator; namespace hardware { namespace cas { namespace native { Loading Loading @@ -418,6 +419,7 @@ private: void updateLowLatency(const sp<AMessage> &msg); constexpr const char *asString(TunnelPeekState state, const char *default_string="?"); void updateTunnelPeek(const sp<AMessage> &msg); void updatePlaybackDuration(const sp<AMessage> &msg); sp<AMessage> mOutputFormat; sp<AMessage> mInputFormat; Loading Loading @@ -485,6 +487,9 @@ private: std::shared_ptr<BufferChannelBase> mBufferChannel; PlaybackDurationAccumulator * mPlaybackDurationAccumulator; bool mIsSurfaceToScreen; MediaCodec( const sp<ALooper> &looper, pid_t pid, uid_t uid, std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr, Loading Loading
media/libstagefright/MediaCodec.cpp +41 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <C2Buffer.h> #include "include/SoftwareRenderer.h" #include "PlaybackDurationAccumulator.h" #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h> Loading Loading @@ -152,6 +153,8 @@ static const char *kCodecRecentLatencyMin = "android.media.mediacodec.recent.min static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg"; /* in us */ static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n"; static const char *kCodecRecentLatencyHist = "android.media.mediacodec.recent.hist"; /* in us */ static const char *kCodecPlaybackDuration = "android.media.mediacodec.playback-duration"; /* in sec */ static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped"; /* 0/1 */ Loading Loading @@ -740,6 +743,8 @@ MediaCodec::MediaCodec( mHaveInputSurface(false), mHavePendingInputBuffers(false), mCpuBoostRequested(false), mPlaybackDurationAccumulator(new PlaybackDurationAccumulator()), mIsSurfaceToScreen(false), mLatencyUnknown(0), mBytesEncoded(0), mEarliestEncodedPtsUs(INT64_MAX), Loading Loading @@ -846,6 +851,10 @@ void MediaCodec::updateMediametrics() { if (mLatencyUnknown > 0) { mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown); } int64_t playbackDuration = mPlaybackDurationAccumulator->getDurationInSeconds(); if (playbackDuration > 0) { mediametrics_setInt64(mMetricsHandle, kCodecPlaybackDuration, playbackDuration); } if (mLifetimeStartNs > 0) { nsecs_t lifetime = systemTime(SYSTEM_TIME_MONOTONIC) - mLifetimeStartNs; lifetime = lifetime / (1000 * 1000); // emitted in ms, truncated not rounded Loading Loading @@ -985,6 +994,28 @@ void MediaCodec::updateTunnelPeek(const sp<AMessage> &msg) { ALOGV("Ignoring tunnel-peek=%d for %s", tunnelPeek, asString(mTunnelPeekState)); } void MediaCodec::updatePlaybackDuration(const sp<AMessage> &msg) { int what = 0; msg->findInt32("what", &what); if (msg->what() != kWhatCodecNotify && what != kWhatOutputFramesRendered) { static bool logged = false; if (!logged) { logged = true; ALOGE("updatePlaybackDuration: expected kWhatOuputFramesRendered (%d)", msg->what()); } return; } // Playback duration only counts if the buffers are going to the screen. if (!mIsSurfaceToScreen) { return; } int64_t renderTimeNs; size_t index = 0; while (msg->findInt64(AStringPrintf("%zu-system-nano", index++).c_str(), &renderTimeNs)) { mPlaybackDurationAccumulator->processRenderTime(renderTimeNs); } } bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor) { if (nbuckets <= 0 || width <= 0) { Loading Loading @@ -3199,6 +3230,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { ALOGV("TunnelPeekState: %s -> %s", asString(previousState), asString(TunnelPeekState::kBufferRendered)); updatePlaybackDuration(msg); // check that we have a notification set if (mOnFrameRenderedNotification != NULL) { sp<AMessage> notify = mOnFrameRenderedNotification->dup(); Loading Loading @@ -4905,6 +4937,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { return ALREADY_EXISTS; } // in case we don't connect, ensure that we don't signal the surface is // connected to the screen mIsSurfaceToScreen = false; err = nativeWindowConnect(surface.get(), "connectToSurface"); if (err == OK) { // Require a fresh set of buffers after each connect by using a unique generation Loading @@ -4930,6 +4966,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { if (!mAllowFrameDroppingBySurface) { disableLegacyBufferDropPostQ(surface); } // keep track whether or not the buffers of the connected surface go to the screen int result = 0; surface->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &result); mIsSurfaceToScreen = result != 0; } } // do not return ALREADY_EXISTS unless surfaces are the same Loading @@ -4947,6 +4987,7 @@ status_t MediaCodec::disconnectFromSurface() { } // assume disconnected even on error mSurface.clear(); mIsSurfaceToScreen = false; } return err; } Loading
media/libstagefright/PlaybackDurationAccumulator.h 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PLAYBACK_DURATION_ACCUMULATOR_H_ namespace android { // Accumulates playback duration by processing render times of individual frames and by ignoring // frames rendered during inactive playbacks such as seeking, pausing, or re-buffering. class PlaybackDurationAccumulator { private: // Controls the maximum delta between render times before considering the playback is not // active and has stalled. static const int64_t MAX_PRESENTATION_DURATION_NS = 500 * 1000 * 1000; public: PlaybackDurationAccumulator() { mPlaybackDurationNs = 0; mPreviousRenderTimeNs = 0; } // Process a render time expressed in nanoseconds. void processRenderTime(int64_t newRenderTimeNs) { // If we detect wrap-around or out of order frames, just ignore the duration for this // and the next frame. if (newRenderTimeNs < mPreviousRenderTimeNs) { mPreviousRenderTimeNs = 0; } if (mPreviousRenderTimeNs > 0) { int64_t presentationDurationNs = newRenderTimeNs - mPreviousRenderTimeNs; if (presentationDurationNs < MAX_PRESENTATION_DURATION_NS) { mPlaybackDurationNs += presentationDurationNs; } } mPreviousRenderTimeNs = newRenderTimeNs; } int64_t getDurationInSeconds() { return mPlaybackDurationNs / 1000 / 1000 / 1000; // Nanoseconds to seconds. } private: // The playback duration accumulated so far. int64_t mPlaybackDurationNs; // The previous render time used to compute the next presentation duration. int64_t mPreviousRenderTimeNs; }; } #endif
media/libstagefright/include/media/stagefright/MediaCodec.h +5 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ class IMemory; struct PersistentSurface; class SoftwareRenderer; class Surface; class PlaybackDurationAccumulator; namespace hardware { namespace cas { namespace native { Loading Loading @@ -418,6 +419,7 @@ private: void updateLowLatency(const sp<AMessage> &msg); constexpr const char *asString(TunnelPeekState state, const char *default_string="?"); void updateTunnelPeek(const sp<AMessage> &msg); void updatePlaybackDuration(const sp<AMessage> &msg); sp<AMessage> mOutputFormat; sp<AMessage> mInputFormat; Loading Loading @@ -485,6 +487,9 @@ private: std::shared_ptr<BufferChannelBase> mBufferChannel; PlaybackDurationAccumulator * mPlaybackDurationAccumulator; bool mIsSurfaceToScreen; MediaCodec( const sp<ALooper> &looper, pid_t pid, uid_t uid, std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr, Loading