mirror of
https://github.com/androidx/media.git
synced 2025-05-17 12:39:52 +08:00
DRM refactor / cleanup
PiperOrigin-RevId: 391403236
This commit is contained in:
parent
cd297b048a
commit
85142be9a4
@ -23,8 +23,8 @@ import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.TraceUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
@ -132,7 +132,7 @@ public class Libgav1VideoRenderer extends DecoderVideoRenderer {
|
||||
|| !Gav1Library.isAvailable()) {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
|
||||
}
|
||||
if (format.exoMediaCryptoType != null) {
|
||||
if (format.cryptoType != C.CRYPTO_TYPE_NONE) {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_DRM);
|
||||
}
|
||||
return RendererCapabilities.create(
|
||||
@ -140,7 +140,7 @@ public class Libgav1VideoRenderer extends DecoderVideoRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Gav1Decoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
|
||||
protected Gav1Decoder createDecoder(Format format, @Nullable CryptoConfig cryptoConfig)
|
||||
throws Gav1DecoderException {
|
||||
TraceUtil.beginSection("createGav1Decoder");
|
||||
int initialInputBufferSize =
|
||||
|
@ -29,7 +29,7 @@ import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.audio.AudioSink.SinkFormatSupport;
|
||||
import com.google.android.exoplayer2.audio.DecoderAudioRenderer;
|
||||
import com.google.android.exoplayer2.audio.DefaultAudioSink;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.TraceUtil;
|
||||
@ -97,7 +97,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer<FfmpegAudioD
|
||||
|| (!sinkSupportsFormat(format, C.ENCODING_PCM_16BIT)
|
||||
&& !sinkSupportsFormat(format, C.ENCODING_PCM_FLOAT))) {
|
||||
return C.FORMAT_UNSUPPORTED_SUBTYPE;
|
||||
} else if (format.exoMediaCryptoType != null) {
|
||||
} else if (format.cryptoType != C.CRYPTO_TYPE_NONE) {
|
||||
return C.FORMAT_UNSUPPORTED_DRM;
|
||||
} else {
|
||||
return C.FORMAT_HANDLED;
|
||||
@ -111,7 +111,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer<FfmpegAudioD
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FfmpegAudioDecoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
|
||||
protected FfmpegAudioDecoder createDecoder(Format format, @Nullable CryptoConfig cryptoConfig)
|
||||
throws FfmpegDecoderException {
|
||||
TraceUtil.beginSection("createFfmpegAudioDecoder");
|
||||
int initialInputBufferSize =
|
||||
|
@ -25,9 +25,9 @@ import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.Decoder;
|
||||
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.util.TraceUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.video.DecoderVideoRenderer;
|
||||
@ -95,7 +95,7 @@ public final class FfmpegVideoRenderer extends DecoderVideoRenderer {
|
||||
@SuppressWarnings("nullness:return")
|
||||
@Override
|
||||
protected Decoder<VideoDecoderInputBuffer, VideoDecoderOutputBuffer, FfmpegDecoderException>
|
||||
createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
|
||||
createDecoder(Format format, @Nullable CryptoConfig cryptoConfig)
|
||||
throws FfmpegDecoderException {
|
||||
TraceUtil.beginSection("createFfmpegVideoDecoder");
|
||||
// TODO: Implement, remove the SuppressWarnings annotation, and update the return type to use
|
||||
|
@ -23,7 +23,7 @@ import com.google.android.exoplayer2.audio.AudioProcessor;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.audio.DecoderAudioRenderer;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.extractor.FlacStreamMetadata;
|
||||
import com.google.android.exoplayer2.util.FlacConstants;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
@ -100,7 +100,7 @@ public final class LibflacAudioRenderer extends DecoderAudioRenderer<FlacDecoder
|
||||
}
|
||||
if (!sinkSupportsFormat(outputFormat)) {
|
||||
return C.FORMAT_UNSUPPORTED_SUBTYPE;
|
||||
} else if (format.exoMediaCryptoType != null) {
|
||||
} else if (format.cryptoType != C.CRYPTO_TYPE_NONE) {
|
||||
return C.FORMAT_UNSUPPORTED_DRM;
|
||||
} else {
|
||||
return C.FORMAT_HANDLED;
|
||||
@ -108,7 +108,7 @@ public final class LibflacAudioRenderer extends DecoderAudioRenderer<FlacDecoder
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FlacDecoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
|
||||
protected FlacDecoder createDecoder(Format format, @Nullable CryptoConfig cryptoConfig)
|
||||
throws FlacDecoderException {
|
||||
TraceUtil.beginSection("createFlacDecoder");
|
||||
FlacDecoder decoder =
|
||||
|
@ -25,7 +25,7 @@ import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.audio.AudioSink.SinkFormatSupport;
|
||||
import com.google.android.exoplayer2.audio.DecoderAudioRenderer;
|
||||
import com.google.android.exoplayer2.audio.OpusUtil;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.TraceUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
@ -81,9 +81,7 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer<OpusDecoder> {
|
||||
@Override
|
||||
@C.FormatSupport
|
||||
protected int supportsFormatInternal(Format format) {
|
||||
boolean drmIsSupported =
|
||||
format.exoMediaCryptoType == null
|
||||
|| OpusLibrary.matchesExpectedExoMediaCryptoType(format.exoMediaCryptoType);
|
||||
boolean drmIsSupported = OpusLibrary.supportsCryptoType(format.cryptoType);
|
||||
if (!OpusLibrary.isAvailable()
|
||||
|| !MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType)) {
|
||||
return C.FORMAT_UNSUPPORTED_TYPE;
|
||||
@ -98,7 +96,7 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer<OpusDecoder> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OpusDecoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
|
||||
protected OpusDecoder createDecoder(Format format, @Nullable CryptoConfig cryptoConfig)
|
||||
throws OpusDecoderException {
|
||||
TraceUtil.beginSection("createOpusDecoder");
|
||||
@SinkFormatSupport
|
||||
@ -115,7 +113,7 @@ public class LibopusAudioRenderer extends DecoderAudioRenderer<OpusDecoder> {
|
||||
NUM_BUFFERS,
|
||||
initialInputBufferSize,
|
||||
format.initializationData,
|
||||
mediaCrypto,
|
||||
cryptoConfig,
|
||||
outputFloat);
|
||||
|
||||
TraceUtil.endSection();
|
||||
|
@ -21,12 +21,12 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.audio.OpusUtil;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.CryptoException;
|
||||
import com.google.android.exoplayer2.decoder.CryptoInfo;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -44,7 +44,7 @@ public final class OpusDecoder
|
||||
public final boolean outputFloat;
|
||||
public final int channelCount;
|
||||
|
||||
@Nullable private final ExoMediaCrypto exoMediaCrypto;
|
||||
@Nullable private final CryptoConfig cryptoConfig;
|
||||
private final int preSkipSamples;
|
||||
private final int seekPreRollSamples;
|
||||
private final long nativeDecoderContext;
|
||||
@ -60,8 +60,8 @@ public final class OpusDecoder
|
||||
* @param initializationData Codec-specific initialization data. The first element must contain an
|
||||
* opus header. Optionally, the list may contain two additional buffers, which must contain
|
||||
* the encoder delay and seek pre roll values in nanoseconds, encoded as longs.
|
||||
* @param exoMediaCrypto The {@link ExoMediaCrypto} object required for decoding encrypted
|
||||
* content. Maybe null and can be ignored if decoder does not handle encrypted content.
|
||||
* @param cryptoConfig The {@link CryptoConfig} object required for decoding encrypted content.
|
||||
* May be null and can be ignored if decoder does not handle encrypted content.
|
||||
* @param outputFloat Forces the decoder to output float PCM samples when set
|
||||
* @throws OpusDecoderException Thrown if an exception occurs when initializing the decoder.
|
||||
*/
|
||||
@ -70,15 +70,15 @@ public final class OpusDecoder
|
||||
int numOutputBuffers,
|
||||
int initialInputBufferSize,
|
||||
List<byte[]> initializationData,
|
||||
@Nullable ExoMediaCrypto exoMediaCrypto,
|
||||
@Nullable CryptoConfig cryptoConfig,
|
||||
boolean outputFloat)
|
||||
throws OpusDecoderException {
|
||||
super(new DecoderInputBuffer[numInputBuffers], new SimpleOutputBuffer[numOutputBuffers]);
|
||||
if (!OpusLibrary.isAvailable()) {
|
||||
throw new OpusDecoderException("Failed to load decoder native libraries");
|
||||
}
|
||||
this.exoMediaCrypto = exoMediaCrypto;
|
||||
if (exoMediaCrypto != null && !OpusLibrary.opusIsSecureDecodeSupported()) {
|
||||
this.cryptoConfig = cryptoConfig;
|
||||
if (cryptoConfig != null && !OpusLibrary.opusIsSecureDecodeSupported()) {
|
||||
throw new OpusDecoderException("Opus decoder does not support secure decode");
|
||||
}
|
||||
int initializationDataSize = initializationData.size();
|
||||
@ -177,7 +177,7 @@ public final class OpusDecoder
|
||||
inputData.limit(),
|
||||
outputBuffer,
|
||||
OpusUtil.SAMPLE_RATE,
|
||||
exoMediaCrypto,
|
||||
cryptoConfig,
|
||||
cryptoInfo.mode,
|
||||
Assertions.checkNotNull(cryptoInfo.key),
|
||||
Assertions.checkNotNull(cryptoInfo.iv),
|
||||
@ -248,7 +248,7 @@ public final class OpusDecoder
|
||||
int inputSize,
|
||||
SimpleOutputBuffer outputBuffer,
|
||||
int sampleRate,
|
||||
@Nullable ExoMediaCrypto mediaCrypto,
|
||||
@Nullable CryptoConfig mediaCrypto,
|
||||
int inputMode,
|
||||
byte[] key,
|
||||
byte[] iv,
|
||||
|
@ -16,10 +16,9 @@
|
||||
package com.google.android.exoplayer2.ext.opus;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
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.Util;
|
||||
|
||||
/** Configures and queries the underlying native library. */
|
||||
public final class OpusLibrary {
|
||||
@ -29,7 +28,7 @@ public final class OpusLibrary {
|
||||
}
|
||||
|
||||
private static final LibraryLoader LOADER = new LibraryLoader("opusV2JNI");
|
||||
@Nullable private static Class<? extends ExoMediaCrypto> exoMediaCryptoType;
|
||||
@C.CryptoType private static int cryptoType = C.CRYPTO_TYPE_UNSUPPORTED;
|
||||
|
||||
private OpusLibrary() {}
|
||||
|
||||
@ -38,14 +37,14 @@ public final class OpusLibrary {
|
||||
* it must do so before calling any other method defined by this class, and before instantiating a
|
||||
* {@link LibopusAudioRenderer} instance.
|
||||
*
|
||||
* @param exoMediaCryptoType The {@link ExoMediaCrypto} type expected for decoding protected
|
||||
* content.
|
||||
* @param cryptoType The {@link C.CryptoType} for which the decoder library supports decrypting
|
||||
* protected content, or {@link C#CRYPTO_TYPE_UNSUPPORTED} if the library does not support
|
||||
* decryption.
|
||||
* @param libraries The names of the Opus native libraries.
|
||||
*/
|
||||
public static void setLibraries(
|
||||
Class<? extends ExoMediaCrypto> exoMediaCryptoType, String... libraries) {
|
||||
public static void setLibraries(@C.CryptoType int cryptoType, String... libraries) {
|
||||
OpusLibrary.cryptoType = cryptoType;
|
||||
LOADER.setLibraries(libraries);
|
||||
OpusLibrary.exoMediaCryptoType = exoMediaCryptoType;
|
||||
}
|
||||
|
||||
/** Returns whether the underlying library is available, loading it if necessary. */
|
||||
@ -59,13 +58,10 @@ public final class OpusLibrary {
|
||||
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);
|
||||
/** Returns whether the library supports the given {@link C.CryptoType}. */
|
||||
public static boolean supportsCryptoType(@C.CryptoType int cryptoType) {
|
||||
return cryptoType == C.CRYPTO_TYPE_NONE
|
||||
|| (cryptoType != C.CRYPTO_TYPE_UNSUPPORTED && cryptoType == OpusLibrary.cryptoType);
|
||||
}
|
||||
|
||||
public static native String opusGetVersion();
|
||||
|
@ -24,8 +24,8 @@ import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.TraceUtil;
|
||||
import com.google.android.exoplayer2.video.DecoderVideoRenderer;
|
||||
@ -129,9 +129,7 @@ public class LibvpxVideoRenderer extends DecoderVideoRenderer {
|
||||
if (!VpxLibrary.isAvailable() || !MimeTypes.VIDEO_VP9.equalsIgnoreCase(format.sampleMimeType)) {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
|
||||
}
|
||||
boolean drmIsSupported =
|
||||
format.exoMediaCryptoType == null
|
||||
|| VpxLibrary.matchesExpectedExoMediaCryptoType(format.exoMediaCryptoType);
|
||||
boolean drmIsSupported = VpxLibrary.supportsCryptoType(format.cryptoType);
|
||||
if (!drmIsSupported) {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_DRM);
|
||||
}
|
||||
@ -140,14 +138,14 @@ public class LibvpxVideoRenderer extends DecoderVideoRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VpxDecoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
|
||||
protected VpxDecoder createDecoder(Format format, @Nullable CryptoConfig cryptoConfig)
|
||||
throws VpxDecoderException {
|
||||
TraceUtil.beginSection("createVpxDecoder");
|
||||
int initialInputBufferSize =
|
||||
format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE;
|
||||
VpxDecoder decoder =
|
||||
new VpxDecoder(
|
||||
numInputBuffers, numOutputBuffers, initialInputBufferSize, mediaCrypto, threads);
|
||||
numInputBuffers, numOutputBuffers, initialInputBufferSize, cryptoConfig, threads);
|
||||
this.decoder = decoder;
|
||||
TraceUtil.endSection();
|
||||
return decoder;
|
||||
|
@ -21,11 +21,11 @@ import android.view.Surface;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.CryptoException;
|
||||
import com.google.android.exoplayer2.decoder.CryptoInfo;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.video.VideoDecoderInputBuffer;
|
||||
@ -43,7 +43,7 @@ public final class VpxDecoder
|
||||
private static final int DECODE_ERROR = -1;
|
||||
private static final int DRM_ERROR = -2;
|
||||
|
||||
@Nullable private final ExoMediaCrypto exoMediaCrypto;
|
||||
@Nullable private final CryptoConfig cryptoConfig;
|
||||
private final long vpxDecContext;
|
||||
|
||||
@Nullable private ByteBuffer lastSupplementalData;
|
||||
@ -56,8 +56,8 @@ public final class VpxDecoder
|
||||
* @param numInputBuffers The number of input buffers.
|
||||
* @param numOutputBuffers The number of output buffers.
|
||||
* @param initialInputBufferSize The initial size of each input buffer.
|
||||
* @param exoMediaCrypto The {@link ExoMediaCrypto} object required for decoding encrypted
|
||||
* content. Maybe null and can be ignored if decoder does not handle encrypted content.
|
||||
* @param cryptoConfig The {@link CryptoConfig} object required for decoding encrypted content.
|
||||
* May be null and can be ignored if decoder does not handle encrypted content.
|
||||
* @param threads Number of threads libvpx will use to decode.
|
||||
* @throws VpxDecoderException Thrown if an exception occurs when initializing the decoder.
|
||||
*/
|
||||
@ -65,7 +65,7 @@ public final class VpxDecoder
|
||||
int numInputBuffers,
|
||||
int numOutputBuffers,
|
||||
int initialInputBufferSize,
|
||||
@Nullable ExoMediaCrypto exoMediaCrypto,
|
||||
@Nullable CryptoConfig cryptoConfig,
|
||||
int threads)
|
||||
throws VpxDecoderException {
|
||||
super(
|
||||
@ -74,8 +74,8 @@ public final class VpxDecoder
|
||||
if (!VpxLibrary.isAvailable()) {
|
||||
throw new VpxDecoderException("Failed to load decoder native libraries.");
|
||||
}
|
||||
this.exoMediaCrypto = exoMediaCrypto;
|
||||
if (exoMediaCrypto != null && !VpxLibrary.vpxIsSecureDecodeSupported()) {
|
||||
this.cryptoConfig = cryptoConfig;
|
||||
if (cryptoConfig != null && !VpxLibrary.vpxIsSecureDecodeSupported()) {
|
||||
throw new VpxDecoderException("Vpx decoder does not support secure decode.");
|
||||
}
|
||||
vpxDecContext =
|
||||
@ -134,7 +134,7 @@ public final class VpxDecoder
|
||||
vpxDecContext,
|
||||
inputData,
|
||||
inputSize,
|
||||
exoMediaCrypto,
|
||||
cryptoConfig,
|
||||
cryptoInfo.mode,
|
||||
Assertions.checkNotNull(cryptoInfo.key),
|
||||
Assertions.checkNotNull(cryptoInfo.iv),
|
||||
@ -215,7 +215,7 @@ public final class VpxDecoder
|
||||
long context,
|
||||
ByteBuffer encoded,
|
||||
int length,
|
||||
@Nullable ExoMediaCrypto mediaCrypto,
|
||||
@Nullable CryptoConfig mediaCrypto,
|
||||
int inputMode,
|
||||
byte[] key,
|
||||
byte[] iv,
|
||||
|
@ -16,10 +16,9 @@
|
||||
package com.google.android.exoplayer2.ext.vp9;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
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.Util;
|
||||
|
||||
/** Configures and queries the underlying native library. */
|
||||
public final class VpxLibrary {
|
||||
@ -29,7 +28,7 @@ public final class VpxLibrary {
|
||||
}
|
||||
|
||||
private static final LibraryLoader LOADER = new LibraryLoader("vpx", "vpxV2JNI");
|
||||
@Nullable private static Class<? extends ExoMediaCrypto> exoMediaCryptoType;
|
||||
@C.CryptoType private static int cryptoType = C.CRYPTO_TYPE_UNSUPPORTED;
|
||||
|
||||
private VpxLibrary() {}
|
||||
|
||||
@ -38,14 +37,14 @@ public final class VpxLibrary {
|
||||
* it must do so before calling any other method defined by this class, and before instantiating a
|
||||
* {@link LibvpxVideoRenderer} instance.
|
||||
*
|
||||
* @param exoMediaCryptoType The {@link ExoMediaCrypto} type required for decoding protected
|
||||
* content.
|
||||
* @param cryptoType The {@link C.CryptoType} for which the decoder library supports decrypting
|
||||
* protected content, or {@link C#CRYPTO_TYPE_UNSUPPORTED} if the library does not support
|
||||
* decryption.
|
||||
* @param libraries The names of the Vpx native libraries.
|
||||
*/
|
||||
public static void setLibraries(
|
||||
Class<? extends ExoMediaCrypto> exoMediaCryptoType, String... libraries) {
|
||||
public static void setLibraries(@C.CryptoType int cryptoType, String... libraries) {
|
||||
VpxLibrary.cryptoType = cryptoType;
|
||||
LOADER.setLibraries(libraries);
|
||||
VpxLibrary.exoMediaCryptoType = exoMediaCryptoType;
|
||||
}
|
||||
|
||||
/** Returns whether the underlying library is available, loading it if necessary. */
|
||||
@ -75,13 +74,10 @@ public final class VpxLibrary {
|
||||
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);
|
||||
/** Returns whether the library supports the given {@link C.CryptoType}. */
|
||||
public static boolean supportsCryptoType(@C.CryptoType int cryptoType) {
|
||||
return cryptoType == C.CRYPTO_TYPE_NONE
|
||||
|| (cryptoType != C.CRYPTO_TYPE_UNSUPPORTED && cryptoType == VpxLibrary.cryptoType);
|
||||
}
|
||||
|
||||
private static native String vpxGetVersion();
|
||||
|
@ -20,6 +20,7 @@ import android.media.AudioAttributes;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
import android.view.Surface;
|
||||
import androidx.annotation.IntDef;
|
||||
@ -116,6 +117,33 @@ public final class C {
|
||||
/** The name of the sans-serif font family. */
|
||||
public static final String SANS_SERIF_NAME = "sans-serif";
|
||||
|
||||
/**
|
||||
* Types of crypto implementation. May be one of {@link #CRYPTO_TYPE_NONE}, {@link
|
||||
* #CRYPTO_TYPE_UNSUPPORTED} or {@link #CRYPTO_TYPE_FRAMEWORK}. May also be an app-defined value
|
||||
* (see {@link #CRYPTO_TYPE_CUSTOM_BASE}).
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(
|
||||
open = true,
|
||||
value = {
|
||||
CRYPTO_TYPE_UNSUPPORTED,
|
||||
CRYPTO_TYPE_NONE,
|
||||
CRYPTO_TYPE_FRAMEWORK,
|
||||
})
|
||||
public @interface CryptoType {}
|
||||
/** No crypto. */
|
||||
public static final int CRYPTO_TYPE_NONE = 0;
|
||||
/** An unsupported crypto type. */
|
||||
public static final int CRYPTO_TYPE_UNSUPPORTED = 1;
|
||||
/** Framework crypto in which a {@link MediaCodec} is configured with a {@link MediaCrypto}. */
|
||||
public static final int CRYPTO_TYPE_FRAMEWORK = 2;
|
||||
/**
|
||||
* Applications or extensions may define custom {@code CRYPTO_TYPE_*} constants greater than or
|
||||
* equal to this value.
|
||||
*/
|
||||
public static final int CRYPTO_TYPE_CUSTOM_BASE = 10000;
|
||||
|
||||
/**
|
||||
* Crypto modes for a codec. One of {@link #CRYPTO_MODE_UNENCRYPTED}, {@link #CRYPTO_MODE_AES_CTR}
|
||||
* or {@link #CRYPTO_MODE_AES_CBC}.
|
||||
|
@ -19,8 +19,6 @@ import android.os.Bundle;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.drm.UnsupportedMediaCrypto;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.util.BundleableUtils;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
@ -174,7 +172,7 @@ public final class Format implements Bundleable {
|
||||
|
||||
// Provided by the source.
|
||||
|
||||
@Nullable private Class<? extends ExoMediaCrypto> exoMediaCryptoType;
|
||||
@C.CryptoType private int cryptoType;
|
||||
|
||||
/** Creates a new instance with default values. */
|
||||
public Builder() {
|
||||
@ -195,6 +193,8 @@ public final class Format implements Bundleable {
|
||||
pcmEncoding = NO_VALUE;
|
||||
// Text specific.
|
||||
accessibilityChannel = NO_VALUE;
|
||||
// Provided by the source.
|
||||
cryptoType = C.CRYPTO_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -238,7 +238,7 @@ public final class Format implements Bundleable {
|
||||
// Text specific.
|
||||
this.accessibilityChannel = format.accessibilityChannel;
|
||||
// Provided by the source.
|
||||
this.exoMediaCryptoType = format.exoMediaCryptoType;
|
||||
this.cryptoType = format.cryptoType;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -585,14 +585,13 @@ public final class Format implements Bundleable {
|
||||
// Provided by source.
|
||||
|
||||
/**
|
||||
* Sets {@link Format#exoMediaCryptoType}. The default value is {@code null}.
|
||||
* Sets {@link Format#cryptoType}. The default value is {@link C#CRYPTO_TYPE_NONE}.
|
||||
*
|
||||
* @param exoMediaCryptoType The {@link Format#exoMediaCryptoType}.
|
||||
* @param cryptoType The {@link C.CryptoType}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setExoMediaCryptoType(
|
||||
@Nullable Class<? extends ExoMediaCrypto> exoMediaCryptoType) {
|
||||
this.exoMediaCryptoType = exoMediaCryptoType;
|
||||
public Builder setCryptoType(@C.CryptoType int cryptoType) {
|
||||
this.cryptoType = cryptoType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -756,11 +755,12 @@ public final class Format implements Bundleable {
|
||||
// Provided by source.
|
||||
|
||||
/**
|
||||
* The type of {@link ExoMediaCrypto} that will be associated with the content this format
|
||||
* describes, or {@code null} if the content is not encrypted. Cannot be null if {@link
|
||||
* #drmInitData} is non-null.
|
||||
* The type of crypto that must be used to decode samples associated with this format, or {@link
|
||||
* C#CRYPTO_TYPE_NONE} if the content is not encrypted. Cannot be {@link C#CRYPTO_TYPE_NONE} if
|
||||
* {@link #drmInitData} is non-null, but may be {@link C#CRYPTO_TYPE_UNSUPPORTED} to indicate that
|
||||
* the samples are encrypted using an unsupported crypto type.
|
||||
*/
|
||||
@Nullable public final Class<? extends ExoMediaCrypto> exoMediaCryptoType;
|
||||
@C.CryptoType public final int cryptoType;
|
||||
|
||||
// Lazily initialized hashcode.
|
||||
private int hashCode;
|
||||
@ -964,11 +964,11 @@ public final class Format implements Bundleable {
|
||||
// Text specific.
|
||||
accessibilityChannel = builder.accessibilityChannel;
|
||||
// Provided by source.
|
||||
if (builder.exoMediaCryptoType == null && drmInitData != null) {
|
||||
// Encrypted content must always have a non-null exoMediaCryptoType.
|
||||
exoMediaCryptoType = UnsupportedMediaCrypto.class;
|
||||
if (builder.cryptoType == C.CRYPTO_TYPE_NONE && drmInitData != null) {
|
||||
// Encrypted content cannot use CRYPTO_TYPE_NONE.
|
||||
cryptoType = C.CRYPTO_TYPE_UNSUPPORTED;
|
||||
} else {
|
||||
exoMediaCryptoType = builder.exoMediaCryptoType;
|
||||
cryptoType = builder.cryptoType;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1113,10 +1113,9 @@ public final class Format implements Bundleable {
|
||||
return buildUpon().setWidth(width).setHeight(height).build();
|
||||
}
|
||||
|
||||
/** Returns a copy of this format with the specified {@link #exoMediaCryptoType}. */
|
||||
public Format copyWithExoMediaCryptoType(
|
||||
@Nullable Class<? extends ExoMediaCrypto> exoMediaCryptoType) {
|
||||
return buildUpon().setExoMediaCryptoType(exoMediaCryptoType).build();
|
||||
/** Returns a copy of this format with the specified {@link #cryptoType}. */
|
||||
public Format copyWithCryptoType(@C.CryptoType int cryptoType) {
|
||||
return buildUpon().setCryptoType(cryptoType).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1197,7 +1196,7 @@ public final class Format implements Bundleable {
|
||||
// Text specific.
|
||||
result = 31 * result + accessibilityChannel;
|
||||
// Provided by the source.
|
||||
result = 31 * result + (exoMediaCryptoType == null ? 0 : exoMediaCryptoType.hashCode());
|
||||
result = 31 * result + cryptoType;
|
||||
hashCode = result;
|
||||
}
|
||||
return hashCode;
|
||||
@ -1232,9 +1231,9 @@ public final class Format implements Bundleable {
|
||||
&& encoderDelay == other.encoderDelay
|
||||
&& encoderPadding == other.encoderPadding
|
||||
&& accessibilityChannel == other.accessibilityChannel
|
||||
&& cryptoType == other.cryptoType
|
||||
&& Float.compare(frameRate, other.frameRate) == 0
|
||||
&& Float.compare(pixelWidthHeightRatio, other.pixelWidthHeightRatio) == 0
|
||||
&& Util.areEqual(exoMediaCryptoType, other.exoMediaCryptoType)
|
||||
&& Util.areEqual(id, other.id)
|
||||
&& Util.areEqual(label, other.label)
|
||||
&& Util.areEqual(codecs, other.codecs)
|
||||
@ -1360,6 +1359,7 @@ public final class Format implements Bundleable {
|
||||
FIELD_ENCODER_DELAY,
|
||||
FIELD_ENCODER_PADDING,
|
||||
FIELD_ACCESSIBILITY_CHANNEL,
|
||||
FIELD_CRYPTO_TYPE,
|
||||
})
|
||||
private @interface FieldNumber {}
|
||||
|
||||
@ -1392,13 +1392,8 @@ public final class Format implements Bundleable {
|
||||
private static final int FIELD_ENCODER_DELAY = 26;
|
||||
private static final int FIELD_ENCODER_PADDING = 27;
|
||||
private static final int FIELD_ACCESSIBILITY_CHANNEL = 28;
|
||||
private static final int FIELD_CRYPTO_TYPE = 29;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>Omits the {@link #exoMediaCryptoType} field. The {@link #exoMediaCryptoType} of an instance
|
||||
* restored by {@link #CREATOR} will always be {@link UnsupportedMediaCrypto}.
|
||||
*/
|
||||
@Override
|
||||
public Bundle toBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
@ -1443,6 +1438,8 @@ public final class Format implements Bundleable {
|
||||
bundle.putInt(keyForField(FIELD_ENCODER_PADDING), encoderPadding);
|
||||
// Text specific.
|
||||
bundle.putInt(keyForField(FIELD_ACCESSIBILITY_CHANNEL), accessibilityChannel);
|
||||
// Source specific.
|
||||
bundle.putInt(keyForField(FIELD_CRYPTO_TYPE), cryptoType);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@ -1512,7 +1509,9 @@ public final class Format implements Bundleable {
|
||||
bundle.getInt(keyForField(FIELD_ENCODER_PADDING), DEFAULT.encoderPadding))
|
||||
// Text specific.
|
||||
.setAccessibilityChannel(
|
||||
bundle.getInt(keyForField(FIELD_ACCESSIBILITY_CHANNEL), DEFAULT.accessibilityChannel));
|
||||
bundle.getInt(keyForField(FIELD_ACCESSIBILITY_CHANNEL), DEFAULT.accessibilityChannel))
|
||||
// Source specific.
|
||||
.setCryptoType(bundle.getInt(keyForField(FIELD_CRYPTO_TYPE), DEFAULT.cryptoType));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -13,7 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
/** Enables decoding of encrypted data using keys in a DRM session. */
|
||||
public interface ExoMediaCrypto {}
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
||||
/**
|
||||
* Configuration for a decoder to allow it to decode encrypted media data. The configuration is
|
||||
* {@link C.CryptoType} specific.
|
||||
*/
|
||||
public interface CryptoConfig {}
|
@ -21,7 +21,11 @@ import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/** Compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}. */
|
||||
/**
|
||||
* Metadata describing the structure of an encrypted input sample.
|
||||
*
|
||||
* <p>This class is a compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}.
|
||||
*/
|
||||
public final class CryptoInfo {
|
||||
|
||||
/**
|
||||
|
@ -22,8 +22,6 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.drm.UnsupportedMediaCrypto;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
@ -45,15 +43,11 @@ public final class FormatTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundTripViaBundle_ofParameters_yieldsEqualInstanceExceptExoMediaCryptoType() {
|
||||
public void roundTripViaBundle_ofParameters_yieldsEqualInstance() {
|
||||
Format formatToBundle = createTestFormat();
|
||||
|
||||
Format formatFromBundle = Format.CREATOR.fromBundle(formatToBundle.toBundle());
|
||||
|
||||
assertThat(formatFromBundle.exoMediaCryptoType).isEqualTo(UnsupportedMediaCrypto.class);
|
||||
assertThat(formatFromBundle)
|
||||
.isEqualTo(
|
||||
formatToBundle.buildUpon().setExoMediaCryptoType(UnsupportedMediaCrypto.class).build());
|
||||
assertThat(formatFromBundle).isEqualTo(formatToBundle);
|
||||
}
|
||||
|
||||
private static Format createTestFormat() {
|
||||
@ -93,7 +87,7 @@ public final class FormatTest {
|
||||
.setPeakBitrate(2048)
|
||||
.setCodecs("codec")
|
||||
.setMetadata(metadata)
|
||||
.setContainerMimeType(MimeTypes.VIDEO_MP4)
|
||||
.setContainerMimeType(VIDEO_MP4)
|
||||
.setSampleMimeType(MimeTypes.VIDEO_H264)
|
||||
.setMaxInputSize(5000)
|
||||
.setInitializationData(initializationData)
|
||||
@ -113,7 +107,7 @@ public final class FormatTest {
|
||||
.setEncoderDelay(1001)
|
||||
.setEncoderPadding(1002)
|
||||
.setAccessibilityChannel(2)
|
||||
.setExoMediaCryptoType(ExoMediaCrypto.class)
|
||||
.setCryptoType(C.CRYPTO_TYPE_CUSTOM_BASE)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ import com.google.android.exoplayer2.PlayerMessage.Target;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.audio.AudioSink.SinkFormatSupport;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.Decoder;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.decoder.DecoderException;
|
||||
@ -46,7 +47,6 @@ import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
|
||||
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
@ -330,12 +330,12 @@ public abstract class DecoderAudioRenderer<
|
||||
* Creates a decoder for the given format.
|
||||
*
|
||||
* @param format The format for which a decoder is required.
|
||||
* @param mediaCrypto The {@link ExoMediaCrypto} object required for decoding encrypted content.
|
||||
* Maybe null and can be ignored if decoder does not handle encrypted content.
|
||||
* @param cryptoConfig The {@link CryptoConfig} object required for decoding encrypted content.
|
||||
* May be null and can be ignored if decoder does not handle encrypted content.
|
||||
* @return The decoder.
|
||||
* @throws DecoderException If an error occurred creating a suitable decoder.
|
||||
*/
|
||||
protected abstract T createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto)
|
||||
protected abstract T createDecoder(Format format, @Nullable CryptoConfig cryptoConfig)
|
||||
throws DecoderException;
|
||||
|
||||
/**
|
||||
@ -603,10 +603,10 @@ public abstract class DecoderAudioRenderer<
|
||||
|
||||
setDecoderDrmSession(sourceDrmSession);
|
||||
|
||||
ExoMediaCrypto mediaCrypto = null;
|
||||
CryptoConfig cryptoConfig = null;
|
||||
if (decoderDrmSession != null) {
|
||||
mediaCrypto = decoderDrmSession.getMediaCrypto();
|
||||
if (mediaCrypto == null) {
|
||||
cryptoConfig = decoderDrmSession.getCryptoConfig();
|
||||
if (cryptoConfig == null) {
|
||||
DrmSessionException drmError = decoderDrmSession.getError();
|
||||
if (drmError != null) {
|
||||
// Continue for now. We may be able to avoid failure if a new input format causes the
|
||||
@ -621,7 +621,7 @@ public abstract class DecoderAudioRenderer<
|
||||
try {
|
||||
long codecInitializingTimestamp = SystemClock.elapsedRealtime();
|
||||
TraceUtil.beginSection("createAudioDecoder");
|
||||
decoder = createDecoder(inputFormat, mediaCrypto);
|
||||
decoder = createDecoder(inputFormat, cryptoConfig);
|
||||
TraceUtil.endSection();
|
||||
long codecInitializedTimestamp = SystemClock.elapsedRealtime();
|
||||
eventDispatcher.decoderInitialized(
|
||||
|
@ -272,7 +272,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
}
|
||||
@TunnelingSupport
|
||||
int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED;
|
||||
boolean formatHasDrm = format.exoMediaCryptoType != null;
|
||||
boolean formatHasDrm = format.cryptoType != C.CRYPTO_TYPE_NONE;
|
||||
boolean supportsFormatDrm = supportsFormatDrm(format);
|
||||
// In direct mode, if the format has DRM then we need to use a decoder that only decrypts.
|
||||
// Else we don't don't need a decoder at all.
|
||||
|
@ -31,6 +31,7 @@ import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
@ -141,7 +142,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
private int referenceCount;
|
||||
@Nullable private HandlerThread requestHandlerThread;
|
||||
@Nullable private RequestHandler requestHandler;
|
||||
@Nullable private ExoMediaCrypto mediaCrypto;
|
||||
@Nullable private CryptoConfig cryptoConfig;
|
||||
@Nullable private DrmSessionException lastException;
|
||||
@Nullable private byte[] sessionId;
|
||||
private byte @MonotonicNonNull [] offlineLicenseKeySetId;
|
||||
@ -260,7 +261,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable DrmSessionException getError() {
|
||||
@Nullable
|
||||
public final DrmSessionException getError() {
|
||||
return state == STATE_ERROR ? lastException : null;
|
||||
}
|
||||
|
||||
@ -270,8 +272,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable ExoMediaCrypto getMediaCrypto() {
|
||||
return mediaCrypto;
|
||||
@Nullable
|
||||
public final CryptoConfig getCryptoConfig() {
|
||||
return cryptoConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -326,7 +329,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
requestHandler = null;
|
||||
Util.castNonNull(requestHandlerThread).quit();
|
||||
requestHandlerThread = null;
|
||||
mediaCrypto = null;
|
||||
cryptoConfig = null;
|
||||
lastException = null;
|
||||
currentKeyRequest = null;
|
||||
currentProvisionRequest = null;
|
||||
@ -361,7 +364,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
try {
|
||||
sessionId = mediaDrm.openSession();
|
||||
mediaCrypto = mediaDrm.createMediaCrypto(sessionId);
|
||||
cryptoConfig = mediaDrm.createCryptoConfig(sessionId);
|
||||
state = STATE_OPENED;
|
||||
// Capture state into a local so a consistent value is seen by the lambda.
|
||||
int localState = state;
|
||||
|
@ -579,19 +579,16 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Class<? extends ExoMediaCrypto> getExoMediaCryptoType(Format format) {
|
||||
Class<? extends ExoMediaCrypto> exoMediaCryptoType =
|
||||
checkNotNull(exoMediaDrm).getExoMediaCryptoType();
|
||||
@C.CryptoType
|
||||
public int getCryptoType(Format format) {
|
||||
@C.CryptoType int cryptoType = checkNotNull(exoMediaDrm).getCryptoType();
|
||||
if (format.drmInitData == null) {
|
||||
int trackType = MimeTypes.getTrackType(format.sampleMimeType);
|
||||
return Util.linearSearch(useDrmSessionsForClearContentTrackTypes, trackType) != C.INDEX_UNSET
|
||||
? exoMediaCryptoType
|
||||
: null;
|
||||
? cryptoType
|
||||
: C.CRYPTO_TYPE_NONE;
|
||||
} else {
|
||||
return canAcquireSession(format.drmInitData)
|
||||
? exoMediaCryptoType
|
||||
: UnsupportedMediaCrypto.class;
|
||||
return canAcquireSession(format.drmInitData) ? cryptoType : C.CRYPTO_TYPE_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -602,12 +599,12 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
||||
int trackType, boolean shouldReleasePreacquiredSessionsBeforeRetrying) {
|
||||
ExoMediaDrm exoMediaDrm = checkNotNull(this.exoMediaDrm);
|
||||
boolean avoidPlaceholderDrmSessions =
|
||||
FrameworkMediaCrypto.class.equals(exoMediaDrm.getExoMediaCryptoType())
|
||||
&& FrameworkMediaCrypto.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC;
|
||||
exoMediaDrm.getCryptoType() == C.CRYPTO_TYPE_FRAMEWORK
|
||||
&& FrameworkCryptoConfig.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC;
|
||||
// Avoid attaching a session to sparse formats.
|
||||
if (avoidPlaceholderDrmSessions
|
||||
|| Util.linearSearch(useDrmSessionsForClearContentTrackTypes, trackType) == C.INDEX_UNSET
|
||||
|| UnsupportedMediaCrypto.class.equals(exoMediaDrm.getExoMediaCryptoType())) {
|
||||
|| exoMediaDrm.getCryptoType() == C.CRYPTO_TYPE_UNSUPPORTED) {
|
||||
return null;
|
||||
}
|
||||
if (placeholderDrmSession == null) {
|
||||
|
@ -19,6 +19,7 @@ import android.media.MediaDrm;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
@ -109,11 +110,11 @@ public interface DrmSession {
|
||||
UUID getSchemeUuid();
|
||||
|
||||
/**
|
||||
* Returns an {@link ExoMediaCrypto} for the open session, or null if called before the session
|
||||
* has been opened or after it's been released.
|
||||
* Returns a {@link CryptoConfig} for the open session, or null if called before the session has
|
||||
* been opened or after it's been released.
|
||||
*/
|
||||
@Nullable
|
||||
ExoMediaCrypto getMediaCrypto();
|
||||
CryptoConfig getCryptoConfig();
|
||||
|
||||
/**
|
||||
* Returns a map describing the key status for the session, or null if called before the session
|
||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
|
||||
@ -61,9 +62,9 @@ public interface DrmSessionManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Class<UnsupportedMediaCrypto> getExoMediaCryptoType(Format format) {
|
||||
return format.drmInitData != null ? UnsupportedMediaCrypto.class : null;
|
||||
@C.CryptoType
|
||||
public int getCryptoType(Format format) {
|
||||
return format.drmInitData != null ? C.CRYPTO_TYPE_UNSUPPORTED : C.CRYPTO_TYPE_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
@ -171,19 +172,18 @@ public interface DrmSessionManager {
|
||||
Format format);
|
||||
|
||||
/**
|
||||
* Returns the {@link ExoMediaCrypto} type associated to sessions acquired for the given {@link
|
||||
* Format}. Returns the {@link UnsupportedMediaCrypto} type if this DRM session manager does not
|
||||
* support any of the DRM schemes defined in the given {@link Format}. Returns null if {@link
|
||||
* Format#drmInitData} is null and {@link #acquireSession} would return null for the given {@link
|
||||
* Format}.
|
||||
*
|
||||
* @param format The {@link Format} for which to return the {@link ExoMediaCrypto} type.
|
||||
* @return The {@link ExoMediaCrypto} type associated to sessions acquired using the given {@link
|
||||
* Format}, or {@link UnsupportedMediaCrypto} if this DRM session manager does not support any
|
||||
* of the DRM schemes defined in the given {@link Format}. May be null if {@link
|
||||
* Format#drmInitData} is null and {@link #acquireSession} would return null for the given
|
||||
* Returns the {@link C.CryptoType} that the DRM session manager will use for a given {@link
|
||||
* Format}. Returns {@link C#CRYPTO_TYPE_UNSUPPORTED} if the manager does not support any of the
|
||||
* DRM schemes defined in the {@link Format}. Returns {@link C#CRYPTO_TYPE_NONE} if {@link
|
||||
* Format#drmInitData} is null and {@link #acquireSession} will return {@code null} for the given
|
||||
* {@link Format}.
|
||||
*
|
||||
* @param format The {@link Format}.
|
||||
* @return The {@link C.CryptoType} that the manager will use, or @link C#CRYPTO_TYPE_UNSUPPORTED}
|
||||
* if the manager does not support any of the DRM schemes defined in the {@link Format}. Will
|
||||
* be {@link C#CRYPTO_TYPE_NONE} if {@link Format#drmInitData} is null and {@link
|
||||
* #acquireSession} will return null for the given {@link Format}.
|
||||
*/
|
||||
@Nullable
|
||||
Class<? extends ExoMediaCrypto> getExoMediaCryptoType(Format format);
|
||||
@C.CryptoType
|
||||
int getCryptoType(Format format);
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import android.media.MediaDrmException;
|
||||
import android.os.PersistableBundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -142,13 +144,14 @@ public final class DummyExoMediaDrm implements ExoMediaDrm {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExoMediaCrypto createMediaCrypto(byte[] sessionId) {
|
||||
public CryptoConfig createCryptoConfig(byte[] sessionId) {
|
||||
// Should not be invoked. No session should exist.
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<UnsupportedMediaCrypto> getExoMediaCryptoType() {
|
||||
return UnsupportedMediaCrypto.class;
|
||||
@C.CryptoType
|
||||
public int getCryptoType() {
|
||||
return C.CRYPTO_TYPE_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.drm;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -53,7 +54,7 @@ public final class ErrorStateDrmSession implements DrmSession {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ExoMediaCrypto getMediaCrypto() {
|
||||
public CryptoConfig getCryptoConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@ import android.os.Handler;
|
||||
import android.os.PersistableBundle;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
@ -538,14 +540,19 @@ public interface ExoMediaDrm {
|
||||
void setPropertyByteArray(String propertyName, byte[] value);
|
||||
|
||||
/**
|
||||
* Creates an {@link ExoMediaCrypto} for a given session.
|
||||
* Creates a {@link CryptoConfig} that can be passed to a compatible decoder to allow decryption
|
||||
* of protected content using the specified session.
|
||||
*
|
||||
* @param sessionId The ID of the session.
|
||||
* @return An {@link ExoMediaCrypto} for the given session.
|
||||
* @throws MediaCryptoException If an {@link ExoMediaCrypto} could not be created.
|
||||
* @return A {@link CryptoConfig} for the given session.
|
||||
* @throws MediaCryptoException If a {@link CryptoConfig} could not be created.
|
||||
*/
|
||||
ExoMediaCrypto createMediaCrypto(byte[] sessionId) throws MediaCryptoException;
|
||||
CryptoConfig createCryptoConfig(byte[] sessionId) throws MediaCryptoException;
|
||||
|
||||
/** Returns the {@link ExoMediaCrypto} type created by {@link #createMediaCrypto(byte[])}. */
|
||||
Class<? extends ExoMediaCrypto> getExoMediaCryptoType();
|
||||
/**
|
||||
* Returns the {@link C.CryptoType type} of {@link CryptoConfig} instances returned by {@link
|
||||
* #createCryptoConfig}.
|
||||
*/
|
||||
@C.CryptoType
|
||||
int getCryptoType();
|
||||
}
|
||||
|
@ -15,15 +15,19 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCrypto;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* An {@link ExoMediaCrypto} implementation that contains the necessary information to build or
|
||||
* update a framework {@link MediaCrypto}.
|
||||
* A {@link CryptoConfig} for {@link C#CRYPTO_TYPE_FRAMEWORK}. Contains the necessary information to
|
||||
* build or update a framework {@link MediaCrypto} that can be used to configure a {@link
|
||||
* MediaCodec}.
|
||||
*/
|
||||
public final class FrameworkMediaCrypto implements ExoMediaCrypto {
|
||||
public final class FrameworkCryptoConfig implements CryptoConfig {
|
||||
|
||||
/**
|
||||
* Whether the device needs keys to have been loaded into the {@link DrmSession} before codec
|
||||
@ -50,7 +54,7 @@ public final class FrameworkMediaCrypto implements ExoMediaCrypto {
|
||||
* @param forceAllowInsecureDecoderComponents Whether to allow use of insecure decoder components
|
||||
* even if the underlying platform says otherwise.
|
||||
*/
|
||||
public FrameworkMediaCrypto(
|
||||
public FrameworkCryptoConfig(
|
||||
UUID uuid, byte[] sessionId, boolean forceAllowInsecureDecoderComponents) {
|
||||
this.uuid = uuid;
|
||||
this.sessionId = sessionId;
|
@ -314,20 +314,21 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameworkMediaCrypto createMediaCrypto(byte[] sessionId) throws MediaCryptoException {
|
||||
public FrameworkCryptoConfig createCryptoConfig(byte[] sessionId) throws MediaCryptoException {
|
||||
// Work around a bug prior to Lollipop where L1 Widevine forced into L3 mode would still
|
||||
// indicate that it required secure video decoders [Internal ref: b/11428937].
|
||||
boolean forceAllowInsecureDecoderComponents =
|
||||
Util.SDK_INT < 21
|
||||
&& C.WIDEVINE_UUID.equals(uuid)
|
||||
&& "L3".equals(getPropertyString("securityLevel"));
|
||||
return new FrameworkMediaCrypto(
|
||||
return new FrameworkCryptoConfig(
|
||||
adjustUuid(uuid), sessionId, forceAllowInsecureDecoderComponents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<FrameworkMediaCrypto> getExoMediaCryptoType() {
|
||||
return FrameworkMediaCrypto.class;
|
||||
@C.CryptoType
|
||||
public int getCryptoType() {
|
||||
return C.CRYPTO_TYPE_FRAMEWORK;
|
||||
}
|
||||
|
||||
private static SchemeData getSchemeData(UUID uuid, List<SchemeData> schemeDatas) {
|
||||
|
@ -50,6 +50,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer.InsufficientCapacityException;
|
||||
@ -57,8 +58,7 @@ import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
|
||||
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import com.google.android.exoplayer2.drm.FrameworkCryptoConfig;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
@ -545,8 +545,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
if (codecDrmSession != null) {
|
||||
if (mediaCrypto == null) {
|
||||
@Nullable
|
||||
FrameworkMediaCrypto sessionMediaCrypto = getFrameworkMediaCrypto(codecDrmSession);
|
||||
if (sessionMediaCrypto == null) {
|
||||
FrameworkCryptoConfig sessionCryptoConfig = getFrameworkCryptoConfig(codecDrmSession);
|
||||
if (sessionCryptoConfig == null) {
|
||||
@Nullable DrmSessionException drmError = codecDrmSession.getError();
|
||||
if (drmError != null) {
|
||||
// Continue for now. We may be able to avoid failure if a new input format causes the
|
||||
@ -557,17 +557,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
mediaCrypto = new MediaCrypto(sessionMediaCrypto.uuid, sessionMediaCrypto.sessionId);
|
||||
mediaCrypto = new MediaCrypto(sessionCryptoConfig.uuid, sessionCryptoConfig.sessionId);
|
||||
} catch (MediaCryptoException e) {
|
||||
throw createRendererException(
|
||||
e, inputFormat, PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR);
|
||||
}
|
||||
mediaCryptoRequiresSecureDecoder =
|
||||
!sessionMediaCrypto.forceAllowInsecureDecoderComponents
|
||||
!sessionCryptoConfig.forceAllowInsecureDecoderComponents
|
||||
&& mediaCrypto.requiresSecureDecoderComponent(mimeType);
|
||||
}
|
||||
}
|
||||
if (FrameworkMediaCrypto.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC) {
|
||||
if (FrameworkCryptoConfig.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC) {
|
||||
@DrmSession.State int drmSessionState = codecDrmSession.getState();
|
||||
if (drmSessionState == DrmSession.STATE_ERROR) {
|
||||
DrmSessionException drmSessionException =
|
||||
@ -1074,11 +1074,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
return codecInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures rendering where no codec is used. Called instead of {@link
|
||||
* #configureCodec(MediaCodecInfo, MediaCodecAdapter, Format, MediaCrypto, float)} when no codec
|
||||
* is used to render.
|
||||
*/
|
||||
/** Configures rendering where no codec is used. */
|
||||
private void initBypass(Format format) {
|
||||
disableBypass(); // In case of transition between 2 bypass formats.
|
||||
|
||||
@ -2047,8 +2043,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
|
||||
/** Returns whether this renderer supports the given {@link Format Format's} DRM scheme. */
|
||||
protected static boolean supportsFormatDrm(Format format) {
|
||||
return format.exoMediaCryptoType == null
|
||||
|| FrameworkMediaCrypto.class.equals(format.exoMediaCryptoType);
|
||||
return format.cryptoType == C.CRYPTO_TYPE_NONE || format.cryptoType == C.CRYPTO_TYPE_FRAMEWORK;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2088,8 +2083,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
// TODO: Add an API check once [Internal ref: b/128835874] is fixed.
|
||||
return true;
|
||||
}
|
||||
@Nullable FrameworkMediaCrypto newMediaCrypto = getFrameworkMediaCrypto(newSession);
|
||||
if (newMediaCrypto == null) {
|
||||
@Nullable FrameworkCryptoConfig newCryptoConfig = getFrameworkCryptoConfig(newSession);
|
||||
if (newCryptoConfig == null) {
|
||||
// We'd only expect this to happen if the CDM from which newSession is obtained needs
|
||||
// provisioning. This is unlikely to happen (it probably requires a switch from one DRM scheme
|
||||
// to another, where the new CDM hasn't been used before and needs provisioning). It would be
|
||||
@ -2101,7 +2096,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
}
|
||||
|
||||
boolean requiresSecureDecoder;
|
||||
if (newMediaCrypto.forceAllowInsecureDecoderComponents) {
|
||||
if (newCryptoConfig.forceAllowInsecureDecoderComponents) {
|
||||
requiresSecureDecoder = false;
|
||||
} else {
|
||||
requiresSecureDecoder = newSession.requiresSecureDecoder(newFormat.sampleMimeType);
|
||||
@ -2136,7 +2131,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
@RequiresApi(23)
|
||||
private void updateDrmSessionV23() throws ExoPlaybackException {
|
||||
try {
|
||||
mediaCrypto.setMediaDrmSession(getFrameworkMediaCrypto(sourceDrmSession).sessionId);
|
||||
mediaCrypto.setMediaDrmSession(getFrameworkCryptoConfig(sourceDrmSession).sessionId);
|
||||
} catch (MediaCryptoException e) {
|
||||
throw createRendererException(e, inputFormat, PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR);
|
||||
}
|
||||
@ -2146,18 +2141,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private FrameworkMediaCrypto getFrameworkMediaCrypto(DrmSession drmSession)
|
||||
private FrameworkCryptoConfig getFrameworkCryptoConfig(DrmSession drmSession)
|
||||
throws ExoPlaybackException {
|
||||
@Nullable ExoMediaCrypto mediaCrypto = drmSession.getMediaCrypto();
|
||||
if (mediaCrypto != null && !(mediaCrypto instanceof FrameworkMediaCrypto)) {
|
||||
@Nullable CryptoConfig cryptoConfig = drmSession.getCryptoConfig();
|
||||
if (cryptoConfig != null && !(cryptoConfig instanceof FrameworkCryptoConfig)) {
|
||||
// This should not happen if the track went through a supportsFormatDrm() check, during track
|
||||
// selection.
|
||||
throw createRendererException(
|
||||
new IllegalArgumentException("Expecting FrameworkMediaCrypto but found: " + mediaCrypto),
|
||||
new IllegalArgumentException(
|
||||
"Expecting FrameworkCryptoConfig but found: " + cryptoConfig),
|
||||
inputFormat,
|
||||
PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED);
|
||||
}
|
||||
return (FrameworkMediaCrypto) mediaCrypto;
|
||||
return (FrameworkCryptoConfig) cryptoConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,7 +93,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
|
||||
public int supportsFormat(Format format) {
|
||||
if (decoderFactory.supportsFormat(format)) {
|
||||
return RendererCapabilities.create(
|
||||
format.exoMediaCryptoType == null ? C.FORMAT_HANDLED : C.FORMAT_UNSUPPORTED_DRM);
|
||||
format.cryptoType == C.CRYPTO_TYPE_NONE ? C.FORMAT_HANDLED : C.FORMAT_UNSUPPORTED_DRM);
|
||||
} else {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
|
||||
}
|
||||
|
@ -783,9 +783,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
trackFormat = trackFormat.buildUpon().setAverageBitrate(icyHeaders.bitrate).build();
|
||||
}
|
||||
}
|
||||
trackFormat =
|
||||
trackFormat.copyWithExoMediaCryptoType(
|
||||
drmSessionManager.getExoMediaCryptoType(trackFormat));
|
||||
trackFormat = trackFormat.copyWithCryptoType(drmSessionManager.getCryptoType(trackFormat));
|
||||
trackArray[i] = new TrackGroup(trackFormat);
|
||||
}
|
||||
trackState = new TrackState(new TrackGroupArray(trackArray), trackIsAudioVideoFlags);
|
||||
|
@ -899,8 +899,7 @@ public class SampleQueue implements TrackOutput {
|
||||
|
||||
outputFormatHolder.format =
|
||||
drmSessionManager != null
|
||||
? newFormat.copyWithExoMediaCryptoType(
|
||||
drmSessionManager.getExoMediaCryptoType(newFormat))
|
||||
? newFormat.copyWithCryptoType(drmSessionManager.getCryptoType(newFormat))
|
||||
: newFormat;
|
||||
outputFormatHolder.drmSession = currentDrmSession;
|
||||
if (drmSessionManager == null) {
|
||||
|
@ -134,7 +134,7 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
||||
public int supportsFormat(Format format) {
|
||||
if (decoderFactory.supportsFormat(format)) {
|
||||
return RendererCapabilities.create(
|
||||
format.exoMediaCryptoType == null ? C.FORMAT_HANDLED : C.FORMAT_UNSUPPORTED_DRM);
|
||||
format.cryptoType == C.CRYPTO_TYPE_NONE ? C.FORMAT_HANDLED : C.FORMAT_UNSUPPORTED_DRM);
|
||||
} else if (MimeTypes.isText(format.sampleMimeType)) {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
|
||||
} else {
|
||||
|
@ -36,6 +36,7 @@ import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
import com.google.android.exoplayer2.PlayerMessage.Target;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.Decoder;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.decoder.DecoderException;
|
||||
@ -43,7 +44,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
@ -529,14 +529,14 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
||||
* Creates a decoder for the given format.
|
||||
*
|
||||
* @param format The format for which a decoder is required.
|
||||
* @param mediaCrypto The {@link ExoMediaCrypto} object required for decoding encrypted content.
|
||||
* @param cryptoConfig The {@link CryptoConfig} object required for decoding encrypted content.
|
||||
* May be null and can be ignored if decoder does not handle encrypted content.
|
||||
* @return The decoder.
|
||||
* @throws DecoderException If an error occurred creating a suitable decoder.
|
||||
*/
|
||||
protected abstract Decoder<
|
||||
VideoDecoderInputBuffer, ? extends VideoDecoderOutputBuffer, ? extends DecoderException>
|
||||
createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) throws DecoderException;
|
||||
createDecoder(Format format, @Nullable CryptoConfig cryptoConfig) throws DecoderException;
|
||||
|
||||
/**
|
||||
* Renders the specified output buffer.
|
||||
@ -664,10 +664,10 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
||||
|
||||
setDecoderDrmSession(sourceDrmSession);
|
||||
|
||||
ExoMediaCrypto mediaCrypto = null;
|
||||
CryptoConfig cryptoConfig = null;
|
||||
if (decoderDrmSession != null) {
|
||||
mediaCrypto = decoderDrmSession.getMediaCrypto();
|
||||
if (mediaCrypto == null) {
|
||||
cryptoConfig = decoderDrmSession.getCryptoConfig();
|
||||
if (cryptoConfig == null) {
|
||||
DrmSessionException drmError = decoderDrmSession.getError();
|
||||
if (drmError != null) {
|
||||
// Continue for now. We may be able to avoid failure if a new input format causes the
|
||||
@ -681,7 +681,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
||||
|
||||
try {
|
||||
long decoderInitializingTimestamp = SystemClock.elapsedRealtime();
|
||||
decoder = createDecoder(inputFormat, mediaCrypto);
|
||||
decoder = createDecoder(inputFormat, cryptoConfig);
|
||||
setDecoderOutputMode(outputMode);
|
||||
long decoderInitializedTimestamp = SystemClock.elapsedRealtime();
|
||||
eventDispatcher.decoderInitialized(
|
||||
|
@ -30,13 +30,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.RendererConfiguration;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.DecoderException;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
@ -75,7 +75,7 @@ public class DecoderAudioRendererTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FakeDecoder createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) {
|
||||
protected FakeDecoder createDecoder(Format format, @Nullable CryptoConfig cryptoConfig) {
|
||||
return new FakeDecoder();
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,8 @@ import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.testutil.FakeCryptoConfig;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
@ -73,7 +73,7 @@ public final class SampleQueueTest {
|
||||
private static final Format FORMAT_ENCRYPTED =
|
||||
new Format.Builder().setId(/* id= */ "encrypted").setDrmInitData(new DrmInitData()).build();
|
||||
private static final Format FORMAT_ENCRYPTED_WITH_EXO_MEDIA_CRYPTO_TYPE =
|
||||
FORMAT_ENCRYPTED.copyWithExoMediaCryptoType(MockExoMediaCrypto.class);
|
||||
FORMAT_ENCRYPTED.copyWithCryptoType(FakeCryptoConfig.TYPE);
|
||||
private static final byte[] DATA = TestUtil.buildTestData(ALLOCATION_SIZE * 10);
|
||||
|
||||
/*
|
||||
@ -1761,8 +1761,6 @@ public final class SampleQueueTest {
|
||||
return format.buildUpon().setLabel(label).build();
|
||||
}
|
||||
|
||||
private static final class MockExoMediaCrypto implements ExoMediaCrypto {}
|
||||
|
||||
private static final class MockDrmSessionManager implements DrmSessionManager {
|
||||
|
||||
private final DrmSession mockDrmSession;
|
||||
@ -1772,8 +1770,8 @@ public final class SampleQueueTest {
|
||||
this.mockDrmSession = mockDrmSession;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@Nullable
|
||||
public DrmSession acquireSession(
|
||||
Looper playbackLooper,
|
||||
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
|
||||
@ -1781,12 +1779,12 @@ public final class SampleQueueTest {
|
||||
return format.drmInitData != null ? mockDrmSession : mockPlaceholderDrmSession;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<? extends ExoMediaCrypto> getExoMediaCryptoType(Format format) {
|
||||
@C.CryptoType
|
||||
public int getCryptoType(Format format) {
|
||||
return mockPlaceholderDrmSession != null || format.drmInitData != null
|
||||
? MockExoMediaCrypto.class
|
||||
: null;
|
||||
? FakeCryptoConfig.TYPE
|
||||
: C.CRYPTO_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,12 +34,12 @@ import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.RendererConfiguration;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.decoder.DecoderException;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
@ -128,7 +128,7 @@ public final class DecoderVideoRendererTest {
|
||||
VideoDecoderInputBuffer,
|
||||
? extends VideoDecoderOutputBuffer,
|
||||
? extends DecoderException>
|
||||
createDecoder(Format format, @Nullable ExoMediaCrypto mediaCrypto) {
|
||||
createDecoder(Format format, @Nullable CryptoConfig cryptoConfig) {
|
||||
return new SimpleDecoder<
|
||||
VideoDecoderInputBuffer, VideoDecoderOutputBuffer, DecoderException>(
|
||||
new VideoDecoderInputBuffer[10], new VideoDecoderOutputBuffer[10]) {
|
||||
|
@ -667,8 +667,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
Format[] formats = new Format[representations.size()];
|
||||
for (int j = 0; j < formats.length; j++) {
|
||||
Format format = representations.get(j).format;
|
||||
formats[j] =
|
||||
format.copyWithExoMediaCryptoType(drmSessionManager.getExoMediaCryptoType(format));
|
||||
formats[j] = format.copyWithCryptoType(drmSessionManager.getCryptoType(format));
|
||||
}
|
||||
|
||||
AdaptationSet firstAdaptationSet = adaptationSets.get(adaptationSetIndices[0]);
|
||||
|
@ -1411,8 +1411,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
Format[] exposedFormats = new Format[trackGroup.length];
|
||||
for (int j = 0; j < trackGroup.length; j++) {
|
||||
Format format = trackGroup.getFormat(j);
|
||||
exposedFormats[j] =
|
||||
format.copyWithExoMediaCryptoType(drmSessionManager.getExoMediaCryptoType(format));
|
||||
exposedFormats[j] = format.copyWithCryptoType(drmSessionManager.getCryptoType(format));
|
||||
}
|
||||
trackGroups[i] = new TrackGroup(exposedFormats);
|
||||
}
|
||||
|
@ -261,8 +261,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
for (int j = 0; j < manifestFormats.length; j++) {
|
||||
Format manifestFormat = manifestFormats[j];
|
||||
exposedFormats[j] =
|
||||
manifestFormat.copyWithExoMediaCryptoType(
|
||||
drmSessionManager.getExoMediaCryptoType(manifestFormat));
|
||||
manifestFormat.copyWithCryptoType(drmSessionManager.getCryptoType(manifestFormat));
|
||||
}
|
||||
trackGroups[i] = new TrackGroup(exposedFormats);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -13,7 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.testutil;
|
||||
|
||||
/** {@link ExoMediaCrypto} type that cannot be used to handle any type of protected content. */
|
||||
public final class UnsupportedMediaCrypto implements ExoMediaCrypto {}
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
|
||||
/** Fake {@link CryptoConfig}. */
|
||||
public final class FakeCryptoConfig implements CryptoConfig {
|
||||
public static final int TYPE = C.CRYPTO_TYPE_CUSTOM_BASE;
|
||||
}
|
@ -26,8 +26,9 @@ import android.os.Parcelable;
|
||||
import android.os.PersistableBundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoConfig;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm;
|
||||
import com.google.android.exoplayer2.drm.MediaDrmCallback;
|
||||
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
||||
@ -334,15 +335,16 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExoMediaCrypto createMediaCrypto(byte[] sessionId) throws MediaCryptoException {
|
||||
public CryptoConfig createCryptoConfig(byte[] sessionId) throws MediaCryptoException {
|
||||
Assertions.checkState(referenceCount > 0);
|
||||
Assertions.checkState(openSessionIds.contains(toByteList(sessionId)));
|
||||
return new FakeExoMediaCrypto();
|
||||
return new FakeCryptoConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<FakeExoMediaCrypto> getExoMediaCryptoType() {
|
||||
return FakeExoMediaCrypto.class;
|
||||
@C.CryptoType
|
||||
public int getCryptoType() {
|
||||
return FakeCryptoConfig.TYPE;
|
||||
}
|
||||
|
||||
// Methods to facilitate testing
|
||||
@ -389,8 +391,6 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
|
||||
return ImmutableList.copyOf(Bytes.asList(byteArray));
|
||||
}
|
||||
|
||||
private static class FakeExoMediaCrypto implements ExoMediaCrypto {}
|
||||
|
||||
/** An license server implementation to interact with {@link FakeExoMediaDrm}. */
|
||||
public static class LicenseServer implements MediaDrmCallback {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user