Merge "Restrict unsigned integer overflow in MPEG4Writer writeEdtsBox" into main
diff --git a/media/libstagefright/VideoRenderQualityTracker.cpp b/media/libstagefright/VideoRenderQualityTracker.cpp
index 90d5405..3bd236a 100644
--- a/media/libstagefright/VideoRenderQualityTracker.cpp
+++ b/media/libstagefright/VideoRenderQualityTracker.cpp
@@ -126,6 +126,7 @@
contentFrameRate = FRAME_RATE_UNDETERMINED;
desiredFrameRate = FRAME_RATE_UNDETERMINED;
actualFrameRate = FRAME_RATE_UNDETERMINED;
+ maxContentDroppedAfterPauseMs = 0;
freezeEventCount = 0;
freezeDurationMsHistogram.clear();
freezeDistanceMsHistogram.clear();
@@ -144,6 +145,7 @@
getFlag(maxExpectedContentFrameDurationUs, "max_expected_content_frame_duration_us");
getFlag(frameRateDetectionToleranceUs, "frame_rate_detection_tolerance_us");
getFlag(liveContentFrameDropToleranceUs, "live_content_frame_drop_tolerance_us");
+ getFlag(pauseAudioLatencyUs, "pause_audio_latency_us");
getFlag(freezeDurationMsHistogramBuckets, "freeze_duration_ms_histogram_buckets");
getFlag(freezeDurationMsHistogramToScore, "freeze_duration_ms_histogram_to_score");
getFlag(freezeDistanceMsHistogramBuckets, "freeze_distance_ms_histogram_buckets");
@@ -181,6 +183,9 @@
// because of frame drops for live content, or because the user is seeking.
liveContentFrameDropToleranceUs = 200 * 1000;
+ // After a pause is initiated, audio should likely stop playback within 200ms.
+ pauseAudioLatencyUs = 200 * 1000;
+
// 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};
@@ -397,13 +402,13 @@
mLastRenderTimeUs = -1;
mLastFreezeEndTimeUs = -1;
mLastJudderEndTimeUs = -1;
- mWasPreviousFrameDropped = false;
+ mDroppedContentDurationUs = 0;
mFreezeEvent.valid = false;
mJudderEvent.valid = false;
- // Don't worry about tracking frame rendering times from now up until playback catches up to the
- // discontinuity. While stuttering or freezing could be found in the next few frames, the impact
- // to the user is is minimal, so better to just keep things simple and don't bother.
+ // Don't worry about tracking frame rendering times from now up until playback catches up to
+ // the discontinuity. While stuttering or freezing could be found in the next few frames, the
+ // impact to the user is is minimal, so better to just keep things simple and don't bother.
mNextExpectedRenderedFrameQueue = {};
mTunnelFrameQueuedContentTimeUs = -1;
@@ -472,7 +477,7 @@
updateFrameDurations(mDesiredFrameDurationUs, -1);
updateFrameDurations(mActualFrameDurationUs, -1);
updateFrameRate(mMetrics.contentFrameRate, mContentFrameDurationUs, mConfiguration);
- mWasPreviousFrameDropped = false;
+ mDroppedContentDurationUs = 0;
}
void VideoRenderQualityTracker::processMetricsForDroppedFrame(int64_t contentTimeUs,
@@ -483,7 +488,9 @@
updateFrameDurations(mActualFrameDurationUs, -1);
updateFrameRate(mMetrics.contentFrameRate, mContentFrameDurationUs, mConfiguration);
updateFrameRate(mMetrics.desiredFrameRate, mDesiredFrameDurationUs, mConfiguration);
- mWasPreviousFrameDropped = true;
+ if (mContentFrameDurationUs[0] != -1) {
+ mDroppedContentDurationUs += mContentFrameDurationUs[0];
+ }
}
void VideoRenderQualityTracker::processMetricsForRenderedFrame(int64_t contentTimeUs,
@@ -491,6 +498,8 @@
int64_t actualRenderTimeUs,
FreezeEvent *freezeEventOut,
JudderEvent *judderEventOut) {
+ const Configuration& c = mConfiguration;
+
// Capture the timestamp at which the first frame was rendered
if (mMetrics.firstRenderTimeUs == 0) {
mMetrics.firstRenderTimeUs = actualRenderTimeUs;
@@ -513,11 +522,36 @@
updateFrameRate(mMetrics.desiredFrameRate, mDesiredFrameDurationUs, mConfiguration);
updateFrameRate(mMetrics.actualFrameRate, mActualFrameDurationUs, mConfiguration);
- // If the previous frame was dropped, there was a freeze if we've already rendered a frame
- if (mWasPreviousFrameDropped && mLastRenderTimeUs != -1) {
- processFreeze(actualRenderTimeUs, mLastRenderTimeUs, mLastFreezeEndTimeUs, mFreezeEvent,
- mMetrics, mConfiguration);
- mLastFreezeEndTimeUs = actualRenderTimeUs;
+ // A freeze occurs if frames were dropped NOT after a discontinuity
+ if (mDroppedContentDurationUs != 0 && mLastRenderTimeUs != -1) {
+ // When pausing, audio playback may continue for a brief period of time after video
+ // pauses while the audio buffers drain. When resuming, a small number of video frames
+ // might be dropped to catch up to the audio position. This is acceptable behacvior and
+ // should not count as a freeze.
+ bool isLikelyCatchingUpAfterPause = false;
+ // A pause can be detected if a freeze occurs for a longer period of time than the
+ // content duration of the dropped frames. This strategy works because, for freeze
+ // events (no video pause), the content duration of the dropped frames will closely track
+ // the wall clock time (freeze duration). When pausing, however, the wall clock time
+ // (freeze duration) will be longer than the content duration of the dropped frames
+ // required to catch up to the audio position.
+ const int64_t wallClockDurationUs = actualRenderTimeUs - mLastRenderTimeUs;
+ // 200ms is chosen because it is larger than what a hiccup in the display pipeline could
+ // likely be, but shorter than the duration for which a user could pause for.
+ static const int32_t MAX_PIPELINE_HICCUP_DURATION_US = 200 * 1000;
+ if (wallClockDurationUs > mDroppedContentDurationUs + MAX_PIPELINE_HICCUP_DURATION_US) {
+ // Capture the amount of content that is dropped after pause, so we can push apps to be
+ // better about this behavior.
+ if (mDroppedContentDurationUs / 1000 > mMetrics.maxContentDroppedAfterPauseMs) {
+ mMetrics.maxContentDroppedAfterPauseMs = int32_t(mDroppedContentDurationUs / 1000);
+ }
+ isLikelyCatchingUpAfterPause = mDroppedContentDurationUs <= c.pauseAudioLatencyUs;
+ }
+ if (!isLikelyCatchingUpAfterPause) {
+ processFreeze(actualRenderTimeUs, mLastRenderTimeUs, mLastFreezeEndTimeUs, mFreezeEvent,
+ mMetrics, mConfiguration);
+ mLastFreezeEndTimeUs = actualRenderTimeUs;
+ }
}
maybeCaptureFreezeEvent(actualRenderTimeUs, mLastFreezeEndTimeUs, mFreezeEvent, mMetrics,
mConfiguration, freezeEventOut);
@@ -536,7 +570,7 @@
maybeCaptureJudderEvent(actualRenderTimeUs, mLastJudderEndTimeUs, mJudderEvent, mMetrics,
mConfiguration, judderEventOut);
- mWasPreviousFrameDropped = false;
+ mDroppedContentDurationUs = 0;
}
void VideoRenderQualityTracker::processFreeze(int64_t actualRenderTimeUs, int64_t lastRenderTimeUs,
diff --git a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index cf53f27..d58dfad 100644
--- a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -63,6 +63,11 @@
// post-render.
float actualFrameRate;
+ // The amount of content duration skipped by the app after a pause when video was trying to
+ // resume. This sometimes happen when catching up to the audio position which continued playing
+ // after video pauses.
+ int32_t maxContentDroppedAfterPauseMs;
+
// 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
@@ -155,6 +160,11 @@
// seeking forward.
int32_t liveContentFrameDropToleranceUs;
+ // The amount of time it takes for audio to stop playback after a pause is initiated. Used
+ // for providing some allowance of dropped video frames to catch back up to the audio
+ // position when resuming playback.
+ int32_t pauseAudioLatencyUs;
+
// Freeze configuration
//
// The values used to distribute freeze durations across a histogram.
@@ -441,8 +451,8 @@
// The render duration of the playback.
int64_t mRenderDurationMs;
- // True if the previous frame was dropped.
- bool mWasPreviousFrameDropped;
+ // The duration of the content that was dropped.
+ int64_t mDroppedContentDurationUs;
// The freeze event that's currently being tracked.
FreezeEvent mFreezeEvent;
diff --git a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
index 78140dd..9b6315c 100644
--- a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
+++ b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
@@ -140,6 +140,7 @@
EXPECT_EQ(c.maxExpectedContentFrameDurationUs, d.maxExpectedContentFrameDurationUs);
EXPECT_EQ(c.frameRateDetectionToleranceUs, d.frameRateDetectionToleranceUs);
EXPECT_EQ(c.liveContentFrameDropToleranceUs, d.liveContentFrameDropToleranceUs);
+ EXPECT_EQ(c.pauseAudioLatencyUs, d.pauseAudioLatencyUs);
EXPECT_EQ(c.freezeDurationMsHistogramBuckets, d.freezeDurationMsHistogramBuckets);
EXPECT_EQ(c.freezeDurationMsHistogramToScore, d.freezeDurationMsHistogramToScore);
EXPECT_EQ(c.freezeDistanceMsHistogramBuckets, d.freezeDistanceMsHistogramBuckets);
@@ -171,6 +172,7 @@
EXPECT_EQ(c.maxExpectedContentFrameDurationUs, d.maxExpectedContentFrameDurationUs);
EXPECT_EQ(c.frameRateDetectionToleranceUs, d.frameRateDetectionToleranceUs);
EXPECT_EQ(c.liveContentFrameDropToleranceUs, d.liveContentFrameDropToleranceUs);
+ EXPECT_EQ(c.pauseAudioLatencyUs, d.pauseAudioLatencyUs);
EXPECT_EQ(c.freezeDurationMsHistogramBuckets, d.freezeDurationMsHistogramBuckets);
EXPECT_EQ(c.freezeDurationMsHistogramToScore, d.freezeDurationMsHistogramToScore);
EXPECT_EQ(c.freezeDistanceMsHistogramBuckets, d.freezeDistanceMsHistogramBuckets);
@@ -202,6 +204,7 @@
EXPECT_EQ(c.maxExpectedContentFrameDurationUs, d.maxExpectedContentFrameDurationUs);
EXPECT_EQ(c.frameRateDetectionToleranceUs, d.frameRateDetectionToleranceUs);
EXPECT_EQ(c.liveContentFrameDropToleranceUs, d.liveContentFrameDropToleranceUs);
+ EXPECT_EQ(c.pauseAudioLatencyUs, d.pauseAudioLatencyUs);
EXPECT_EQ(c.freezeDurationMsHistogramBuckets, d.freezeDurationMsHistogramBuckets);
EXPECT_EQ(c.freezeDurationMsHistogramToScore, d.freezeDurationMsHistogramToScore);
EXPECT_EQ(c.freezeDistanceMsHistogramBuckets, d.freezeDistanceMsHistogramBuckets);
@@ -233,6 +236,8 @@
return "10b0";
} else if (flag == "render_metrics_live_content_frame_drop_tolerance_us") {
return "c100";
+ } else if (flag == "render_metrics_pause_audio_latency_us") {
+ return "1ab0";
} else if (flag == "render_metrics_freeze_duration_ms_histogram_buckets") {
return "1,5300,3b400,123";
} else if (flag == "render_metrics_freeze_duration_ms_histogram_to_score") {
@@ -276,6 +281,7 @@
EXPECT_EQ(c.maxExpectedContentFrameDurationUs, d.maxExpectedContentFrameDurationUs);
EXPECT_EQ(c.frameRateDetectionToleranceUs, d.frameRateDetectionToleranceUs);
EXPECT_EQ(c.liveContentFrameDropToleranceUs, d.liveContentFrameDropToleranceUs);
+ EXPECT_EQ(c.pauseAudioLatencyUs, d.pauseAudioLatencyUs);
EXPECT_EQ(c.freezeDurationMsHistogramBuckets, d.freezeDurationMsHistogramBuckets);
EXPECT_EQ(c.freezeDurationMsHistogramToScore, d.freezeDurationMsHistogramToScore);
EXPECT_EQ(c.freezeDistanceMsHistogramBuckets, d.freezeDistanceMsHistogramBuckets);
@@ -307,6 +313,8 @@
return "3000";
} else if (flag == "render_metrics_live_content_frame_drop_tolerance_us") {
return "4000";
+ } else if (flag == "render_metrics_pause_audio_latency_us") {
+ return "300000";
} else if (flag == "render_metrics_freeze_duration_ms_histogram_buckets") {
return "100,200,300,400";
} else if (flag == "render_metrics_freeze_duration_ms_histogram_to_score") {
@@ -359,6 +367,8 @@
EXPECT_NE(c.frameRateDetectionToleranceUs, d.frameRateDetectionToleranceUs);
EXPECT_EQ(c.liveContentFrameDropToleranceUs, 4000);
EXPECT_NE(c.liveContentFrameDropToleranceUs, d.liveContentFrameDropToleranceUs);
+ EXPECT_EQ(c.pauseAudioLatencyUs, 300000);
+ EXPECT_NE(c.pauseAudioLatencyUs, d.pauseAudioLatencyUs);
{
std::vector<int32_t> expected({100,200,300,400});
EXPECT_EQ(c.freezeDurationMsHistogramBuckets, expected);
@@ -1181,4 +1191,53 @@
EXPECT_EQ(h.getTraceTriggeredCount(), 0);
}
+
+TEST_F(VideoRenderQualityTrackerTest, doesNotCountCatchUpAfterPauseAsFreeze) {
+ Configuration c;
+ c.enabled = true;
+ c.pauseAudioLatencyUs = 200 * 1000; // allows for up to 10 frames to be dropped to catch up
+ // to the audio position
+ Helper h(20, c);
+ // A few frames followed by a long pause
+ h.render({20, 20, 1000});
+ h.drop(10); // simulate catching up to audio
+ h.render({20, 20, 1000});
+ h.drop(11); // simulate catching up to audio but then also dropping frames
+ h.render({20});
+
+ // Only 1 freeze is counted because the first freeze (200ms) because it's equal to or below the
+ // pause latency allowance, and the algorithm assumes a legitimate case of the video trying to
+ // catch up to the audio position, which continued to play for a short period of time (less than
+ // 200ms) after the pause was initiated
+ EXPECT_EQ(h.getMetrics().freezeDurationMsHistogram.getCount(), 1);
+}
+
+TEST_F(VideoRenderQualityTrackerTest, capturesMaximumContentDroppedAfterPause) {
+ Configuration c;
+ c.enabled = true;
+ c.pauseAudioLatencyUs = 200 * 1000; // allows for up to 10 frames to be dropped to catch up
+ // to the audio position
+ Helper h(20, c);
+
+ // Freezes are below the pause latency are captured
+ h.render({20, 20, 1000});
+ h.drop(6);
+ h.render({20, 20, 1000});
+ h.drop(8);
+ h.render({20, 20, 1000});
+ h.drop(7);
+ h.render({20});
+ EXPECT_EQ(h.getMetrics().maxContentDroppedAfterPauseMs, 8 * 20);
+
+ // Freezes are above the pause latency are also captured
+ h.render({20, 20, 1000});
+ h.drop(10);
+ h.render({20, 20, 1000});
+ h.drop(12);
+ h.render({20, 20, 1000});
+ h.drop(11);
+ h.render({20});
+ EXPECT_EQ(h.getMetrics().maxContentDroppedAfterPauseMs, 12 * 20);
+}
+
} // android
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index 921ad7d..efc58b4 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -60,15 +60,21 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
"android-camera-fwk-eng@google.com",
],
- componentid: 155276,
+ componentid: 41727,
libfuzzer_options: [
//based on b/187360866
"timeout=770",
],
-
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libcameraservice",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/services/camera/virtualcamera/OWNERS b/services/camera/virtualcamera/OWNERS
new file mode 100644
index 0000000..db34336
--- /dev/null
+++ b/services/camera/virtualcamera/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 1171888
+include platform/frameworks/base:/services/companion/java/com/android/server/companion/virtual/OWNERS
+caen@google.com
+jsebechlebsky@google.com