Skip to content

Commit

Permalink
Add DRM support to RendererCapabilities
Browse files Browse the repository at this point in the history
This CL also makes DefaultTrackSelector take it into account when RendererCapabilities
sets it to unsupported.

A following CL could add a DefaultTrackSelector parameter to force DRM "known support" for specific track types.

Issue:#1661
Issue:#1989
Issue:#2089

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161556467
  • Loading branch information
AquilesCanta authored and ojw28 committed Jul 12, 2017
1 parent 3c5688d commit f728334
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ private DrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManager(UUID uuid
keyRequestPropertiesArray[i + 1]);
}
}
return new DefaultDrmSessionManager<>(uuid,
FrameworkMediaDrm.newInstance(uuid), drmCallback, null, mainHandler, eventLogger);
return new DefaultDrmSessionManager<>(uuid, FrameworkMediaDrm.newInstance(uuid), drmCallback,
null, mainHandler, eventLogger);
}

private void releasePlayer() {
Expand Down
20 changes: 20 additions & 0 deletions library/core/src/main/java/com/google/android/exoplayer2/C.java
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,26 @@ private C() {}
public static final int DEFAULT_MUXED_BUFFER_SIZE = DEFAULT_VIDEO_BUFFER_SIZE
+ DEFAULT_AUDIO_BUFFER_SIZE + DEFAULT_TEXT_BUFFER_SIZE;

/**
* "cenc" scheme type name as defined in ISO/IEC 23001-7:2016.
*/
public static final String CENC_TYPE_cenc = "cenc";

/**
* "cbc1" scheme type name as defined in ISO/IEC 23001-7:2016.
*/
public static final String CENC_TYPE_cbc1 = "cbc1";

/**
* "cens" scheme type name as defined in ISO/IEC 23001-7:2016.
*/
public static final String CENC_TYPE_cens = "cens";

/**
* "cbcs" scheme type name as defined in ISO/IEC 23001-7:2016.
*/
public static final String CENC_TYPE_cbcs = "cbcs";

/**
* The Nil UUID as defined by
* <a href="https://tools.ietf.org/html/rfc4122#section-4.1.7">RFC4122</a>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public interface RendererCapabilities {
* {@link #FORMAT_HANDLED}, {@link #FORMAT_EXCEEDS_CAPABILITIES},
* {@link #FORMAT_UNSUPPORTED_SUBTYPE} and {@link #FORMAT_UNSUPPORTED_TYPE}.
*/
int FORMAT_SUPPORT_MASK = 0b11;
int FORMAT_SUPPORT_MASK = 0b111;
/**
* The {@link Renderer} is capable of rendering the format.
*/
int FORMAT_HANDLED = 0b11;
int FORMAT_HANDLED = 0b100;
/**
* The {@link Renderer} is capable of rendering formats with the same mime type, but the
* properties of the format exceed the renderer's capability.
Expand All @@ -40,7 +40,16 @@ public interface RendererCapabilities {
* {@link MimeTypes#VIDEO_H264}, but the format's resolution exceeds the maximum limit supported
* by the underlying H264 decoder.
*/
int FORMAT_EXCEEDS_CAPABILITIES = 0b10;
int FORMAT_EXCEEDS_CAPABILITIES = 0b011;
/**
* The {@link Renderer} is capable of rendering formats with the same mime type, but the
* drm scheme used is not supported.
* <p>
* Example: The {@link Renderer} is capable of rendering H264 and the format's mime type is
* {@link MimeTypes#VIDEO_H264}, but the format indicates cbcs encryption, which is not supported
* by the underlying content decryption module.
*/
int FORMAT_UNSUPPORTED_DRM = 0b010;
/**
* The {@link Renderer} is a general purpose renderer for formats of the same top-level type,
* but is not capable of rendering the format or any other format with the same mime type because
Expand All @@ -49,7 +58,7 @@ public interface RendererCapabilities {
* Example: The {@link Renderer} is a general purpose audio renderer and the format's
* mime type matches audio/[subtype], but there does not exist a suitable decoder for [subtype].
*/
int FORMAT_UNSUPPORTED_SUBTYPE = 0b01;
int FORMAT_UNSUPPORTED_SUBTYPE = 0b001;
/**
* The {@link Renderer} is not capable of rendering the format, either because it does not
* support the format's top-level type, or because it's a specialized renderer for a different
Expand All @@ -58,40 +67,40 @@ public interface RendererCapabilities {
* Example: The {@link Renderer} is a general purpose video renderer, but the format has an
* audio mime type.
*/
int FORMAT_UNSUPPORTED_TYPE = 0b00;
int FORMAT_UNSUPPORTED_TYPE = 0b000;

/**
* A mask to apply to the result of {@link #supportsFormat(Format)} to obtain one of
* {@link #ADAPTIVE_SEAMLESS}, {@link #ADAPTIVE_NOT_SEAMLESS} and {@link #ADAPTIVE_NOT_SUPPORTED}.
*/
int ADAPTIVE_SUPPORT_MASK = 0b1100;
int ADAPTIVE_SUPPORT_MASK = 0b11000;
/**
* The {@link Renderer} can seamlessly adapt between formats.
*/
int ADAPTIVE_SEAMLESS = 0b1000;
int ADAPTIVE_SEAMLESS = 0b10000;
/**
* The {@link Renderer} can adapt between formats, but may suffer a brief discontinuity
* (~50-100ms) when adaptation occurs.
*/
int ADAPTIVE_NOT_SEAMLESS = 0b0100;
int ADAPTIVE_NOT_SEAMLESS = 0b01000;
/**
* The {@link Renderer} does not support adaptation between formats.
*/
int ADAPTIVE_NOT_SUPPORTED = 0b0000;
int ADAPTIVE_NOT_SUPPORTED = 0b00000;

/**
* A mask to apply to the result of {@link #supportsFormat(Format)} to obtain one of
* {@link #TUNNELING_SUPPORTED} and {@link #TUNNELING_NOT_SUPPORTED}.
*/
int TUNNELING_SUPPORT_MASK = 0b10000;
int TUNNELING_SUPPORT_MASK = 0b100000;
/**
* The {@link Renderer} supports tunneled output.
*/
int TUNNELING_SUPPORTED = 0b10000;
int TUNNELING_SUPPORTED = 0b100000;
/**
* The {@link Renderer} does not support tunneled output.
*/
int TUNNELING_NOT_SUPPORTED = 0b00000;
int TUNNELING_NOT_SUPPORTED = 0b000000;

/**
* Returns the track type that the {@link Renderer} handles. For example, a video renderer will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import android.os.Looper;
import android.os.Message;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
Expand Down Expand Up @@ -306,6 +307,26 @@ public void setMode(@Mode int mode, byte[] offlineLicenseKeySetId) {

// DrmSessionManager implementation.

@Override
public boolean canAcquireSession(@NonNull DrmInitData drmInitData) {
SchemeData schemeData = drmInitData.get(uuid);
if (schemeData == null) {
// No data for this manager's scheme.
return false;
}
String schemeType = schemeData.type;
if (schemeType == null || C.CENC_TYPE_cenc.equals(schemeType)) {
// If there is no scheme information, assume patternless AES-CTR.
return true;
} else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType)
|| C.CENC_TYPE_cens.equals(schemeType)) {
// AES-CBC and pattern encryption are supported on API 24 onwards.
return Util.SDK_INT >= 24;
}
// Unknown schemes, assume one of them is supported.
return true;
}

@Override
public DrmSession<T> acquireSession(Looper playbackLooper, DrmInitData drmInitData) {
Assertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@
@TargetApi(16)
public interface DrmSessionManager<T extends ExoMediaCrypto> {

/**
* Returns whether the manager is capable of acquiring a session for the given
* {@link DrmInitData}.
*
* @param drmInitData DRM initialization data.
* @return Whether the manager is capable of acquiring a session for the given
* {@link DrmInitData}.
*/
boolean canAcquireSession(DrmInitData drmInitData);

/**
* Acquires a {@link DrmSession} for the specified {@link DrmInitData}. The {@link DrmSession}
* must be returned to {@link #releaseSession(DrmSession)} when it is no longer required.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ private static int schemeToCryptoMode(@Nullable String schemeType) {
return C.CRYPTO_MODE_AES_CTR;
}
switch (schemeType) {
case "cenc":
case "cens":
case C.CENC_TYPE_cenc:
case C.CENC_TYPE_cens:
return C.CRYPTO_MODE_AES_CTR;
case "cbc1":
case "cbcs":
case C.CENC_TYPE_cbc1:
case C.CENC_TYPE_cbcs:
return C.CRYPTO_MODE_AES_CBC;
default:
Log.w(TAG, "Unsupported protection scheme type '" + schemeType + "'. Assuming AES-CTR "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import android.media.MediaFormat;
import android.os.Looper;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.exoplayer2.BaseRenderer;
import com.google.android.exoplayer2.C;
Expand All @@ -31,6 +32,7 @@
import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmSession;
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
import com.google.android.exoplayer2.drm.DrmSessionManager;
Expand Down Expand Up @@ -245,7 +247,14 @@ public final int supportsMixedMimeTypeAdaptation() {
@Override
public final int supportsFormat(Format format) throws ExoPlaybackException {
try {
return supportsFormat(mediaCodecSelector, format);
int formatSupport = supportsFormat(mediaCodecSelector, format);
if ((formatSupport & FORMAT_SUPPORT_MASK) > FORMAT_UNSUPPORTED_DRM
&& !isDrmSchemeSupported(drmSessionManager, format.drmInitData)) {
// The renderer advertises higher support than FORMAT_UNSUPPORTED_DRM but the DRM scheme is
// not supported. The format support is truncated to reflect this.
formatSupport = (formatSupport & ~FORMAT_SUPPORT_MASK) | FORMAT_UNSUPPORTED_DRM;
}
return formatSupport;
} catch (DecoderQueryException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
Expand Down Expand Up @@ -1074,6 +1083,25 @@ private boolean shouldSkipOutputBuffer(long presentationTimeUs) {
return false;
}

/**
* Returns whether the encryption scheme is supported, or true if {@code drmInitData} is null.
*
* @param drmSessionManager The drm session manager associated with the renderer.
* @param drmInitData {@link DrmInitData} of the format to check for support.
* @return Whether the encryption scheme is supported, or true if {@code drmInitData} is null.
*/
private static boolean isDrmSchemeSupported(DrmSessionManager drmSessionManager,
@Nullable DrmInitData drmInitData) {
if (drmInitData == null) {
// Content is unencrypted.
return true;
} else if (drmSessionManager == null) {
// Content is encrypted, but no drm session manager is available.
return false;
}
return drmSessionManager.canAcquireSession(drmInitData);
}

/**
* Returns whether the decoder is known to fail when flushed.
* <p>
Expand Down

0 comments on commit f728334

Please sign in to comment.