Commit 7408b435 by aquilescanta Committed by Oliver Woodman

Add DRM format support checks for MediaSource provided DRM

PiperOrigin-RevId: 256161522
parent 16bf7f91
...@@ -77,12 +77,17 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { ...@@ -77,12 +77,17 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
@Override @Override
protected int supportsFormatInternal(DrmSessionManager<ExoMediaCrypto> drmSessionManager, protected int supportsFormatInternal(DrmSessionManager<ExoMediaCrypto> drmSessionManager,
Format format) { Format format) {
boolean drmIsSupported =
format.drmInitData == null
|| OpusLibrary.matchesExpectedExoMediaCryptoType(format.exoMediaCryptoType)
|| (format.exoMediaCryptoType == null
&& supportsFormatDrm(drmSessionManager, format.drmInitData));
if (!OpusLibrary.isAvailable() if (!OpusLibrary.isAvailable()
|| !MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType)) { || !MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType)) {
return FORMAT_UNSUPPORTED_TYPE; return FORMAT_UNSUPPORTED_TYPE;
} else if (!supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) { } else if (!supportsOutput(format.channelCount, C.ENCODING_PCM_16BIT)) {
return FORMAT_UNSUPPORTED_SUBTYPE; return FORMAT_UNSUPPORTED_SUBTYPE;
} else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { } else if (!drmIsSupported) {
return FORMAT_UNSUPPORTED_DRM; return FORMAT_UNSUPPORTED_DRM;
} else { } else {
return FORMAT_HANDLED; return FORMAT_HANDLED;
...@@ -110,5 +115,4 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { ...@@ -110,5 +115,4 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
Format.NO_VALUE, decoder.getChannelCount(), decoder.getSampleRate(), C.ENCODING_PCM_16BIT, Format.NO_VALUE, decoder.getChannelCount(), decoder.getSampleRate(), C.ENCODING_PCM_16BIT,
null, null, 0, null); null, null, 0, null);
} }
} }
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
package com.google.android.exoplayer2.ext.opus; package com.google.android.exoplayer2.ext.opus;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.LibraryLoader; import com.google.android.exoplayer2.util.LibraryLoader;
import com.google.android.exoplayer2.util.Util;
/** /**
* Configures and queries the underlying native library. * Configures and queries the underlying native library.
...@@ -28,6 +30,7 @@ public final class OpusLibrary { ...@@ -28,6 +30,7 @@ public final class OpusLibrary {
} }
private static final LibraryLoader LOADER = new LibraryLoader("opusV2JNI"); private static final LibraryLoader LOADER = new LibraryLoader("opusV2JNI");
private static Class<? extends ExoMediaCrypto> exoMediaCryptoType;
private OpusLibrary() {} private OpusLibrary() {}
...@@ -36,10 +39,14 @@ public final class OpusLibrary { ...@@ -36,10 +39,14 @@ public final class OpusLibrary {
* it must do so before calling any other method defined by this class, and before instantiating a * it must do so before calling any other method defined by this class, and before instantiating a
* {@link LibopusAudioRenderer} instance. * {@link LibopusAudioRenderer} instance.
* *
* @param exoMediaCryptoType The {@link ExoMediaCrypto} type expected for decoding protected
* content.
* @param libraries The names of the Opus native libraries. * @param libraries The names of the Opus native libraries.
*/ */
public static void setLibraries(String... libraries) { public static void setLibraries(
Class<? extends ExoMediaCrypto> exoMediaCryptoType, String... libraries) {
LOADER.setLibraries(libraries); LOADER.setLibraries(libraries);
OpusLibrary.exoMediaCryptoType = exoMediaCryptoType;
} }
/** /**
...@@ -56,6 +63,15 @@ public final class OpusLibrary { ...@@ -56,6 +63,15 @@ public final class OpusLibrary {
return isAvailable() ? opusGetVersion() : null; return isAvailable() ? opusGetVersion() : null;
} }
/**
* Returns whether the given {@link ExoMediaCrypto} type matches the one required for decoding
* protected content.
*/
public static boolean matchesExpectedExoMediaCryptoType(
Class<? extends ExoMediaCrypto> exoMediaCryptoType) {
return Util.areEqual(OpusLibrary.exoMediaCryptoType, exoMediaCryptoType);
}
public static native String opusGetVersion(); public static native String opusGetVersion();
public static native boolean opusIsSecureDecodeSupported(); public static native boolean opusIsSecureDecodeSupported();
} }
...@@ -284,7 +284,13 @@ public class LibvpxVideoRenderer extends BaseRenderer { ...@@ -284,7 +284,13 @@ public class LibvpxVideoRenderer extends BaseRenderer {
public int supportsFormat(Format format) { public int supportsFormat(Format format) {
if (!VpxLibrary.isAvailable() || !MimeTypes.VIDEO_VP9.equalsIgnoreCase(format.sampleMimeType)) { if (!VpxLibrary.isAvailable() || !MimeTypes.VIDEO_VP9.equalsIgnoreCase(format.sampleMimeType)) {
return FORMAT_UNSUPPORTED_TYPE; return FORMAT_UNSUPPORTED_TYPE;
} else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { }
boolean drmIsSupported =
format.drmInitData == null
|| VpxLibrary.matchesExpectedExoMediaCryptoType(format.exoMediaCryptoType)
|| (format.exoMediaCryptoType == null
&& supportsFormatDrm(drmSessionManager, format.drmInitData));
if (!drmIsSupported) {
return FORMAT_UNSUPPORTED_DRM; return FORMAT_UNSUPPORTED_DRM;
} }
return FORMAT_HANDLED | ADAPTIVE_SEAMLESS; return FORMAT_HANDLED | ADAPTIVE_SEAMLESS;
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
package com.google.android.exoplayer2.ext.vp9; package com.google.android.exoplayer2.ext.vp9;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.LibraryLoader; import com.google.android.exoplayer2.util.LibraryLoader;
import com.google.android.exoplayer2.util.Util;
/** /**
* Configures and queries the underlying native library. * Configures and queries the underlying native library.
...@@ -28,6 +30,7 @@ public final class VpxLibrary { ...@@ -28,6 +30,7 @@ public final class VpxLibrary {
} }
private static final LibraryLoader LOADER = new LibraryLoader("vpx", "vpxV2JNI"); private static final LibraryLoader LOADER = new LibraryLoader("vpx", "vpxV2JNI");
private static Class<? extends ExoMediaCrypto> exoMediaCryptoType;
private VpxLibrary() {} private VpxLibrary() {}
...@@ -36,10 +39,14 @@ public final class VpxLibrary { ...@@ -36,10 +39,14 @@ public final class VpxLibrary {
* it must do so before calling any other method defined by this class, and before instantiating a * it must do so before calling any other method defined by this class, and before instantiating a
* {@link LibvpxVideoRenderer} instance. * {@link LibvpxVideoRenderer} instance.
* *
* @param exoMediaCryptoType The {@link ExoMediaCrypto} type required for decoding protected
* content.
* @param libraries The names of the Vpx native libraries. * @param libraries The names of the Vpx native libraries.
*/ */
public static void setLibraries(String... libraries) { public static void setLibraries(
Class<? extends ExoMediaCrypto> exoMediaCryptoType, String... libraries) {
LOADER.setLibraries(libraries); LOADER.setLibraries(libraries);
VpxLibrary.exoMediaCryptoType = exoMediaCryptoType;
} }
/** /**
...@@ -74,6 +81,15 @@ public final class VpxLibrary { ...@@ -74,6 +81,15 @@ public final class VpxLibrary {
return indexHbd >= 0; return indexHbd >= 0;
} }
/**
* Returns whether the given {@link ExoMediaCrypto} type matches the one required for decoding
* protected content.
*/
public static boolean matchesExpectedExoMediaCryptoType(
Class<? extends ExoMediaCrypto> exoMediaCryptoType) {
return Util.areEqual(VpxLibrary.exoMediaCryptoType, exoMediaCryptoType);
}
private static native String vpxGetVersion(); private static native String vpxGetVersion();
private static native String vpxGetBuildConfig(); private static native String vpxGetBuildConfig();
public static native boolean vpxIsSecureDecodeSupported(); public static native boolean vpxIsSecureDecodeSupported();
......
...@@ -308,7 +308,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -308,7 +308,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
return FORMAT_UNSUPPORTED_TYPE; return FORMAT_UNSUPPORTED_TYPE;
} }
int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED; int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED;
boolean supportsFormatDrm = supportsFormatDrm(drmSessionManager, format.drmInitData); boolean supportsFormatDrm =
format.drmInitData == null
|| FrameworkMediaCrypto.class.equals(format.exoMediaCryptoType)
|| (format.exoMediaCryptoType == null
&& supportsFormatDrm(drmSessionManager, format.drmInitData));
if (supportsFormatDrm if (supportsFormatDrm
&& allowPassthrough(format.channelCount, mimeType) && allowPassthrough(format.channelCount, mimeType)
&& mediaCodecSelector.getPassthroughDecoderInfo() != null) { && mediaCodecSelector.getPassthroughDecoderInfo() != null) {
......
...@@ -436,6 +436,12 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> ...@@ -436,6 +436,12 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
return session; return session;
} }
@Override
@Nullable
public Class<T> getExoMediaCryptoType(DrmInitData drmInitData) {
return canAcquireSession(drmInitData) ? mediaDrm.getExoMediaCryptoType() : null;
}
// ProvisioningManager implementation. // ProvisioningManager implementation.
@Override @Override
......
...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.drm; ...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.drm;
import android.os.Looper; import android.os.Looper;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
...@@ -49,6 +50,12 @@ public interface DrmSessionManager<T extends ExoMediaCrypto> { ...@@ -49,6 +50,12 @@ public interface DrmSessionManager<T extends ExoMediaCrypto> {
new DrmSession.DrmSessionException( new DrmSession.DrmSessionException(
new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME))); new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME)));
} }
@Override
@Nullable
public Class<ExoMediaCrypto> getExoMediaCryptoType(DrmInitData drmInitData) {
return null;
}
}; };
/** Flags that control the handling of DRM protected content. */ /** Flags that control the handling of DRM protected content. */
...@@ -99,4 +106,11 @@ public interface DrmSessionManager<T extends ExoMediaCrypto> { ...@@ -99,4 +106,11 @@ public interface DrmSessionManager<T extends ExoMediaCrypto> {
default int getFlags() { default int getFlags() {
return 0; return 0;
} }
/**
* Returns the {@link ExoMediaCrypto} type returned by sessions acquired using the given {@link
* DrmInitData}, or null if a session cannot be acquired with the given {@link DrmInitData}.
*/
@Nullable
Class<? extends ExoMediaCrypto> getExoMediaCryptoType(DrmInitData drmInitData);
} }
...@@ -271,4 +271,7 @@ public interface ExoMediaDrm<T extends ExoMediaCrypto> { ...@@ -271,4 +271,7 @@ public interface ExoMediaDrm<T extends ExoMediaCrypto> {
* @throws MediaCryptoException If the instance can't be created. * @throws MediaCryptoException If the instance can't be created.
*/ */
T createMediaCrypto(byte[] sessionId) throws MediaCryptoException; T createMediaCrypto(byte[] sessionId) throws MediaCryptoException;
/** Returns the {@link ExoMediaCrypto} type created by {@link #createMediaCrypto(byte[])}. */
Class<T> getExoMediaCryptoType();
} }
...@@ -225,6 +225,11 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto ...@@ -225,6 +225,11 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
adjustUuid(uuid), initData, forceAllowInsecureDecoderComponents); adjustUuid(uuid), initData, forceAllowInsecureDecoderComponents);
} }
@Override
public Class<FrameworkMediaCrypto> getExoMediaCryptoType() {
return FrameworkMediaCrypto.class;
}
private static SchemeData getSchemeData(UUID uuid, List<SchemeData> schemeDatas) { private static SchemeData getSchemeData(UUID uuid, List<SchemeData> schemeDatas) {
if (!C.WIDEVINE_UUID.equals(uuid)) { if (!C.WIDEVINE_UUID.equals(uuid)) {
// For non-Widevine CDMs always use the first scheme data. // For non-Widevine CDMs always use the first scheme data.
......
...@@ -336,7 +336,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -336,7 +336,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
if (decoderInfos.isEmpty()) { if (decoderInfos.isEmpty()) {
return FORMAT_UNSUPPORTED_SUBTYPE; return FORMAT_UNSUPPORTED_SUBTYPE;
} }
if (!supportsFormatDrm(drmSessionManager, drmInitData)) { boolean supportsFormatDrm =
format.drmInitData == null
|| FrameworkMediaCrypto.class.equals(format.exoMediaCryptoType)
|| (format.exoMediaCryptoType == null
&& supportsFormatDrm(drmSessionManager, format.drmInitData));
if (!supportsFormatDrm) {
return FORMAT_UNSUPPORTED_DRM; return FORMAT_UNSUPPORTED_DRM;
} }
// Check capabilities for the first decoder in the list, which takes priority. // Check capabilities for the first decoder in the list, which takes priority.
......
...@@ -91,7 +91,8 @@ public final class FormatTest { ...@@ -91,7 +91,8 @@ public final class FormatTest {
/* encoderDelay= */ 1001, /* encoderDelay= */ 1001,
/* encoderPadding= */ 1002, /* encoderPadding= */ 1002,
"language", "language",
/* accessibilityChannel= */ Format.NO_VALUE); /* accessibilityChannel= */ Format.NO_VALUE,
/* exoMediaCryptoType= */ null);
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
formatToParcel.writeToParcel(parcel, 0); formatToParcel.writeToParcel(parcel, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment