28
28
import static com .google .android .exoplayer2 .decoder .DecoderReuseEvaluation .REUSE_RESULT_YES_WITHOUT_RECONFIGURATION ;
29
29
import static com .google .android .exoplayer2 .decoder .DecoderReuseEvaluation .REUSE_RESULT_YES_WITH_FLUSH ;
30
30
import static com .google .android .exoplayer2 .decoder .DecoderReuseEvaluation .REUSE_RESULT_YES_WITH_RECONFIGURATION ;
31
+ import static java .lang .annotation .ElementType .TYPE_USE ;
31
32
32
33
import android .graphics .Point ;
33
34
import android .media .MediaCodec ;
34
35
import android .media .MediaCodecInfo .AudioCapabilities ;
35
36
import android .media .MediaCodecInfo .CodecCapabilities ;
36
37
import android .media .MediaCodecInfo .CodecProfileLevel ;
37
38
import android .media .MediaCodecInfo .VideoCapabilities ;
39
+ import android .media .MediaCodecInfo .VideoCapabilities .PerformancePoint ;
38
40
import android .util .Pair ;
41
+ import androidx .annotation .DoNotInline ;
42
+ import androidx .annotation .IntDef ;
39
43
import androidx .annotation .Nullable ;
40
44
import androidx .annotation .RequiresApi ;
41
45
import androidx .annotation .VisibleForTesting ;
47
51
import com .google .android .exoplayer2 .util .Log ;
48
52
import com .google .android .exoplayer2 .util .MimeTypes ;
49
53
import com .google .android .exoplayer2 .util .Util ;
54
+ import java .lang .annotation .Documented ;
55
+ import java .lang .annotation .Retention ;
56
+ import java .lang .annotation .RetentionPolicy ;
57
+ import java .lang .annotation .Target ;
58
+ import java .util .List ;
50
59
51
60
/** Information about a {@link MediaCodec} for a given mime type. */
52
61
@ SuppressWarnings ("InlinedApi" )
@@ -480,8 +489,6 @@ public DecoderReuseEvaluation canReuseCodec(Format oldFormat, Format newFormat)
480
489
/**
481
490
* Whether the decoder supports video with a given width, height and frame rate.
482
491
*
483
- * Must not be called if the device SDK version is less than 21.
484
- *
485
492
* @param width Width in pixels.
486
493
* @param height Height in pixels.
487
494
* @param frameRate Optional frame rate in frames per second. Ignored if set to {@link
@@ -499,14 +506,28 @@ public boolean isVideoSizeAndRateSupportedV21(int width, int height, double fram
499
506
logNoSupport ("sizeAndRate.vCaps" );
500
507
return false ;
501
508
}
509
+
510
+ if (Util .SDK_INT >= 29 ) {
511
+ @ PerformancePointCoverageResult
512
+ int evaluation =
513
+ Api29 .areResolutionAndFrameRateCovered (videoCapabilities , width , height , frameRate );
514
+ if (evaluation == COVERAGE_RESULT_YES ) {
515
+ return true ;
516
+ } else if (evaluation == COVERAGE_RESULT_NO ) {
517
+ logNoSupport ("sizeAndRate.cover, " + width + "x" + height + "@" + frameRate );
518
+ return false ;
519
+ }
520
+ // COVERAGE_RESULT_NO_EMPTY_LIST falls through to API 21+ code below
521
+ }
522
+
502
523
if (!areSizeAndRateSupportedV21 (videoCapabilities , width , height , frameRate )) {
503
524
if (width >= height
504
525
|| !needsRotatedVerticalResolutionWorkaround (name )
505
526
|| !areSizeAndRateSupportedV21 (videoCapabilities , height , width , frameRate )) {
506
- logNoSupport ("sizeAndRate.support, " + width + "x" + height + "x " + frameRate );
527
+ logNoSupport ("sizeAndRate.support, " + width + "x" + height + "@ " + frameRate );
507
528
return false ;
508
529
}
509
- logAssumedSupport ("sizeAndRate.rotated, " + width + "x" + height + "x " + frameRate );
530
+ logAssumedSupport ("sizeAndRate.rotated, " + width + "x" + height + "@ " + frameRate );
510
531
}
511
532
return true ;
512
533
}
@@ -842,4 +863,47 @@ private static boolean needsProfileExcludedWorkaround(String mimeType, int profi
842
863
&& CodecProfileLevel .HEVCProfileMain10 == profile
843
864
&& ("sailfish" .equals (Util .DEVICE ) || "marlin" .equals (Util .DEVICE ));
844
865
}
866
+
867
+ /** Possible outcomes of evaluating PerformancePoint coverage */
868
+ @ Documented
869
+ @ Retention (RetentionPolicy .SOURCE )
870
+ @ Target (TYPE_USE )
871
+ @ IntDef ({COVERAGE_RESULT_YES , COVERAGE_RESULT_NO , COVERAGE_RESULT_NO_EMPTY_LIST })
872
+ private @interface PerformancePointCoverageResult {}
873
+
874
+ /** The decoder has a PerformancePoint that covers the resolution and frame rate */
875
+ private static final int COVERAGE_RESULT_YES = 2 ;
876
+ /**
877
+ * The decoder has at least one PerformancePoint, but none of them cover the resolution and frame
878
+ * rate
879
+ */
880
+ private static final int COVERAGE_RESULT_NO = 1 ;
881
+ /** The VideoCapabilities does not contain any PerformancePoints */
882
+ private static final int COVERAGE_RESULT_NO_EMPTY_LIST = 0 ;
883
+
884
+ @ RequiresApi (29 )
885
+ private static final class Api29 {
886
+ @ DoNotInline
887
+ public static @ PerformancePointCoverageResult int areResolutionAndFrameRateCovered (
888
+ VideoCapabilities videoCapabilities , int width , int height , double frameRate ) {
889
+ List <PerformancePoint > performancePointList =
890
+ videoCapabilities .getSupportedPerformancePoints ();
891
+ if (performancePointList == null || performancePointList .isEmpty ()) {
892
+ return COVERAGE_RESULT_NO_EMPTY_LIST ;
893
+ }
894
+
895
+ // Round frame rate down to to avoid situations where a range check in
896
+ // covers fails due to slightly exceeding the limits for a standard format
897
+ // (e.g., 1080p at 30 fps). [Internal ref: b/134706676]
898
+ PerformancePoint targetPerformancePoint =
899
+ new PerformancePoint (width , height , (int ) frameRate );
900
+
901
+ for (int i = 0 ; i < performancePointList .size (); i ++) {
902
+ if (performancePointList .get (i ).covers (targetPerformancePoint )) {
903
+ return COVERAGE_RESULT_YES ;
904
+ }
905
+ }
906
+ return COVERAGE_RESULT_NO ;
907
+ }
908
+ }
845
909
}
0 commit comments