Commit 41d4a132 by christosts Committed by Andrew Lewis

Add configure() in MediaCodecAdapter

The correct order of initializing the MediaCodec should be (as per
documentation
https://developer.android.com/reference/android/media/MediaCodec#initialization)

"create -> setCallback -> configure -> start"

but the MediaCodecRenderer currently does

"create -> configure -> setCallback -> start"

MediaCodec implementations did not complain about this so far, but the
wrong sequence does not work with the MediaCodec in block mode (new mode
in Android R) and also the ShadowMediaCodec won't operate in
asynchronous mode otherwise. To initialize the MediaCodec in the correct
order, this commit adds configure() in the MediaCodecAdapter so the
MediaCodecRenderer can do:

adapter.configure(); // sets the callback and then configures the codec
adapter.start();     // starts the codec

PiperOrigin-RevId: 316127680
parent 0a617146
...@@ -32,6 +32,7 @@ import com.google.android.exoplayer2.PlayerMessage.Target; ...@@ -32,6 +32,7 @@ import com.google.android.exoplayer2.PlayerMessage.Target;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher; import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.mediacodec.MediaCodecAdapter;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer; import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
...@@ -289,7 +290,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -289,7 +290,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override @Override
protected void configureCodec( protected void configureCodec(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo,
MediaCodec codec, MediaCodecAdapter codecAdapter,
Format format, Format format,
@Nullable MediaCrypto crypto, @Nullable MediaCrypto crypto,
float codecOperatingRate) { float codecOperatingRate) {
...@@ -301,7 +302,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -301,7 +302,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
&& !MimeTypes.AUDIO_RAW.equals(format.sampleMimeType); && !MimeTypes.AUDIO_RAW.equals(format.sampleMimeType);
MediaFormat mediaFormat = MediaFormat mediaFormat =
getMediaFormat(format, codecInfo.codecMimeType, codecMaxInputSize, codecOperatingRate); getMediaFormat(format, codecInfo.codecMimeType, codecMaxInputSize, codecOperatingRate);
codec.configure(mediaFormat, /* surface= */ null, crypto, /* flags= */ 0); codecAdapter.configure(mediaFormat, /* surface= */ null, crypto, /* flags= */ 0);
// Store the input MIME type if we're using the passthrough codec. // Store the input MIME type if we're using the passthrough codec.
passthroughFormat = passthroughEnabled ? format : null; passthroughFormat = passthroughEnabled ? format : null;
} }
......
...@@ -17,9 +17,13 @@ ...@@ -17,9 +17,13 @@
package com.google.android.exoplayer2.mediacodec; package com.google.android.exoplayer2.mediacodec;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Looper;
import android.view.Surface;
import androidx.annotation.GuardedBy;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
...@@ -45,22 +49,32 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -45,22 +49,32 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_CREATED, STATE_STARTED, STATE_SHUT_DOWN}) @IntDef({STATE_CREATED, STATE_CONFIGURED, STATE_STARTED, STATE_SHUT_DOWN})
private @interface State {} private @interface State {}
private static final int STATE_CREATED = 0; private static final int STATE_CREATED = 0;
private static final int STATE_STARTED = 1; private static final int STATE_CONFIGURED = 1;
private static final int STATE_SHUT_DOWN = 2; private static final int STATE_STARTED = 2;
private static final int STATE_SHUT_DOWN = 3;
private final Object lock;
@GuardedBy("lock")
private final MediaCodecAsyncCallback mediaCodecAsyncCallback; private final MediaCodecAsyncCallback mediaCodecAsyncCallback;
private final MediaCodec codec; private final MediaCodec codec;
private final HandlerThread handlerThread; private final HandlerThread handlerThread;
private @MonotonicNonNull Handler handler; private @MonotonicNonNull Handler handler;
@GuardedBy("lock")
private long pendingFlushCount; private long pendingFlushCount;
private @State int state; private @State int state;
private Runnable codecStartRunnable;
private final MediaCodecInputBufferEnqueuer bufferEnqueuer; private final MediaCodecInputBufferEnqueuer bufferEnqueuer;
@Nullable private IllegalStateException internalException;
@GuardedBy("lock")
@Nullable
private IllegalStateException internalException;
/** /**
* Creates an instance that wraps the specified {@link MediaCodec}. Instances created with this * Creates an instance that wraps the specified {@link MediaCodec}. Instances created with this
...@@ -101,121 +115,164 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -101,121 +115,164 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
boolean enableAsynchronousQueueing, boolean enableAsynchronousQueueing,
int trackType, int trackType,
HandlerThread handlerThread) { HandlerThread handlerThread) {
mediaCodecAsyncCallback = new MediaCodecAsyncCallback(); this.lock = new Object();
this.mediaCodecAsyncCallback = new MediaCodecAsyncCallback();
this.codec = codec; this.codec = codec;
this.handlerThread = handlerThread; this.handlerThread = handlerThread;
state = STATE_CREATED; this.bufferEnqueuer =
codecStartRunnable = codec::start; enableAsynchronousQueueing
if (enableAsynchronousQueueing) { ? new AsynchronousMediaCodecBufferEnqueuer(codec, trackType)
bufferEnqueuer = new AsynchronousMediaCodecBufferEnqueuer(codec, trackType); : new SynchronousMediaCodecBufferEnqueuer(this.codec);
} else { this.state = STATE_CREATED;
bufferEnqueuer = new SynchronousMediaCodecBufferEnqueuer(this.codec);
}
} }
@Override @Override
public synchronized void start() { public void configure(
@Nullable MediaFormat mediaFormat,
@Nullable Surface surface,
@Nullable MediaCrypto crypto,
int flags) {
handlerThread.start(); handlerThread.start();
handler = new Handler(handlerThread.getLooper()); handler = new Handler(handlerThread.getLooper());
codec.setCallback(this, handler); codec.setCallback(this, handler);
codec.configure(mediaFormat, surface, crypto, flags);
state = STATE_CONFIGURED;
}
@Override
public void start() {
bufferEnqueuer.start(); bufferEnqueuer.start();
codecStartRunnable.run(); codec.start();
state = STATE_STARTED; state = STATE_STARTED;
} }
@Override @Override
public void queueInputBuffer( public void queueInputBuffer(
int index, int offset, int size, long presentationTimeUs, int flags) { int index, int offset, int size, long presentationTimeUs, int flags) {
// This method does not need to be synchronized because it does not interact with the
// mediaCodecAsyncCallback.
bufferEnqueuer.queueInputBuffer(index, offset, size, presentationTimeUs, flags); bufferEnqueuer.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
} }
@Override @Override
public void queueSecureInputBuffer( public void queueSecureInputBuffer(
int index, int offset, CryptoInfo info, long presentationTimeUs, int flags) { int index, int offset, CryptoInfo info, long presentationTimeUs, int flags) {
// This method does not need to be synchronized because it does not interact with the
// mediaCodecAsyncCallback.
bufferEnqueuer.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags); bufferEnqueuer.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags);
} }
@Override @Override
public synchronized int dequeueInputBufferIndex() { public int dequeueInputBufferIndex() {
if (isFlushing()) { synchronized (lock) {
return MediaCodec.INFO_TRY_AGAIN_LATER; if (isFlushing()) {
} else { return MediaCodec.INFO_TRY_AGAIN_LATER;
maybeThrowException(); } else {
return mediaCodecAsyncCallback.dequeueInputBufferIndex(); maybeThrowException();
return mediaCodecAsyncCallback.dequeueInputBufferIndex();
}
} }
} }
@Override @Override
public synchronized int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) { public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
if (isFlushing()) { synchronized (lock) {
return MediaCodec.INFO_TRY_AGAIN_LATER; if (isFlushing()) {
} else { return MediaCodec.INFO_TRY_AGAIN_LATER;
maybeThrowException(); } else {
return mediaCodecAsyncCallback.dequeueOutputBufferIndex(bufferInfo); maybeThrowException();
return mediaCodecAsyncCallback.dequeueOutputBufferIndex(bufferInfo);
}
} }
} }
@Override @Override
public synchronized MediaFormat getOutputFormat() { public MediaFormat getOutputFormat() {
return mediaCodecAsyncCallback.getOutputFormat(); synchronized (lock) {
return mediaCodecAsyncCallback.getOutputFormat();
}
} }
@Override @Override
public synchronized void flush() { public void flush() {
bufferEnqueuer.flush(); synchronized (lock) {
codec.flush(); bufferEnqueuer.flush();
++pendingFlushCount; codec.flush();
Util.castNonNull(handler).post(this::onFlushCompleted); ++pendingFlushCount;
Util.castNonNull(handler).post(this::onFlushCompleted);
}
} }
@Override @Override
public synchronized void shutdown() { public void shutdown() {
if (state == STATE_STARTED) { synchronized (lock) {
bufferEnqueuer.shutdown(); if (state == STATE_STARTED) {
handlerThread.quit(); bufferEnqueuer.shutdown();
mediaCodecAsyncCallback.flush(); }
if (state == STATE_CONFIGURED || state == STATE_STARTED) {
handlerThread.quit();
mediaCodecAsyncCallback.flush();
// Leave the adapter in a flushing state so that
// it will not dequeue anything.
++pendingFlushCount;
}
state = STATE_SHUT_DOWN;
} }
state = STATE_SHUT_DOWN;
} }
@Override @Override
public synchronized void onInputBufferAvailable(MediaCodec codec, int index) { public MediaCodec getCodec() {
mediaCodecAsyncCallback.onInputBufferAvailable(codec, index); return codec;
} }
// Called from the handler thread.
@Override @Override
public synchronized void onOutputBufferAvailable( public void onInputBufferAvailable(MediaCodec codec, int index) {
MediaCodec codec, int index, MediaCodec.BufferInfo info) { synchronized (lock) {
mediaCodecAsyncCallback.onOutputBufferAvailable(codec, index, info); mediaCodecAsyncCallback.onInputBufferAvailable(codec, index);
}
} }
@Override @Override
public synchronized void onError(MediaCodec codec, MediaCodec.CodecException e) { public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
mediaCodecAsyncCallback.onError(codec, e); synchronized (lock) {
mediaCodecAsyncCallback.onOutputBufferAvailable(codec, index, info);
}
} }
@Override @Override
public synchronized void onOutputFormatChanged(MediaCodec codec, MediaFormat format) { public void onError(MediaCodec codec, MediaCodec.CodecException e) {
mediaCodecAsyncCallback.onOutputFormatChanged(codec, format); synchronized (lock) {
mediaCodecAsyncCallback.onError(codec, e);
}
}
@Override
public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
synchronized (lock) {
mediaCodecAsyncCallback.onOutputFormatChanged(codec, format);
}
} }
@VisibleForTesting @VisibleForTesting
/* package */ void onMediaCodecError(IllegalStateException e) { /* package */ void onMediaCodecError(IllegalStateException e) {
mediaCodecAsyncCallback.onMediaCodecError(e); synchronized (lock) {
mediaCodecAsyncCallback.onMediaCodecError(e);
}
} }
@VisibleForTesting @VisibleForTesting
/* package */ void setCodecStartRunnable(Runnable codecStartRunnable) { @Nullable
this.codecStartRunnable = codecStartRunnable; /* package */ Looper getLooper() {
return handlerThread.getLooper();
}
private void onFlushCompleted() {
synchronized (lock) {
onFlushCompletedSynchronized();
}
} }
private synchronized void onFlushCompleted() { @GuardedBy("lock")
if (state != STATE_STARTED) { private void onFlushCompletedSynchronized() {
// The adapter has been shutdown. if (state == STATE_SHUT_DOWN) {
return; return;
} }
...@@ -231,7 +288,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -231,7 +288,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
mediaCodecAsyncCallback.flush(); mediaCodecAsyncCallback.flush();
try { try {
codecStartRunnable.run(); codec.start();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
internalException = e; internalException = e;
} catch (Exception e) { } catch (Exception e) {
...@@ -239,16 +296,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -239,16 +296,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
} }
private synchronized boolean isFlushing() { @GuardedBy("lock")
private boolean isFlushing() {
return pendingFlushCount > 0; return pendingFlushCount > 0;
} }
private synchronized void maybeThrowException() { @GuardedBy("lock")
private void maybeThrowException() {
maybeThrowInternalException(); maybeThrowInternalException();
mediaCodecAsyncCallback.maybeThrowMediaCodecException(); mediaCodecAsyncCallback.maybeThrowMediaCodecException();
} }
private synchronized void maybeThrowInternalException() { @GuardedBy("lock")
private void maybeThrowInternalException() {
if (internalException != null) { if (internalException != null) {
IllegalStateException e = internalException; IllegalStateException e = internalException;
internalException = null; internalException = null;
......
...@@ -17,7 +17,10 @@ ...@@ -17,7 +17,10 @@
package com.google.android.exoplayer2.mediacodec; package com.google.android.exoplayer2.mediacodec;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.view.Surface;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.decoder.CryptoInfo; import com.google.android.exoplayer2.decoder.CryptoInfo;
/** /**
...@@ -30,12 +33,24 @@ import com.google.android.exoplayer2.decoder.CryptoInfo; ...@@ -30,12 +33,24 @@ import com.google.android.exoplayer2.decoder.CryptoInfo;
* *
* @see com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.MediaCodecOperationMode * @see com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.MediaCodecOperationMode
*/ */
/* package */ interface MediaCodecAdapter { public interface MediaCodecAdapter {
/** /**
* Starts this instance. * Configures this adapter and the underlying {@link MediaCodec}. Needs to be called before {@link
* #start()}.
* *
* @see MediaCodec#start(). * @see MediaCodec#configure(MediaFormat, Surface, MediaCrypto, int)
*/
void configure(
@Nullable MediaFormat mediaFormat,
@Nullable Surface surface,
@Nullable MediaCrypto crypto,
int flags);
/**
* Starts this instance. Needs to be called after {@link #configure}.
*
* @see MediaCodec#start()
*/ */
void start(); void start();
...@@ -109,4 +124,7 @@ import com.google.android.exoplayer2.decoder.CryptoInfo; ...@@ -109,4 +124,7 @@ import com.google.android.exoplayer2.decoder.CryptoInfo;
* is a risk the adapter might interact with a stopped or released {@link MediaCodec}. * is a risk the adapter might interact with a stopped or released {@link MediaCodec}.
*/ */
void shutdown(); void shutdown();
/** Returns the {@link MediaCodec} instance of this adapter. */
MediaCodec getCodec();
} }
...@@ -532,7 +532,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -532,7 +532,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* Configures a newly created {@link MediaCodec}. * Configures a newly created {@link MediaCodec}.
* *
* @param codecInfo Information about the {@link MediaCodec} being configured. * @param codecInfo Information about the {@link MediaCodec} being configured.
* @param codec The {@link MediaCodec} to configure. * @param codecAdapter The {@link MediaCodecAdapter} to configure.
* @param format The {@link Format} for which the codec is being configured. * @param format The {@link Format} for which the codec is being configured.
* @param crypto For drm protected playbacks, a {@link MediaCrypto} to use for decryption. * @param crypto For drm protected playbacks, a {@link MediaCrypto} to use for decryption.
* @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if * @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if
...@@ -540,7 +540,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -540,7 +540,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/ */
protected abstract void configureCodec( protected abstract void configureCodec(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo,
MediaCodec codec, MediaCodecAdapter codecAdapter,
Format format, Format format,
@Nullable MediaCrypto crypto, @Nullable MediaCrypto crypto,
float codecOperatingRate); float codecOperatingRate);
...@@ -1036,8 +1036,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1036,8 +1036,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
/** /**
* Configures passthrough where no codec is used. Called instead of {@link * Configures passthrough where no codec is used. Called instead of {@link
* #configureCodec(MediaCodecInfo, MediaCodec, Format, MediaCrypto, float)} when no codec is used * #configureCodec(MediaCodecInfo, MediaCodecAdapter, Format, MediaCrypto, float)} when no codec
* in passthrough. * is used in passthrough.
*/ */
private void initPassthrough(Format format) { private void initPassthrough(Format format) {
disablePassthrough(); // In case of transition between 2 passthrough formats. disablePassthrough(); // In case of transition between 2 passthrough formats.
...@@ -1088,7 +1088,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1088,7 +1088,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
TraceUtil.endSection(); TraceUtil.endSection();
TraceUtil.beginSection("configureCodec"); TraceUtil.beginSection("configureCodec");
configureCodec(codecInfo, codec, inputFormat, crypto, codecOperatingRate); configureCodec(codecInfo, codecAdapter, inputFormat, crypto, codecOperatingRate);
TraceUtil.endSection(); TraceUtil.endSection();
TraceUtil.beginSection("startCodec"); TraceUtil.beginSection("startCodec");
codecAdapter.start(); codecAdapter.start();
......
...@@ -17,7 +17,10 @@ ...@@ -17,7 +17,10 @@
package com.google.android.exoplayer2.mediacodec; package com.google.android.exoplayer2.mediacodec;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.view.Surface;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.decoder.CryptoInfo; import com.google.android.exoplayer2.decoder.CryptoInfo;
/** /**
...@@ -32,6 +35,15 @@ import com.google.android.exoplayer2.decoder.CryptoInfo; ...@@ -32,6 +35,15 @@ import com.google.android.exoplayer2.decoder.CryptoInfo;
} }
@Override @Override
public void configure(
@Nullable MediaFormat mediaFormat,
@Nullable Surface surface,
@Nullable MediaCrypto crypto,
int flags) {
codec.configure(mediaFormat, surface, crypto, flags);
}
@Override
public void start() { public void start() {
codec.start(); codec.start();
} }
...@@ -71,4 +83,9 @@ import com.google.android.exoplayer2.decoder.CryptoInfo; ...@@ -71,4 +83,9 @@ import com.google.android.exoplayer2.decoder.CryptoInfo;
@Override @Override
public void shutdown() {} public void shutdown() {}
@Override
public MediaCodec getCodec() {
return codec;
}
} }
...@@ -42,6 +42,7 @@ import com.google.android.exoplayer2.PlayerMessage.Target; ...@@ -42,6 +42,7 @@ import com.google.android.exoplayer2.PlayerMessage.Target;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.mediacodec.MediaCodecAdapter;
import com.google.android.exoplayer2.mediacodec.MediaCodecDecoderException; import com.google.android.exoplayer2.mediacodec.MediaCodecDecoderException;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer; import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
...@@ -552,7 +553,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -552,7 +553,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@Override @Override
protected void configureCodec( protected void configureCodec(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo,
MediaCodec codec, MediaCodecAdapter codecAdapter,
Format format, Format format,
@Nullable MediaCrypto crypto, @Nullable MediaCrypto crypto,
float codecOperatingRate) { float codecOperatingRate) {
...@@ -575,9 +576,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -575,9 +576,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
} }
surface = dummySurface; surface = dummySurface;
} }
codec.configure(mediaFormat, surface, crypto, 0); codecAdapter.configure(mediaFormat, surface, crypto, 0);
if (Util.SDK_INT >= 23 && tunneling) { if (Util.SDK_INT >= 23 && tunneling) {
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec); tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codecAdapter.getCodec());
} }
} }
......
...@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.Format; ...@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.mediacodec.MediaCodecAdapter;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
...@@ -107,7 +108,7 @@ import java.util.ArrayList; ...@@ -107,7 +108,7 @@ import java.util.ArrayList;
@Override @Override
protected void configureCodec( protected void configureCodec(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo,
MediaCodec codec, MediaCodecAdapter codecAdapter,
Format format, Format format,
MediaCrypto crypto, MediaCrypto crypto,
float operatingRate) { float operatingRate) {
...@@ -117,7 +118,7 @@ import java.util.ArrayList; ...@@ -117,7 +118,7 @@ import java.util.ArrayList;
// dropped frames allowed, this is not desired behavior. Hence we skip (rather than drop) // dropped frames allowed, this is not desired behavior. Hence we skip (rather than drop)
// frames up to the current playback position [Internal: b/66494991]. // frames up to the current playback position [Internal: b/66494991].
skipToPositionBeforeRenderingFirstFrame = getState() == Renderer.STATE_STARTED; skipToPositionBeforeRenderingFirstFrame = getState() == Renderer.STATE_STARTED;
super.configureCodec(codecInfo, codec, format, crypto, operatingRate); super.configureCodec(codecInfo, codecAdapter, format, crypto, operatingRate);
} }
@Override @Override
......
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