Add DRM support to RendererCapabilities
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
This commit is contained in:
parent
3c5688de73
commit
f72833476e
@ -386,8 +386,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
||||
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() {
|
||||
|
@ -578,6 +578,26 @@ public final class 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>.
|
||||
|
@ -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.
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
|
@ -25,6 +25,7 @@ import android.os.HandlerThread;
|
||||
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;
|
||||
@ -306,6 +307,26 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
|
||||
// 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);
|
||||
|
@ -24,6 +24,16 @@ import android.os.Looper;
|
||||
@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.
|
||||
|
@ -84,11 +84,11 @@ public final class TrackEncryptionBox {
|
||||
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 "
|
||||
|
@ -23,6 +23,7 @@ import android.media.MediaCrypto;
|
||||
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;
|
||||
@ -31,6 +32,7 @@ import com.google.android.exoplayer2.Format;
|
||||
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;
|
||||
@ -245,7 +247,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
@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());
|
||||
}
|
||||
@ -1074,6 +1083,25 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user