DRM: Pass sessionId rather than MediaCrypto

ExoMediaCrypto.requiresSecureDecoderComponent() is removed, and
FrameworkMediaCrypto.forceAllowInsecureDecoderComponents is made
public to allow determining whether a secure decoder is required
to be implemented in MediaCodecRenderer.

PiperOrigin-RevId: 228909771
This commit is contained in:
olly 2019-01-11 19:02:00 +00:00 committed by Oliver Woodman
parent 2d30d66746
commit 1f03093dc5
5 changed files with 58 additions and 67 deletions

View File

@ -15,14 +15,5 @@
*/
package com.google.android.exoplayer2.drm;
/**
* An opaque {@link android.media.MediaCrypto} equivalent.
*/
public interface ExoMediaCrypto {
/**
* @see android.media.MediaCrypto#requiresSecureDecoderComponent(String)
*/
boolean requiresSecureDecoderComponent(String mimeType);
}
/** An opaque {@link android.media.MediaCrypto} equivalent. */
public interface ExoMediaCrypto {}

View File

@ -265,11 +265,9 @@ public interface ExoMediaDrm<T extends ExoMediaCrypto> {
/**
* @see android.media.MediaCrypto#MediaCrypto(UUID, byte[])
*
* @param initData Opaque initialization data specific to the crypto scheme.
* @param sessionId The DRM session ID.
* @return An object extends {@link ExoMediaCrypto}, using opaque crypto scheme specific data.
* @throws MediaCryptoException If the instance can't be created.
*/
T createMediaCrypto(byte[] initData) throws MediaCryptoException;
T createMediaCrypto(byte[] sessionId) throws MediaCryptoException;
}

View File

@ -17,48 +17,35 @@ package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi;
import android.media.MediaCrypto;
import com.google.android.exoplayer2.util.Assertions;
import java.util.UUID;
/**
* An {@link ExoMediaCrypto} implementation that wraps the framework {@link MediaCrypto}.
* An {@link ExoMediaCrypto} implementation that contains the necessary information to build or
* update a framework {@link MediaCrypto}.
*/
@TargetApi(16)
public final class FrameworkMediaCrypto implements ExoMediaCrypto {
private final MediaCrypto mediaCrypto;
private final boolean forceAllowInsecureDecoderComponents;
/** The DRM scheme UUID. */
public final UUID uuid;
/** The DRM session id. */
public final byte[] sessionId;
/**
* Whether to allow use of insecure decoder components even if the underlying platform says
* otherwise.
*/
public final boolean forceAllowInsecureDecoderComponents;
/**
* @param mediaCrypto The {@link MediaCrypto} to wrap.
* @param uuid The DRM scheme UUID.
* @param sessionId The DRM session id.
* @param forceAllowInsecureDecoderComponents Whether to allow use of insecure decoder components
* even if the underlying platform says otherwise.
*/
public FrameworkMediaCrypto(MediaCrypto mediaCrypto) {
this(mediaCrypto, false);
}
/**
* @param mediaCrypto The {@link MediaCrypto} to wrap.
* @param forceAllowInsecureDecoderComponents Whether to force
* {@link #requiresSecureDecoderComponent(String)} to return {@code false}, rather than
* {@link MediaCrypto#requiresSecureDecoderComponent(String)} of the wrapped
* {@link MediaCrypto}.
*/
public FrameworkMediaCrypto(MediaCrypto mediaCrypto,
boolean forceAllowInsecureDecoderComponents) {
this.mediaCrypto = Assertions.checkNotNull(mediaCrypto);
public FrameworkMediaCrypto(
UUID uuid, byte[] sessionId, boolean forceAllowInsecureDecoderComponents) {
this.uuid = uuid;
this.sessionId = sessionId;
this.forceAllowInsecureDecoderComponents = forceAllowInsecureDecoderComponents;
}
/**
* Returns the wrapped {@link MediaCrypto}.
*/
public MediaCrypto getWrappedMediaCrypto() {
return mediaCrypto;
}
@Override
public boolean requiresSecureDecoderComponent(String mimeType) {
return !forceAllowInsecureDecoderComponents
&& mediaCrypto.requiresSecureDecoderComponent(mimeType);
}
}

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.drm;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.media.DeniedByServerException;
import android.media.MediaCrypto;
import android.media.MediaCryptoException;
import android.media.MediaDrm;
import android.media.MediaDrmException;
@ -210,7 +209,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
boolean forceAllowInsecureDecoderComponents = Util.SDK_INT < 21
&& C.WIDEVINE_UUID.equals(uuid) && "L3".equals(getPropertyString("securityLevel"));
return new FrameworkMediaCrypto(
new MediaCrypto(adjustUuid(uuid), initData), forceAllowInsecureDecoderComponents);
adjustUuid(uuid), initData, forceAllowInsecureDecoderComponents);
}
private static SchemeData getSchemeData(UUID uuid, List<SchemeData> schemeDatas) {

View File

@ -20,6 +20,7 @@ import android.media.MediaCodec;
import android.media.MediaCodec.CodecException;
import android.media.MediaCodec.CryptoException;
import android.media.MediaCrypto;
import android.media.MediaCryptoException;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Looper;
@ -294,6 +295,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private Format outputFormat;
@Nullable private DrmSession<FrameworkMediaCrypto> codecDrmSession;
@Nullable private DrmSession<FrameworkMediaCrypto> sourceDrmSession;
@Nullable private MediaCrypto mediaCrypto;
private boolean drmSessionRequiresSecureDecoder;
private long renderTimeLimitMs;
private float rendererOperatingRate;
@Nullable private MediaCodec codec;
@ -460,22 +463,28 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
setCodecDrmSession(sourceDrmSession);
String mimeType = inputFormat.sampleMimeType;
MediaCrypto wrappedMediaCrypto = null;
boolean drmSessionRequiresSecureDecoder = false;
if (codecDrmSession != null) {
FrameworkMediaCrypto mediaCrypto = codecDrmSession.getMediaCrypto();
if (mediaCrypto == null) {
DrmSessionException drmError = codecDrmSession.getError();
if (drmError != null) {
// Continue for now. We may be able to avoid failure if the session recovers, or if a new
// input format causes the session to be replaced before it's used.
FrameworkMediaCrypto sessionMediaCrypto = codecDrmSession.getMediaCrypto();
if (sessionMediaCrypto == null) {
DrmSessionException drmError = codecDrmSession.getError();
if (drmError != null) {
// Continue for now. We may be able to avoid failure if the session recovers, or if a
// new input format causes the session to be replaced before it's used.
} else {
// The drm session isn't open yet.
return;
}
} else {
// The drm session isn't open yet.
return;
try {
mediaCrypto = new MediaCrypto(sessionMediaCrypto.uuid, sessionMediaCrypto.sessionId);
} catch (MediaCryptoException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
drmSessionRequiresSecureDecoder =
!sessionMediaCrypto.forceAllowInsecureDecoderComponents
&& mediaCrypto.requiresSecureDecoderComponent(mimeType);
}
} else {
wrappedMediaCrypto = mediaCrypto.getWrappedMediaCrypto();
drmSessionRequiresSecureDecoder = mediaCrypto.requiresSecureDecoderComponent(mimeType);
}
if (deviceNeedsDrmKeysToConfigureCodecWorkaround()) {
@DrmSession.State int drmSessionState = codecDrmSession.getState();
@ -489,7 +498,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
try {
maybeInitCodecWithFallback(wrappedMediaCrypto, drmSessionRequiresSecureDecoder);
maybeInitCodecWithFallback(mediaCrypto, drmSessionRequiresSecureDecoder);
} catch (DecoderInitializationException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
@ -553,7 +562,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Override
protected void onDisabled() {
inputFormat = null;
if (codecDrmSession != null || sourceDrmSession != null) {
if (sourceDrmSession != null || codecDrmSession != null) {
// TODO: Do something better with this case.
onReset();
} else {
@ -591,7 +600,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
} finally {
codec = null;
setCodecDrmSession(null);
try {
if (mediaCrypto != null) {
mediaCrypto.release();
}
} finally {
mediaCrypto = null;
setCodecDrmSession(null);
}
}
}
@ -923,7 +939,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
private void releaseDrmSessionIfUnused(@Nullable DrmSession<FrameworkMediaCrypto> session) {
if (session != null && session != codecDrmSession && session != sourceDrmSession) {
if (session != null && session != sourceDrmSession && session != codecDrmSession) {
drmSessionManager.releaseSession(session);
}
}
@ -1128,7 +1144,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
DrmSession<FrameworkMediaCrypto> session =
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
if (session == codecDrmSession || session == sourceDrmSession) {
if (session == sourceDrmSession || session == codecDrmSession) {
// We already had this session. The manager must be reference counting, so release it once
// to get the count attributed to this renderer back down to 1.
drmSessionManager.releaseSession(session);