diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index dd303af0d8..ac944a7b01 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -92,6 +92,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { private static final int INITIAL_INPUT_BUFFER_SIZE = 768 * 1024; // Value based on cs/SoftVpx.cpp. private final boolean scaleToFit; + private final boolean disableLoopFilter; private final long allowedJoiningTimeMs; private final int maxDroppedFramesToNotify; private final boolean playClearSamplesWithoutKeys; @@ -154,7 +155,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { Handler eventHandler, VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) { this(scaleToFit, allowedJoiningTimeMs, eventHandler, eventListener, maxDroppedFramesToNotify, - null, false); + null, false, false); } /** @@ -173,13 +174,15 @@ public final class LibvpxVideoRenderer extends BaseRenderer { * begin in parallel with key acquisition. This parameter specifies whether the renderer is * permitted to play clear regions of encrypted media files before {@code drmSessionManager} * has obtained the keys necessary to decrypt encrypted regions of the media. + * @param disableLoopFilter Disable the libvpx in-loop smoothing filter. */ public LibvpxVideoRenderer(boolean scaleToFit, long allowedJoiningTimeMs, Handler eventHandler, VideoRendererEventListener eventListener, int maxDroppedFramesToNotify, DrmSessionManager drmSessionManager, - boolean playClearSamplesWithoutKeys) { + boolean playClearSamplesWithoutKeys, boolean disableLoopFilter) { super(C.TRACK_TYPE_VIDEO); this.scaleToFit = scaleToFit; + this.disableLoopFilter = disableLoopFilter; this.allowedJoiningTimeMs = allowedJoiningTimeMs; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.drmSessionManager = drmSessionManager; @@ -625,7 +628,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { long codecInitializingTimestamp = SystemClock.elapsedRealtime(); TraceUtil.beginSection("createVpxDecoder"); decoder = new VpxDecoder(NUM_INPUT_BUFFERS, NUM_OUTPUT_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, - mediaCrypto); + mediaCrypto, disableLoopFilter); decoder.setOutputMode(outputMode); TraceUtil.endSection(); long codecInitializedTimestamp = SystemClock.elapsedRealtime(); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java index ef999d5d2b..6a15023c0b 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java @@ -49,10 +49,11 @@ import java.nio.ByteBuffer; * @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 disableLoopFilter Disable the libvpx in-loop smoothing filter. * @throws VpxDecoderException Thrown if an exception occurs when initializing the decoder. */ public VpxDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, - ExoMediaCrypto exoMediaCrypto) throws VpxDecoderException { + ExoMediaCrypto exoMediaCrypto, boolean disableLoopFilter) throws VpxDecoderException { super(new VpxInputBuffer[numInputBuffers], new VpxOutputBuffer[numOutputBuffers]); if (!VpxLibrary.isAvailable()) { throw new VpxDecoderException("Failed to load decoder native libraries."); @@ -61,7 +62,7 @@ import java.nio.ByteBuffer; if (exoMediaCrypto != null && !VpxLibrary.vpxIsSecureDecodeSupported()) { throw new VpxDecoderException("Vpx decoder does not support secure decode."); } - vpxDecContext = vpxInit(); + vpxDecContext = vpxInit(disableLoopFilter); if (vpxDecContext == 0) { throw new VpxDecoderException("Failed to initialize decoder"); } @@ -139,7 +140,7 @@ import java.nio.ByteBuffer; vpxClose(vpxDecContext); } - private native long vpxInit(); + private native long vpxInit(boolean disableLoopFilter); private native long vpxClose(long context); private native long vpxDecode(long context, ByteBuffer encoded, int length); private native long vpxSecureDecode(long context, ByteBuffer encoded, int length, diff --git a/extensions/vp9/src/main/jni/vpx_jni.cc b/extensions/vp9/src/main/jni/vpx_jni.cc index 5c480d1525..9666875b04 100644 --- a/extensions/vp9/src/main/jni/vpx_jni.cc +++ b/extensions/vp9/src/main/jni/vpx_jni.cc @@ -283,7 +283,7 @@ static void convert_16_to_8_standard(const vpx_image_t* const img, } } -DECODER_FUNC(jlong, vpxInit) { +DECODER_FUNC(jlong, vpxInit, jboolean disableLoopFilter) { vpx_codec_ctx_t* context = new vpx_codec_ctx_t(); vpx_codec_dec_cfg_t cfg = {0, 0, 0}; cfg.threads = android_getCpuCount(); @@ -295,6 +295,9 @@ DECODER_FUNC(jlong, vpxInit) { errorCode = err; return 0; } + if (disableLoopFilter) { + vpx_codec_control_(context, VP9_SET_SKIP_LOOP_FILTER, true); + } // Populate JNI References. const jclass outputBufferClass = env->FindClass(