mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Allow to disable libyuv dependency on LIBVPX
Goal: reduce binary size. PiperOrigin-RevId: 231198579
This commit is contained in:
parent
866835ea03
commit
19144c4c73
10 changed files with 47 additions and 155 deletions
|
|
@ -41,6 +41,9 @@
|
||||||
* Add `Handler` parameter to `ConcatenatingMediaSource` methods which take a
|
* Add `Handler` parameter to `ConcatenatingMediaSource` methods which take a
|
||||||
callback `Runnable`.
|
callback `Runnable`.
|
||||||
* Remove `player` and `isTopLevelSource` parameters from `MediaSource.prepare`.
|
* Remove `player` and `isTopLevelSource` parameters from `MediaSource.prepare`.
|
||||||
|
* VP9 extension: Remove RGB output mode and libyuv dependency, and switch to
|
||||||
|
surface YUV output as the default. Remove constructor parameters `scaleToFit`
|
||||||
|
and `useSurfaceYuvOutput`.
|
||||||
* Change signature of `PlayerNotificationManager.NotificationListener` to better
|
* Change signature of `PlayerNotificationManager.NotificationListener` to better
|
||||||
fit service requirements. Remove ability to set a custom stop action.
|
fit service requirements. Remove ability to set a custom stop action.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,26 +34,6 @@ VP9_EXT_PATH="${EXOPLAYER_ROOT}/extensions/vp9/src/main"
|
||||||
NDK_PATH="<path to Android NDK>"
|
NDK_PATH="<path to Android NDK>"
|
||||||
```
|
```
|
||||||
|
|
||||||
* Fetch libvpx and libyuv:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd "${VP9_EXT_PATH}/jni" && \
|
|
||||||
git clone https://chromium.googlesource.com/webm/libvpx libvpx && \
|
|
||||||
git clone https://chromium.googlesource.com/libyuv/libyuv libyuv
|
|
||||||
```
|
|
||||||
|
|
||||||
* Checkout the appropriate branches of libvpx and libyuv (the scripts and
|
|
||||||
makefiles bundled in this repo are known to work only at these versions of the
|
|
||||||
libraries - we will update this periodically as newer versions of
|
|
||||||
libvpx/libyuv are released):
|
|
||||||
|
|
||||||
```
|
|
||||||
cd "${VP9_EXT_PATH}/jni/libvpx" && \
|
|
||||||
git checkout tags/v1.7.0 -b v1.7.0 && \
|
|
||||||
cd "${VP9_EXT_PATH}/jni/libyuv" && \
|
|
||||||
git checkout 996a2bbd
|
|
||||||
```
|
|
||||||
|
|
||||||
* Run a script that generates necessary configuration files for libvpx:
|
* Run a script that generates necessary configuration files for libvpx:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -78,10 +58,6 @@ ${NDK_PATH}/ndk-build APP_ABI=all -j4
|
||||||
* Android config scripts should be re-generated by running
|
* Android config scripts should be re-generated by running
|
||||||
`generate_libvpx_android_configs.sh`
|
`generate_libvpx_android_configs.sh`
|
||||||
* Clean and re-build the project.
|
* Clean and re-build the project.
|
||||||
* If you want to use your own version of libvpx or libyuv, place it in
|
|
||||||
`${VP9_EXT_PATH}/jni/libvpx` or `${VP9_EXT_PATH}/jni/libyuv` respectively. But
|
|
||||||
please note that `generate_libvpx_android_configs.sh` and the makefiles need
|
|
||||||
to be modified to work with arbitrary versions of libvpx and libyuv.
|
|
||||||
|
|
||||||
## Using the extension ##
|
## Using the extension ##
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ public class VpxPlaybackTest {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
LibvpxVideoRenderer videoRenderer = new LibvpxVideoRenderer(true, 0);
|
LibvpxVideoRenderer videoRenderer = new LibvpxVideoRenderer(0);
|
||||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
|
||||||
player = ExoPlayerFactory.newInstance(context, new Renderer[] {videoRenderer}, trackSelector);
|
player = ExoPlayerFactory.newInstance(context, new Renderer[] {videoRenderer}, trackSelector);
|
||||||
player.addListener(this);
|
player.addListener(this);
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.ext.vp9;
|
package com.google.android.exoplayer2.ext.vp9;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
@ -109,7 +107,6 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
/** The default input buffer size. */
|
/** The default input buffer size. */
|
||||||
private static final int DEFAULT_INPUT_BUFFER_SIZE = 768 * 1024; // Value based on cs/SoftVpx.cpp.
|
private static final int DEFAULT_INPUT_BUFFER_SIZE = 768 * 1024; // Value based on cs/SoftVpx.cpp.
|
||||||
|
|
||||||
private final boolean scaleToFit;
|
|
||||||
private final boolean disableLoopFilter;
|
private final boolean disableLoopFilter;
|
||||||
private final long allowedJoiningTimeMs;
|
private final long allowedJoiningTimeMs;
|
||||||
private final int maxDroppedFramesToNotify;
|
private final int maxDroppedFramesToNotify;
|
||||||
|
|
@ -119,7 +116,6 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
private final TimedValueQueue<Format> formatQueue;
|
private final TimedValueQueue<Format> formatQueue;
|
||||||
private final DecoderInputBuffer flagsOnlyBuffer;
|
private final DecoderInputBuffer flagsOnlyBuffer;
|
||||||
private final DrmSessionManager<ExoMediaCrypto> drmSessionManager;
|
private final DrmSessionManager<ExoMediaCrypto> drmSessionManager;
|
||||||
private final boolean useSurfaceYuvOutput;
|
|
||||||
|
|
||||||
private Format format;
|
private Format format;
|
||||||
private Format pendingFormat;
|
private Format pendingFormat;
|
||||||
|
|
@ -133,7 +129,6 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
private @ReinitializationState int decoderReinitializationState;
|
private @ReinitializationState int decoderReinitializationState;
|
||||||
private boolean decoderReceivedBuffers;
|
private boolean decoderReceivedBuffers;
|
||||||
|
|
||||||
private Bitmap bitmap;
|
|
||||||
private boolean renderedFirstFrame;
|
private boolean renderedFirstFrame;
|
||||||
private long initialPositionUs;
|
private long initialPositionUs;
|
||||||
private long joiningDeadlineMs;
|
private long joiningDeadlineMs;
|
||||||
|
|
@ -158,16 +153,14 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
protected DecoderCounters decoderCounters;
|
protected DecoderCounters decoderCounters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param scaleToFit Whether video frames should be scaled to fit when rendering.
|
|
||||||
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
|
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
|
||||||
* can attempt to seamlessly join an ongoing playback.
|
* can attempt to seamlessly join an ongoing playback.
|
||||||
*/
|
*/
|
||||||
public LibvpxVideoRenderer(boolean scaleToFit, long allowedJoiningTimeMs) {
|
public LibvpxVideoRenderer(long allowedJoiningTimeMs) {
|
||||||
this(scaleToFit, allowedJoiningTimeMs, null, null, 0);
|
this(allowedJoiningTimeMs, null, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param scaleToFit Whether video frames should be scaled to fit when rendering.
|
|
||||||
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
|
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
|
||||||
* can attempt to seamlessly join an ongoing playback.
|
* can attempt to seamlessly join an ongoing playback.
|
||||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||||
|
|
@ -176,23 +169,22 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
* @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between
|
* @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between
|
||||||
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
|
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
|
||||||
*/
|
*/
|
||||||
public LibvpxVideoRenderer(boolean scaleToFit, long allowedJoiningTimeMs,
|
public LibvpxVideoRenderer(
|
||||||
Handler eventHandler, VideoRendererEventListener eventListener,
|
long allowedJoiningTimeMs,
|
||||||
|
Handler eventHandler,
|
||||||
|
VideoRendererEventListener eventListener,
|
||||||
int maxDroppedFramesToNotify) {
|
int maxDroppedFramesToNotify) {
|
||||||
this(
|
this(
|
||||||
scaleToFit,
|
|
||||||
allowedJoiningTimeMs,
|
allowedJoiningTimeMs,
|
||||||
eventHandler,
|
eventHandler,
|
||||||
eventListener,
|
eventListener,
|
||||||
maxDroppedFramesToNotify,
|
maxDroppedFramesToNotify,
|
||||||
/* drmSessionManager= */ null,
|
/* drmSessionManager= */ null,
|
||||||
/* playClearSamplesWithoutKeys= */ false,
|
/* playClearSamplesWithoutKeys= */ false,
|
||||||
/* disableLoopFilter= */ false,
|
/* disableLoopFilter= */ false);
|
||||||
/* useSurfaceYuvOutput= */ false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param scaleToFit Whether video frames should be scaled to fit when rendering.
|
|
||||||
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
|
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
|
||||||
* can attempt to seamlessly join an ongoing playback.
|
* can attempt to seamlessly join an ongoing playback.
|
||||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||||
|
|
@ -208,26 +200,21 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
* permitted to play clear regions of encrypted media files before {@code drmSessionManager}
|
* permitted to play clear regions of encrypted media files before {@code drmSessionManager}
|
||||||
* has obtained the keys necessary to decrypt encrypted regions of the media.
|
* has obtained the keys necessary to decrypt encrypted regions of the media.
|
||||||
* @param disableLoopFilter Disable the libvpx in-loop smoothing filter.
|
* @param disableLoopFilter Disable the libvpx in-loop smoothing filter.
|
||||||
* @param useSurfaceYuvOutput Directly output YUV to the Surface via ANativeWindow.
|
|
||||||
*/
|
*/
|
||||||
public LibvpxVideoRenderer(
|
public LibvpxVideoRenderer(
|
||||||
boolean scaleToFit,
|
|
||||||
long allowedJoiningTimeMs,
|
long allowedJoiningTimeMs,
|
||||||
Handler eventHandler,
|
Handler eventHandler,
|
||||||
VideoRendererEventListener eventListener,
|
VideoRendererEventListener eventListener,
|
||||||
int maxDroppedFramesToNotify,
|
int maxDroppedFramesToNotify,
|
||||||
DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
||||||
boolean playClearSamplesWithoutKeys,
|
boolean playClearSamplesWithoutKeys,
|
||||||
boolean disableLoopFilter,
|
boolean disableLoopFilter) {
|
||||||
boolean useSurfaceYuvOutput) {
|
|
||||||
super(C.TRACK_TYPE_VIDEO);
|
super(C.TRACK_TYPE_VIDEO);
|
||||||
this.scaleToFit = scaleToFit;
|
|
||||||
this.disableLoopFilter = disableLoopFilter;
|
this.disableLoopFilter = disableLoopFilter;
|
||||||
this.allowedJoiningTimeMs = allowedJoiningTimeMs;
|
this.allowedJoiningTimeMs = allowedJoiningTimeMs;
|
||||||
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
|
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
|
||||||
this.drmSessionManager = drmSessionManager;
|
this.drmSessionManager = drmSessionManager;
|
||||||
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
|
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
|
||||||
this.useSurfaceYuvOutput = useSurfaceYuvOutput;
|
|
||||||
joiningDeadlineMs = C.TIME_UNSET;
|
joiningDeadlineMs = C.TIME_UNSET;
|
||||||
clearReportedVideoSize();
|
clearReportedVideoSize();
|
||||||
formatHolder = new FormatHolder();
|
formatHolder = new FormatHolder();
|
||||||
|
|
@ -586,18 +573,14 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
*/
|
*/
|
||||||
protected void renderOutputBuffer(VpxOutputBuffer outputBuffer) throws VpxDecoderException {
|
protected void renderOutputBuffer(VpxOutputBuffer outputBuffer) throws VpxDecoderException {
|
||||||
int bufferMode = outputBuffer.mode;
|
int bufferMode = outputBuffer.mode;
|
||||||
boolean renderRgb = bufferMode == VpxDecoder.OUTPUT_MODE_RGB && surface != null;
|
|
||||||
boolean renderSurface = bufferMode == VpxDecoder.OUTPUT_MODE_SURFACE_YUV && surface != null;
|
boolean renderSurface = bufferMode == VpxDecoder.OUTPUT_MODE_SURFACE_YUV && surface != null;
|
||||||
boolean renderYuv = bufferMode == VpxDecoder.OUTPUT_MODE_YUV && outputBufferRenderer != null;
|
boolean renderYuv = bufferMode == VpxDecoder.OUTPUT_MODE_YUV && outputBufferRenderer != null;
|
||||||
lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;
|
lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;
|
||||||
if (!renderRgb && !renderYuv && !renderSurface) {
|
if (!renderYuv && !renderSurface) {
|
||||||
dropOutputBuffer(outputBuffer);
|
dropOutputBuffer(outputBuffer);
|
||||||
} else {
|
} else {
|
||||||
maybeNotifyVideoSizeChanged(outputBuffer.width, outputBuffer.height);
|
maybeNotifyVideoSizeChanged(outputBuffer.width, outputBuffer.height);
|
||||||
if (renderRgb) {
|
if (renderYuv) {
|
||||||
renderRgbFrame(outputBuffer, scaleToFit);
|
|
||||||
outputBuffer.release();
|
|
||||||
} else if (renderYuv) {
|
|
||||||
outputBufferRenderer.setOutputBuffer(outputBuffer);
|
outputBufferRenderer.setOutputBuffer(outputBuffer);
|
||||||
// The renderer will release the buffer.
|
// The renderer will release the buffer.
|
||||||
} else { // renderSurface
|
} else { // renderSurface
|
||||||
|
|
@ -675,8 +658,7 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
this.surface = surface;
|
this.surface = surface;
|
||||||
this.outputBufferRenderer = outputBufferRenderer;
|
this.outputBufferRenderer = outputBufferRenderer;
|
||||||
if (surface != null) {
|
if (surface != null) {
|
||||||
outputMode =
|
outputMode = VpxDecoder.OUTPUT_MODE_SURFACE_YUV;
|
||||||
useSurfaceYuvOutput ? VpxDecoder.OUTPUT_MODE_SURFACE_YUV : VpxDecoder.OUTPUT_MODE_RGB;
|
|
||||||
} else {
|
} else {
|
||||||
outputMode =
|
outputMode =
|
||||||
outputBufferRenderer != null ? VpxDecoder.OUTPUT_MODE_YUV : VpxDecoder.OUTPUT_MODE_NONE;
|
outputBufferRenderer != null ? VpxDecoder.OUTPUT_MODE_YUV : VpxDecoder.OUTPUT_MODE_NONE;
|
||||||
|
|
@ -739,8 +721,7 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
NUM_OUTPUT_BUFFERS,
|
NUM_OUTPUT_BUFFERS,
|
||||||
initialInputBufferSize,
|
initialInputBufferSize,
|
||||||
mediaCrypto,
|
mediaCrypto,
|
||||||
disableLoopFilter,
|
disableLoopFilter);
|
||||||
useSurfaceYuvOutput);
|
|
||||||
decoder.setOutputMode(outputMode);
|
decoder.setOutputMode(outputMode);
|
||||||
TraceUtil.endSection();
|
TraceUtil.endSection();
|
||||||
long decoderInitializedTimestamp = SystemClock.elapsedRealtime();
|
long decoderInitializedTimestamp = SystemClock.elapsedRealtime();
|
||||||
|
|
@ -940,23 +921,6 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
||||||
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRgbFrame(VpxOutputBuffer outputBuffer, boolean scale) {
|
|
||||||
if (bitmap == null
|
|
||||||
|| bitmap.getWidth() != outputBuffer.width
|
|
||||||
|| bitmap.getHeight() != outputBuffer.height) {
|
|
||||||
bitmap = Bitmap.createBitmap(outputBuffer.width, outputBuffer.height, Bitmap.Config.RGB_565);
|
|
||||||
}
|
|
||||||
bitmap.copyPixelsFromBuffer(outputBuffer.data);
|
|
||||||
Canvas canvas = surface.lockCanvas(null);
|
|
||||||
if (scale) {
|
|
||||||
canvas.scale(
|
|
||||||
((float) canvas.getWidth()) / outputBuffer.width,
|
|
||||||
((float) canvas.getHeight()) / outputBuffer.height);
|
|
||||||
}
|
|
||||||
canvas.drawBitmap(bitmap, 0, 0, null);
|
|
||||||
surface.unlockCanvasAndPost(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setJoiningDeadlineMs() {
|
private void setJoiningDeadlineMs() {
|
||||||
joiningDeadlineMs = allowedJoiningTimeMs > 0
|
joiningDeadlineMs = allowedJoiningTimeMs > 0
|
||||||
? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET;
|
? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET;
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public static final int OUTPUT_MODE_NONE = -1;
|
public static final int OUTPUT_MODE_NONE = -1;
|
||||||
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_SURFACE_YUV = 1;
|
||||||
public static final int OUTPUT_MODE_SURFACE_YUV = 2;
|
|
||||||
|
|
||||||
private static final int NO_ERROR = 0;
|
private static final int NO_ERROR = 0;
|
||||||
private static final int DECODE_ERROR = 1;
|
private static final int DECODE_ERROR = 1;
|
||||||
|
|
@ -52,7 +51,6 @@ import java.nio.ByteBuffer;
|
||||||
* @param exoMediaCrypto The {@link ExoMediaCrypto} object required for decoding encrypted
|
* @param exoMediaCrypto The {@link ExoMediaCrypto} object required for decoding encrypted
|
||||||
* content. Maybe null and can be ignored if decoder does not handle encrypted content.
|
* content. Maybe null and can be ignored if decoder does not handle encrypted content.
|
||||||
* @param disableLoopFilter Disable the libvpx in-loop smoothing filter.
|
* @param disableLoopFilter Disable the libvpx in-loop smoothing filter.
|
||||||
* @param enableSurfaceYuvOutputMode Whether OUTPUT_MODE_SURFACE_YUV is allowed.
|
|
||||||
* @throws VpxDecoderException Thrown if an exception occurs when initializing the decoder.
|
* @throws VpxDecoderException Thrown if an exception occurs when initializing the decoder.
|
||||||
*/
|
*/
|
||||||
public VpxDecoder(
|
public VpxDecoder(
|
||||||
|
|
@ -60,8 +58,7 @@ import java.nio.ByteBuffer;
|
||||||
int numOutputBuffers,
|
int numOutputBuffers,
|
||||||
int initialInputBufferSize,
|
int initialInputBufferSize,
|
||||||
ExoMediaCrypto exoMediaCrypto,
|
ExoMediaCrypto exoMediaCrypto,
|
||||||
boolean disableLoopFilter,
|
boolean disableLoopFilter)
|
||||||
boolean enableSurfaceYuvOutputMode)
|
|
||||||
throws VpxDecoderException {
|
throws VpxDecoderException {
|
||||||
super(new VpxInputBuffer[numInputBuffers], new VpxOutputBuffer[numOutputBuffers]);
|
super(new VpxInputBuffer[numInputBuffers], new VpxOutputBuffer[numOutputBuffers]);
|
||||||
if (!VpxLibrary.isAvailable()) {
|
if (!VpxLibrary.isAvailable()) {
|
||||||
|
|
@ -71,7 +68,7 @@ import java.nio.ByteBuffer;
|
||||||
if (exoMediaCrypto != null && !VpxLibrary.vpxIsSecureDecodeSupported()) {
|
if (exoMediaCrypto != null && !VpxLibrary.vpxIsSecureDecodeSupported()) {
|
||||||
throw new VpxDecoderException("Vpx decoder does not support secure decode.");
|
throw new VpxDecoderException("Vpx decoder does not support secure decode.");
|
||||||
}
|
}
|
||||||
vpxDecContext = vpxInit(disableLoopFilter, enableSurfaceYuvOutputMode);
|
vpxDecContext = vpxInit(disableLoopFilter, true);
|
||||||
if (vpxDecContext == 0) {
|
if (vpxDecContext == 0) {
|
||||||
throw new VpxDecoderException("Failed to initialize decoder");
|
throw new VpxDecoderException("Failed to initialize decoder");
|
||||||
}
|
}
|
||||||
|
|
@ -86,8 +83,8 @@ import java.nio.ByteBuffer;
|
||||||
/**
|
/**
|
||||||
* Sets the output mode for frames rendered by the decoder.
|
* Sets the output mode for frames rendered by the decoder.
|
||||||
*
|
*
|
||||||
* @param outputMode The output mode. One of {@link #OUTPUT_MODE_NONE}, {@link #OUTPUT_MODE_RGB}
|
* @param outputMode The output mode. One of {@link #OUTPUT_MODE_NONE} and {@link
|
||||||
* and {@link #OUTPUT_MODE_YUV}.
|
* #OUTPUT_MODE_YUV}.
|
||||||
*/
|
*/
|
||||||
public void setOutputMode(int outputMode) {
|
public void setOutputMode(int outputMode) {
|
||||||
this.outputMode = outputMode;
|
this.outputMode = outputMode;
|
||||||
|
|
|
||||||
|
|
@ -60,36 +60,20 @@ public final class VpxOutputBuffer extends OutputBuffer {
|
||||||
* Initializes the buffer.
|
* Initializes the buffer.
|
||||||
*
|
*
|
||||||
* @param timeUs The presentation timestamp for the buffer, in microseconds.
|
* @param timeUs The presentation timestamp for the buffer, in microseconds.
|
||||||
* @param mode The output mode. One of {@link VpxDecoder#OUTPUT_MODE_NONE},
|
* @param mode The output mode. One of {@link VpxDecoder#OUTPUT_MODE_NONE} and {@link
|
||||||
* {@link VpxDecoder#OUTPUT_MODE_RGB} and {@link VpxDecoder#OUTPUT_MODE_YUV}.
|
* VpxDecoder#OUTPUT_MODE_YUV}.
|
||||||
*/
|
*/
|
||||||
public void init(long timeUs, int mode) {
|
public void init(long timeUs, int mode) {
|
||||||
this.timeUs = timeUs;
|
this.timeUs = timeUs;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resizes the buffer based on the given dimensions. Called via JNI after decoding completes.
|
|
||||||
* @return Whether the buffer was resized successfully.
|
|
||||||
*/
|
|
||||||
public boolean initForRgbFrame(int width, int height) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.yuvPlanes = null;
|
|
||||||
if (!isSafeToMultiply(width, height) || !isSafeToMultiply(width * height, 2)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int minimumRgbSize = width * height * 2;
|
|
||||||
initData(minimumRgbSize);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the buffer based on the given stride. Called via JNI after decoding completes.
|
* Resizes the buffer based on the given stride. Called via JNI after decoding completes.
|
||||||
|
*
|
||||||
* @return Whether the buffer was resized successfully.
|
* @return Whether the buffer was resized successfully.
|
||||||
*/
|
*/
|
||||||
public boolean initForYuvFrame(int width, int height, int yStride, int uvStride,
|
public boolean initForYuvFrame(int width, int height, int yStride, int uvStride, int colorspace) {
|
||||||
int colorspace) {
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.colorspace = colorspace;
|
this.colorspace = colorspace;
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,6 @@
|
||||||
WORKING_DIR := $(call my-dir)
|
WORKING_DIR := $(call my-dir)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LIBVPX_ROOT := $(WORKING_DIR)/libvpx
|
LIBVPX_ROOT := $(WORKING_DIR)/libvpx
|
||||||
LIBYUV_ROOT := $(WORKING_DIR)/libyuv
|
|
||||||
|
|
||||||
# build libyuv_static.a
|
|
||||||
LOCAL_PATH := $(WORKING_DIR)
|
|
||||||
LIBYUV_DISABLE_JPEG := "yes"
|
|
||||||
include $(LIBYUV_ROOT)/Android.mk
|
|
||||||
|
|
||||||
# build libvpx.so
|
# build libvpx.so
|
||||||
LOCAL_PATH := $(WORKING_DIR)
|
LOCAL_PATH := $(WORKING_DIR)
|
||||||
|
|
@ -37,7 +31,7 @@ LOCAL_CPP_EXTENSION := .cc
|
||||||
LOCAL_SRC_FILES := vpx_jni.cc
|
LOCAL_SRC_FILES := vpx_jni.cc
|
||||||
LOCAL_LDLIBS := -llog -lz -lm -landroid
|
LOCAL_LDLIBS := -llog -lz -lm -landroid
|
||||||
LOCAL_SHARED_LIBRARIES := libvpx
|
LOCAL_SHARED_LIBRARIES := libvpx
|
||||||
LOCAL_STATIC_LIBRARIES := libyuv_static cpufeatures
|
LOCAL_STATIC_LIBRARIES := cpufeatures
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
$(call import-module,android/cpufeatures)
|
$(call import-module,android/cpufeatures)
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "libyuv.h" // NOLINT
|
|
||||||
|
|
||||||
#define VPX_CODEC_DISABLE_COMPAT 1
|
#define VPX_CODEC_DISABLE_COMPAT 1
|
||||||
#include "vpx/vpx_decoder.h"
|
#include "vpx/vpx_decoder.h"
|
||||||
#include "vpx/vp8dx.h"
|
#include "vpx/vp8dx.h"
|
||||||
|
|
@ -61,7 +59,6 @@
|
||||||
(JNIEnv* env, jobject thiz, ##__VA_ARGS__)\
|
(JNIEnv* env, jobject thiz, ##__VA_ARGS__)\
|
||||||
|
|
||||||
// JNI references for VpxOutputBuffer class.
|
// JNI references for VpxOutputBuffer class.
|
||||||
static jmethodID initForRgbFrame;
|
|
||||||
static jmethodID initForYuvFrame;
|
static jmethodID initForYuvFrame;
|
||||||
static jfieldID dataField;
|
static jfieldID dataField;
|
||||||
static jfieldID outputModeField;
|
static jfieldID outputModeField;
|
||||||
|
|
@ -393,11 +390,7 @@ class JniBufferManager {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JniCtx {
|
struct JniCtx {
|
||||||
JniCtx(bool enableBufferManager) {
|
JniCtx() { buffer_manager = new JniBufferManager(); }
|
||||||
if (enableBufferManager) {
|
|
||||||
buffer_manager = new JniBufferManager();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~JniCtx() {
|
~JniCtx() {
|
||||||
if (native_window) {
|
if (native_window) {
|
||||||
|
|
@ -440,9 +433,8 @@ int vpx_release_frame_buffer(void* priv, vpx_codec_frame_buffer_t* fb) {
|
||||||
return buffer_manager->release(*(int*)fb->priv);
|
return buffer_manager->release(*(int*)fb->priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
DECODER_FUNC(jlong, vpxInit, jboolean disableLoopFilter,
|
jlong vpxInit(JNIEnv* env, jboolean disableLoopFilter) {
|
||||||
jboolean enableBufferManager) {
|
JniCtx* context = new JniCtx();
|
||||||
JniCtx* context = new JniCtx(enableBufferManager);
|
|
||||||
context->decoder = new vpx_codec_ctx_t();
|
context->decoder = 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();
|
||||||
|
|
@ -469,14 +461,12 @@ DECODER_FUNC(jlong, vpxInit, jboolean disableLoopFilter,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (enableBufferManager) {
|
err = vpx_codec_set_frame_buffer_functions(
|
||||||
err = vpx_codec_set_frame_buffer_functions(
|
context->decoder, vpx_get_frame_buffer, vpx_release_frame_buffer,
|
||||||
context->decoder, vpx_get_frame_buffer, vpx_release_frame_buffer,
|
context->buffer_manager);
|
||||||
context->buffer_manager);
|
if (err) {
|
||||||
if (err) {
|
LOGE("ERROR: Failed to set libvpx frame buffer functions, error = %d.",
|
||||||
LOGE("ERROR: Failed to set libvpx frame buffer functions, error = %d.",
|
err);
|
||||||
err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate JNI References.
|
// Populate JNI References.
|
||||||
|
|
@ -484,8 +474,6 @@ DECODER_FUNC(jlong, vpxInit, jboolean disableLoopFilter,
|
||||||
"com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer");
|
"com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer");
|
||||||
initForYuvFrame = env->GetMethodID(outputBufferClass, "initForYuvFrame",
|
initForYuvFrame = env->GetMethodID(outputBufferClass, "initForYuvFrame",
|
||||||
"(IIIII)Z");
|
"(IIIII)Z");
|
||||||
initForRgbFrame = env->GetMethodID(outputBufferClass, "initForRgbFrame",
|
|
||||||
"(II)Z");
|
|
||||||
dataField = env->GetFieldID(outputBufferClass, "data",
|
dataField = env->GetFieldID(outputBufferClass, "data",
|
||||||
"Ljava/nio/ByteBuffer;");
|
"Ljava/nio/ByteBuffer;");
|
||||||
outputModeField = env->GetFieldID(outputBufferClass, "mode", "I");
|
outputModeField = env->GetFieldID(outputBufferClass, "mode", "I");
|
||||||
|
|
@ -494,6 +482,15 @@ DECODER_FUNC(jlong, vpxInit, jboolean disableLoopFilter,
|
||||||
return reinterpret_cast<intptr_t>(context);
|
return reinterpret_cast<intptr_t>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODER_FUNC(jlong, vpxInit, jboolean disableLoopFilter,
|
||||||
|
jboolean enableBufferManager) {
|
||||||
|
return vpxInit(env, disableLoopFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECODER_FUNC(jlong, vpxInitilization, jboolean disableLoopFilter) {
|
||||||
|
return vpxInit(env, disableLoopFilter);
|
||||||
|
}
|
||||||
|
|
||||||
DECODER_FUNC(jlong, vpxDecode, jlong jContext, jobject encoded, jint len) {
|
DECODER_FUNC(jlong, vpxDecode, jlong jContext, jobject encoded, jint len) {
|
||||||
JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
|
JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
|
||||||
const uint8_t* const buffer =
|
const uint8_t* const buffer =
|
||||||
|
|
@ -537,28 +534,10 @@ DECODER_FUNC(jint, vpxGetFrame, jlong jContext, jobject jOutputBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const int kOutputModeYuv = 0;
|
const int kOutputModeYuv = 0;
|
||||||
const int kOutputModeRgb = 1;
|
const int kOutputModeSurfaceYuv = 1;
|
||||||
const int kOutputModeSurfaceYuv = 2;
|
|
||||||
|
|
||||||
int outputMode = env->GetIntField(jOutputBuffer, outputModeField);
|
int outputMode = env->GetIntField(jOutputBuffer, outputModeField);
|
||||||
if (outputMode == kOutputModeRgb) {
|
if (outputMode == kOutputModeYuv) {
|
||||||
// resize buffer if required.
|
|
||||||
jboolean initResult = env->CallBooleanMethod(jOutputBuffer, initForRgbFrame,
|
|
||||||
img->d_w, img->d_h);
|
|
||||||
if (env->ExceptionCheck() || !initResult) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get pointer to the data buffer.
|
|
||||||
const jobject dataObject = env->GetObjectField(jOutputBuffer, dataField);
|
|
||||||
uint8_t* const dst =
|
|
||||||
reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataObject));
|
|
||||||
|
|
||||||
libyuv::I420ToRGB565(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
|
|
||||||
img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
|
|
||||||
img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
|
|
||||||
dst, img->d_w * 2, img->d_w, img->d_h);
|
|
||||||
} else if (outputMode == kOutputModeYuv) {
|
|
||||||
const int kColorspaceUnknown = 0;
|
const int kColorspaceUnknown = 0;
|
||||||
const int kColorspaceBT601 = 1;
|
const int kColorspaceBT601 = 1;
|
||||||
const int kColorspaceBT709 = 2;
|
const int kColorspaceBT709 = 2;
|
||||||
|
|
@ -616,9 +595,6 @@ DECODER_FUNC(jint, vpxGetFrame, jlong jContext, jobject jOutputBuffer) {
|
||||||
}
|
}
|
||||||
} else if (outputMode == kOutputModeSurfaceYuv &&
|
} else if (outputMode == kOutputModeSurfaceYuv &&
|
||||||
img->fmt != VPX_IMG_FMT_I42016) {
|
img->fmt != VPX_IMG_FMT_I42016) {
|
||||||
if (!context->buffer_manager) {
|
|
||||||
return -1; // enableBufferManager was not set in vpxInit.
|
|
||||||
}
|
|
||||||
int id = *(int*)img->fb_priv;
|
int id = *(int*)img->fb_priv;
|
||||||
context->buffer_manager->add_ref(id);
|
context->buffer_manager->add_ref(id);
|
||||||
JniFrameBuffer* jfb = context->buffer_manager->get_buffer(id);
|
JniFrameBuffer* jfb = context->buffer_manager->get_buffer(id);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
# Constructors accessed via reflection in DefaultRenderersFactory
|
# Constructors accessed via reflection in DefaultRenderersFactory
|
||||||
-dontnote com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer
|
-dontnote com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer
|
||||||
-keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer {
|
-keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer {
|
||||||
<init>(boolean, long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int);
|
<init>(long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int);
|
||||||
}
|
}
|
||||||
-dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer
|
-dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer
|
||||||
-keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer {
|
-keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer {
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,6 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer");
|
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer");
|
||||||
Constructor<?> constructor =
|
Constructor<?> constructor =
|
||||||
clazz.getConstructor(
|
clazz.getConstructor(
|
||||||
boolean.class,
|
|
||||||
long.class,
|
long.class,
|
||||||
android.os.Handler.class,
|
android.os.Handler.class,
|
||||||
com.google.android.exoplayer2.video.VideoRendererEventListener.class,
|
com.google.android.exoplayer2.video.VideoRendererEventListener.class,
|
||||||
|
|
@ -242,7 +241,6 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||||
Renderer renderer =
|
Renderer renderer =
|
||||||
(Renderer)
|
(Renderer)
|
||||||
constructor.newInstance(
|
constructor.newInstance(
|
||||||
true,
|
|
||||||
allowedVideoJoiningTimeMs,
|
allowedVideoJoiningTimeMs,
|
||||||
eventHandler,
|
eventHandler,
|
||||||
eventListener,
|
eventListener,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue