Fallback to legacy sizerate check for H264 if CDD PerfPoint check fails
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: google/ExoPlayer#10898 Issue: androidx/media#693 PiperOrigin-RevId: 575768836
This commit is contained in:
parent
a79d44edc5
commit
4515a0c3f2
@ -26,6 +26,10 @@
|
|||||||
`IllegalArgumentException`
|
`IllegalArgumentException`
|
||||||
([#677](https://github.com/androidx/media/issues/677)).
|
([#677](https://github.com/androidx/media/issues/677)).
|
||||||
* Video:
|
* Video:
|
||||||
|
* Add workaround for a device issue on Galaxy Tab S7 FE, Chromecast with
|
||||||
|
Google TV, and Lenovo M10 FHD Plus that causes 60fps AVC streams to be
|
||||||
|
marked as unsupported
|
||||||
|
([#693](https://github.com/androidx/media/issues/693)).
|
||||||
* Text:
|
* Text:
|
||||||
* Remove `ExoplayerCuesDecoder`. Text tracks with `sampleMimeType =
|
* Remove `ExoplayerCuesDecoder`. Text tracks with `sampleMimeType =
|
||||||
application/x-media3-cues` are now directly handled by `TextRenderer`
|
application/x-media3-cues` are now directly handled by `TextRenderer`
|
||||||
|
@ -522,14 +522,16 @@ public final class MediaCodecInfo {
|
|||||||
if (Util.SDK_INT >= 29) {
|
if (Util.SDK_INT >= 29) {
|
||||||
@PerformancePointCoverageResult
|
@PerformancePointCoverageResult
|
||||||
int evaluation =
|
int evaluation =
|
||||||
Api29.areResolutionAndFrameRateCovered(videoCapabilities, width, height, frameRate);
|
Api29.areResolutionAndFrameRateCovered(
|
||||||
|
videoCapabilities, mimeType, width, height, frameRate);
|
||||||
if (evaluation == COVERAGE_RESULT_YES) {
|
if (evaluation == COVERAGE_RESULT_YES) {
|
||||||
return true;
|
return true;
|
||||||
} else if (evaluation == COVERAGE_RESULT_NO) {
|
} else if (evaluation == COVERAGE_RESULT_NO) {
|
||||||
logNoSupport("sizeAndRate.cover, " + width + "x" + height + "@" + frameRate);
|
logNoSupport("sizeAndRate.cover, " + width + "x" + height + "@" + frameRate);
|
||||||
return false;
|
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)) {
|
if (!areSizeAndRateSupportedV21(videoCapabilities, width, height, frameRate)) {
|
||||||
@ -876,47 +878,44 @@ public final class MediaCodecInfo {
|
|||||||
&& ("sailfish".equals(Util.DEVICE) || "marlin".equals(Util.DEVICE));
|
&& ("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 */
|
/** Possible outcomes of evaluating PerformancePoint coverage */
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@Target(TYPE_USE)
|
@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 {}
|
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
|
* The decoder has at least one PerformancePoint, but none cover the resolution and frame rate.
|
||||||
* rate
|
|
||||||
*/
|
*/
|
||||||
private static final int COVERAGE_RESULT_NO = 1;
|
private static final int COVERAGE_RESULT_NO = 1;
|
||||||
|
|
||||||
/** The VideoCapabilities does not contain any PerformancePoints */
|
/** The decoder has a PerformancePoint that covers the resolution and frame rate. */
|
||||||
private static final int COVERAGE_RESULT_NO_EMPTY_LIST = 0;
|
private static final int COVERAGE_RESULT_YES = 2;
|
||||||
|
|
||||||
@RequiresApi(29)
|
@RequiresApi(29)
|
||||||
private static final class Api29 {
|
private static final class Api29 {
|
||||||
@DoNotInline
|
@DoNotInline
|
||||||
public static @PerformancePointCoverageResult int areResolutionAndFrameRateCovered(
|
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 =
|
List<PerformancePoint> performancePointList =
|
||||||
videoCapabilities.getSupportedPerformancePoints();
|
videoCapabilities.getSupportedPerformancePoints();
|
||||||
if (performancePointList == null
|
if (performancePointList == null || performancePointList.isEmpty()) {
|
||||||
|| performancePointList.isEmpty()
|
return COVERAGE_RESULT_NO_PERFORMANCE_POINTS_UNSUPPORTED;
|
||||||
|| needsIgnorePerformancePointsWorkaround()) {
|
|
||||||
return COVERAGE_RESULT_NO_EMPTY_LIST;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round frame rate down to to avoid situations where a range check in
|
// Round frame rate down to to avoid situations where a range check in
|
||||||
@ -925,6 +924,27 @@ public final class MediaCodecInfo {
|
|||||||
PerformancePoint targetPerformancePoint =
|
PerformancePoint targetPerformancePoint =
|
||||||
new PerformancePoint(width, height, (int) frameRate);
|
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++) {
|
for (int i = 0; i < performancePointList.size(); i++) {
|
||||||
if (performancePointList.get(i).covers(targetPerformancePoint)) {
|
if (performancePointList.get(i).covers(targetPerformancePoint)) {
|
||||||
return COVERAGE_RESULT_YES;
|
return COVERAGE_RESULT_YES;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user