Skip to content

Commit

Permalink
Surface MediaCodecInfo methods added in Android Q
Browse files Browse the repository at this point in the history
- Surface information provided by methods isHardwareAccelerated,
  isSoftwareOnly and isVendor added in Android Q in MediaCodecInfo
  class.
- Estimate this information based on the codec name for earlier API
  levels.

Issue:#5839
PiperOrigin-RevId: 266334850
  • Loading branch information
kim-vde authored and ojw28 committed Aug 30, 2019
1 parent f5c1e8b commit 4855555
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 0 deletions.
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

### dev-v2 (not yet released) ###

* Surface information provided by methods `isHardwareAccelerated`,
`isSoftwareOnly` and `isVendor` added in Android Q in `MediaCodecInfo` class
([#5839](https://github.com/google/ExoPlayer/issues/5839)).
* Update `DefaultTrackSelector` to apply a viewport constraint for the default
display by default.
* Add `PlaybackStatsListener` to collect `PlaybackStats` for playbacks analysis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,33 @@ public final class MediaCodecInfo {
/** Whether this instance describes a passthrough codec. */
public final boolean passthrough;

/**
* Whether the codec is hardware accelerated.
*
* <p>This could be an approximation as the exact information is only provided in API levels 29+.
*
* @see android.media.MediaCodecInfo#isHardwareAccelerated()
*/
public final boolean hardwareAccelerated;

/**
* Whether the codec is software only.
*
* <p>This could be an approximation as the exact information is only provided in API levels 29+.
*
* @see android.media.MediaCodecInfo#isSoftwareOnly()
*/
public final boolean softwareOnly;

/**
* Whether the codec is from the vendor.
*
* <p>This could be an approximation as the exact information is only provided in API levels 29+.
*
* @see android.media.MediaCodecInfo#isVendor()
*/
public final boolean vendor;

private final boolean isVideo;

/**
Expand All @@ -108,6 +135,9 @@ public static MediaCodecInfo newPassthroughInstance(String name) {
/* codecMimeType= */ null,
/* capabilities= */ null,
/* passthrough= */ true,
/* hardwareAccelerated= */ false,
/* softwareOnly= */ true,
/* vendor= */ false,
/* forceDisableAdaptive= */ false,
/* forceSecure= */ false);
}
Expand All @@ -121,6 +151,9 @@ public static MediaCodecInfo newPassthroughInstance(String name) {
* Equal to {@code mimeType} unless the codec is known to use a non-standard MIME type alias.
* @param capabilities The capabilities of the {@link MediaCodec} for the specified mime type, or
* {@code null} if not known.
* @param hardwareAccelerated Whether the {@link MediaCodec} is hardware accelerated.
* @param softwareOnly Whether the {@link MediaCodec} is software only.
* @param vendor Whether the {@link MediaCodec} is provided by the vendor.
* @param forceDisableAdaptive Whether {@link #adaptive} should be forced to {@code false}.
* @param forceSecure Whether {@link #secure} should be forced to {@code true}.
* @return The created instance.
Expand All @@ -130,6 +163,9 @@ public static MediaCodecInfo newInstance(
String mimeType,
String codecMimeType,
@Nullable CodecCapabilities capabilities,
boolean hardwareAccelerated,
boolean softwareOnly,
boolean vendor,
boolean forceDisableAdaptive,
boolean forceSecure) {
return new MediaCodecInfo(
Expand All @@ -138,6 +174,9 @@ public static MediaCodecInfo newInstance(
codecMimeType,
capabilities,
/* passthrough= */ false,
hardwareAccelerated,
softwareOnly,
vendor,
forceDisableAdaptive,
forceSecure);
}
Expand All @@ -148,13 +187,19 @@ private MediaCodecInfo(
@Nullable String codecMimeType,
@Nullable CodecCapabilities capabilities,
boolean passthrough,
boolean hardwareAccelerated,
boolean softwareOnly,
boolean vendor,
boolean forceDisableAdaptive,
boolean forceSecure) {
this.name = Assertions.checkNotNull(name);
this.mimeType = mimeType;
this.codecMimeType = codecMimeType;
this.capabilities = capabilities;
this.passthrough = passthrough;
this.hardwareAccelerated = hardwareAccelerated;
this.softwareOnly = softwareOnly;
this.vendor = vendor;
adaptive = !forceDisableAdaptive && capabilities != null && isAdaptive(capabilities);
tunneling = capabilities != null && isTunneling(capabilities);
secure = forceSecure || (capabilities != null && isSecure(capabilities));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@ private static ArrayList<MediaCodecInfo> getDecoderInfosInternal(
if ((!key.secure && secureRequired) || (key.secure && !secureSupported)) {
continue;
}
boolean hardwareAccelerated = isHardwareAccelerated(codecInfo);
boolean softwareOnly = isSoftwareOnly(codecInfo);
boolean vendor = isVendor(codecInfo);
boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(name);
if ((secureDecodersExplicit && key.secure == secureSupported)
|| (!secureDecodersExplicit && !key.secure)) {
Expand All @@ -321,6 +324,9 @@ private static ArrayList<MediaCodecInfo> getDecoderInfosInternal(
mimeType,
codecMimeType,
capabilities,
hardwareAccelerated,
softwareOnly,
vendor,
forceDisableAdaptive,
/* forceSecure= */ false));
} else if (!secureDecodersExplicit && secureSupported) {
Expand All @@ -330,6 +336,9 @@ private static ArrayList<MediaCodecInfo> getDecoderInfosInternal(
mimeType,
codecMimeType,
capabilities,
hardwareAccelerated,
softwareOnly,
vendor,
forceDisableAdaptive,
/* forceSecure= */ true));
// It only makes sense to have one synthesized secure decoder, return immediately.
Expand Down Expand Up @@ -532,6 +541,9 @@ private static void applyWorkarounds(String mimeType, List<MediaCodecInfo> decod
/* mimeType= */ MimeTypes.AUDIO_RAW,
/* codecMimeType= */ MimeTypes.AUDIO_RAW,
/* capabilities= */ null,
/* hardwareAccelerated= */ false,
/* softwareOnly= */ true,
/* vendor= */ false,
/* forceDisableAdaptive= */ false,
/* forceSecure= */ false));
}
Expand Down Expand Up @@ -565,6 +577,69 @@ private static void applyWorkarounds(String mimeType, List<MediaCodecInfo> decod
}
}

/**
* The result of {@link android.media.MediaCodecInfo#isHardwareAccelerated()} for API levels 29+,
* or a best-effort approximation for lower levels.
*/
private static boolean isHardwareAccelerated(android.media.MediaCodecInfo codecInfo) {
if (Util.SDK_INT >= 29) {
return isHardwareAcceleratedV29(codecInfo);
}
// codecInfo.isHardwareAccelerated() != codecInfo.isSoftwareOnly() is not necessarily true.
// However, we assume this to be true as an approximation.
return !isSoftwareOnly(codecInfo);
}

@TargetApi(29)
private static boolean isHardwareAcceleratedV29(android.media.MediaCodecInfo codecInfo) {
return codecInfo.isHardwareAccelerated();
}

/**
* The result of {@link android.media.MediaCodecInfo#isSoftwareOnly()} for API levels 29+, or a
* best-effort approximation for lower levels.
*/
private static boolean isSoftwareOnly(android.media.MediaCodecInfo codecInfo) {
if (Util.SDK_INT >= 29) {
return isSoftwareOnlyV29(codecInfo);
}
String codecName = codecInfo.getName().toLowerCase();
if (codecName.startsWith("arc.")) { // App Runtime for Chrome (ARC) codecs
return false;
}
return codecName.startsWith("omx.google.")
|| codecName.startsWith("omx.ffmpeg.")
|| (codecName.startsWith("omx.sec.") && codecName.contains(".sw."))
|| codecName.equals("omx.qcom.video.decoder.hevcswvdec")
|| codecName.startsWith("c2.android.")
|| codecName.startsWith("c2.google.")
|| (!codecName.startsWith("omx.") && !codecName.startsWith("c2."));
}

@TargetApi(29)
private static boolean isSoftwareOnlyV29(android.media.MediaCodecInfo codecInfo) {
return codecInfo.isSoftwareOnly();
}

/**
* The result of {@link android.media.MediaCodecInfo#isVendor()} for API levels 29+, or a
* best-effort approximation for lower levels.
*/
private static boolean isVendor(android.media.MediaCodecInfo codecInfo) {
if (Util.SDK_INT >= 29) {
return isVendorV29(codecInfo);
}
String codecName = codecInfo.getName().toLowerCase();
return !codecName.startsWith("omx.google.")
&& !codecName.startsWith("c2.android.")
&& !codecName.startsWith("c2.google.");
}

@TargetApi(29)
private static boolean isVendorV29(android.media.MediaCodecInfo codecInfo) {
return codecInfo.isVendor();
}

/**
* Returns whether the decoder is known to fail when adapting, despite advertising itself as an
* adaptive decoder.
Expand Down

0 comments on commit 4855555

Please sign in to comment.