Merge "Fix frame duration computations after discontinuities" into udc-dev
diff --git a/media/libstagefright/VideoRenderQualityTracker.cpp b/media/libstagefright/VideoRenderQualityTracker.cpp
index c9f461e..4f12a37 100644
--- a/media/libstagefright/VideoRenderQualityTracker.cpp
+++ b/media/libstagefright/VideoRenderQualityTracker.cpp
@@ -326,11 +326,8 @@
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.freezeScore += mMetrics.freezeDurationMsHistogram[i] *
+ mConfiguration.freezeDurationMsHistogramToScore[i];
}
}
mMetrics.freezeRate = float(double(mMetrics.freezeDurationMsHistogram.getSum()) /
@@ -339,11 +336,8 @@
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.judderScore += mMetrics.judderScoreHistogram[i] *
+ mConfiguration.judderScoreHistogramToScore[i];
}
}
mMetrics.judderRate = float(double(mMetrics.judderScoreHistogram.getCount()) /
diff --git a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index 2b3dbcb..82ba81c 100644
--- a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -62,7 +62,13 @@
// A histogram of the durations of freezes due to dropped/skipped frames.
MediaHistogram<int32_t> freezeDurationMsHistogram;
- // The computed overall freeze score using the above histogram and score conversion table.
+ // The computed overall freeze score using the above histogram and score conversion table. The
+ // score is based on counts in the histogram bucket, multiplied by the value in the score
+ // conversion table for that bucket. For example, the impact of a short freeze may be minimal,
+ // but the impact of long freeze may be disproportionally worse. Therefore, the score
+ // multipliers for each bucket might increase exponentially instead of linearly. A score
+ // multiplier of zero would reflect that small freeze durations have near-zero impact to the
+ // user experience.
int32_t freezeScore;
// The computed percentage of total playback duration that was frozen.
float freezeRate;
@@ -72,9 +78,16 @@
// A histogram of the durations between each freeze.
MediaHistogram<int32_t> freezeDistanceMsHistogram;
- // A histogram of the judder scores.
+ // A histogram of the judder scores - based on the error tolerance between actual render
+ // duration of each frame and the ideal render duration.
MediaHistogram<int32_t> judderScoreHistogram;
- // The computed overall judder score using the above histogram and score conversion table.
+ // The computed overall judder score using the above histogram and score conversion table. The
+ // score is based on counts in the histogram bucket, multiplied by the value in the score
+ // conversion table for that bucket. For example, the impact of minimal judder may be small,
+ // but the impact of large judder may be disproportionally worse. Therefore, the score
+ // multipliers for each bucket might increase exponentially instead of linearly. A score
+ // multiplier of zero would reflect that small judder errors have near-zero impact to the user
+ // experience.
int32_t judderScore;
// The computed percentage of total frames that had judder.
float judderRate;
@@ -143,15 +156,21 @@
//
// 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.
+ //
+ // The values used to multiply the counts in the histogram buckets above to compute an
+ // overall score. This allows the score to reflect disproportionate impact as freeze
+ // durations increase.
std::vector<int64_t> freezeDurationMsHistogramToScore;
+ //
// The values used to distribute distances between freezes across a histogram.
std::vector<int32_t> freezeDistanceMsHistogramBuckets;
+ //
// The maximum number of freeze events to send back to the caller.
int32_t freezeEventMax;
+ //
// The maximum number of detail entries tracked per freeze event.
int32_t freezeEventDetailsMax;
+ //
// The maximum distance in time between two freeze occurrences such that both will be
// lumped into the same freeze event.
int32_t freezeEventDistanceToleranceMs;
@@ -160,15 +179,21 @@
//
// A judder error lower than this value is not scored as judder.
int32_t judderErrorToleranceUs;
+ //
// 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.
+ //
+ // The values used to multiply the counts in the histogram buckets above to compute an
+ // overall score. This allows the score to reflect disproportionate impact as judder scores
+ // increase.
std::vector<int64_t> judderScoreHistogramToScore;
+ //
// The maximum number of judder events to send back to the caller.
int32_t judderEventMax;
+ //
// The maximum number of detail entries tracked per judder event.
int32_t judderEventDetailsMax;
+ //
// The maximum distance in time between two judder occurrences such that both will be
// lumped into the same judder event.
int32_t judderEventDistanceToleranceMs;
diff --git a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
index 1d4c581..7823922 100644
--- a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
+++ b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
@@ -986,4 +986,42 @@
EXPECT_EQ(h.getAndClearJudderEvent().valid, false); // max number of judder events exceeded
}
+TEST_F(VideoRenderQualityTrackerTest, capturesOverallFreezeScore) {
+ Configuration c;
+ // # drops * 20ms + 20ms because current frame is frozen + 1 for bucket threshold
+ c.freezeDurationMsHistogramBuckets = {1 * 20 + 21, 5 * 20 + 21, 10 * 20 + 21};
+ c.freezeDurationMsHistogramToScore = {10, 100, 1000};
+ Helper h(20, c);
+ h.render(5);
+ h.drop(2); // bucket = 0, bucket count = 1, bucket score = 10
+ h.render(5);
+ h.drop(11); // bucket = 2, bucket count = 1, bucket score = 1000
+ h.render(5);
+ h.drop(6); // bucket = 1, bucket count = 1, bucket score = 100
+ h.render(5);
+ h.drop(1); // bucket = null
+ h.render(5);
+ h.drop(3); // bucket = 0, bucket count = 2, bucket score = 20
+ h.render(5);
+ h.drop(10); // bucket = 1, bucket count = 2, bucket score = 200
+ h.render(5);
+ h.drop(7); // bucket = 1, bucket count = 3, bucket score = 300
+ h.render(5);
+ EXPECT_EQ(h.getMetrics().freezeScore, 20 + 300 + 1000);
+}
+
+TEST_F(VideoRenderQualityTrackerTest, capturesOverallJudderScore) {
+ Configuration c;
+ c.judderScoreHistogramBuckets = {0, 6, 10};
+ c.judderScoreHistogramToScore = {10, 100, 1000};
+ Helper h(20, c);
+ h.render({20, 20, 15, 20, 20}); // bucket = 0, bucket count = 1, bucket score = 10
+ h.render({20, 20, 11, 20, 20}); // bucket = 1, bucket count = 1, bucket score = 100
+ h.render({20, 20, 13, 20, 20}); // bucket = 1, bucket count = 2, bucket score = 200
+ h.render({20, 20, 5, 20, 20}); // bucket = 2, bucket count = 1, bucket score = 1000
+ h.render({20, 20, 14, 20, 20}); // bucket = 1, bucket count = 3, bucket score = 300
+ h.render({20, 20, 10, 20, 20}); // bucket = 2, bucket count = 2, bucket score = 2000
+ EXPECT_EQ(h.getMetrics().judderScore, 10 + 300 + 2000);
+}
+
} // android