Skip to content

Commit

Permalink
Fallback to legacy sizerate check for H264 if CDD PerfPoint check fails
Browse files Browse the repository at this point in the history
Some devices supporting Performance Points for decoder coverage are missing coverage over the CDD requirements for H264. For these cases ExoPlayer should fall back to legacy resolution and frame rate support checks. If there is an H264 stream evaluated as a `PerformancePointCoverageResult` of `COVERAGE_RESULT_NO`, then ExoPlayer checks for coverage of the [720p CDD requirement](https://source.android.com/docs/compatibility/10/android-10-cdd#5_3_4_h_264).

Issue: #10898

Issue: androidx/media#693
PiperOrigin-RevId: 575768836
  • Loading branch information
microkatz authored and Copybara-Service committed Oct 23, 2023
1 parent a41465b commit 9a3e1da
Showing 1 changed file with 45 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -528,14 +528,16 @@ public boolean isVideoSizeAndRateSupportedV21(int width, int height, double fram
if (Util.SDK_INT >= 29) {
@PerformancePointCoverageResult
int evaluation =
Api29.areResolutionAndFrameRateCovered(videoCapabilities, width, height, frameRate);
Api29.areResolutionAndFrameRateCovered(
videoCapabilities, mimeType, width, height, frameRate);
if (evaluation == COVERAGE_RESULT_YES) {
return true;
} else if (evaluation == COVERAGE_RESULT_NO) {
logNoSupport("sizeAndRate.cover, " + width + "x" + height + "@" + frameRate);
return false;
}
// COVERAGE_RESULT_NO_EMPTY_LIST falls through to API 21+ code below
// If COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED then logic falls through
// to API 21+ code below.
}

if (!areSizeAndRateSupportedV21(videoCapabilities, width, height, frameRate)) {
Expand Down Expand Up @@ -882,47 +884,44 @@ private static boolean needsProfileExcludedWorkaround(String mimeType, int profi
&& ("sailfish".equals(Util.DEVICE) || "marlin".equals(Util.DEVICE));
}

/** Whether the device is known to have wrong {@link PerformancePoint} declarations. */
private static boolean needsIgnorePerformancePointsWorkaround() {
// See https://github.com/google/ExoPlayer/issues/10898 and [internal ref: b/267324685].
return /* Chromecast with Google TV */ Util.DEVICE.equals("sabrina")
|| Util.DEVICE.equals("boreal")
/* Lenovo Tablet M10 FHD Plus */
|| Util.MODEL.startsWith("Lenovo TB-X605")
|| Util.MODEL.startsWith("Lenovo TB-X606")
|| Util.MODEL.startsWith("Lenovo TB-X616");
}

/** Possible outcomes of evaluating PerformancePoint coverage */
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({COVERAGE_RESULT_YES, COVERAGE_RESULT_NO, COVERAGE_RESULT_NO_EMPTY_LIST})
@IntDef({
COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED,
COVERAGE_RESULT_NO,
COVERAGE_RESULT_YES
})
private @interface PerformancePointCoverageResult {}

/** The decoder has a PerformancePoint that covers the resolution and frame rate */
private static final int COVERAGE_RESULT_YES = 2;
/**
* The VideoCapabilities does not contain any PerformancePoints or its PerformancePoints do not
* cover CDD requirements.
*/
private static final int COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED = 0;

/**
* The decoder has at least one PerformancePoint, but none of them cover the resolution and frame
* rate
* The decoder has at least one PerformancePoint, but none cover the resolution and frame rate.
*/
private static final int COVERAGE_RESULT_NO = 1;

/** The VideoCapabilities does not contain any PerformancePoints */
private static final int COVERAGE_RESULT_NO_EMPTY_LIST = 0;
/** The decoder has a PerformancePoint that covers the resolution and frame rate. */
private static final int COVERAGE_RESULT_YES = 2;

@RequiresApi(29)
private static final class Api29 {
@DoNotInline
public static @PerformancePointCoverageResult int areResolutionAndFrameRateCovered(
VideoCapabilities videoCapabilities, int width, int height, double frameRate) {
VideoCapabilities videoCapabilities,
String mimeType,
int width,
int height,
double frameRate) {
List<PerformancePoint> performancePointList =
videoCapabilities.getSupportedPerformancePoints();
if (performancePointList == null
|| performancePointList.isEmpty()
|| needsIgnorePerformancePointsWorkaround()) {
return COVERAGE_RESULT_NO_EMPTY_LIST;
if (performancePointList == null || performancePointList.isEmpty()) {
return COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED;
}

// Round frame rate down to to avoid situations where a range check in
Expand All @@ -931,6 +930,27 @@ private static final class Api29 {
PerformancePoint targetPerformancePoint =
new PerformancePoint(width, height, (int) frameRate);

@PerformancePointCoverageResult
int performancePointCoverageResult =
evaluatePerformancePointCoverage(performancePointList, targetPerformancePoint);

if (performancePointCoverageResult == COVERAGE_RESULT_NO
&& mimeType.equals(MimeTypes.VIDEO_H264)) {
if (evaluatePerformancePointCoverage(
performancePointList,
new PerformancePoint(/* width= */ 1280, /* height= */ 720, /* frameRate= */ 60))
!= COVERAGE_RESULT_YES) {
// See https://github.com/google/ExoPlayer/issues/10898,
// https://github.com/androidx/media/issues/693 and [internal ref: b/267324685].
return COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED;
}
}

return performancePointCoverageResult;
}

private static @PerformancePointCoverageResult int evaluatePerformancePointCoverage(
List<PerformancePoint> performancePointList, PerformancePoint targetPerformancePoint) {
for (int i = 0; i < performancePointList.size(); i++) {
if (performancePointList.get(i).covers(targetPerformancePoint)) {
return COVERAGE_RESULT_YES;
Expand Down

0 comments on commit 9a3e1da

Please sign in to comment.