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

Commit 2648a336 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Record MediaCodec video playback duration" into sc-dev am: bea13757 am: 339d950a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/av/+/14424498

Change-Id: I250a45f5a302a98add61ebe33865074fd1406f86
parents 8ed317f1 339d950a
Loading
Loading
Loading
Loading
+41 −0
Original line number Original line Diff line number Diff line
@@ -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>
@@ -152,6 +153,8 @@ static const char *kCodecRecentLatencyMin = "android.media.mediacodec.recent.min
static const char *kCodecRecentLatencyAvg = "android.media.mediacodec.recent.avg";      /* in us */
static const char *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 */
static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped";    /* 0/1 */


@@ -740,6 +743,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),
@@ -846,6 +851,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
@@ -985,6 +994,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) {
@@ -3199,6 +3230,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();
@@ -4905,6 +4937,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
@@ -4930,6 +4966,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
@@ -4947,6 +4987,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;
}
}
+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
+5 −0
Original line number Original line Diff line number Diff line
@@ -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 {
@@ -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;
@@ -485,6 +487,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,