Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ff07c77 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add atom reporting for MediaCodecRendered" into udc-dev am: 13e40cb2 am: c2dc3b47

parents e7e31837 c2dc3b47
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -255,7 +255,6 @@ cc_library {
        "MediaCodecSource.cpp",
        "MediaExtractor.cpp",
        "MediaExtractorFactory.cpp",
        "MediaHistogram.cpp",
        "MediaSource.cpp",
        "MediaSync.cpp",
        "MediaTrack.cpp",
+73 −49
Original line number Diff line number Diff line
@@ -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 *kCodecModeAudio = "audio";
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 *kCodecConfigColorTransfer = "android.media.mediacodec.config-
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 *kCodecRecentLatencyMin = "android.media.mediacodec.recent.min
static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg";      /* in us */
static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n";
static const char *kCodecRecentLatencyHist = "android.media.mediacodec.recent.hist";    /* in us */
static const char *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;

@@ -1120,6 +1130,7 @@ void MediaCodec::updateMediametrics() {
    {
        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 @@ void MediaCodec::updateMediametrics() {
            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 @@ void MediaCodec::updateHdrMetrics(bool isConfig) {
            && 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 @@ void MediaCodec::updateHdrMetrics(bool isConfig) {
            && 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 @@ void MediaCodec::updateEphemeralMediametrics(mediametrics_handle_t item) {
        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 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

                                setState(UNINITIALIZED);
                            } else {
                                setState(
                                        (mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
                                setState((mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
                            }
                            break;
                        }
@@ -3719,6 +3738,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        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 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    if (mIsSurfaceToDisplay) {
                        mVideoRenderQualityTracker.resetForDiscontinuity();
                    }

                    // Notify the RM that the codec has been stopped.
                    ClientConfigParcel clientConfig;
                    initClientConfigParcel(clientConfig);
@@ -4443,6 +4466,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            } else {
                mTunneled = false;
            }
            mediametrics_setInt32(mMetricsHandle, kCodecTunneled, mTunneled ? 1 : 0);

            int32_t background = 0;
            if (format->findInt32("android._background-mode", &background) && background) {
+0 −173
Original line number Diff line number Diff line
/*
 * 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
+75 −7
Original line number Diff line number Diff line
@@ -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 @@ VideoRenderQualityMetrics::VideoRenderQualityMetrics() {
    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 @@ VideoRenderQualityTracker::Configuration::Configuration() {

    // 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) {

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::onFrameReleased(int64_t contentTimeUs,
}

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 @@ void VideoRenderQualityTracker::onFrameRendered(int64_t contentTimeUs, int64_t a
    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 @@ void VideoRenderQualityTracker::processMetricsForRenderedFrame(int64_t contentTi
                                                               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 @@ float VideoRenderQualityTracker::detectFrameRate(const FrameDurationUs &duration
    // 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];
}
+1 −1
Original line number Diff line number Diff line
@@ -715,7 +715,7 @@ private:
    int mRecentHead;
    Mutex mRecentLock;

    MediaHistogram mLatencyHist;
    MediaHistogram<int64_t> mLatencyHist;

    // An unique ID for the codec - Used by the metrics.
    uint64_t mCodecId = 0;
Loading