Commit 92ec1ab6 by christosts Committed by Andrew Lewis

Add more MediaCodec methods to MediaCodecAdapter

Add more MediaCodec methods to MediaCodedAdapter so that renderers
interact with the MediaCodec through the MediaCodecAdapter.

PiperOrigin-RevId: 341023452
parent ae4cf9f1
......@@ -19,6 +19,8 @@ package com.google.android.exoplayer2.mediacodec;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.view.Surface;
import androidx.annotation.IntDef;
......@@ -26,6 +28,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Renderer.VideoScalingMode;
import com.google.android.exoplayer2.decoder.CryptoInfo;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
......@@ -109,6 +112,16 @@ import java.nio.ByteBuffer;
}
@Override
public void releaseOutputBuffer(int index, boolean render) {
codec.releaseOutputBuffer(index, render);
}
@Override
public void releaseOutputBuffer(int index, long renderTimeStampNs) {
codec.releaseOutputBuffer(index, renderTimeStampNs);
}
@Override
public int dequeueInputBufferIndex() {
return asynchronousMediaCodecCallback.dequeueInputBufferIndex();
}
......@@ -148,14 +161,14 @@ import java.nio.ByteBuffer;
}
@Override
public void shutdown() {
if (state == STATE_STARTED) {
bufferEnqueuer.shutdown();
}
if (state == STATE_CONFIGURED || state == STATE_STARTED) {
public void release() {
if (state == STATE_STARTED) {
bufferEnqueuer.shutdown();
}
if (state == STATE_CONFIGURED || state == STATE_STARTED) {
asynchronousMediaCodecCallback.shutdown();
}
state = STATE_SHUT_DOWN;
}
state = STATE_SHUT_DOWN;
}
@Override
......@@ -163,6 +176,30 @@ import java.nio.ByteBuffer;
return codec;
}
@Override
public void setOnFrameRenderedListener(OnFrameRenderedListener listener, Handler handler) {
codec.setOnFrameRenderedListener(
(codec, presentationTimeUs, nanoTime) ->
listener.onFrameRendered(
AsynchronousMediaCodecAdapter.this, presentationTimeUs, nanoTime),
handler);
}
@Override
public void setOutputSurface(Surface surface) {
codec.setOutputSurface(surface);
}
@Override
public void setParameters(Bundle params) {
codec.setParameters(params);
}
@Override
public void setVideoScalingMode(@VideoScalingMode int scalingMode) {
codec.setVideoScalingMode(scalingMode);
}
@VisibleForTesting
/* package */ void onError(MediaCodec.CodecException error) {
asynchronousMediaCodecCallback.onError(codec, error);
......
......@@ -19,8 +19,12 @@ package com.google.android.exoplayer2.mediacodec;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Handler;
import android.view.Surface;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.Renderer.VideoScalingMode;
import com.google.android.exoplayer2.decoder.CryptoInfo;
import java.nio.ByteBuffer;
......@@ -33,6 +37,15 @@ import java.nio.ByteBuffer;
public interface MediaCodecAdapter {
/**
* Listener to be called when an output frame has rendered on the output surface.
*
* @see MediaCodec.OnFrameRenderedListener
*/
interface OnFrameRenderedListener {
void onFrameRendered(MediaCodecAdapter codec, long presentationTimeUs, long nanoTime);
}
/**
* Configures this adapter and the underlying {@link MediaCodec}. Needs to be called before {@link
* #start()}.
*
......@@ -118,18 +131,64 @@ public interface MediaCodecAdapter {
void queueSecureInputBuffer(
int index, int offset, CryptoInfo info, long presentationTimeUs, int flags);
/** Flushes both the adapter and the underlying {@link MediaCodec}. */
void flush();
/**
* Returns the buffer to the {@link MediaCodec}. If the {@link MediaCodec} was configured with an
* output surface, setting {@code render} to {@code true} will first send the buffer to the output
* surface. The surface will release the buffer back to the codec once it is no longer
* used/displayed.
*
* @see MediaCodec#releaseOutputBuffer(int, boolean)
*/
void releaseOutputBuffer(int index, boolean render);
/**
* Shuts down the adapter.
* Updates the output buffer's surface timestamp and sends it to the {@link MediaCodec} to render
* it on the output surface. If the {@link MediaCodec} is not configured with an output surface,
* this call will simply return the buffer to the {@link MediaCodec}.
*
* <p>This method does not stop or release the underlying {@link MediaCodec}. It should be called
* before stopping or releasing the {@link MediaCodec} to avoid the possibility of the adapter
* interacting with a stopped or released {@link MediaCodec}.
* @see MediaCodec#releaseOutputBuffer(int, long)
*/
void shutdown();
@RequiresApi(21)
void releaseOutputBuffer(int index, long renderTimeStampNs);
/** Flushes the adapter and the underlying {@link MediaCodec}. */
void flush();
/** Releases the adapter and the underlying {@link MediaCodec}. */
void release();
/** Returns the {@link MediaCodec} instance of this adapter. */
MediaCodec getCodec();
/**
* Registers a callback to be invoked when an output frame is rendered on the output surface.
*
* @see MediaCodec#setOnFrameRenderedListener
*/
@RequiresApi(23)
void setOnFrameRenderedListener(OnFrameRenderedListener listener, Handler handler);
/**
* Dynamically sets the output surface of a {@link MediaCodec}.
*
* @see MediaCodec#setOutputSurface(Surface)
*/
@RequiresApi(23)
void setOutputSurface(Surface surface);
/**
* Communicate additional parameter changes to the {@link MediaCodec} instance.
*
* @see MediaCodec#setParameters(Bundle)
*/
@RequiresApi(19)
void setParameters(Bundle params);
/**
* Specifies the scaling mode to use, if a surface has been specified in a previous call to {@link
* #configure}.
*
* @see MediaCodec#setVideoScalingMode(int)
*/
void setVideoScalingMode(@VideoScalingMode int scalingMode);
}
......@@ -719,7 +719,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
protected void releaseCodec() {
try {
if (codecAdapter != null) {
codecAdapter.shutdown();
codecAdapter.release();
}
if (codec != null) {
decoderCounters.decoderReleaseCount++;
......@@ -1071,7 +1071,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecInitializedTimestamp = SystemClock.elapsedRealtime();
} catch (Exception e) {
if (codecAdapter != null) {
codecAdapter.shutdown();
codecAdapter.release();
}
if (codec != null) {
codec.release();
......
......@@ -21,8 +21,12 @@ import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Handler;
import android.view.Surface;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.Renderer.VideoScalingMode;
import com.google.android.exoplayer2.decoder.CryptoInfo;
import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer;
......@@ -115,12 +119,23 @@ import java.nio.ByteBuffer;
}
@Override
public void releaseOutputBuffer(int index, boolean render) {
codec.releaseOutputBuffer(index, render);
}
@Override
@RequiresApi(21)
public void releaseOutputBuffer(int index, long renderTimeStampNs) {
codec.releaseOutputBuffer(index, renderTimeStampNs);
}
@Override
public void flush() {
codec.flush();
}
@Override
public void shutdown() {
public void release() {
inputByteBuffers = null;
outputByteBuffers = null;
}
......@@ -129,4 +144,31 @@ import java.nio.ByteBuffer;
public MediaCodec getCodec() {
return codec;
}
@Override
@RequiresApi(23)
public void setOnFrameRenderedListener(OnFrameRenderedListener listener, Handler handler) {
codec.setOnFrameRenderedListener(
(codec, presentationTimeUs, nanoTime) ->
listener.onFrameRendered(
SynchronousMediaCodecAdapter.this, presentationTimeUs, nanoTime),
handler);
}
@Override
@RequiresApi(23)
public void setOutputSurface(Surface surface) {
codec.setOutputSurface(surface);
}
@Override
@RequiresApi(19)
public void setParameters(Bundle params) {
codec.setParameters(params);
}
@Override
public void setVideoScalingMode(@VideoScalingMode int scalingMode) {
codec.setVideoScalingMode(scalingMode);
}
}
......@@ -52,8 +52,7 @@ public class AsynchronousMediaCodecAdapterTest {
@After
public void tearDown() {
adapter.shutdown();
codec.release();
adapter.release();
}
@Test
......@@ -106,7 +105,7 @@ public class AsynchronousMediaCodecAdapterTest {
// non-empty adapter.
shadowOf(callbackThread.getLooper()).idle();
adapter.shutdown();
adapter.release();
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(MediaCodec.INFO_TRY_AGAIN_LATER);
}
......@@ -183,7 +182,7 @@ public class AsynchronousMediaCodecAdapterTest {
adapter.queueInputBuffer(index, 0, 0, 0, 0);
// Progress the looper so that the ShadowMediaCodec processes the input buffer.
shadowLooper.idle();
adapter.shutdown();
adapter.release();
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo))
.isEqualTo(MediaCodec.INFO_TRY_AGAIN_LATER);
......
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