Commit 4cd8c770 by hoangtc Committed by Oliver Woodman

Add layer of indirection for DRM.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=138383979
parent a6e27701
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.audio.AudioCapabilities; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioTrack; import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer; import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
/** /**
...@@ -71,7 +72,8 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { ...@@ -71,7 +72,8 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
} }
@Override @Override
protected FfmpegDecoder createDecoder(Format format) throws FfmpegDecoderException { protected FfmpegDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto)
throws FfmpegDecoderException {
decoder = new FfmpegDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, decoder = new FfmpegDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE,
format.sampleMimeType, format.initializationData); format.sampleMimeType, format.initializationData);
return decoder; return decoder;
......
...@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.audio.AudioCapabilities; ...@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioTrack; import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer; import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
/** /**
...@@ -63,7 +64,8 @@ public class LibflacAudioRenderer extends SimpleDecoderAudioRenderer { ...@@ -63,7 +64,8 @@ public class LibflacAudioRenderer extends SimpleDecoderAudioRenderer {
} }
@Override @Override
protected FlacDecoder createDecoder(Format format) throws FlacDecoderException { protected FlacDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto)
throws FlacDecoderException {
return new FlacDecoder(NUM_BUFFERS, NUM_BUFFERS, format.initializationData); return new FlacDecoder(NUM_BUFFERS, NUM_BUFFERS, format.initializationData);
} }
......
...@@ -21,6 +21,8 @@ import com.google.android.exoplayer2.audio.AudioCapabilities; ...@@ -21,6 +21,8 @@ import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioTrack; import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer; import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
/** /**
...@@ -57,6 +59,21 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { ...@@ -57,6 +59,21 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
super(eventHandler, eventListener, audioCapabilities, streamType); super(eventHandler, eventListener, audioCapabilities, streamType);
} }
/**
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
* default capabilities (no encoded audio passthrough support) should be assumed.
* @param streamType The type of audio stream for the {@link AudioTrack}.
*/
public LibopusAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
AudioCapabilities audioCapabilities, int streamType,
DrmSessionManager<ExoMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys) {
super(eventHandler, eventListener, audioCapabilities, streamType, drmSessionManager,
playClearSamplesWithoutKeys);
}
@Override @Override
public int supportsFormat(Format format) { public int supportsFormat(Format format) {
return OpusLibrary.isAvailable() && MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType) return OpusLibrary.isAvailable() && MimeTypes.AUDIO_OPUS.equalsIgnoreCase(format.sampleMimeType)
...@@ -64,9 +81,10 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { ...@@ -64,9 +81,10 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
} }
@Override @Override
protected OpusDecoder createDecoder(Format format) throws OpusDecoderException { protected OpusDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto)
throws OpusDecoderException {
return new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, return new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE,
format.initializationData); format.initializationData, mediaCrypto);
} }
} }
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
package com.google.android.exoplayer2.ext.opus; package com.google.android.exoplayer2.ext.opus;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.CryptoInfo;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.SimpleDecoder;
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
import com.google.android.exoplayer2.drm.DecryptionException;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.List; import java.util.List;
...@@ -36,6 +39,12 @@ import java.util.List; ...@@ -36,6 +39,12 @@ import java.util.List;
*/ */
private static final int SAMPLE_RATE = 48000; private static final int SAMPLE_RATE = 48000;
private static final int NO_ERROR = 0;
private static final int DECODE_ERROR = -1;
private static final int DRM_ERROR = -2;
private final ExoMediaCrypto exoMediaCrypto;
private final int channelCount; private final int channelCount;
private final int headerSkipSamples; private final int headerSkipSamples;
private final int headerSeekPreRollSamples; private final int headerSeekPreRollSamples;
...@@ -52,14 +61,20 @@ import java.util.List; ...@@ -52,14 +61,20 @@ import java.util.List;
* @param initializationData Codec-specific initialization data. The first element must contain an * @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 * 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. * 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.
* @throws OpusDecoderException Thrown if an exception occurs when initializing the decoder. * @throws OpusDecoderException Thrown if an exception occurs when initializing the decoder.
*/ */
public OpusDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, public OpusDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize,
List<byte[]> initializationData) throws OpusDecoderException { List<byte[]> initializationData, ExoMediaCrypto exoMediaCrypto) throws OpusDecoderException {
super(new DecoderInputBuffer[numInputBuffers], new SimpleOutputBuffer[numOutputBuffers]); super(new DecoderInputBuffer[numInputBuffers], new SimpleOutputBuffer[numOutputBuffers]);
if (!OpusLibrary.isAvailable()) { if (!OpusLibrary.isAvailable()) {
throw new OpusDecoderException("Failed to load decoder native libraries."); throw new OpusDecoderException("Failed to load decoder native libraries.");
} }
this.exoMediaCrypto = exoMediaCrypto;
if (exoMediaCrypto != null && !OpusLibrary.opusIsSecureDecodeSupported()) {
throw new OpusDecoderException("Opus decoder does not support secure decode.");
}
byte[] headerBytes = initializationData.get(0); byte[] headerBytes = initializationData.get(0);
if (headerBytes.length < 19) { if (headerBytes.length < 19) {
throw new OpusDecoderException("Header size is too small."); throw new OpusDecoderException("Header size is too small.");
...@@ -139,11 +154,25 @@ import java.util.List; ...@@ -139,11 +154,25 @@ import java.util.List;
skipSamples = (inputBuffer.timeUs == 0) ? headerSkipSamples : headerSeekPreRollSamples; skipSamples = (inputBuffer.timeUs == 0) ? headerSkipSamples : headerSeekPreRollSamples;
} }
ByteBuffer inputData = inputBuffer.data; ByteBuffer inputData = inputBuffer.data;
int result = opusDecode(nativeDecoderContext, inputBuffer.timeUs, inputData, inputData.limit(), CryptoInfo cryptoInfo = inputBuffer.cryptoInfo;
outputBuffer, SAMPLE_RATE); int result = inputBuffer.isEncrypted()
? opusSecureDecode(nativeDecoderContext, inputBuffer.timeUs, inputData, inputData.limit(),
outputBuffer, SAMPLE_RATE, exoMediaCrypto, cryptoInfo.mode,
cryptoInfo.key, cryptoInfo.iv, cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData, cryptoInfo.numBytesOfEncryptedData)
: opusDecode(nativeDecoderContext, inputBuffer.timeUs, inputData, inputData.limit(),
outputBuffer, SAMPLE_RATE);
if (result < 0) { if (result < 0) {
return new OpusDecoderException("Decode error: " + opusGetErrorMessage(result)); if (result == DRM_ERROR) {
String message = "Drm error: " + opusGetErrorMessage(nativeDecoderContext);
DecryptionException cause = new DecryptionException(
opusGetErrorCode(nativeDecoderContext), message);
return new OpusDecoderException(message, cause);
} else {
return new OpusDecoderException("Decode error: " + opusGetErrorMessage(result));
}
} }
ByteBuffer outputData = outputBuffer.data; ByteBuffer outputData = outputBuffer.data;
outputData.position(0); outputData.position(0);
outputData.limit(result); outputData.limit(result);
...@@ -182,8 +211,13 @@ import java.util.List; ...@@ -182,8 +211,13 @@ import java.util.List;
int gain, byte[] streamMap); int gain, byte[] streamMap);
private native int opusDecode(long decoder, long timeUs, ByteBuffer inputBuffer, int inputSize, private native int opusDecode(long decoder, long timeUs, ByteBuffer inputBuffer, int inputSize,
SimpleOutputBuffer outputBuffer, int sampleRate); SimpleOutputBuffer outputBuffer, int sampleRate);
private native int opusSecureDecode(long decoder, long timeUs, ByteBuffer inputBuffer,
int inputSize, SimpleOutputBuffer outputBuffer, int sampleRate,
ExoMediaCrypto wvCrypto, int inputMode, byte[] key, byte[] iv,
int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData);
private native void opusClose(long decoder); private native void opusClose(long decoder);
private native void opusReset(long decoder); private native void opusReset(long decoder);
private native String opusGetErrorMessage(int errorCode); private native int opusGetErrorCode(long decoder);
private native String opusGetErrorMessage(long decoder);
} }
...@@ -26,4 +26,8 @@ public final class OpusDecoderException extends AudioDecoderException { ...@@ -26,4 +26,8 @@ public final class OpusDecoderException extends AudioDecoderException {
super(message); super(message);
} }
/* package */ OpusDecoderException(String message, Throwable cause) {
super(message, cause);
}
} }
...@@ -50,5 +50,5 @@ public final class OpusLibrary { ...@@ -50,5 +50,5 @@ public final class OpusLibrary {
} }
public static native String opusGetVersion(); public static native String opusGetVersion();
public static native boolean opusIsSecureDecodeSupported();
} }
...@@ -60,11 +60,13 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { ...@@ -60,11 +60,13 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
static const int kBytesPerSample = 2; // opus fixed point uses 16 bit samples. static const int kBytesPerSample = 2; // opus fixed point uses 16 bit samples.
static int channelCount; static int channelCount;
static int errorCode;
DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount, DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
jint numStreams, jint numCoupled, jint gain, jbyteArray jStreamMap) { jint numStreams, jint numCoupled, jint gain, jbyteArray jStreamMap) {
int status = OPUS_INVALID_STATE; int status = OPUS_INVALID_STATE;
::channelCount = channelCount; ::channelCount = channelCount;
errorCode = 0;
jbyte* streamMapBytes = env->GetByteArrayElements(jStreamMap, 0); jbyte* streamMapBytes = env->GetByteArrayElements(jStreamMap, 0);
uint8_t* streamMap = reinterpret_cast<uint8_t*>(streamMapBytes); uint8_t* streamMap = reinterpret_cast<uint8_t*>(streamMapBytes);
OpusMSDecoder* decoder = opus_multistream_decoder_create( OpusMSDecoder* decoder = opus_multistream_decoder_create(
...@@ -109,10 +111,24 @@ DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs, ...@@ -109,10 +111,24 @@ DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs,
env->GetDirectBufferAddress(jOutputBufferData)); env->GetDirectBufferAddress(jOutputBufferData));
int sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize, int sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize,
outputBufferData, outputSize, 0); outputBufferData, outputSize, 0);
// record error code
errorCode = (sampleCount < 0) ? sampleCount : 0;
return (sampleCount < 0) ? sampleCount return (sampleCount < 0) ? sampleCount
: sampleCount * kBytesPerSample * channelCount; : sampleCount * kBytesPerSample * channelCount;
} }
DECODER_FUNC(jint, opusSecureDecode, jlong jDecoder, jlong jTimeUs,
jobject jInputBuffer, jint inputSize, jobject jOutputBuffer,
jint sampleRate, jobject mediaCrypto, jint inputMode, jbyteArray key,
jbyteArray javaIv, jint inputNumSubSamples, jintArray numBytesOfClearData,
jintArray numBytesOfEncryptedData) {
// Doesn't support
// Java client should have checked vpxSupportSecureDecode
// and avoid calling this
// return -2 (DRM Error)
return -2;
}
DECODER_FUNC(void, opusClose, jlong jDecoder) { DECODER_FUNC(void, opusClose, jlong jDecoder) {
OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder); OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
opus_multistream_decoder_destroy(decoder); opus_multistream_decoder_destroy(decoder);
...@@ -123,10 +139,19 @@ DECODER_FUNC(void, opusReset, jlong jDecoder) { ...@@ -123,10 +139,19 @@ DECODER_FUNC(void, opusReset, jlong jDecoder) {
opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE); opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE);
} }
DECODER_FUNC(jstring, opusGetErrorMessage, jint errorCode) { DECODER_FUNC(jstring, opusGetErrorMessage, jlong jContext) {
return env->NewStringUTF(opus_strerror(errorCode)); return env->NewStringUTF(opus_strerror(errorCode));
} }
DECODER_FUNC(jint, opusGetErrorCode, jlong jContext) {
return errorCode;
}
LIBRARY_FUNC(jstring, opusIsSecureDecodeSupported) {
// Doesn't support
return 0;
}
LIBRARY_FUNC(jstring, opusGetVersion) { LIBRARY_FUNC(jstring, opusGetVersion) {
return env->NewStringUTF(opus_get_version_string()); return env->NewStringUTF(opus_get_version_string());
} }
...@@ -16,8 +16,11 @@ ...@@ -16,8 +16,11 @@
package com.google.android.exoplayer2.ext.vp9; package com.google.android.exoplayer2.ext.vp9;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.CryptoInfo;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.SimpleDecoder;
import com.google.android.exoplayer2.drm.DecryptionException;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
...@@ -30,6 +33,11 @@ import java.nio.ByteBuffer; ...@@ -30,6 +33,11 @@ import java.nio.ByteBuffer;
public static final int OUTPUT_MODE_YUV = 0; public static final int OUTPUT_MODE_YUV = 0;
public static final int OUTPUT_MODE_RGB = 1; public static final int OUTPUT_MODE_RGB = 1;
private static final int NO_ERROR = 0;
private static final int DECODE_ERROR = 1;
private static final int DRM_ERROR = 2;
private final ExoMediaCrypto exoMediaCrypto;
private final long vpxDecContext; private final long vpxDecContext;
private volatile int outputMode; private volatile int outputMode;
...@@ -40,14 +48,20 @@ import java.nio.ByteBuffer; ...@@ -40,14 +48,20 @@ import java.nio.ByteBuffer;
* @param numInputBuffers The number of input buffers. * @param numInputBuffers The number of input buffers.
* @param numOutputBuffers The number of output buffers. * @param numOutputBuffers The number of output buffers.
* @param initialInputBufferSize The initial size of each input buffer. * @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.
* @throws VpxDecoderException Thrown if an exception occurs when initializing the decoder. * @throws VpxDecoderException Thrown if an exception occurs when initializing the decoder.
*/ */
public VpxDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize) public VpxDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize,
throws VpxDecoderException { ExoMediaCrypto exoMediaCrypto) throws VpxDecoderException {
super(new DecoderInputBuffer[numInputBuffers], new VpxOutputBuffer[numOutputBuffers]); super(new DecoderInputBuffer[numInputBuffers], new VpxOutputBuffer[numOutputBuffers]);
if (!VpxLibrary.isAvailable()) { if (!VpxLibrary.isAvailable()) {
throw new VpxDecoderException("Failed to load decoder native libraries."); throw new VpxDecoderException("Failed to load decoder native libraries.");
} }
this.exoMediaCrypto = exoMediaCrypto;
if (exoMediaCrypto != null && !VpxLibrary.vpxIsSecureDecodeSupported()) {
throw new VpxDecoderException("Vpx decoder does not support secure decode.");
}
vpxDecContext = vpxInit(); vpxDecContext = vpxInit();
if (vpxDecContext == 0) { if (vpxDecContext == 0) {
throw new VpxDecoderException("Failed to initialize decoder"); throw new VpxDecoderException("Failed to initialize decoder");
...@@ -90,9 +104,23 @@ import java.nio.ByteBuffer; ...@@ -90,9 +104,23 @@ import java.nio.ByteBuffer;
boolean reset) { boolean reset) {
ByteBuffer inputData = inputBuffer.data; ByteBuffer inputData = inputBuffer.data;
int inputSize = inputData.limit(); int inputSize = inputData.limit();
if (vpxDecode(vpxDecContext, inputData, inputSize) != 0) { CryptoInfo cryptoInfo = inputBuffer.cryptoInfo;
return new VpxDecoderException("Decode error: " + vpxGetErrorMessage(vpxDecContext)); final long result = inputBuffer.isEncrypted()
? vpxSecureDecode(vpxDecContext, inputData, inputSize, exoMediaCrypto,
cryptoInfo.mode, cryptoInfo.key, cryptoInfo.iv, cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData, cryptoInfo.numBytesOfEncryptedData)
: vpxDecode(vpxDecContext, inputData, inputSize);
if (result != NO_ERROR) {
if (result == DRM_ERROR) {
String message = "Drm error: " + vpxGetErrorMessage(vpxDecContext);
DecryptionException cause = new DecryptionException(
vpxGetErrorCode(vpxDecContext), message);
return new VpxDecoderException(message, cause);
} else {
return new VpxDecoderException("Decode error: " + vpxGetErrorMessage(vpxDecContext));
}
} }
outputBuffer.init(inputBuffer.timeUs, outputMode); outputBuffer.init(inputBuffer.timeUs, outputMode);
if (vpxGetFrame(vpxDecContext, outputBuffer) != 0) { if (vpxGetFrame(vpxDecContext, outputBuffer) != 0) {
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY); outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
...@@ -109,7 +137,11 @@ import java.nio.ByteBuffer; ...@@ -109,7 +137,11 @@ import java.nio.ByteBuffer;
private native long vpxInit(); private native long vpxInit();
private native long vpxClose(long context); private native long vpxClose(long context);
private native long vpxDecode(long context, ByteBuffer encoded, int length); private native long vpxDecode(long context, ByteBuffer encoded, int length);
private native long vpxSecureDecode(long context, ByteBuffer encoded, int length,
ExoMediaCrypto wvCrypto, int inputMode, byte[] key, byte[] iv,
int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData);
private native int vpxGetFrame(long context, VpxOutputBuffer outputBuffer); private native int vpxGetFrame(long context, VpxOutputBuffer outputBuffer);
private native int vpxGetErrorCode(long context);
private native String vpxGetErrorMessage(long context); private native String vpxGetErrorMessage(long context);
} }
...@@ -20,8 +20,11 @@ package com.google.android.exoplayer2.ext.vp9; ...@@ -20,8 +20,11 @@ package com.google.android.exoplayer2.ext.vp9;
*/ */
public class VpxDecoderException extends Exception { public class VpxDecoderException extends Exception {
/* package */ VpxDecoderException(String message) { /* package */ VpxDecoderException(String message) {
super(message); super(message);
} }
/* package */ VpxDecoderException(String message, Throwable cause) {
super(message, cause);
}
} }
...@@ -59,5 +59,5 @@ public final class VpxLibrary { ...@@ -59,5 +59,5 @@ public final class VpxLibrary {
private static native String vpxGetVersion(); private static native String vpxGetVersion();
private static native String vpxGetBuildConfig(); private static native String vpxGetBuildConfig();
public static native boolean vpxIsSecureDecodeSupported();
} }
...@@ -59,6 +59,7 @@ static jmethodID initForRgbFrame; ...@@ -59,6 +59,7 @@ static jmethodID initForRgbFrame;
static jmethodID initForYuvFrame; static jmethodID initForYuvFrame;
static jfieldID dataField; static jfieldID dataField;
static jfieldID outputModeField; static jfieldID outputModeField;
static int errorCode;
jint JNI_OnLoad(JavaVM* vm, void* reserved) { jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env; JNIEnv* env;
...@@ -72,6 +73,7 @@ DECODER_FUNC(jlong, vpxInit) { ...@@ -72,6 +73,7 @@ DECODER_FUNC(jlong, vpxInit) {
vpx_codec_ctx_t* context = new vpx_codec_ctx_t(); vpx_codec_ctx_t* context = new vpx_codec_ctx_t();
vpx_codec_dec_cfg_t cfg = {0, 0, 0}; vpx_codec_dec_cfg_t cfg = {0, 0, 0};
cfg.threads = android_getCpuCount(); cfg.threads = android_getCpuCount();
errorCode = 0;
if (vpx_codec_dec_init(context, &vpx_codec_vp9_dx_algo, &cfg, 0)) { if (vpx_codec_dec_init(context, &vpx_codec_vp9_dx_algo, &cfg, 0)) {
LOGE("ERROR: Fail to initialize libvpx decoder."); LOGE("ERROR: Fail to initialize libvpx decoder.");
return 0; return 0;
...@@ -97,13 +99,26 @@ DECODER_FUNC(jlong, vpxDecode, jlong jContext, jobject encoded, jint len) { ...@@ -97,13 +99,26 @@ DECODER_FUNC(jlong, vpxDecode, jlong jContext, jobject encoded, jint len) {
reinterpret_cast<const uint8_t*>(env->GetDirectBufferAddress(encoded)); reinterpret_cast<const uint8_t*>(env->GetDirectBufferAddress(encoded));
const vpx_codec_err_t status = const vpx_codec_err_t status =
vpx_codec_decode(context, buffer, len, NULL, 0); vpx_codec_decode(context, buffer, len, NULL, 0);
errorCode = 0;
if (status != VPX_CODEC_OK) { if (status != VPX_CODEC_OK) {
LOGE("ERROR: vpx_codec_decode() failed, status= %d", status); LOGE("ERROR: vpx_codec_decode() failed, status= %d", status);
errorCode = status;
return -1; return -1;
} }
return 0; return 0;
} }
DECODER_FUNC(jlong, vpxSecureDecode, jlong jContext, jobject encoded, jint len,
jobject mediaCrypto, jint inputMode, jbyteArray&, jbyteArray&,
jint inputNumSubSamples, jintArray numBytesOfClearData,
jintArray numBytesOfEncryptedData) {
// Doesn't support
// Java client should have checked vpxSupportSecureDecode
// and avoid calling this
// return -2 (DRM Error)
return -2;
}
DECODER_FUNC(jlong, vpxClose, jlong jContext) { DECODER_FUNC(jlong, vpxClose, jlong jContext) {
vpx_codec_ctx_t* const context = reinterpret_cast<vpx_codec_ctx_t*>(jContext); vpx_codec_ctx_t* const context = reinterpret_cast<vpx_codec_ctx_t*>(jContext);
vpx_codec_destroy(context); vpx_codec_destroy(context);
...@@ -181,6 +196,15 @@ DECODER_FUNC(jstring, vpxGetErrorMessage, jlong jContext) { ...@@ -181,6 +196,15 @@ DECODER_FUNC(jstring, vpxGetErrorMessage, jlong jContext) {
return env->NewStringUTF(vpx_codec_error(context)); return env->NewStringUTF(vpx_codec_error(context));
} }
DECODER_FUNC(jint, vpxGetErrorCode, jlong jContext) {
return errorCode;
}
LIBRARY_FUNC(jstring, vpxIsSecureDecodeSupported) {
// Doesn't support
return 0;
}
LIBRARY_FUNC(jstring, vpxGetVersion) { LIBRARY_FUNC(jstring, vpxGetVersion) {
return env->NewStringUTF(vpx_codec_version_str()); return env->NewStringUTF(vpx_codec_version_str());
} }
......
...@@ -27,4 +27,15 @@ public abstract class AudioDecoderException extends Exception { ...@@ -27,4 +27,15 @@ public abstract class AudioDecoderException extends Exception {
super(detailMessage); super(detailMessage);
} }
/**
* @param detailMessage The detail message for this exception.
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
public AudioDecoderException(String detailMessage, Throwable cause) {
super(detailMessage, cause);
}
} }
package com.google.android.exoplayer2.drm;
/**
* An exception when doing drm decryption using the In-App Drm
*/
public class DecryptionException extends Exception {
private final int errorCode;
public DecryptionException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
/**
* Get error code
*/
public int getErrorCode() {
return errorCode;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment