Move Histogram out of MediaCodec so it can be used for render quality
metrics
Bug: 234833109
Test: m -j99
Change-Id: Ie3995fb91e0c3528d8692541fbb86805f017bebe
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index f1534c9..09d2802 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -255,6 +255,7 @@
"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 15817d2..435f547 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1322,7 +1322,7 @@
return;
}
- Histogram recentHist;
+ MediaHistogram recentHist;
// build an empty histogram
recentHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
@@ -1331,7 +1331,7 @@
{
Mutex::Autolock al(mRecentLock);
- for (int i=0; i<kRecentLatencyFrames; i++) {
+ for (int i = 0; i < kRecentLatencyFrames; i++) {
if (mRecentSamples[i] != kRecentSampleInvalid) {
recentHist.insert(mRecentSamples[i]);
}
@@ -1339,7 +1339,7 @@
}
// spit the data (if any) into the supplied analytics record
- if (recentHist.getCount()!= 0 ) {
+ if (recentHist.getCount() != 0 ) {
mediametrics_setInt64(item, kCodecRecentLatencyMax, recentHist.getMax());
mediametrics_setInt64(item, kCodecRecentLatencyMin, recentHist.getMin());
mediametrics_setInt64(item, kCodecRecentLatencyAvg, recentHist.getAvg());
@@ -1486,96 +1486,6 @@
}
}
-bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor)
-{
- if (nbuckets <= 0 || width <= 0) {
- return false;
- }
-
- // get histogram buckets
- if (nbuckets == mBucketCount && mBuckets != NULL) {
- // reuse our existing buffer
- memset(mBuckets, 0, sizeof(*mBuckets) * mBucketCount);
- } else {
- // get a new pre-zeroed buffer
- int64_t *newbuckets = (int64_t *)calloc(nbuckets, sizeof (*mBuckets));
- if (newbuckets == NULL) {
- goto bad;
- }
- if (mBuckets != NULL)
- free(mBuckets);
- mBuckets = newbuckets;
- }
-
- mWidth = width;
- mFloor = floor;
- mCeiling = floor + nbuckets * width;
- mBucketCount = nbuckets;
-
- mMin = INT64_MAX;
- mMax = INT64_MIN;
- mSum = 0;
- mCount = 0;
- mBelow = mAbove = 0;
-
- return true;
-
- bad:
- if (mBuckets != NULL) {
- free(mBuckets);
- mBuckets = NULL;
- }
-
- return false;
-}
-
-void MediaCodec::Histogram::insert(int64_t sample)
-{
- // histogram is not set up
- if (mBuckets == NULL) {
- return;
- }
-
- mCount++;
- mSum += sample;
- if (mMin > sample) mMin = sample;
- if (mMax < sample) mMax = sample;
-
- if (sample < mFloor) {
- mBelow++;
- } else if (sample >= mCeiling) {
- mAbove++;
- } else {
- int64_t slot = (sample - mFloor) / mWidth;
- CHECK(slot < mBucketCount);
- mBuckets[slot]++;
- }
- return;
-}
-
-std::string MediaCodec::Histogram::emit()
-{
- std::string value;
- char buffer[64];
-
- // emits: width,Below{bucket0,bucket1,...., bucketN}above
- // unconfigured will emit: 0,0{}0
- // XXX: is this best representation?
- snprintf(buffer, sizeof(buffer), "%" PRId64 ",%" PRId64 ",%" PRId64 "{",
- mFloor, mWidth, mBelow);
- value = buffer;
- for (int i = 0; i < mBucketCount; i++) {
- if (i != 0) {
- value = value + ",";
- }
- snprintf(buffer, sizeof(buffer), "%" PRId64, mBuckets[i]);
- value = value + buffer;
- }
- snprintf(buffer, sizeof(buffer), "}%" PRId64 , mAbove);
- value = value + buffer;
- return value;
-}
-
// when we send a buffer to the codec;
void MediaCodec::statsBufferSent(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer) {
diff --git a/media/libstagefright/MediaHistogram.cpp b/media/libstagefright/MediaHistogram.cpp
new file mode 100644
index 0000000..396d90e
--- /dev/null
+++ b/media/libstagefright/MediaHistogram.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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 <stdint.h>
+
+namespace android {
+
+bool MediaHistogram::setup(int bucketCount, int64_t width, int64_t floor)
+{
+ if (bucketCount <= 0 || width <= 0) {
+ return false;
+ }
+
+ // get histogram buckets
+ if (bucketCount == mBucketCount && mBuckets != NULL) {
+ // reuse our existing buffer
+ memset(mBuckets, 0, sizeof(*mBuckets) * mBucketCount);
+ } else {
+ // get a new pre-zeroed buffer
+ int64_t *newbuckets = (int64_t *)calloc(bucketCount, sizeof (*mBuckets));
+ if (newbuckets == NULL) {
+ goto bad;
+ }
+ if (mBuckets != NULL)
+ free(mBuckets);
+ mBuckets = newbuckets;
+ }
+
+ mWidth = width;
+ mFloor = floor;
+ mCeiling = floor + bucketCount * width;
+ mBucketCount = bucketCount;
+
+ mMin = INT64_MAX;
+ mMax = INT64_MIN;
+ mSum = 0;
+ mCount = 0;
+ mBelow = mAbove = 0;
+
+ return true;
+
+ bad:
+ if (mBuckets != NULL) {
+ free(mBuckets);
+ mBuckets = NULL;
+ }
+
+ return false;
+}
+
+void MediaHistogram::insert(int64_t sample)
+{
+ // histogram is not set up
+ if (mBuckets == NULL) {
+ return;
+ }
+
+ mCount++;
+ mSum += sample;
+ if (mMin > sample) mMin = sample;
+ if (mMax < sample) mMax = sample;
+
+ if (sample < mFloor) {
+ mBelow++;
+ } else if (sample >= mCeiling) {
+ mAbove++;
+ } else {
+ int64_t slot = (sample - mFloor) / mWidth;
+ assert(slot < mBucketCount);
+ mBuckets[slot]++;
+ }
+ return;
+}
+
+std::string MediaHistogram::emit()
+{
+ std::string value;
+ char buffer[64];
+
+ // emits: width,Below{bucket0,bucket1,...., bucketN}above
+ // unconfigured will emit: 0,0{}0
+ // XXX: is this best representation?
+ snprintf(buffer, sizeof(buffer), "%" PRId64 ",%" PRId64 ",%" PRId64 "{",
+ mFloor, mWidth, mBelow);
+ value = buffer;
+ for (int i = 0; i < mBucketCount; i++) {
+ if (i != 0) {
+ value = value + ",";
+ }
+ snprintf(buffer, sizeof(buffer), "%" PRId64, mBuckets[i]);
+ value = value + buffer;
+ }
+ snprintf(buffer, sizeof(buffer), "}%" PRId64 , mAbove);
+ value = value + buffer;
+ return value;
+}
+
+} // android
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 386b177..e534ad3 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -30,6 +30,7 @@
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/CodecErrorLog.h>
#include <media/stagefright/FrameRenderTracker.h>
+#include <media/stagefright/MediaHistogram.h>
#include <media/stagefright/PlaybackDurationAccumulator.h>
#include <media/stagefright/VideoRenderQualityTracker.h>
#include <utils/Vector.h>
@@ -714,31 +715,8 @@
int mRecentHead;
Mutex mRecentLock;
- class Histogram {
- public:
- Histogram() : mFloor(0), mWidth(0), mBelow(0), mAbove(0),
- mMin(INT64_MAX), mMax(INT64_MIN), mSum(0), mCount(0),
- mBucketCount(0), mBuckets(NULL) {};
- ~Histogram() { clear(); };
- void clear() { if (mBuckets != NULL) free(mBuckets); mBuckets = NULL; };
- bool setup(int nbuckets, int64_t width, int64_t floor = 0);
- 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); }
- std::string emit();
- private:
- int64_t mFloor, mCeiling, mWidth;
- int64_t mBelow, mAbove;
- int64_t mMin, mMax, mSum, mCount;
+ MediaHistogram mLatencyHist;
- int mBucketCount;
- int64_t *mBuckets;
- };
-
- Histogram 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
new file mode 100644
index 0000000..4883203
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaHistogram.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef MEDIA_HISTOGRAM_H_
+#define MEDIA_HISTOGRAM_H_
+
+#include <string>
+
+namespace android {
+
+class MediaHistogram {
+ public:
+ MediaHistogram() : mFloor(0), mWidth(0), mBelow(0), mAbove(0),
+ mMin(INT64_MAX), mMax(INT64_MIN), mSum(0), mCount(0),
+ mBucketCount(0), mBuckets(NULL) {};
+ ~MediaHistogram() { clear(); };
+ void clear() { if (mBuckets != NULL) free(mBuckets); mBuckets = NULL; };
+ bool setup(int bucketCount, int64_t width, int64_t floor = 0);
+ 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); }
+ std::string emit();
+private:
+ int64_t mFloor, mCeiling, mWidth;
+ int64_t mBelow, mAbove;
+ int64_t mMin, mMax, mSum, mCount;
+
+ int mBucketCount;
+ int64_t *mBuckets;
+};
+
+} // android
+
+#endif // MEDIA_HISTOGRAM_H_
\ No newline at end of file