Loading media/libstagefright/MediaCodec.cpp +116 −26 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <C2Buffer.h> #include <C2Buffer.h> #include "include/SoftwareRenderer.h" #include "include/SoftwareRenderer.h" #include "PlaybackDurationAccumulator.h" #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h> #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h> Loading Loading @@ -92,6 +93,7 @@ static const char *kCodecKeyName = "codec"; // NB: these are matched with public Java API constants defined // NB: these are matched with public Java API constants defined // in frameworks/base/media/java/android/media/MediaCodec.java // in frameworks/base/media/java/android/media/MediaCodec.java // These must be kept synchronized with the constants there. // These must be kept synchronized with the constants there. static const char *kCodecLogSessionId = "android.media.mediacodec.log-session-id"; static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */ static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */ static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */ static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */ static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */ static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */ Loading @@ -107,6 +109,16 @@ static const char *kCodecFrameRate = "android.media.mediacodec.frame-rate"; static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate"; static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate"; static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate"; static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate"; static const char *kCodecPriority = "android.media.mediacodec.priority"; static const char *kCodecPriority = "android.media.mediacodec.priority"; // Min/Max QP before shaping static const char *kCodecOriginalVideoQPIMin = "android.media.mediacodec.original-video-qp-i-min"; static const char *kCodecOriginalVideoQPIMax = "android.media.mediacodec.original-video-qp-i-max"; static const char *kCodecOriginalVideoQPPMin = "android.media.mediacodec.original-video-qp-p-min"; static const char *kCodecOriginalVideoQPPMax = "android.media.mediacodec.original-video-qp-p-max"; static const char *kCodecOriginalVideoQPBMin = "android.media.mediacodec.original-video-qp-b-min"; static const char *kCodecOriginalVideoQPBMax = "android.media.mediacodec.original-video-qp-b-max"; // Min/Max QP after shaping static const char *kCodecRequestedVideoQPIMin = "android.media.mediacodec.video-qp-i-min"; static const char *kCodecRequestedVideoQPIMin = "android.media.mediacodec.video-qp-i-min"; static const char *kCodecRequestedVideoQPIMax = "android.media.mediacodec.video-qp-i-max"; static const char *kCodecRequestedVideoQPIMax = "android.media.mediacodec.video-qp-i-max"; static const char *kCodecRequestedVideoQPPMin = "android.media.mediacodec.video-qp-p-min"; static const char *kCodecRequestedVideoQPPMin = "android.media.mediacodec.video-qp-p-min"; Loading Loading @@ -152,8 +164,12 @@ static const char *kCodecRecentLatencyMin = "android.media.mediacodec.recent.min static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg"; /* in us */ static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg"; /* in us */ static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n"; static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n"; static const char *kCodecRecentLatencyHist = "android.media.mediacodec.recent.hist"; /* in us */ 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 */ /* -1: shaper disabled >=0: number of fields changed */ static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped"; // XXX suppress until we get our representation right // XXX suppress until we get our representation right static bool kEmitHistogram = false; static bool kEmitHistogram = false; Loading Loading @@ -740,6 +756,8 @@ MediaCodec::MediaCodec( mHaveInputSurface(false), mHaveInputSurface(false), mHavePendingInputBuffers(false), mHavePendingInputBuffers(false), mCpuBoostRequested(false), mCpuBoostRequested(false), mPlaybackDurationAccumulator(new PlaybackDurationAccumulator()), mIsSurfaceToScreen(false), mLatencyUnknown(0), mLatencyUnknown(0), mBytesEncoded(0), mBytesEncoded(0), mEarliestEncodedPtsUs(INT64_MAX), mEarliestEncodedPtsUs(INT64_MAX), Loading Loading @@ -846,6 +864,10 @@ void MediaCodec::updateMediametrics() { if (mLatencyUnknown > 0) { if (mLatencyUnknown > 0) { mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown); mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown); } } int64_t playbackDuration = mPlaybackDurationAccumulator->getDurationInSeconds(); if (playbackDuration > 0) { mediametrics_setInt64(mMetricsHandle, kCodecPlaybackDuration, playbackDuration); } if (mLifetimeStartNs > 0) { if (mLifetimeStartNs > 0) { nsecs_t lifetime = systemTime(SYSTEM_TIME_MONOTONIC) - mLifetimeStartNs; nsecs_t lifetime = systemTime(SYSTEM_TIME_MONOTONIC) - mLifetimeStartNs; lifetime = lifetime / (1000 * 1000); // emitted in ms, truncated not rounded lifetime = lifetime / (1000 * 1000); // emitted in ms, truncated not rounded Loading Loading @@ -985,6 +1007,28 @@ void MediaCodec::updateTunnelPeek(const sp<AMessage> &msg) { ALOGV("Ignoring tunnel-peek=%d for %s", tunnelPeek, asString(mTunnelPeekState)); 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) bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor) { { if (nbuckets <= 0 || width <= 0) { if (nbuckets <= 0 || width <= 0) { Loading Loading @@ -1460,6 +1504,8 @@ status_t MediaCodec::configure( } } if (mIsVideo) { if (mIsVideo) { // TODO: validity check log-session-id: it should be a 32-hex-digit. format->findString("log-session-id", &mLogSessionId); format->findInt32("width", &mVideoWidth); format->findInt32("width", &mVideoWidth); format->findInt32("height", &mVideoHeight); format->findInt32("height", &mVideoHeight); if (!format->findInt32("rotation-degrees", &mRotationDegrees)) { if (!format->findInt32("rotation-degrees", &mRotationDegrees)) { Loading @@ -1467,6 +1513,7 @@ status_t MediaCodec::configure( } } if (mMetricsHandle != 0) { if (mMetricsHandle != 0) { mediametrics_setCString(mMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str()); mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth); mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth); mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight); mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight); mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees); mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees); Loading Loading @@ -1498,30 +1545,6 @@ status_t MediaCodec::configure( if (format->findInt32("priority", &priority)) { if (format->findInt32("priority", &priority)) { mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority); mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority); } } int32_t qpIMin = -1; if (format->findInt32("video-qp-i-min", &qpIMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin); } int32_t qpIMax = -1; if (format->findInt32("video-qp-i-max", &qpIMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax); } int32_t qpPMin = -1; if (format->findInt32("video-qp-p-min", &qpPMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin); } int32_t qpPMax = -1; if (format->findInt32("video-qp-p-max", &qpPMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax); } int32_t qpBMin = -1; if (format->findInt32("video-qp-b-min", &qpBMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin); } int32_t qpBMax = -1; if (format->findInt32("video-qp-b-max", &qpBMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax); } } } // Prevent possible integer overflow in downstream code. // Prevent possible integer overflow in downstream code. Loading Loading @@ -1549,6 +1572,9 @@ status_t MediaCodec::configure( enableMediaFormatShapingDefault); enableMediaFormatShapingDefault); if (!enableShaping) { if (!enableShaping) { ALOGI("format shaping disabled, property '%s'", enableMediaFormatShapingProperty); ALOGI("format shaping disabled, property '%s'", enableMediaFormatShapingProperty); if (mMetricsHandle != 0) { mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, -1); } } else { } else { (void) shapeMediaFormat(format, flags); (void) shapeMediaFormat(format, flags); // XXX: do we want to do this regardless of shaping enablement? // XXX: do we want to do this regardless of shaping enablement? Loading @@ -1556,6 +1582,34 @@ status_t MediaCodec::configure( } } } } // push min/max QP to MediaMetrics after shaping if (mIsVideo && mMetricsHandle != 0) { int32_t qpIMin = -1; if (format->findInt32("video-qp-i-min", &qpIMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin); } int32_t qpIMax = -1; if (format->findInt32("video-qp-i-max", &qpIMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax); } int32_t qpPMin = -1; if (format->findInt32("video-qp-p-min", &qpPMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin); } int32_t qpPMax = -1; if (format->findInt32("video-qp-p-max", &qpPMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax); } int32_t qpBMin = -1; if (format->findInt32("video-qp-b-min", &qpBMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin); } int32_t qpBMax = -1; if (format->findInt32("video-qp-b-max", &qpBMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax); } } updateLowLatency(format); updateLowLatency(format); msg->setMessage("format", format); msg->setMessage("format", format); Loading Loading @@ -1875,14 +1929,40 @@ status_t MediaCodec::shapeMediaFormat( sp<AMessage> deltas = updatedFormat->changesFrom(format, false /* deep */); sp<AMessage> deltas = updatedFormat->changesFrom(format, false /* deep */); size_t changeCount = deltas->countEntries(); size_t changeCount = deltas->countEntries(); ALOGD("shapeMediaFormat: deltas(%zu): %s", changeCount, deltas->debugString(2).c_str()); ALOGD("shapeMediaFormat: deltas(%zu): %s", changeCount, deltas->debugString(2).c_str()); if (changeCount > 0) { if (mMetricsHandle != 0) { if (mMetricsHandle != 0) { mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount); mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount); } if (changeCount > 0) { if (mMetricsHandle != 0) { // save some old properties before we fold in the new ones // save some old properties before we fold in the new ones int32_t bitrate; int32_t bitrate; if (format->findInt32(KEY_BIT_RATE, &bitrate)) { if (format->findInt32(KEY_BIT_RATE, &bitrate)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalBitrate, bitrate); mediametrics_setInt32(mMetricsHandle, kCodecOriginalBitrate, bitrate); } } int32_t qpIMin = -1; if (format->findInt32("original-video-qp-i-min", &qpIMin)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMin, qpIMin); } int32_t qpIMax = -1; if (format->findInt32("original-video-qp-i-max", &qpIMax)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMax, qpIMax); } int32_t qpPMin = -1; if (format->findInt32("original-video-qp-p-min", &qpPMin)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMin, qpPMin); } int32_t qpPMax = -1; if (format->findInt32("original-video-qp-p-max", &qpPMax)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMax, qpPMax); } int32_t qpBMin = -1; if (format->findInt32("original-video-qp-b-min", &qpBMin)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMin, qpBMin); } int32_t qpBMax = -1; if (format->findInt32("original-video-qp-b-max", &qpBMax)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMax, qpBMax); } } } // NB: for any field in both format and deltas, the deltas copy wins // NB: for any field in both format and deltas, the deltas copy wins format->extend(deltas); format->extend(deltas); Loading Loading @@ -3199,6 +3279,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { ALOGV("TunnelPeekState: %s -> %s", ALOGV("TunnelPeekState: %s -> %s", asString(previousState), asString(previousState), asString(TunnelPeekState::kBufferRendered)); asString(TunnelPeekState::kBufferRendered)); updatePlaybackDuration(msg); // check that we have a notification set // check that we have a notification set if (mOnFrameRenderedNotification != NULL) { if (mOnFrameRenderedNotification != NULL) { sp<AMessage> notify = mOnFrameRenderedNotification->dup(); sp<AMessage> notify = mOnFrameRenderedNotification->dup(); Loading Loading @@ -4905,6 +4986,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { return ALREADY_EXISTS; 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"); err = nativeWindowConnect(surface.get(), "connectToSurface"); if (err == OK) { if (err == OK) { // Require a fresh set of buffers after each connect by using a unique generation // Require a fresh set of buffers after each connect by using a unique generation Loading @@ -4930,6 +5015,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { if (!mAllowFrameDroppingBySurface) { if (!mAllowFrameDroppingBySurface) { disableLegacyBufferDropPostQ(surface); 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 // do not return ALREADY_EXISTS unless surfaces are the same Loading @@ -4947,6 +5036,7 @@ status_t MediaCodec::disconnectFromSurface() { } } // assume disconnected even on error // assume disconnected even on error mSurface.clear(); mSurface.clear(); mIsSurfaceToScreen = false; } } return err; return err; } } Loading media/libstagefright/PlaybackDurationAccumulator.h 0 → 100644 +65 −0 Original line number Original line 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 +6 −0 Original line number Original line Diff line number Diff line Loading @@ -58,6 +58,7 @@ class IMemory; struct PersistentSurface; struct PersistentSurface; class SoftwareRenderer; class SoftwareRenderer; class Surface; class Surface; class PlaybackDurationAccumulator; namespace hardware { namespace hardware { namespace cas { namespace cas { namespace native { namespace native { Loading Loading @@ -418,6 +419,7 @@ private: void updateLowLatency(const sp<AMessage> &msg); void updateLowLatency(const sp<AMessage> &msg); constexpr const char *asString(TunnelPeekState state, const char *default_string="?"); constexpr const char *asString(TunnelPeekState state, const char *default_string="?"); void updateTunnelPeek(const sp<AMessage> &msg); void updateTunnelPeek(const sp<AMessage> &msg); void updatePlaybackDuration(const sp<AMessage> &msg); sp<AMessage> mOutputFormat; sp<AMessage> mOutputFormat; sp<AMessage> mInputFormat; sp<AMessage> mInputFormat; Loading @@ -429,6 +431,7 @@ private: sp<ResourceManagerServiceProxy> mResourceManagerProxy; sp<ResourceManagerServiceProxy> mResourceManagerProxy; bool mIsVideo; bool mIsVideo; AString mLogSessionId; int32_t mVideoWidth; int32_t mVideoWidth; int32_t mVideoHeight; int32_t mVideoHeight; int32_t mRotationDegrees; int32_t mRotationDegrees; Loading Loading @@ -485,6 +488,9 @@ private: std::shared_ptr<BufferChannelBase> mBufferChannel; std::shared_ptr<BufferChannelBase> mBufferChannel; PlaybackDurationAccumulator * mPlaybackDurationAccumulator; bool mIsSurfaceToScreen; MediaCodec( MediaCodec( const sp<ALooper> &looper, pid_t pid, uid_t uid, const sp<ALooper> &looper, pid_t pid, uid_t uid, std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr, std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr, Loading services/mediametrics/statsd_audiopolicy.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -32,7 +32,7 @@ #include <statslog.h> #include <statslog.h> #include "MediaMetricsService.h" #include "MediaMetricsService.h" #include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h" #include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h" #include "iface_statsd.h" #include "iface_statsd.h" namespace android { namespace android { Loading @@ -50,7 +50,7 @@ bool statsd_audiopolicy(const std::shared_ptr<const mediametrics::Item>& item, // the rest into our own proto // the rest into our own proto // // ::android::stats::mediametrics::AudioPolicyData metrics_proto; ::android::stats::mediametrics_message::AudioPolicyData metrics_proto; // flesh out the protobuf we'll hand off with our data // flesh out the protobuf we'll hand off with our data // // Loading services/mediametrics/statsd_audiorecord.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -33,7 +33,7 @@ #include "MediaMetricsService.h" #include "MediaMetricsService.h" #include "StringUtils.h" #include "StringUtils.h" #include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h" #include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h" #include "iface_statsd.h" #include "iface_statsd.h" namespace android { namespace android { Loading @@ -50,7 +50,7 @@ bool statsd_audiorecord(const std::shared_ptr<const mediametrics::Item>& item, // the rest into our own proto // the rest into our own proto // // ::android::stats::mediametrics::AudioRecordData metrics_proto; ::android::stats::mediametrics_message::AudioRecordData metrics_proto; // flesh out the protobuf we'll hand off with our data // flesh out the protobuf we'll hand off with our data // // Loading Loading
media/libstagefright/MediaCodec.cpp +116 −26 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <C2Buffer.h> #include <C2Buffer.h> #include "include/SoftwareRenderer.h" #include "include/SoftwareRenderer.h" #include "PlaybackDurationAccumulator.h" #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h> #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h> Loading Loading @@ -92,6 +93,7 @@ static const char *kCodecKeyName = "codec"; // NB: these are matched with public Java API constants defined // NB: these are matched with public Java API constants defined // in frameworks/base/media/java/android/media/MediaCodec.java // in frameworks/base/media/java/android/media/MediaCodec.java // These must be kept synchronized with the constants there. // These must be kept synchronized with the constants there. static const char *kCodecLogSessionId = "android.media.mediacodec.log-session-id"; static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */ static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */ static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */ static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */ static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */ static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */ Loading @@ -107,6 +109,16 @@ static const char *kCodecFrameRate = "android.media.mediacodec.frame-rate"; static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate"; static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate"; static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate"; static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate"; static const char *kCodecPriority = "android.media.mediacodec.priority"; static const char *kCodecPriority = "android.media.mediacodec.priority"; // Min/Max QP before shaping static const char *kCodecOriginalVideoQPIMin = "android.media.mediacodec.original-video-qp-i-min"; static const char *kCodecOriginalVideoQPIMax = "android.media.mediacodec.original-video-qp-i-max"; static const char *kCodecOriginalVideoQPPMin = "android.media.mediacodec.original-video-qp-p-min"; static const char *kCodecOriginalVideoQPPMax = "android.media.mediacodec.original-video-qp-p-max"; static const char *kCodecOriginalVideoQPBMin = "android.media.mediacodec.original-video-qp-b-min"; static const char *kCodecOriginalVideoQPBMax = "android.media.mediacodec.original-video-qp-b-max"; // Min/Max QP after shaping static const char *kCodecRequestedVideoQPIMin = "android.media.mediacodec.video-qp-i-min"; static const char *kCodecRequestedVideoQPIMin = "android.media.mediacodec.video-qp-i-min"; static const char *kCodecRequestedVideoQPIMax = "android.media.mediacodec.video-qp-i-max"; static const char *kCodecRequestedVideoQPIMax = "android.media.mediacodec.video-qp-i-max"; static const char *kCodecRequestedVideoQPPMin = "android.media.mediacodec.video-qp-p-min"; static const char *kCodecRequestedVideoQPPMin = "android.media.mediacodec.video-qp-p-min"; Loading Loading @@ -152,8 +164,12 @@ static const char *kCodecRecentLatencyMin = "android.media.mediacodec.recent.min static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg"; /* in us */ static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg"; /* in us */ static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n"; static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n"; static const char *kCodecRecentLatencyHist = "android.media.mediacodec.recent.hist"; /* in us */ 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 */ /* -1: shaper disabled >=0: number of fields changed */ static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped"; // XXX suppress until we get our representation right // XXX suppress until we get our representation right static bool kEmitHistogram = false; static bool kEmitHistogram = false; Loading Loading @@ -740,6 +756,8 @@ MediaCodec::MediaCodec( mHaveInputSurface(false), mHaveInputSurface(false), mHavePendingInputBuffers(false), mHavePendingInputBuffers(false), mCpuBoostRequested(false), mCpuBoostRequested(false), mPlaybackDurationAccumulator(new PlaybackDurationAccumulator()), mIsSurfaceToScreen(false), mLatencyUnknown(0), mLatencyUnknown(0), mBytesEncoded(0), mBytesEncoded(0), mEarliestEncodedPtsUs(INT64_MAX), mEarliestEncodedPtsUs(INT64_MAX), Loading Loading @@ -846,6 +864,10 @@ void MediaCodec::updateMediametrics() { if (mLatencyUnknown > 0) { if (mLatencyUnknown > 0) { mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown); mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown); } } int64_t playbackDuration = mPlaybackDurationAccumulator->getDurationInSeconds(); if (playbackDuration > 0) { mediametrics_setInt64(mMetricsHandle, kCodecPlaybackDuration, playbackDuration); } if (mLifetimeStartNs > 0) { if (mLifetimeStartNs > 0) { nsecs_t lifetime = systemTime(SYSTEM_TIME_MONOTONIC) - mLifetimeStartNs; nsecs_t lifetime = systemTime(SYSTEM_TIME_MONOTONIC) - mLifetimeStartNs; lifetime = lifetime / (1000 * 1000); // emitted in ms, truncated not rounded lifetime = lifetime / (1000 * 1000); // emitted in ms, truncated not rounded Loading Loading @@ -985,6 +1007,28 @@ void MediaCodec::updateTunnelPeek(const sp<AMessage> &msg) { ALOGV("Ignoring tunnel-peek=%d for %s", tunnelPeek, asString(mTunnelPeekState)); 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) bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor) { { if (nbuckets <= 0 || width <= 0) { if (nbuckets <= 0 || width <= 0) { Loading Loading @@ -1460,6 +1504,8 @@ status_t MediaCodec::configure( } } if (mIsVideo) { if (mIsVideo) { // TODO: validity check log-session-id: it should be a 32-hex-digit. format->findString("log-session-id", &mLogSessionId); format->findInt32("width", &mVideoWidth); format->findInt32("width", &mVideoWidth); format->findInt32("height", &mVideoHeight); format->findInt32("height", &mVideoHeight); if (!format->findInt32("rotation-degrees", &mRotationDegrees)) { if (!format->findInt32("rotation-degrees", &mRotationDegrees)) { Loading @@ -1467,6 +1513,7 @@ status_t MediaCodec::configure( } } if (mMetricsHandle != 0) { if (mMetricsHandle != 0) { mediametrics_setCString(mMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str()); mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth); mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth); mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight); mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight); mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees); mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees); Loading Loading @@ -1498,30 +1545,6 @@ status_t MediaCodec::configure( if (format->findInt32("priority", &priority)) { if (format->findInt32("priority", &priority)) { mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority); mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority); } } int32_t qpIMin = -1; if (format->findInt32("video-qp-i-min", &qpIMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin); } int32_t qpIMax = -1; if (format->findInt32("video-qp-i-max", &qpIMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax); } int32_t qpPMin = -1; if (format->findInt32("video-qp-p-min", &qpPMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin); } int32_t qpPMax = -1; if (format->findInt32("video-qp-p-max", &qpPMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax); } int32_t qpBMin = -1; if (format->findInt32("video-qp-b-min", &qpBMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin); } int32_t qpBMax = -1; if (format->findInt32("video-qp-b-max", &qpBMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax); } } } // Prevent possible integer overflow in downstream code. // Prevent possible integer overflow in downstream code. Loading Loading @@ -1549,6 +1572,9 @@ status_t MediaCodec::configure( enableMediaFormatShapingDefault); enableMediaFormatShapingDefault); if (!enableShaping) { if (!enableShaping) { ALOGI("format shaping disabled, property '%s'", enableMediaFormatShapingProperty); ALOGI("format shaping disabled, property '%s'", enableMediaFormatShapingProperty); if (mMetricsHandle != 0) { mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, -1); } } else { } else { (void) shapeMediaFormat(format, flags); (void) shapeMediaFormat(format, flags); // XXX: do we want to do this regardless of shaping enablement? // XXX: do we want to do this regardless of shaping enablement? Loading @@ -1556,6 +1582,34 @@ status_t MediaCodec::configure( } } } } // push min/max QP to MediaMetrics after shaping if (mIsVideo && mMetricsHandle != 0) { int32_t qpIMin = -1; if (format->findInt32("video-qp-i-min", &qpIMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin); } int32_t qpIMax = -1; if (format->findInt32("video-qp-i-max", &qpIMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax); } int32_t qpPMin = -1; if (format->findInt32("video-qp-p-min", &qpPMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin); } int32_t qpPMax = -1; if (format->findInt32("video-qp-p-max", &qpPMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax); } int32_t qpBMin = -1; if (format->findInt32("video-qp-b-min", &qpBMin)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin); } int32_t qpBMax = -1; if (format->findInt32("video-qp-b-max", &qpBMax)) { mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax); } } updateLowLatency(format); updateLowLatency(format); msg->setMessage("format", format); msg->setMessage("format", format); Loading Loading @@ -1875,14 +1929,40 @@ status_t MediaCodec::shapeMediaFormat( sp<AMessage> deltas = updatedFormat->changesFrom(format, false /* deep */); sp<AMessage> deltas = updatedFormat->changesFrom(format, false /* deep */); size_t changeCount = deltas->countEntries(); size_t changeCount = deltas->countEntries(); ALOGD("shapeMediaFormat: deltas(%zu): %s", changeCount, deltas->debugString(2).c_str()); ALOGD("shapeMediaFormat: deltas(%zu): %s", changeCount, deltas->debugString(2).c_str()); if (changeCount > 0) { if (mMetricsHandle != 0) { if (mMetricsHandle != 0) { mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount); mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount); } if (changeCount > 0) { if (mMetricsHandle != 0) { // save some old properties before we fold in the new ones // save some old properties before we fold in the new ones int32_t bitrate; int32_t bitrate; if (format->findInt32(KEY_BIT_RATE, &bitrate)) { if (format->findInt32(KEY_BIT_RATE, &bitrate)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalBitrate, bitrate); mediametrics_setInt32(mMetricsHandle, kCodecOriginalBitrate, bitrate); } } int32_t qpIMin = -1; if (format->findInt32("original-video-qp-i-min", &qpIMin)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMin, qpIMin); } int32_t qpIMax = -1; if (format->findInt32("original-video-qp-i-max", &qpIMax)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPIMax, qpIMax); } int32_t qpPMin = -1; if (format->findInt32("original-video-qp-p-min", &qpPMin)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMin, qpPMin); } int32_t qpPMax = -1; if (format->findInt32("original-video-qp-p-max", &qpPMax)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPPMax, qpPMax); } int32_t qpBMin = -1; if (format->findInt32("original-video-qp-b-min", &qpBMin)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMin, qpBMin); } int32_t qpBMax = -1; if (format->findInt32("original-video-qp-b-max", &qpBMax)) { mediametrics_setInt32(mMetricsHandle, kCodecOriginalVideoQPBMax, qpBMax); } } } // NB: for any field in both format and deltas, the deltas copy wins // NB: for any field in both format and deltas, the deltas copy wins format->extend(deltas); format->extend(deltas); Loading Loading @@ -3199,6 +3279,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { ALOGV("TunnelPeekState: %s -> %s", ALOGV("TunnelPeekState: %s -> %s", asString(previousState), asString(previousState), asString(TunnelPeekState::kBufferRendered)); asString(TunnelPeekState::kBufferRendered)); updatePlaybackDuration(msg); // check that we have a notification set // check that we have a notification set if (mOnFrameRenderedNotification != NULL) { if (mOnFrameRenderedNotification != NULL) { sp<AMessage> notify = mOnFrameRenderedNotification->dup(); sp<AMessage> notify = mOnFrameRenderedNotification->dup(); Loading Loading @@ -4905,6 +4986,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { return ALREADY_EXISTS; 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"); err = nativeWindowConnect(surface.get(), "connectToSurface"); if (err == OK) { if (err == OK) { // Require a fresh set of buffers after each connect by using a unique generation // Require a fresh set of buffers after each connect by using a unique generation Loading @@ -4930,6 +5015,10 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { if (!mAllowFrameDroppingBySurface) { if (!mAllowFrameDroppingBySurface) { disableLegacyBufferDropPostQ(surface); 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 // do not return ALREADY_EXISTS unless surfaces are the same Loading @@ -4947,6 +5036,7 @@ status_t MediaCodec::disconnectFromSurface() { } } // assume disconnected even on error // assume disconnected even on error mSurface.clear(); mSurface.clear(); mIsSurfaceToScreen = false; } } return err; return err; } } Loading
media/libstagefright/PlaybackDurationAccumulator.h 0 → 100644 +65 −0 Original line number Original line 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 +6 −0 Original line number Original line Diff line number Diff line Loading @@ -58,6 +58,7 @@ class IMemory; struct PersistentSurface; struct PersistentSurface; class SoftwareRenderer; class SoftwareRenderer; class Surface; class Surface; class PlaybackDurationAccumulator; namespace hardware { namespace hardware { namespace cas { namespace cas { namespace native { namespace native { Loading Loading @@ -418,6 +419,7 @@ private: void updateLowLatency(const sp<AMessage> &msg); void updateLowLatency(const sp<AMessage> &msg); constexpr const char *asString(TunnelPeekState state, const char *default_string="?"); constexpr const char *asString(TunnelPeekState state, const char *default_string="?"); void updateTunnelPeek(const sp<AMessage> &msg); void updateTunnelPeek(const sp<AMessage> &msg); void updatePlaybackDuration(const sp<AMessage> &msg); sp<AMessage> mOutputFormat; sp<AMessage> mOutputFormat; sp<AMessage> mInputFormat; sp<AMessage> mInputFormat; Loading @@ -429,6 +431,7 @@ private: sp<ResourceManagerServiceProxy> mResourceManagerProxy; sp<ResourceManagerServiceProxy> mResourceManagerProxy; bool mIsVideo; bool mIsVideo; AString mLogSessionId; int32_t mVideoWidth; int32_t mVideoWidth; int32_t mVideoHeight; int32_t mVideoHeight; int32_t mRotationDegrees; int32_t mRotationDegrees; Loading Loading @@ -485,6 +488,9 @@ private: std::shared_ptr<BufferChannelBase> mBufferChannel; std::shared_ptr<BufferChannelBase> mBufferChannel; PlaybackDurationAccumulator * mPlaybackDurationAccumulator; bool mIsSurfaceToScreen; MediaCodec( MediaCodec( const sp<ALooper> &looper, pid_t pid, uid_t uid, const sp<ALooper> &looper, pid_t pid, uid_t uid, std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr, std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr, Loading
services/mediametrics/statsd_audiopolicy.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -32,7 +32,7 @@ #include <statslog.h> #include <statslog.h> #include "MediaMetricsService.h" #include "MediaMetricsService.h" #include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h" #include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h" #include "iface_statsd.h" #include "iface_statsd.h" namespace android { namespace android { Loading @@ -50,7 +50,7 @@ bool statsd_audiopolicy(const std::shared_ptr<const mediametrics::Item>& item, // the rest into our own proto // the rest into our own proto // // ::android::stats::mediametrics::AudioPolicyData metrics_proto; ::android::stats::mediametrics_message::AudioPolicyData metrics_proto; // flesh out the protobuf we'll hand off with our data // flesh out the protobuf we'll hand off with our data // // Loading
services/mediametrics/statsd_audiorecord.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -33,7 +33,7 @@ #include "MediaMetricsService.h" #include "MediaMetricsService.h" #include "StringUtils.h" #include "StringUtils.h" #include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h" #include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h" #include "iface_statsd.h" #include "iface_statsd.h" namespace android { namespace android { Loading @@ -50,7 +50,7 @@ bool statsd_audiorecord(const std::shared_ptr<const mediametrics::Item>& item, // the rest into our own proto // the rest into our own proto // // ::android::stats::mediametrics::AudioRecordData metrics_proto; ::android::stats::mediametrics_message::AudioRecordData metrics_proto; // flesh out the protobuf we'll hand off with our data // flesh out the protobuf we'll hand off with our data // // Loading