Loading media/libstagefright/MediaCodec.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -6130,7 +6130,7 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) { ALOGI("rendring output error %d", err); } } else { if (mIsSurfaceToDisplay) { if (mIsSurfaceToDisplay && buffer->size() != 0) { int64_t mediaTimeUs = INT64_MIN; if (buffer->meta()->findInt64("timeUs", &mediaTimeUs)) { mVideoRenderQualityTracker.onFrameSkipped(mediaTimeUs); Loading media/libstagefright/VideoRenderQualityTracker.cpp +16 −7 Original line number Diff line number Diff line Loading @@ -228,6 +228,9 @@ void VideoRenderQualityTracker::onFrameSkipped(int64_t contentTimeUs) { if (mLastRenderTimeUs == -1) { return; } resetIfDiscontinuity(contentTimeUs, -1); // Frames skipped at the end of playback shouldn't be counted as skipped frames, since the // app could be terminating the playback. The pending count will be added to the metrics if and // when the next frame is rendered. Loading Loading @@ -374,6 +377,9 @@ void VideoRenderQualityTracker::resetForDiscontinuity() { mDesiredFrameDurationUs[i] = -1; mContentFrameDurationUs[i] = -1; } mActualFrameDurationUs.priorTimestampUs = -1; mDesiredFrameDurationUs.priorTimestampUs = -1; mContentFrameDurationUs.priorTimestampUs = -1; } bool VideoRenderQualityTracker::resetIfDiscontinuity(int64_t contentTimeUs, Loading @@ -397,11 +403,14 @@ bool VideoRenderQualityTracker::resetIfDiscontinuity(int64_t contentTimeUs, // occur if the time the user spends seeking is equal to the duration of the seek. This is // very unlikely to occur in practice but CAN occur - the user starts seeking forward, gets // distracted, and then returns to seeking forward. bool skippedForwardDueToLiveContentFrameDrops = false; if (desiredRenderTimeUs != -1) { int64_t contentFrameDurationUs = contentTimeUs - mLastContentTimeUs; int64_t desiredFrameDurationUs = desiredRenderTimeUs - mLastRenderTimeUs; bool skippedForwardDueToLiveContentFrameDrops = skippedForwardDueToLiveContentFrameDrops = abs(contentFrameDurationUs - desiredFrameDurationUs) < mConfiguration.liveContentFrameDropToleranceUs; } if (!skippedForwardDueToLiveContentFrameDrops) { ALOGI("Video playback jumped %d ms forward in content time (%d -> %d) ", int((contentTimeUs - mLastContentTimeUs) / 1000), int(mLastContentTimeUs / 1000), Loading Loading @@ -475,9 +484,9 @@ void VideoRenderQualityTracker::processMetricsForRenderedFrame(int64_t contentTi int64_t judderScore = computePreviousJudderScore(mActualFrameDurationUs, mContentFrameDurationUs, mConfiguration); if (judderScore != 0) { int64_t judderTimeUs = actualRenderTimeUs - mActualFrameDurationUs[0] - mActualFrameDurationUs[1]; if (judderScore != 0) { processJudder(judderScore, judderTimeUs, mLastJudderEndTimeUs, mActualFrameDurationUs, mContentFrameDurationUs, mJudderEvent, mMetrics, mConfiguration); mLastJudderEndTimeUs = judderTimeUs + mActualFrameDurationUs[1]; Loading media/libstagefright/tests/VideoRenderQualityTracker_test.cpp +74 −0 Original line number Diff line number Diff line Loading @@ -432,6 +432,80 @@ TEST_F(VideoRenderQualityTrackerTest, detectsFrameRate) { EXPECT_NEAR(h.getMetrics().actualFrameRate, 60.0, 0.5); } TEST_F(VideoRenderQualityTrackerTest, handlesSeeking) { Configuration c; c.maxExpectedContentFrameDurationUs = 30; VideoRenderQualityTracker v(c); v.onFrameReleased(0, 0); v.onFrameRendered(0, 0); v.onFrameReleased(20, 20); v.onFrameRendered(20, 20); v.onFrameReleased(40, 40); v.onFrameRendered(40, 40); v.onFrameReleased(60, 60); v.onFrameRendered(60, 60); v.onFrameReleased(80, 80); v.onFrameRendered(80, 80); v.onFrameReleased(7200000000, 100); v.onFrameRendered(7200000000, 100); v.onFrameReleased(7200000020, 120); v.onFrameRendered(7200000020, 120); v.onFrameReleased(7200000040, 140); v.onFrameRendered(7200000040, 140); v.onFrameReleased(7200000060, 160); v.onFrameRendered(7200000060, 160); v.onFrameReleased(7200000080, 180); v.onFrameRendered(7200000080, 180); v.onFrameReleased(0, 200); v.onFrameRendered(0, 200); v.onFrameReleased(20, 220); v.onFrameRendered(20, 220); v.onFrameReleased(40, 240); v.onFrameRendered(40, 240); v.onFrameReleased(60, 260); v.onFrameRendered(60, 260); const VideoRenderQualityMetrics &m = v.getMetrics(); EXPECT_EQ(m.judderRate, 0); // frame durations can get messed up during discontinuities so if // the discontinuity is not detected, judder is expected EXPECT_NE(m.contentFrameRate, FRAME_RATE_UNDETERMINED); } TEST_F(VideoRenderQualityTrackerTest, withSkipping_handlesSeeking) { Configuration c; c.maxExpectedContentFrameDurationUs = 30; VideoRenderQualityTracker v(c); v.onFrameReleased(0, 0); v.onFrameRendered(0, 0); v.onFrameReleased(20, 20); v.onFrameRendered(20, 20); v.onFrameReleased(40, 40); v.onFrameRendered(40, 40); v.onFrameReleased(60, 60); v.onFrameRendered(60, 60); v.onFrameReleased(80, 80); v.onFrameRendered(80, 80); v.onFrameSkipped(7200000000); v.onFrameSkipped(7200000020); v.onFrameReleased(7200000040, 100); v.onFrameRendered(7200000040, 100); v.onFrameReleased(7200000060, 120); v.onFrameRendered(7200000060, 120); v.onFrameReleased(7200000080, 140); v.onFrameSkipped(0); v.onFrameRendered(7200000080, 140); v.onFrameSkipped(20); v.onFrameReleased(40, 160); v.onFrameRendered(40, 160); v.onFrameReleased(60, 180); v.onFrameRendered(60, 180); v.onFrameReleased(80, 200); v.onFrameRendered(80, 200); const VideoRenderQualityMetrics &m = v.getMetrics(); EXPECT_EQ(m.judderRate, 0); // frame durations can get messed up during discontinuities so if // the discontinuity is not detected, judder is expected EXPECT_NE(m.contentFrameRate, FRAME_RATE_UNDETERMINED); } TEST_F(VideoRenderQualityTrackerTest, whenLowTolerance_doesntDetectFrameRate) { Configuration c; c.frameRateDetectionToleranceUs = 0; Loading Loading
media/libstagefright/MediaCodec.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -6130,7 +6130,7 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) { ALOGI("rendring output error %d", err); } } else { if (mIsSurfaceToDisplay) { if (mIsSurfaceToDisplay && buffer->size() != 0) { int64_t mediaTimeUs = INT64_MIN; if (buffer->meta()->findInt64("timeUs", &mediaTimeUs)) { mVideoRenderQualityTracker.onFrameSkipped(mediaTimeUs); Loading
media/libstagefright/VideoRenderQualityTracker.cpp +16 −7 Original line number Diff line number Diff line Loading @@ -228,6 +228,9 @@ void VideoRenderQualityTracker::onFrameSkipped(int64_t contentTimeUs) { if (mLastRenderTimeUs == -1) { return; } resetIfDiscontinuity(contentTimeUs, -1); // Frames skipped at the end of playback shouldn't be counted as skipped frames, since the // app could be terminating the playback. The pending count will be added to the metrics if and // when the next frame is rendered. Loading Loading @@ -374,6 +377,9 @@ void VideoRenderQualityTracker::resetForDiscontinuity() { mDesiredFrameDurationUs[i] = -1; mContentFrameDurationUs[i] = -1; } mActualFrameDurationUs.priorTimestampUs = -1; mDesiredFrameDurationUs.priorTimestampUs = -1; mContentFrameDurationUs.priorTimestampUs = -1; } bool VideoRenderQualityTracker::resetIfDiscontinuity(int64_t contentTimeUs, Loading @@ -397,11 +403,14 @@ bool VideoRenderQualityTracker::resetIfDiscontinuity(int64_t contentTimeUs, // occur if the time the user spends seeking is equal to the duration of the seek. This is // very unlikely to occur in practice but CAN occur - the user starts seeking forward, gets // distracted, and then returns to seeking forward. bool skippedForwardDueToLiveContentFrameDrops = false; if (desiredRenderTimeUs != -1) { int64_t contentFrameDurationUs = contentTimeUs - mLastContentTimeUs; int64_t desiredFrameDurationUs = desiredRenderTimeUs - mLastRenderTimeUs; bool skippedForwardDueToLiveContentFrameDrops = skippedForwardDueToLiveContentFrameDrops = abs(contentFrameDurationUs - desiredFrameDurationUs) < mConfiguration.liveContentFrameDropToleranceUs; } if (!skippedForwardDueToLiveContentFrameDrops) { ALOGI("Video playback jumped %d ms forward in content time (%d -> %d) ", int((contentTimeUs - mLastContentTimeUs) / 1000), int(mLastContentTimeUs / 1000), Loading Loading @@ -475,9 +484,9 @@ void VideoRenderQualityTracker::processMetricsForRenderedFrame(int64_t contentTi int64_t judderScore = computePreviousJudderScore(mActualFrameDurationUs, mContentFrameDurationUs, mConfiguration); if (judderScore != 0) { int64_t judderTimeUs = actualRenderTimeUs - mActualFrameDurationUs[0] - mActualFrameDurationUs[1]; if (judderScore != 0) { processJudder(judderScore, judderTimeUs, mLastJudderEndTimeUs, mActualFrameDurationUs, mContentFrameDurationUs, mJudderEvent, mMetrics, mConfiguration); mLastJudderEndTimeUs = judderTimeUs + mActualFrameDurationUs[1]; Loading
media/libstagefright/tests/VideoRenderQualityTracker_test.cpp +74 −0 Original line number Diff line number Diff line Loading @@ -432,6 +432,80 @@ TEST_F(VideoRenderQualityTrackerTest, detectsFrameRate) { EXPECT_NEAR(h.getMetrics().actualFrameRate, 60.0, 0.5); } TEST_F(VideoRenderQualityTrackerTest, handlesSeeking) { Configuration c; c.maxExpectedContentFrameDurationUs = 30; VideoRenderQualityTracker v(c); v.onFrameReleased(0, 0); v.onFrameRendered(0, 0); v.onFrameReleased(20, 20); v.onFrameRendered(20, 20); v.onFrameReleased(40, 40); v.onFrameRendered(40, 40); v.onFrameReleased(60, 60); v.onFrameRendered(60, 60); v.onFrameReleased(80, 80); v.onFrameRendered(80, 80); v.onFrameReleased(7200000000, 100); v.onFrameRendered(7200000000, 100); v.onFrameReleased(7200000020, 120); v.onFrameRendered(7200000020, 120); v.onFrameReleased(7200000040, 140); v.onFrameRendered(7200000040, 140); v.onFrameReleased(7200000060, 160); v.onFrameRendered(7200000060, 160); v.onFrameReleased(7200000080, 180); v.onFrameRendered(7200000080, 180); v.onFrameReleased(0, 200); v.onFrameRendered(0, 200); v.onFrameReleased(20, 220); v.onFrameRendered(20, 220); v.onFrameReleased(40, 240); v.onFrameRendered(40, 240); v.onFrameReleased(60, 260); v.onFrameRendered(60, 260); const VideoRenderQualityMetrics &m = v.getMetrics(); EXPECT_EQ(m.judderRate, 0); // frame durations can get messed up during discontinuities so if // the discontinuity is not detected, judder is expected EXPECT_NE(m.contentFrameRate, FRAME_RATE_UNDETERMINED); } TEST_F(VideoRenderQualityTrackerTest, withSkipping_handlesSeeking) { Configuration c; c.maxExpectedContentFrameDurationUs = 30; VideoRenderQualityTracker v(c); v.onFrameReleased(0, 0); v.onFrameRendered(0, 0); v.onFrameReleased(20, 20); v.onFrameRendered(20, 20); v.onFrameReleased(40, 40); v.onFrameRendered(40, 40); v.onFrameReleased(60, 60); v.onFrameRendered(60, 60); v.onFrameReleased(80, 80); v.onFrameRendered(80, 80); v.onFrameSkipped(7200000000); v.onFrameSkipped(7200000020); v.onFrameReleased(7200000040, 100); v.onFrameRendered(7200000040, 100); v.onFrameReleased(7200000060, 120); v.onFrameRendered(7200000060, 120); v.onFrameReleased(7200000080, 140); v.onFrameSkipped(0); v.onFrameRendered(7200000080, 140); v.onFrameSkipped(20); v.onFrameReleased(40, 160); v.onFrameRendered(40, 160); v.onFrameReleased(60, 180); v.onFrameRendered(60, 180); v.onFrameReleased(80, 200); v.onFrameRendered(80, 200); const VideoRenderQualityMetrics &m = v.getMetrics(); EXPECT_EQ(m.judderRate, 0); // frame durations can get messed up during discontinuities so if // the discontinuity is not detected, judder is expected EXPECT_NE(m.contentFrameRate, FRAME_RATE_UNDETERMINED); } TEST_F(VideoRenderQualityTrackerTest, whenLowTolerance_doesntDetectFrameRate) { Configuration c; c.frameRateDetectionToleranceUs = 0; Loading