Merge "Add atom reporting for MediaCodecRendered" into udc-dev
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 09d2802..f1534c9 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -255,7 +255,6 @@
"MediaCodecSource.cpp",
"MediaExtractor.cpp",
"MediaExtractorFactory.cpp",
- "MediaHistogram.cpp",
"MediaSource.cpp",
"MediaSync.cpp",
"MediaTrack.cpp",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index bd56b18..c02573e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -22,7 +22,6 @@
#include <set>
#include <random>
#include <stdlib.h>
-
#include <inttypes.h>
#include <stdlib.h>
#include <dlfcn.h>
@@ -108,7 +107,9 @@
static const char *kCodecModeImage = "image";
static const char *kCodecModeUnknown = "unknown";
static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
+static const char *kCodecHardware = "android.media.mediacodec.hardware"; /* 0,1 */
static const char *kCodecSecure = "android.media.mediacodec.secure"; /* 0, 1 */
+static const char *kCodecTunneled = "android.media.mediacodec.tunneled"; /* 0,1 */
static const char *kCodecWidth = "android.media.mediacodec.width"; /* 0..n */
static const char *kCodecHeight = "android.media.mediacodec.height"; /* 0..n */
static const char *kCodecRotation = "android.media.mediacodec.rotation-degrees"; /* 0/90/180/270 */
@@ -172,9 +173,9 @@
static const char *kCodecParsedColorStandard = "android.media.mediacodec.parsed-color-standard";
static const char *kCodecParsedColorRange = "android.media.mediacodec.parsed-color-range";
static const char *kCodecParsedColorTransfer = "android.media.mediacodec.parsed-color-transfer";
-static const char *kCodecHDRStaticInfo = "android.media.mediacodec.hdr-static-info";
-static const char *kCodecHDR10PlusInfo = "android.media.mediacodec.hdr10-plus-info";
-static const char *kCodecHDRFormat = "android.media.mediacodec.hdr-format";
+static const char *kCodecHdrStaticInfo = "android.media.mediacodec.hdr-static-info";
+static const char *kCodecHdr10PlusInfo = "android.media.mediacodec.hdr10-plus-info";
+static const char *kCodecHdrFormat = "android.media.mediacodec.hdr-format";
// array/sync/async/block modes
static const char *kCodecArrayMode = "android.media.mediacodec.array-mode";
static const char *kCodecOperationMode = "android.media.mediacodec.operation-mode";
@@ -195,35 +196,44 @@
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 *kCodecPlaybackDurationSec =
- "android.media.mediacodec.playback-duration-sec"; /* in sec */
-
-static const char *kCodecFramesReleased = "android.media.mediacodec.frames.released";
-static const char *kCodecFramesRendered = "android.media.mediacodec.frames.rendered";
-static const char *kCodecFramesSkipped = "android.media.mediacodec.frames.skipped";
-static const char *kCodecFramesDropped = "android.media.mediacodec.frames.dropped";
-static const char *kCodecFramerateContent = "android.media.mediacodec.framerate.content";
-static const char *kCodecFramerateDesired = "android.media.mediacodec.framerate.desired";
-static const char *kCodecFramerateActual = "android.media.mediacodec.framerate.actual";
-
-static const char *kCodecFreezeCount = "android.media.mediacodec.freeze.count";
-static const char *kCodecFreezeDurationAverage = "android.media.mediacodec.freeze.duration.average";
-static const char *kCodecFreezeDurationMax = "android.media.mediacodec.freeze.duration.max";
-static const char *kCodecFreezeDurationHistogram =
- "android.media.mediacodec.freeze.duration.histogram";
-static const char *kCodecFreezeDistanceAverage = "android.media.mediacodec.freeze.distance.average";
-static const char *kCodecFreezeDistanceHistogram =
- "android.media.mediacodec.freeze.distance.histogram";
-
-static const char *kCodecJudderCount = "android.media.mediacodec.judder.count";
-static const char *kCodecJudderScoreAverage = "android.media.mediacodec.judder.average";
-static const char *kCodecJudderScoreMax = "android.media.mediacodec.judder.max";
-static const char *kCodecJudderScoreHistogram = "android.media.mediacodec.judder.histogram";
/* -1: shaper disabled
>=0: number of fields changed */
static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped";
+// Render metrics
+static const char *kCodecPlaybackDurationSec = "android.media.mediacodec.playback-duration-sec";
+static const char *kCodecFirstRenderTimeUs = "android.media.mediacodec.first-render-time-us";
+static const char *kCodecFramesReleased = "android.media.mediacodec.frames-released";
+static const char *kCodecFramesRendered = "android.media.mediacodec.frames-rendered";
+static const char *kCodecFramesDropped = "android.media.mediacodec.frames-dropped";
+static const char *kCodecFramesSkipped = "android.media.mediacodec.frames-skipped";
+static const char *kCodecFramerateContent = "android.media.mediacodec.framerate-content";
+static const char *kCodecFramerateDesired = "android.media.mediacodec.framerate-desired";
+static const char *kCodecFramerateActual = "android.media.mediacodec.framerate-actual";
+static const char *kCodecFreezeCount = "android.media.mediacodec.freeze-count";
+static const char *kCodecFreezeScore = "android.media.mediacodec.freeze-score";
+static const char *kCodecFreezeRate = "android.media.mediacodec.freeze-rate";
+static const char *kCodecFreezeDurationMsAvg = "android.media.mediacodec.freeze-duration-ms-avg";
+static const char *kCodecFreezeDurationMsMax = "android.media.mediacodec.freeze-duration-ms-max";
+static const char *kCodecFreezeDurationMsHistogram =
+ "android.media.mediacodec.freeze-duration-ms-histogram";
+static const char *kCodecFreezeDurationMsHistogramBuckets =
+ "android.media.mediacodec.freeze-duration-ms-histogram-buckets";
+static const char *kCodecFreezeDistanceMsAvg = "android.media.mediacodec.freeze-distance-ms-avg";
+static const char *kCodecFreezeDistanceMsHistogram =
+ "android.media.mediacodec.freeze-distance-ms-histogram";
+static const char *kCodecFreezeDistanceMsHistogramBuckets =
+ "android.media.mediacodec.freeze-distance-ms-histogram-buckets";
+static const char *kCodecJudderCount = "android.media.mediacodec.judder-count";
+static const char *kCodecJudderScore = "android.media.mediacodec.judder-score";
+static const char *kCodecJudderRate = "android.media.mediacodec.judder-rate";
+static const char *kCodecJudderScoreAvg = "android.media.mediacodec.judder-score-avg";
+static const char *kCodecJudderScoreMax = "android.media.mediacodec.judder-score-max";
+static const char *kCodecJudderScoreHistogram = "android.media.mediacodec.judder-score-histogram";
+static const char *kCodecJudderScoreHistogramBuckets =
+ "android.media.mediacodec.judder-score-histogram-buckets";
+
// XXX suppress until we get our representation right
static bool kEmitHistogram = false;
@@ -1118,8 +1128,9 @@
// Video rendering quality metrics
{
- const VideoRenderQualityMetrics& m = mVideoRenderQualityTracker.getMetrics();
+ const VideoRenderQualityMetrics &m = mVideoRenderQualityTracker.getMetrics();
if (m.frameRenderedCount > 0) {
+ mediametrics_setInt64(mMetricsHandle, kCodecFirstRenderTimeUs, m.firstRenderTimeUs);
mediametrics_setInt64(mMetricsHandle, kCodecFramesReleased, m.frameReleasedCount);
mediametrics_setInt64(mMetricsHandle, kCodecFramesRendered, m.frameRenderedCount);
mediametrics_setInt64(mMetricsHandle, kCodecFramesSkipped, m.frameSkippedCount);
@@ -1129,23 +1140,33 @@
mediametrics_setDouble(mMetricsHandle, kCodecFramerateActual, m.actualFrameRate);
}
if (m.freezeDurationMsHistogram.getCount() >= 1) {
- const MediaHistogram &histogram = m.freezeDurationMsHistogram;
- mediametrics_setInt64(mMetricsHandle, kCodecFreezeCount, histogram.getCount());
- mediametrics_setInt64(mMetricsHandle, kCodecFreezeDurationAverage, histogram.getAvg());
- mediametrics_setInt64(mMetricsHandle, kCodecFreezeDurationMax, histogram.getMax());
- mediametrics_setString(mMetricsHandle, kCodecFreezeDurationHistogram, histogram.emit());
+ const MediaHistogram<int32_t> &h = m.freezeDurationMsHistogram;
+ mediametrics_setInt64(mMetricsHandle, kCodecFreezeScore, m.freezeScore);
+ mediametrics_setDouble(mMetricsHandle, kCodecFreezeRate, m.freezeRate);
+ mediametrics_setInt64(mMetricsHandle, kCodecFreezeCount, h.getCount());
+ mediametrics_setInt32(mMetricsHandle, kCodecFreezeDurationMsAvg, h.getAvg());
+ mediametrics_setInt32(mMetricsHandle, kCodecFreezeDurationMsMax, h.getMax());
+ mediametrics_setString(mMetricsHandle, kCodecFreezeDurationMsHistogram, h.emit());
+ mediametrics_setString(mMetricsHandle, kCodecFreezeDurationMsHistogramBuckets,
+ h.emitBuckets());
}
if (m.freezeDistanceMsHistogram.getCount() >= 1) {
- const MediaHistogram &histogram = m.freezeDistanceMsHistogram;
- mediametrics_setInt64(mMetricsHandle, kCodecFreezeDistanceAverage, histogram.getAvg());
- mediametrics_setString(mMetricsHandle, kCodecFreezeDistanceHistogram, histogram.emit());
+ const MediaHistogram<int32_t> &h = m.freezeDistanceMsHistogram;
+ mediametrics_setInt32(mMetricsHandle, kCodecFreezeDistanceMsAvg, h.getAvg());
+ mediametrics_setString(mMetricsHandle, kCodecFreezeDistanceMsHistogram, h.emit());
+ mediametrics_setString(mMetricsHandle, kCodecFreezeDistanceMsHistogramBuckets,
+ h.emitBuckets());
}
if (m.judderScoreHistogram.getCount() >= 1) {
- const MediaHistogram &histogram = m.judderScoreHistogram;
- mediametrics_setInt64(mMetricsHandle, kCodecJudderCount, histogram.getCount());
- mediametrics_setInt64(mMetricsHandle, kCodecJudderScoreAverage, histogram.getAvg());
- mediametrics_setInt64(mMetricsHandle, kCodecJudderScoreMax, histogram.getMax());
- mediametrics_setString(mMetricsHandle, kCodecJudderScoreHistogram, histogram.emit());
+ const MediaHistogram<int32_t> &h = m.judderScoreHistogram;
+ mediametrics_setInt64(mMetricsHandle, kCodecJudderScore, m.judderScore);
+ mediametrics_setDouble(mMetricsHandle, kCodecJudderRate, m.judderRate);
+ mediametrics_setInt64(mMetricsHandle, kCodecJudderCount, h.getCount());
+ mediametrics_setInt32(mMetricsHandle, kCodecJudderScoreAvg, h.getAvg());
+ mediametrics_setInt32(mMetricsHandle, kCodecJudderScoreMax, h.getMax());
+ mediametrics_setString(mMetricsHandle, kCodecJudderScoreHistogram, h.emit());
+ mediametrics_setString(mMetricsHandle, kCodecJudderScoreHistogramBuckets,
+ h.emitBuckets());
}
}
@@ -1227,14 +1248,14 @@
&& ColorUtils::isHDRStaticInfoValid(&info)) {
mHdrInfoFlags |= kFlagHasHdrStaticInfo;
}
- mediametrics_setInt32(mMetricsHandle, kCodecHDRStaticInfo,
+ mediametrics_setInt32(mMetricsHandle, kCodecHdrStaticInfo,
(mHdrInfoFlags & kFlagHasHdrStaticInfo) ? 1 : 0);
sp<ABuffer> hdr10PlusInfo;
if (mOutputFormat->findBuffer("hdr10-plus-info", &hdr10PlusInfo)
&& hdr10PlusInfo != nullptr && hdr10PlusInfo->size() > 0) {
mHdrInfoFlags |= kFlagHasHdr10PlusInfo;
}
- mediametrics_setInt32(mMetricsHandle, kCodecHDR10PlusInfo,
+ mediametrics_setInt32(mMetricsHandle, kCodecHdr10PlusInfo,
(mHdrInfoFlags & kFlagHasHdr10PlusInfo) ? 1 : 0);
// hdr format
@@ -1247,7 +1268,7 @@
&& codedFormat->findInt32(KEY_PROFILE, &profile)
&& colorTransfer != -1) {
hdr_format hdrFormat = getHdrFormat(mime, profile, colorTransfer);
- mediametrics_setInt32(mMetricsHandle, kCodecHDRFormat, static_cast<int>(hdrFormat));
+ mediametrics_setInt32(mMetricsHandle, kCodecHdrFormat, static_cast<int>(hdrFormat));
}
}
@@ -1355,9 +1376,8 @@
return;
}
- MediaHistogram recentHist;
-
// build an empty histogram
+ MediaHistogram<int64_t> recentHist;
recentHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
// stuff it with the samples in the ring buffer
@@ -3593,8 +3613,7 @@
setState(UNINITIALIZED);
} else {
- setState(
- (mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
+ setState((mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
}
break;
}
@@ -3719,6 +3738,9 @@
mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
}
+ mediametrics_setInt32(mMetricsHandle, kCodecHardware,
+ MediaCodecList::isSoftwareCodec(mComponentName) ? 0 : 1);
+
mResourceManagerProxy->addResource(MediaResource::CodecResource(
mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
@@ -4133,6 +4155,7 @@
if (mIsSurfaceToDisplay) {
mVideoRenderQualityTracker.resetForDiscontinuity();
}
+
// Notify the RM that the codec has been stopped.
ClientConfigParcel clientConfig;
initClientConfigParcel(clientConfig);
@@ -4443,6 +4466,7 @@
} else {
mTunneled = false;
}
+ mediametrics_setInt32(mMetricsHandle, kCodecTunneled, mTunneled ? 1 : 0);
int32_t background = 0;
if (format->findInt32("android._background-mode", &background) && background) {
diff --git a/media/libstagefright/MediaHistogram.cpp b/media/libstagefright/MediaHistogram.cpp
deleted file mode 100644
index 3dd67b8..0000000
--- a/media/libstagefright/MediaHistogram.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2023 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.
- */
-
-#define LOG_TAG "MediaHistogram"
-#include <utils/Log.h>
-
-#include <media/stagefright/MediaHistogram.h>
-
-#include <assert.h>
-#include <inttypes.h>
-#include <sstream>
-#include <stdio.h>
-
-namespace android {
-
-
-MediaHistogram::MediaHistogram() {
- mBuckets = nullptr;
- mBucketLimits = nullptr;
- mBucketCount = 0;
- mFloor = mCeiling = mWidth = 0;
- mBelow = 0;
- mAbove = 0;
- mSum = 0;
- mCount = 0;
- mMin = INT64_MAX;
- mMax = INT64_MIN;
-}
-
-void MediaHistogram::clear() {
- if (mBuckets != nullptr) {
- free(mBuckets);
- mBuckets = nullptr;
- }
- if (mBucketLimits != nullptr) {
- free(mBucketLimits);
- mBucketLimits = nullptr;
- }
- mBucketCount = 0;
-}
-
-bool MediaHistogram::setup(int bucketCount, int64_t width, int64_t floor)
-{
- if (bucketCount <= 0 || width <= 0) {
- return false;
- }
- if (!allocate(bucketCount, false)) {
- return false;
- }
- mWidth = width;
- mFloor = floor;
- mCeiling = floor + bucketCount * width;
- mMin = INT64_MAX;
- mMax = INT64_MIN;
- mSum = 0;
- mCount = 0;
- mBelow = mAbove = 0;
- return true;
-}
-
-bool MediaHistogram::setup(const std::vector<int64_t> &bucketLimits) {
- if (bucketLimits.size() <= 1) {
- return false;
- }
- int bucketCount = bucketLimits.size() - 1;
- if (!allocate(bucketCount, true)) {
- return false;
- }
-
- mWidth = -1;
- mFloor = bucketLimits[0];
- for (int i = 0; i < bucketCount; ++i) {
- mBucketLimits[i] = bucketLimits[i + 1];
- }
- mCeiling = bucketLimits[bucketCount];
- mMin = INT64_MAX;
- mMax = INT64_MIN;
- mSum = 0;
- mCount = 0;
- mBelow = mAbove = 0;
- return true;
-}
-
-bool MediaHistogram::allocate(int bucketCount, bool withBucketLimits) {
- assert(bucketCount > 0);
- if (bucketCount != mBucketCount) {
- clear();
- mBuckets = (int64_t *) calloc(bucketCount, sizeof(*mBuckets));
- if (mBuckets == nullptr) {
- return false;
- }
- }
- if (withBucketLimits && mBucketLimits == nullptr) {
- mBucketLimits = (int64_t *) calloc(bucketCount, sizeof(*mBucketLimits));
- if (mBucketLimits == nullptr) {
- clear();
- return false;
- }
- }
- mBucketCount = bucketCount;
- memset(mBuckets, 0, sizeof(*mBuckets) * mBucketCount);
- return true;
-}
-
-void MediaHistogram::insert(int64_t sample)
-{
- // histogram is not set up
- if (mBuckets == nullptr) {
- return;
- }
-
- mCount++;
- mSum += sample;
- if (mMin > sample) mMin = sample;
- if (mMax < sample) mMax = sample;
-
- if (sample < mFloor) {
- mBelow++;
- } else if (sample >= mCeiling) {
- mAbove++;
- } else if (mBucketLimits == nullptr) {
- int64_t slot = (sample - mFloor) / mWidth;
- assert(slot < mBucketCount);
- mBuckets[slot]++;
- } else {
- // A binary search might be more efficient for large number of buckets, but it is expected
- // that there will never be a large amount of buckets, so keep the code simple.
- for (int slot = 0; slot < mBucketCount; ++slot) {
- if (sample < mBucketLimits[slot]) {
- mBuckets[slot]++;
- break;
- }
- }
- }
- return;
-}
-
-std::string MediaHistogram::emit() const
-{
- // emits: floor,width,below{bucket0,bucket1,...., bucketN}above
- // or.. emits: below{bucket0,bucket1,...., bucketN}above
- // unconfigured will emit: 0,0,0{}0
- // XXX: is this best representation?
- std::stringstream ss;
- if (mBucketLimits == nullptr) {
- ss << mFloor << "," << mWidth << "," << mBelow << "{";
- } else {
- ss << mBelow << "{";
- }
- for (int i = 0; i < mBucketCount; i++) {
- if (i != 0) {
- ss << ",";
- }
- ss << mBuckets[i];
- }
- ss << "}" << mAbove;
- return ss.str();
-}
-
-} // android
diff --git a/media/libstagefright/VideoRenderQualityTracker.cpp b/media/libstagefright/VideoRenderQualityTracker.cpp
index f995e25..1072cdd 100644
--- a/media/libstagefright/VideoRenderQualityTracker.cpp
+++ b/media/libstagefright/VideoRenderQualityTracker.cpp
@@ -25,8 +25,16 @@
namespace android {
+static constexpr float FRAME_RATE_UNDETERMINED = VideoRenderQualityMetrics::FRAME_RATE_UNDETERMINED;
+static constexpr float FRAME_RATE_24_3_2_PULLDOWN =
+ VideoRenderQualityMetrics::FRAME_RATE_24_3_2_PULLDOWN;
+
VideoRenderQualityMetrics::VideoRenderQualityMetrics() {
- firstFrameRenderTimeUs = 0;
+ clear();
+}
+
+void VideoRenderQualityMetrics::clear() {
+ firstRenderTimeUs = 0;
frameReleasedCount = 0;
frameRenderedCount = 0;
frameDroppedCount = 0;
@@ -34,9 +42,14 @@
contentFrameRate = FRAME_RATE_UNDETERMINED;
desiredFrameRate = FRAME_RATE_UNDETERMINED;
actualFrameRate = FRAME_RATE_UNDETERMINED;
+ freezeDurationMsHistogram.clear();
+ freezeDistanceMsHistogram.clear();
+ judderScoreHistogram.clear();
}
VideoRenderQualityTracker::Configuration::Configuration() {
+ enabled = true;
+
// Assume that the app is skipping frames because it's detected that the frame couldn't be
// rendered in time.
areSkippedFramesDropped = true;
@@ -53,26 +66,32 @@
// Freeze configuration
freezeDurationMsHistogramBuckets = {1, 20, 40, 60, 80, 100, 120, 150, 175, 225, 300, 400, 500};
+ freezeDurationMsHistogramToScore = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
freezeDistanceMsHistogramBuckets = {0, 20, 100, 400, 1000, 2000, 3000, 4000, 8000, 15000, 30000,
60000};
// Judder configuration
judderErrorToleranceUs = 2000;
judderScoreHistogramBuckets = {1, 4, 5, 9, 11, 20, 30, 40, 50, 60, 70, 80};
+ judderScoreHistogramToScore = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
}
VideoRenderQualityTracker::VideoRenderQualityTracker() : mConfiguration(Configuration()) {
configureHistograms(mMetrics, mConfiguration);
- resetForDiscontinuity();
+ clear();
}
VideoRenderQualityTracker::VideoRenderQualityTracker(const Configuration &configuration) :
mConfiguration(configuration) {
configureHistograms(mMetrics, mConfiguration);
- resetForDiscontinuity();
+ clear();
}
void VideoRenderQualityTracker::onFrameSkipped(int64_t contentTimeUs) {
+ if (!mConfiguration.enabled) {
+ return;
+ }
+
// Frames skipped at the beginning shouldn't really be counted as skipped frames, since the
// app might be seeking to a starting point that isn't the first key frame.
if (mLastRenderTimeUs == -1) {
@@ -90,6 +109,10 @@
void VideoRenderQualityTracker::onFrameReleased(int64_t contentTimeUs,
int64_t desiredRenderTimeNs) {
+ if (!mConfiguration.enabled) {
+ return;
+ }
+
int64_t desiredRenderTimeUs = desiredRenderTimeNs / 1000;
resetIfDiscontinuity(contentTimeUs, desiredRenderTimeUs);
mMetrics.frameReleasedCount++;
@@ -98,8 +121,15 @@
}
void VideoRenderQualityTracker::onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs) {
+ if (!mConfiguration.enabled) {
+ return;
+ }
+
int64_t actualRenderTimeUs = actualRenderTimeNs / 1000;
+ if (mLastRenderTimeUs != -1) {
+ mRenderDurationMs += (actualRenderTimeUs - mLastRenderTimeUs) / 1000;
+ }
// Now that a frame has been rendered, the previously skipped frames can be processed as skipped
// frames since the app is not skipping them to terminate playback.
for (int64_t contentTimeUs : mPendingSkippedFrameContentTimeUsList) {
@@ -131,10 +161,47 @@
mLastRenderTimeUs = actualRenderTimeUs;
}
-const VideoRenderQualityMetrics &VideoRenderQualityTracker::getMetrics() const {
+const VideoRenderQualityMetrics &VideoRenderQualityTracker::getMetrics() {
+ if (!mConfiguration.enabled) {
+ return mMetrics;
+ }
+
+ mMetrics.freezeScore = 0;
+ if (mConfiguration.freezeDurationMsHistogramToScore.size() ==
+ mMetrics.freezeDurationMsHistogram.size()) {
+ for (int i = 0; i < mMetrics.freezeDurationMsHistogram.size(); ++i) {
+ int32_t count = 0;
+ for (int j = i; j < mMetrics.freezeDurationMsHistogram.size(); ++j) {
+ count += mMetrics.freezeDurationMsHistogram[j];
+ }
+ mMetrics.freezeScore += count / mConfiguration.freezeDurationMsHistogramToScore[i];
+ }
+ }
+ mMetrics.freezeRate = float(double(mMetrics.freezeDurationMsHistogram.getSum()) /
+ mRenderDurationMs);
+
+ mMetrics.judderScore = 0;
+ if (mConfiguration.judderScoreHistogramToScore.size() == mMetrics.judderScoreHistogram.size()) {
+ for (int i = 0; i < mMetrics.judderScoreHistogram.size(); ++i) {
+ int32_t count = 0;
+ for (int j = i; j < mMetrics.judderScoreHistogram.size(); ++j) {
+ count += mMetrics.judderScoreHistogram[j];
+ }
+ mMetrics.judderScore += count / mConfiguration.judderScoreHistogramToScore[i];
+ }
+ }
+ mMetrics.judderRate = float(double(mMetrics.judderScoreHistogram.getCount()) /
+ (mMetrics.frameReleasedCount + mMetrics.frameSkippedCount));
+
return mMetrics;
}
+void VideoRenderQualityTracker::clear() {
+ mRenderDurationMs = 0;
+ mMetrics.clear();
+ resetForDiscontinuity();
+}
+
void VideoRenderQualityTracker::resetForDiscontinuity() {
mLastContentTimeUs = -1;
mLastRenderTimeUs = -1;
@@ -220,11 +287,12 @@
int64_t desiredRenderTimeUs,
int64_t actualRenderTimeUs) {
// Capture the timestamp at which the first frame was rendered
- if (mMetrics.firstFrameRenderTimeUs == 0) {
- mMetrics.firstFrameRenderTimeUs = actualRenderTimeUs;
+ if (mMetrics.firstRenderTimeUs == 0) {
+ mMetrics.firstRenderTimeUs = actualRenderTimeUs;
}
mMetrics.frameRenderedCount++;
+
// The content time is -1 when it was rendered after a discontinuity (e.g. seek) was detected.
// So, even though a frame was rendered, it's impact on the user is insignificant, so don't do
// anything other than count it as a rendered frame.
@@ -352,7 +420,7 @@
// Only determine frame rate if the render durations are stable across 3 frames
if (abs(durationUs[0] - durationUs[1]) > c.frameRateDetectionToleranceUs ||
abs(durationUs[0] - durationUs[2]) > c.frameRateDetectionToleranceUs) {
- return is32pulldown(durationUs, c) ? FRAME_RATE_24HZ_3_2_PULLDOWN : FRAME_RATE_UNDETERMINED;
+ return is32pulldown(durationUs, c) ? FRAME_RATE_24_3_2_PULLDOWN : FRAME_RATE_UNDETERMINED;
}
return 1000.0 * 1000.0 / durationUs[0];
}
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index e534ad3..52d7d3d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -715,7 +715,7 @@
int mRecentHead;
Mutex mRecentLock;
- MediaHistogram mLatencyHist;
+ MediaHistogram<int64_t> mLatencyHist;
// An unique ID for the codec - Used by the metrics.
uint64_t mCodecId = 0;
diff --git a/media/libstagefright/include/media/stagefright/MediaHistogram.h b/media/libstagefright/include/media/stagefright/MediaHistogram.h
index 3c12901..da8415a 100644
--- a/media/libstagefright/include/media/stagefright/MediaHistogram.h
+++ b/media/libstagefright/include/media/stagefright/MediaHistogram.h
@@ -17,39 +17,197 @@
#ifndef MEDIA_HISTOGRAM_H_
#define MEDIA_HISTOGRAM_H_
+#include <limits>
+#include <sstream>
#include <string>
#include <vector>
namespace android {
+template<typename T>
class MediaHistogram {
- public:
+public:
MediaHistogram();
- ~MediaHistogram() { clear(); };
void clear();
- bool setup(int bucketCount, int64_t width, int64_t floor = 0);
- bool setup(const std::vector<int64_t> &bucketLimits);
- void insert(int64_t sample);
- int64_t getMin() const { return mMin; }
- int64_t getMax() const { return mMax; }
- int64_t getCount() const { return mCount; }
- int64_t getSum() const { return mSum; }
- int64_t getAvg() const { return mSum / (mCount == 0 ? 1 : mCount); }
+ bool setup(int bucketCount, T width, T floor = 0);
+ bool setup(const std::vector<T> &bucketLimits);
+ void insert(T sample);
+ size_t size();
+ int64_t operator[](int);
+ T getMin() const { return mMin; }
+ T getMax() const { return mMax; }
+ T getCount() const { return mCount; }
+ T getSum() const { return mSum; }
+ T getAvg() const { return mSum / (mCount == 0 ? 1 : mCount); }
+ T getPercentile(int) const;
std::string emit() const;
+ std::string emitBuckets() const;
private:
MediaHistogram(const MediaHistogram &); // disallow
bool allocate(int bucketCount, bool withBucketLimits);
- int64_t mFloor, mCeiling, mWidth;
- int64_t mBelow, mAbove;
- int64_t mMin, mMax, mSum, mCount;
-
- int mBucketCount;
- int64_t *mBuckets;
- int64_t *mBucketLimits;
+ T mFloor, mCeiling, mWidth;
+ T mMin, mMax, mSum;
+ int64_t mBelow, mAbove, mCount;
+ std::vector<T> mBuckets;
+ std::vector<T> mBucketLimits;
};
+template<typename T>
+MediaHistogram<T>::MediaHistogram() {
+ mWidth = mCeiling = mFloor = -1;
+ clear();
+}
+
+template<typename T>
+void MediaHistogram<T>::clear() {
+ for (int i = 0; i < mBuckets.size(); ++i) {
+ mBuckets[i] = 0;
+ }
+ mMin = std::numeric_limits<T>::max();
+ mMax = std::numeric_limits<T>::min();
+ mSum = 0;
+ mCount = 0;
+ mBelow = mAbove = 0;
+}
+
+template<typename T>
+bool MediaHistogram<T>::setup(int bucketCount, T width, T floor) {
+ if (bucketCount <= 0 || width <= 0) {
+ return false;
+ }
+ if (!allocate(bucketCount, false)) {
+ return false;
+ }
+ mWidth = width;
+ mFloor = floor;
+ mCeiling = floor + bucketCount * width;
+ clear();
+ return true;
+}
+
+template<typename T>
+bool MediaHistogram<T>::setup(const std::vector<T> &bucketLimits) {
+ if (bucketLimits.size() <= 1) {
+ return false;
+ }
+ int bucketCount = bucketLimits.size() - 1;
+ if (!allocate(bucketCount, true)) {
+ return false;
+ }
+
+ mWidth = -1;
+ mFloor = bucketLimits[0];
+ for (int i = 0; i < bucketCount; ++i) {
+ mBucketLimits[i] = bucketLimits[i + 1];
+ }
+ mCeiling = bucketLimits[bucketCount];
+ clear();
+ return true;
+}
+
+template<typename T>
+bool MediaHistogram<T>::allocate(int bucketCount, bool withBucketLimits) {
+ assert(bucketCount > 0);
+ if (bucketCount != mBuckets.size()) {
+ mBuckets = std::vector<T>(bucketCount, 0);
+ }
+ if (withBucketLimits && mBucketLimits.size() != bucketCount) {
+ mBucketLimits = std::vector<T>(bucketCount, 0);
+ }
+ return true;
+}
+
+template<typename T>
+void MediaHistogram<T>::insert(T sample) {
+ // histogram is not set up
+ if (mBuckets.size() == 0) {
+ return;
+ }
+
+ mCount++;
+ mSum += sample;
+ if (mMin > sample) mMin = sample;
+ if (mMax < sample) mMax = sample;
+
+ if (sample < mFloor) {
+ mBelow++;
+ } else if (sample >= mCeiling) {
+ mAbove++;
+ } else if (mWidth == -1) {
+ // A binary search might be more efficient for large number of buckets, but it is expected
+ // that there will never be a large amount of buckets, so keep the code simple.
+ for (int slot = 0; slot < mBucketLimits.size(); ++slot) {
+ if (sample < mBucketLimits[slot]) {
+ mBuckets[slot]++;
+ break;
+ }
+ }
+ } else {
+ int64_t slot = (sample - mFloor) / mWidth;
+ assert(slot < mBuckets.size());
+ mBuckets[slot]++;
+ }
+ return;
+}
+
+template<typename T>
+size_t MediaHistogram<T>::size() {
+ return mBuckets.size() + 1;
+}
+
+template<typename T>
+int64_t MediaHistogram<T>::operator[](int i) {
+ assert(i >= 0);
+ assert(i <= mBuckets.size());
+ if (i == mBuckets.size()) {
+ return mAbove;
+ }
+ return mBuckets[i];
+}
+
+template<typename T>
+std::string MediaHistogram<T>::emit() const {
+ // emits: floor,width,below{bucket0,bucket1,...., bucketN}above
+ // or.. emits: below{bucket0,bucket1,...., bucketN}above
+ // unconfigured will emit: 0{}0
+ // XXX: is this best representation?
+ std::stringstream ss("");
+ if (mWidth == -1) {
+ ss << mBelow << "{";
+ } else {
+ ss << mFloor << "," << mWidth << "," << mBelow << "{";
+ }
+ for (int i = 0; i < mBuckets.size(); i++) {
+ if (i != 0) {
+ ss << ",";
+ }
+ ss << mBuckets[i];
+ }
+ ss << "}" << mAbove;
+ return ss.str();
+}
+
+template<typename T>
+std::string MediaHistogram<T>::emitBuckets() const {
+ std::stringstream ss("");
+ if (mWidth == -1) {
+ ss << mFloor;
+ for (int i = 0; i < mBucketLimits.size(); ++i) {
+ ss << ',' << mBucketLimits[i];
+ }
+ ss << ',' << mCeiling;
+ } else {
+ ss << mFloor;
+ for (int i = 0; i < mBuckets.size(); ++i) {
+ ss << ',' << (mFloor + i * mWidth);
+ }
+ ss << ',' << mCeiling;
+ }
+ return ss.str();
+}
+
} // android
#endif // MEDIA_HISTOGRAM_H_
\ No newline at end of file
diff --git a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index 25ccfdb..ec25a36 100644
--- a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -26,15 +26,17 @@
namespace android {
-static const float FRAME_RATE_UNDETERMINED = -1.0f;
-static const float FRAME_RATE_24HZ_3_2_PULLDOWN = -2.0f;
-
// A variety of video rendering quality metrics.
struct VideoRenderQualityMetrics {
+ static constexpr float FRAME_RATE_UNDETERMINED = -1.0f;
+ static constexpr float FRAME_RATE_24_3_2_PULLDOWN = -2.0f;
+
VideoRenderQualityMetrics();
+ void clear();
+
// The render time of the first video frame.
- int64_t firstFrameRenderTimeUs;
+ int64_t firstRenderTimeUs;
// The number of frames released to be rendered.
int64_t frameReleasedCount;
@@ -59,13 +61,21 @@
float actualFrameRate;
// A histogram of the durations of freezes due to dropped/skipped frames.
- MediaHistogram freezeDurationMsHistogram;
+ MediaHistogram<int32_t> freezeDurationMsHistogram;
+ // The computed overall freeze score using the above histogram and score conversion table.
+ int32_t freezeScore;
+ // The computed percentage of total playback duration that was frozen.
+ float freezeRate;
// A histogram of the durations between each freeze.
- MediaHistogram freezeDistanceMsHistogram;
+ MediaHistogram<int32_t> freezeDistanceMsHistogram;
// A histogram of the judder scores.
- MediaHistogram judderScoreHistogram;
+ MediaHistogram<int32_t> judderScoreHistogram;
+ // The computed overall judder score using the above histogram and score conversion table.
+ int32_t judderScore;
+ // The computed percentage of total frames that had judder.
+ float judderRate;
};
///////////////////////////////////////////////////////
@@ -93,6 +103,9 @@
public:
Configuration();
+ // Whether or not frame render quality is tracked.
+ bool enabled;
+
// Whether or not frames that are intentionally not rendered by the app should be considered
// as dropped.
bool areSkippedFramesDropped;
@@ -114,11 +127,24 @@
int32_t contentTimeAdvancedForLiveContentToleranceUs;
// Freeze configuration
- std::vector<int64_t> freezeDurationMsHistogramBuckets;
- std::vector<int64_t> freezeDistanceMsHistogramBuckets;
+ //
+ // The values used to distribute freeze durations across a histogram.
+ std::vector<int32_t> freezeDurationMsHistogramBuckets;
+ // The values used to compare against freeze duration counts when determining an overall
+ // score.
+ std::vector<int64_t> freezeDurationMsHistogramToScore;
+ // The values used to distribute distances between freezes across a histogram.
+ std::vector<int32_t> freezeDistanceMsHistogramBuckets;
+ // Judder configuration
+ //
+ // A judder error lower than this value is not scored as judder.
int32_t judderErrorToleranceUs;
- std::vector<int64_t> judderScoreHistogramBuckets;
+ // The values used to distribute judder scores across a histogram.
+ std::vector<int32_t> judderScoreHistogramBuckets;
+ // The values used to compare against judder score histogram counts when determining an
+ // overall score.
+ std::vector<int32_t> judderScoreHistogramToScore;
};
VideoRenderQualityTracker();
@@ -138,11 +164,14 @@
void onFrameRendered(int64_t contentTimeUs, int64_t actualRenderTimeNs);
// Retrieve the metrics.
- const VideoRenderQualityMetrics &getMetrics() const;
+ const VideoRenderQualityMetrics &getMetrics();
// Called when a change in codec state will result in a content discontinuity - e.g. flush.
void resetForDiscontinuity();
+ // Clear out all metrics and tracking - e.g. codec reconfigured.
+ void clear();
+
private:
// Tracking of frames that are pending to be rendered to the display.
struct FrameInfo {
@@ -237,6 +266,9 @@
// The most recent timestamp of the first frame rendered after the freeze.
int64_t mLastFreezeEndTimeUs;
+ // The render duration of the playback.
+ int64_t mRenderDurationMs;
+
// Frames skipped at the end of playback shouldn't really be considered skipped, therefore keep
// a list of the frames, and process them as skipped frames the next time a frame is rendered.
std::list<int64_t> mPendingSkippedFrameContentTimeUsList;
diff --git a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
index efe1990..9f14663 100644
--- a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
+++ b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
@@ -27,6 +27,10 @@
using Metrics = VideoRenderQualityMetrics;
using Configuration = VideoRenderQualityTracker::Configuration;
+static constexpr float FRAME_RATE_UNDETERMINED = VideoRenderQualityMetrics::FRAME_RATE_UNDETERMINED;
+static constexpr float FRAME_RATE_24_3_2_PULLDOWN =
+ VideoRenderQualityMetrics::FRAME_RATE_24_3_2_PULLDOWN;
+
class Helper {
public:
Helper(double contentFrameDurationMs, const Configuration &configuration) :
@@ -76,7 +80,7 @@
}
}
- const Metrics & getMetrics() const {
+ const Metrics & getMetrics() {
return mVideoRenderQualityTracker.getMetrics();
}
@@ -194,7 +198,7 @@
Helper h(41.66, c);
h.render({49.9, 33.2, 50.0, 33.4, 50.1, 33.2});
EXPECT_NEAR(h.getMetrics().contentFrameRate, 24.0, 0.5);
- EXPECT_EQ(h.getMetrics().actualFrameRate, FRAME_RATE_24HZ_3_2_PULLDOWN);
+ EXPECT_EQ(h.getMetrics().actualFrameRate, FRAME_RATE_24_3_2_PULLDOWN);
}
TEST_F(VideoRenderQualityTrackerTest, whenBad32Pulldown_doesntDetect32Pulldown) {
@@ -216,7 +220,7 @@
h.changeContentFrameDuration(41.66);
h.render({50.0, 33.33, 50.0, 33.33, 50.0, 33.33});
EXPECT_NEAR(h.getMetrics().contentFrameRate, 24.0, 0.5);
- EXPECT_EQ(h.getMetrics().actualFrameRate, FRAME_RATE_24HZ_3_2_PULLDOWN);
+ EXPECT_EQ(h.getMetrics().actualFrameRate, FRAME_RATE_24_3_2_PULLDOWN);
}
TEST_F(VideoRenderQualityTrackerTest, whenFrameRateIsUnstable_doesntDetectFrameRate) {
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index 158914a..a0b8f16 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -40,6 +40,159 @@
namespace android {
+using stats::media_metrics::stats_write;
+using stats::media_metrics::MEDIA_CODEC_RENDERED;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_UNKNOWN;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_INVALID;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNKNOWN;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNDETERMINED;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_24_3_2_PULLDOWN;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_NONE;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HLG;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10_PLUS;
+using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_DOLBY_VISION;
+
+static const int BITRATE_UNKNOWN =
+ stats::media_metrics::MEDIA_CODEC_RENDERED__BITRATE__BITRATE_UNKNOWN;
+
+static const std::pair<char const *, int> CODEC_LOOKUP[] = {
+ { "avc", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AVC },
+ { "h264", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AVC },
+ { "hevc", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_HEVC },
+ { "h265", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_HEVC },
+ { "vp8", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_VP8 },
+ { "vp9", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_VP9 },
+ { "av1", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AV1 },
+ { "av01", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AV1 },
+ { "dolby-vision", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_HEVC },
+};
+
+static const int32_t RESOLUTION_LOOKUP[] = {
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_MAX_SIZE,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_32K,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_16K,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_8K_UHD,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_8K_UHD_ALMOST,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_4K_UHD_ALMOST,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1440X2560,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080X2400,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080X2340,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080P_FHD,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080P_FHD_ALMOST,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_720P_HD,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_720P_HD_ALMOST,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_576X1024,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_540X960,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_480X854,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_480X640,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_360X640,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_352X640,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_VERY_LOW,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_SMALLEST,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO,
+};
+
+static const int32_t FRAMERATE_LOOKUP[] = {
+ stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_24,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_25,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_30,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_50,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_60,
+ stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_120,
+};
+
+static int32_t getMetricsCodecEnum(const std::string &mime, const std::string &componentName) {
+ for (const auto & codecStrAndEnum : CODEC_LOOKUP) {
+ if (strcasestr(mime.c_str(), codecStrAndEnum.first) != nullptr ||
+ strcasestr(componentName.c_str(), codecStrAndEnum.first) != nullptr) {
+ return codecStrAndEnum.second;
+ }
+ }
+ return MEDIA_CODEC_RENDERED__CODEC__CODEC_UNKNOWN;
+}
+
+static int32_t getMetricsResolutionEnum(int32_t width, int32_t height) {
+ if (width == 0 || height == 0) {
+ return MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO;
+ }
+ int64_t pixels = int64_t(width) * height / 1000;
+ if (width < 0 || height < 0 || pixels > RESOLUTION_LOOKUP[0]) {
+ return MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_INVALID;
+ }
+ for (int32_t resolutionEnum : RESOLUTION_LOOKUP) {
+ if (pixels > resolutionEnum) {
+ return resolutionEnum;
+ }
+ }
+ return MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO;
+}
+
+static int32_t getMetricsFramerateEnum(float inFramerate) {
+ if (inFramerate == -1.0f) {
+ return MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNDETERMINED;
+ }
+ if (inFramerate == -2.0f) {
+ return MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_24_3_2_PULLDOWN;
+ }
+ int framerate = int(inFramerate * 100); // Table is in hundredths of frames per second
+ static const int framerateTolerance = 40; // Tolerance is 0.4 frames per second - table is 100s
+ for (int32_t framerateEnum : FRAMERATE_LOOKUP) {
+ if (abs(framerate - framerateEnum) < framerateTolerance) {
+ return framerateEnum;
+ }
+ }
+ return MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNKNOWN;
+}
+
+static int32_t getMetricsHdrFormatEnum(std::string &mime, std::string &componentName,
+ int32_t configColorTransfer, int32_t parsedColorTransfer,
+ int32_t hdr10StaticInfo, int32_t hdr10PlusInfo) {
+ if (hdr10PlusInfo) {
+ return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10_PLUS;
+ }
+ if (hdr10StaticInfo) {
+ return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10;
+ }
+ // 7 = COLOR_TRANSFER_HLG in MediaCodecConstants.h
+ if (configColorTransfer == 7 || parsedColorTransfer == 7) {
+ return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HLG;
+ }
+ if (strcasestr(mime.c_str(), "dolby-vision") != nullptr ||
+ strcasestr(componentName.c_str(), "dvhe") != nullptr ||
+ strcasestr(componentName.c_str(), "dvav") != nullptr ||
+ strcasestr(componentName.c_str(), "dav1") != nullptr) {
+ return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_DOLBY_VISION;
+ }
+ return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_NONE;
+}
+
+static void parseVector(const std::string &str, std::vector<int32_t> *vector) {
+ char valueStr[12] = {};
+ int i = 0;
+ for (char const * p = str.c_str(); *p != 0; ++p) {
+ if (*p == ',' || *p == '{' || *p == '}') {
+ valueStr[i] = 0;
+ int64_t value = strtol(valueStr, nullptr, 10);
+ if (value >= std::numeric_limits<int32_t>::max() ||
+ value <= std::numeric_limits<int32_t>::min() ||
+ value == 0) {
+ ALOGE("failed to parse integer vector at '%s' from '%s'", p, str.c_str());
+ return;
+ }
+ vector->push_back(int32_t(value));
+ i = valueStr[0] = 0;
+ } else {
+ valueStr[i++] = *p;
+ if (i == sizeof(valueStr) - 1) { // -1 because we need space for a null terminator
+ ALOGE("failed to parse integer vector at '%s' from '%s'", p, str.c_str());
+ return;
+ }
+ }
+ }
+}
+
bool statsd_codec(const std::shared_ptr<const mediametrics::Item>& item,
const std::shared_ptr<mediametrics::StatsdLog>& statsdLog)
{
@@ -48,17 +201,17 @@
AStatsEvent* event = AStatsEvent_obtain();
AStatsEvent_setAtomId(event, stats::media_metrics::MEDIA_CODEC_REPORTED);
- const nsecs_t timestamp_nanos = MediaMetricsService::roundTime(item->getTimestamp());
- AStatsEvent_writeInt64(event, timestamp_nanos);
+ const nsecs_t timestampNanos = MediaMetricsService::roundTime(item->getTimestamp());
+ AStatsEvent_writeInt64(event, timestampNanos);
- std::string package_name = item->getPkgName();
- AStatsEvent_writeString(event, package_name.c_str());
+ std::string packageName = item->getPkgName();
+ AStatsEvent_writeString(event, packageName.c_str());
- int64_t package_version_code = item->getPkgVersionCode();
- AStatsEvent_writeInt64(event, package_version_code);
+ int64_t packageVersionCode = item->getPkgVersionCode();
+ AStatsEvent_writeInt64(event, packageVersionCode);
- int64_t media_apex_version = 0;
- AStatsEvent_writeInt64(event, media_apex_version);
+ int64_t mediaApexVersion = 0;
+ AStatsEvent_writeInt64(event, mediaApexVersion);
// the rest into our own proto
//
@@ -84,17 +237,25 @@
}
AStatsEvent_writeString(event, mode.c_str());
- int32_t encoder = -1;
- if (item->getInt32("android.media.mediacodec.encoder", &encoder)) {
- metrics_proto.set_encoder(encoder);
+ int32_t isEncoder = -1;
+ if (item->getInt32("android.media.mediacodec.encoder", &isEncoder)) {
+ metrics_proto.set_encoder(isEncoder);
}
- AStatsEvent_writeInt32(event, encoder);
+ AStatsEvent_writeInt32(event, isEncoder);
- int32_t secure = -1;
- if (item->getInt32("android.media.mediacodec.secure", &secure)) {
- metrics_proto.set_secure(secure);
+ int32_t isSecure = -1;
+ if (item->getInt32("android.media.mediacodec.secure", &isSecure)) {
+ metrics_proto.set_secure(isSecure);
}
- AStatsEvent_writeInt32(event, secure);
+ AStatsEvent_writeInt32(event, isSecure);
+
+ int32_t isHardware = -1;
+ item->getInt32("android.media.mediacodec.hardware", &isHardware);
+ // not logged to MediaCodecReported or MediametricsCodecReported
+
+ int32_t isTunneled = -1;
+ item->getInt32("android.media.mediacodec.tunneled", &isTunneled);
+ // not logged to MediaCodecReported or MediametricsCodecReported
int32_t width = -1;
if (item->getInt32("android.media.mediacodec.width", &width)) {
@@ -133,79 +294,78 @@
AStatsEvent_writeInt32(event, level);
- int32_t max_width = -1;
- if ( item->getInt32("android.media.mediacodec.maxwidth", &max_width)) {
- metrics_proto.set_max_width(max_width);
+ int32_t maxWidth = -1;
+ if ( item->getInt32("android.media.mediacodec.maxwidth", &maxWidth)) {
+ metrics_proto.set_max_width(maxWidth);
}
- AStatsEvent_writeInt32(event, max_width);
+ AStatsEvent_writeInt32(event, maxWidth);
- int32_t max_height = -1;
- if ( item->getInt32("android.media.mediacodec.maxheight", &max_height)) {
- metrics_proto.set_max_height(max_height);
+ int32_t maxHeight = -1;
+ if ( item->getInt32("android.media.mediacodec.maxheight", &maxHeight)) {
+ metrics_proto.set_max_height(maxHeight);
}
- AStatsEvent_writeInt32(event, max_height);
+ AStatsEvent_writeInt32(event, maxHeight);
- int32_t error_code = -1;
- if ( item->getInt32("android.media.mediacodec.errcode", &error_code)) {
- metrics_proto.set_error_code(error_code);
+ int32_t errorCode = -1;
+ if ( item->getInt32("android.media.mediacodec.errcode", &errorCode)) {
+ metrics_proto.set_error_code(errorCode);
}
- AStatsEvent_writeInt32(event, error_code);
+ AStatsEvent_writeInt32(event, errorCode);
- std::string error_state;
- if ( item->getString("android.media.mediacodec.errstate", &error_state)) {
- metrics_proto.set_error_state(error_state);
+ std::string errorState;
+ if ( item->getString("android.media.mediacodec.errstate", &errorState)) {
+ metrics_proto.set_error_state(errorState);
}
- AStatsEvent_writeString(event, error_state.c_str());
+ AStatsEvent_writeString(event, errorState.c_str());
- int64_t latency_max = -1;
- if (item->getInt64("android.media.mediacodec.latency.max", &latency_max)) {
- metrics_proto.set_latency_max(latency_max);
+ int64_t latencyMax = -1;
+ if (item->getInt64("android.media.mediacodec.latency.max", &latencyMax)) {
+ metrics_proto.set_latency_max(latencyMax);
}
- AStatsEvent_writeInt64(event, latency_max);
+ AStatsEvent_writeInt64(event, latencyMax);
- int64_t latency_min = -1;
- if (item->getInt64("android.media.mediacodec.latency.min", &latency_min)) {
- metrics_proto.set_latency_min(latency_min);
+ int64_t latencyMin = -1;
+ if (item->getInt64("android.media.mediacodec.latency.min", &latencyMin)) {
+ metrics_proto.set_latency_min(latencyMin);
}
- AStatsEvent_writeInt64(event, latency_min);
+ AStatsEvent_writeInt64(event, latencyMin);
- int64_t latency_avg = -1;
- if (item->getInt64("android.media.mediacodec.latency.avg", &latency_avg)) {
- metrics_proto.set_latency_avg(latency_avg);
+ int64_t latencyAvg = -1;
+ if (item->getInt64("android.media.mediacodec.latency.avg", &latencyAvg)) {
+ metrics_proto.set_latency_avg(latencyAvg);
}
- AStatsEvent_writeInt64(event, latency_avg);
+ AStatsEvent_writeInt64(event, latencyAvg);
- int64_t latency_count = -1;
- if (item->getInt64("android.media.mediacodec.latency.n", &latency_count)) {
- metrics_proto.set_latency_count(latency_count);
+ int64_t latencyCount = -1;
+ if (item->getInt64("android.media.mediacodec.latency.n", &latencyCount)) {
+ metrics_proto.set_latency_count(latencyCount);
}
- AStatsEvent_writeInt64(event, latency_count);
+ AStatsEvent_writeInt64(event, latencyCount);
- int64_t latency_unknown = -1;
- if (item->getInt64("android.media.mediacodec.latency.unknown", &latency_unknown)) {
- metrics_proto.set_latency_unknown(latency_unknown);
+ int64_t latencyUnknown = -1;
+ if (item->getInt64("android.media.mediacodec.latency.unknown", &latencyUnknown)) {
+ metrics_proto.set_latency_unknown(latencyUnknown);
}
- AStatsEvent_writeInt64(event, latency_unknown);
+ AStatsEvent_writeInt64(event, latencyUnknown);
- int32_t queue_secure_input_buffer_error = -1;
+ int32_t queueSecureInputBufferError = -1;
if (item->getInt32("android.media.mediacodec.queueSecureInputBufferError",
- &queue_secure_input_buffer_error)) {
- metrics_proto.set_queue_secure_input_buffer_error(queue_secure_input_buffer_error);
+ &queueSecureInputBufferError)) {
+ metrics_proto.set_queue_secure_input_buffer_error(queueSecureInputBufferError);
}
- AStatsEvent_writeInt32(event, queue_secure_input_buffer_error);
+ AStatsEvent_writeInt32(event, queueSecureInputBufferError);
- int32_t queue_input_buffer_error = -1;
- if (item->getInt32("android.media.mediacodec.queueInputBufferError",
- &queue_input_buffer_error)) {
- metrics_proto.set_queue_input_buffer_error(queue_input_buffer_error);
+ int32_t queueInputBufferError = -1;
+ if (item->getInt32("android.media.mediacodec.queueInputBufferError", &queueInputBufferError)) {
+ metrics_proto.set_queue_input_buffer_error(queueInputBufferError);
}
- AStatsEvent_writeInt32(event, queue_input_buffer_error);
+ AStatsEvent_writeInt32(event, queueInputBufferError);
- std::string bitrate_mode;
- if (item->getString("android.media.mediacodec.bitrate_mode", &bitrate_mode)) {
- metrics_proto.set_bitrate_mode(bitrate_mode);
+ std::string bitrateMode;
+ if (item->getString("android.media.mediacodec.bitrate_mode", &bitrateMode)) {
+ metrics_proto.set_bitrate_mode(bitrateMode);
}
- AStatsEvent_writeString(event, bitrate_mode.c_str());
+ AStatsEvent_writeString(event, bitrateMode.c_str());
int32_t bitrate = -1;
if (item->getInt32("android.media.mediacodec.bitrate", &bitrate)) {
@@ -213,18 +373,18 @@
}
AStatsEvent_writeInt32(event, bitrate);
- int64_t lifetime_millis = -1;
- if (item->getInt64("android.media.mediacodec.lifetimeMs", &lifetime_millis)) {
- lifetime_millis = mediametrics::bucket_time_minutes(lifetime_millis);
- metrics_proto.set_lifetime_millis(lifetime_millis);
+ int64_t lifetimeMillis = -1;
+ if (item->getInt64("android.media.mediacodec.lifetimeMs", &lifetimeMillis)) {
+ lifetimeMillis = mediametrics::bucket_time_minutes(lifetimeMillis);
+ metrics_proto.set_lifetime_millis(lifetimeMillis);
}
- AStatsEvent_writeInt64(event, lifetime_millis);
+ AStatsEvent_writeInt64(event, lifetimeMillis);
- int64_t playback_duration_sec = -1;
- item->getInt64("android.media.mediacodec.playback-duration-sec", &playback_duration_sec);
+ int64_t playbackDurationSec = -1;
+ item->getInt64("android.media.mediacodec.playback-duration-sec", &playbackDurationSec);
// DO NOT record playback-duration in the metrics_proto - it should only
// exist in the flattened atom
- AStatsEvent_writeInt64(event, playback_duration_sec);
+ AStatsEvent_writeInt64(event, playbackDurationSec);
std::string sessionId;
if (item->getString("android.media.mediacodec.log-session-id", &sessionId)) {
@@ -505,61 +665,182 @@
}
AStatsEvent_writeInt32(event, resolutionChangeCount);
+ int64_t firstRenderTimeUs = -1;
+ item->getInt64("android.media.mediacodec.first-render-time-us", &firstRenderTimeUs);
+ int64_t framesReleased = -1;
+ item->getInt64("android.media.mediacodec.frames-released", &framesReleased);
+ int64_t framesRendered = -1;
+ item->getInt64("android.media.mediacodec.frames-rendered", &framesRendered);
+ int64_t framesDropped = -1;
+ item->getInt64("android.media.mediacodec.frames-dropped", &framesDropped);
+ int64_t framesSkipped = -1;
+ item->getInt64("android.media.mediacodec.frames-skipped", &framesSkipped);
+ double framerateContent = -1;
+ item->getDouble("android.media.mediacodec.framerate-content", &framerateContent);
+ double framerateActual = -1;
+ item->getDouble("android.media.mediacodec.framerate-actual", &framerateActual);
+ int64_t freezeScore = -1;
+ item->getInt64("android.media.mediacodec.freeze-score", &freezeScore);
+ double freezeRate = -1;
+ item->getDouble("android.media.mediacodec.freeze-rate", &freezeRate);
+ std::string freezeScoreHistogramStr;
+ item->getString("android.media.mediacodec.freeze-score-histogram", &freezeScoreHistogramStr);
+ std::string freezeScoreHistogramBucketsStr;
+ item->getString("android.media.mediacodec.freeze-score-histogram-buckets",
+ &freezeScoreHistogramBucketsStr);
+ std::string freezeDurationMsHistogramStr;
+ item->getString("android.media.mediacodec.freeze-duration-ms-histogram",
+ &freezeDurationMsHistogramStr);
+ std::string freezeDurationMsHistogramBucketsStr;
+ item->getString("android.media.mediacodec.freeze-duration-ms-histogram-buckets",
+ &freezeDurationMsHistogramBucketsStr);
+ std::string freezeDistanceMsHistogramStr;
+ item->getString("android.media.mediacodec.freeze-distance-ms-histogram",
+ &freezeDistanceMsHistogramStr);
+ std::string freezeDistanceMsHistogramBucketsStr;
+ item->getString("android.media.mediacodec.freeze-distance-ms-histogram-buckets",
+ &freezeDistanceMsHistogramBucketsStr);
+ int64_t judderScore = -1;
+ item->getInt64("android.media.mediacodec.judder-score", &judderScore);
+ double judderRate = -1;
+ item->getDouble("android.media.mediacodec.judder-rate", &judderRate);
+ std::string judderScoreHistogramStr;
+ item->getString("android.media.mediacodec.judder-score-histogram", &judderScoreHistogramStr);
+ std::string judderScoreHistogramBucketsStr;
+ item->getString("android.media.mediacodec.judder-score-histogram-buckets",
+ &judderScoreHistogramBucketsStr);
+
int err = AStatsEvent_write(event);
if (err < 0) {
ALOGE("Failed to write codec metrics to statsd (%d)", err);
}
AStatsEvent_release(event);
+ if (framesRendered > 0) {
+ int32_t statsUid = item->getUid();
+ int64_t statsCodecId = codecId;
+ char const *statsLogSessionId = sessionId.c_str();
+ int32_t statsIsHardware = isHardware;
+ int32_t statsIsSecure = isSecure;
+ int32_t statsIsTunneled = isTunneled;
+ int32_t statsCodec = getMetricsCodecEnum(mime, codec);
+ int32_t statsResolution = getMetricsResolutionEnum(width, height);
+ int32_t statsBitrate = BITRATE_UNKNOWN;
+ int32_t statsContentFramerate = getMetricsFramerateEnum(framerateContent);
+ int32_t statsActualFramerate = getMetricsFramerateEnum(framerateActual);
+ int32_t statsHdrFormat = getMetricsHdrFormatEnum(mime, codec, configColorTransfer,
+ parsedColorTransfer, hdrStaticInfo,
+ hdr10PlusInfo);
+ int64_t statsFirstRenderTimeUs = firstRenderTimeUs;
+ int64_t statsPlaybackDurationSeconds = playbackDurationSec;
+ int64_t statsFramesTotal = framesReleased + framesSkipped;
+ int64_t statsFramesReleased = framesReleased;
+ int64_t statsFramesRendered = framesRendered;
+ int64_t statsFramesDropped = framesDropped;
+ int64_t statsFramesSkipped = framesSkipped;
+ float statsFrameDropRate = float(double(framesDropped) / statsFramesTotal);
+ float statsFrameSkipRate = float(double(framesSkipped) / statsFramesTotal);
+ float statsFrameSkipDropRate = float(double(framesSkipped + framesDropped) /
+ statsFramesTotal);
+ int64_t statsFreezeScore = freezeScore;
+ float statsFreezeRate = freezeRate;
+ std::vector<int32_t> statsFreezeDurationMsHistogram;
+ parseVector(freezeDurationMsHistogramStr, &statsFreezeDurationMsHistogram);
+ std::vector<int32_t> statsFreezeDurationMsHistogramBuckets;
+ parseVector(freezeDurationMsHistogramBucketsStr, &statsFreezeDurationMsHistogramBuckets);
+ std::vector<int32_t> statsFreezeDistanceMsHistogram;
+ parseVector(freezeDistanceMsHistogramStr, &statsFreezeDistanceMsHistogram);
+ std::vector<int32_t> statsFreezeDistanceMsHistogramBuckets;
+ parseVector(freezeDistanceMsHistogramBucketsStr, &statsFreezeDistanceMsHistogramBuckets);
+ int64_t statsJudderScore = judderScore;
+ float statsJudderRate = judderRate;
+ std::vector<int32_t> statsJudderScoreHistogram;
+ parseVector(judderScoreHistogramStr, &statsJudderScoreHistogram);
+ std::vector<int32_t> statsJudderScoreHistogramBuckets;
+ parseVector(judderScoreHistogramBucketsStr, &statsJudderScoreHistogramBuckets);
+ int result = stats_write(
+ MEDIA_CODEC_RENDERED,
+ statsUid,
+ statsCodecId,
+ statsLogSessionId,
+ statsIsHardware,
+ statsIsSecure,
+ statsIsTunneled,
+ statsCodec,
+ statsResolution,
+ statsBitrate,
+ statsContentFramerate,
+ statsActualFramerate,
+ statsHdrFormat,
+ statsFirstRenderTimeUs,
+ statsPlaybackDurationSeconds,
+ statsFramesTotal,
+ statsFramesReleased,
+ statsFramesRendered,
+ statsFramesDropped,
+ statsFramesSkipped,
+ statsFrameDropRate,
+ statsFrameSkipRate,
+ statsFrameSkipDropRate,
+ statsFreezeScore,
+ statsFreezeRate,
+ statsFreezeDurationMsHistogram,
+ statsFreezeDurationMsHistogramBuckets,
+ statsFreezeDistanceMsHistogram,
+ statsFreezeDistanceMsHistogramBuckets,
+ statsJudderScore,
+ statsJudderRate,
+ statsJudderScoreHistogram,
+ statsJudderScoreHistogramBuckets);
+ ALOGE_IF(result < 0, "Failed to record MEDIA_CODEC_RENDERED atom (%d)", result);
+ }
+
std::string serialized;
if (!metrics_proto.SerializeToString(&serialized)) {
ALOGE("Failed to serialize codec metrics");
return false;
}
- const stats::media_metrics::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ const stats::media_metrics::BytesField bf_serialized(serialized.c_str(), serialized.size());
const int result = stats::media_metrics::stats_write(stats::media_metrics::MEDIAMETRICS_CODEC_REPORTED,
- timestamp_nanos, package_name.c_str(), package_version_code,
- media_apex_version,
+ timestampNanos, packageName.c_str(), packageVersionCode,
+ mediaApexVersion,
bf_serialized);
std::stringstream log;
log << "result:" << result << " {"
<< " mediametrics_codec_reported:"
<< stats::media_metrics::MEDIAMETRICS_CODEC_REPORTED
- << " timestamp_nanos:" << timestamp_nanos
- << " package_name:" << package_name
- << " package_version_code:" << package_version_code
- << " media_apex_version:" << media_apex_version
-
+ << " timestamp_nanos:" << timestampNanos
+ << " package_name:" << packageName
+ << " package_version_code:" << packageVersionCode
+ << " media_apex_version:" << mediaApexVersion
<< " codec:" << codec
<< " mime:" << mime
<< " mode:" << mode
- << " encoder:" << encoder
- << " secure:" << secure
+ << " encoder:" << isEncoder
+ << " secure:" << isSecure
<< " width:" << width
<< " height:" << height
<< " rotation:" << rotation
<< " crypto:" << crypto
<< " profile:" << profile
-
<< " level:" << level
- << " max_width:" << max_width
- << " max_height:" << max_height
- << " error_code:" << error_code
- << " error_state:" << error_state
- << " latency_max:" << latency_max
- << " latency_min:" << latency_min
- << " latency_avg:" << latency_avg
- << " latency_count:" << latency_count
- << " latency_unknown:" << latency_unknown
-
- << " queue_input_buffer_error:" << queue_input_buffer_error
- << " queue_secure_input_buffer_error:" << queue_secure_input_buffer_error
- << " bitrate_mode:" << bitrate_mode
+ << " max_width:" << maxWidth
+ << " max_height:" << maxHeight
+ << " error_code:" << errorCode
+ << " error_state:" << errorState
+ << " latency_max:" << latencyMax
+ << " latency_min:" << latencyMin
+ << " latency_avg:" << latencyAvg
+ << " latency_count:" << latencyCount
+ << " latency_unknown:" << latencyUnknown
+ << " queue_input_buffer_error:" << queueInputBufferError
+ << " queue_secure_input_buffer_error:" << queueSecureInputBufferError
+ << " bitrate_mode:" << bitrateMode
<< " bitrate:" << bitrate
<< " original_bitrate:" << originalBitrate
- << " lifetime_millis:" << lifetime_millis
- << " playback_duration_seconds:" << playback_duration_sec
+ << " lifetime_millis:" << lifetimeMillis
+ << " playback_duration_seconds:" << playbackDurationSec
<< " log_session_id:" << sessionId
<< " channel_count:" << channelCount
<< " sample_rate:" << sampleRate
@@ -572,7 +853,6 @@
<< " operating_rate:" << operatingRate
<< " priority:" << priority
<< " shaping_enhanced:" << shapingEnhanced
-
<< " qp_i_min:" << qpIMin
<< " qp_i_max:" << qpIMax
<< " qp_p_min:" << qpPMin