mirror of
https://github.com/samsonjs/media.git
synced 2026-03-30 10:15:48 +00:00
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
This commit is contained in:
parent
ae4cf9f1da
commit
92ec1ab628
5 changed files with 158 additions and 21 deletions
|
|
@ -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;
|
||||
|
|
@ -108,6 +111,16 @@ import java.nio.ByteBuffer;
|
|||
bufferEnqueuer.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags);
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
|
|
@ -32,6 +36,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;
|
||||
|
|
@ -114,13 +118,24 @@ import java.nio.ByteBuffer;
|
|||
index, offset, info.getFrameworkCryptoInfo(), presentationTimeUs, flags);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue