Commit 7a131636 by olly Committed by Oliver Woodman

MediaCodecAdapter.Factory creates a started Adapter.

This change moves the responsibility of creating, configuring and starting the MediaCodec from the MediaCodecRender to the MediaCodecAdapter.Factory.

This move allows ExoPlayer's client to decide how and when codecs are created and/or reused.

To allow the move, this CL replaces MediaCodecRenderer.ConfigureCodec with MediaCodecRenderer.getCodecConfiguration

PiperOrigin-RevId: 369273887
parent 9fc3b483
...@@ -29,6 +29,14 @@ ...@@ -29,6 +29,14 @@
`PlaybackParameters.DEFAULT` instead. `PlaybackParameters.DEFAULT` instead.
* Use an empty string instead of the URI if the media ID is not explicitly * Use an empty string instead of the URI if the media ID is not explicitly
set with `MediaItem.Builder.setMediaId(String)`. set with `MediaItem.Builder.setMediaId(String)`.
* Remove `MediaCodecRenderer.configureCodec()` and add
`MediaCodecRenderer.getMediaCodecConfiguration()`. The new method is
called just before the `MediaCodec` is created and returns the
parameters needed to create and configure the `MediaCodec` instance.
Applications can override `MediaCodecRenderer.onCodecInitialized()` to
get notified after MediaCodec is initialized, or they can inject a
custom `MediaCodecAdapter.Factory` if they want to control how the
`MediaCodec` is configured.
* UI: * UI:
* Add builder for `PlayerNotificationManager`. * Add builder for `PlayerNotificationManager`.
* Add group setting to `PlayerNotificationManager`. * Add group setting to `PlayerNotificationManager`.
......
...@@ -347,9 +347,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -347,9 +347,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
@Override @Override
protected void configureCodec( protected MediaCodecAdapter.Configuration getMediaCodecConfiguration(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo,
MediaCodecAdapter codec,
Format format, Format format,
@Nullable MediaCrypto crypto, @Nullable MediaCrypto crypto,
float codecOperatingRate) { float codecOperatingRate) {
...@@ -357,12 +356,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -357,12 +356,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name); codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name);
MediaFormat mediaFormat = MediaFormat mediaFormat =
getMediaFormat(format, codecInfo.codecMimeType, codecMaxInputSize, codecOperatingRate); getMediaFormat(format, codecInfo.codecMimeType, codecMaxInputSize, codecOperatingRate);
codec.configure(mediaFormat, /* surface= */ null, crypto, /* flags= */ 0);
// Store the input MIME type if we're only using the codec for decryption. // Store the input MIME type if we're only using the codec for decryption.
boolean decryptOnlyCodecEnabled = boolean decryptOnlyCodecEnabled =
MimeTypes.AUDIO_RAW.equals(codecInfo.mimeType) MimeTypes.AUDIO_RAW.equals(codecInfo.mimeType)
&& !MimeTypes.AUDIO_RAW.equals(format.sampleMimeType); && !MimeTypes.AUDIO_RAW.equals(format.sampleMimeType);
decryptOnlyCodecFormat = decryptOnlyCodecEnabled ? format : null; decryptOnlyCodecFormat = decryptOnlyCodecEnabled ? format : null;
return new MediaCodecAdapter.Configuration(
codecInfo, mediaFormat, /* surface= */ null, crypto, /* flags= */ 0);
} }
@Override @Override
......
...@@ -29,7 +29,9 @@ import androidx.annotation.RequiresApi; ...@@ -29,7 +29,9 @@ import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.CryptoInfo; import com.google.android.exoplayer2.decoder.CryptoInfo;
import com.google.android.exoplayer2.util.TraceUtil;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import java.io.IOException;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
...@@ -96,13 +98,41 @@ import java.nio.ByteBuffer; ...@@ -96,13 +98,41 @@ import java.nio.ByteBuffer;
} }
@Override @Override
public AsynchronousMediaCodecAdapter createAdapter(MediaCodec codec) { public AsynchronousMediaCodecAdapter createAdapter(Configuration configuration)
return new AsynchronousMediaCodecAdapter( throws IOException {
codec, String codecName = configuration.codecInfo.name;
callbackThreadSupplier.get(), @Nullable AsynchronousMediaCodecAdapter codecAdapter = null;
queueingThreadSupplier.get(), @Nullable MediaCodec codec = null;
forceQueueingSynchronizationWorkaround, try {
synchronizeCodecInteractionsWithQueueing); TraceUtil.beginSection("createCodec:" + codecName);
codec = MediaCodec.createByCodecName(codecName);
codecAdapter =
new AsynchronousMediaCodecAdapter(
codec,
callbackThreadSupplier.get(),
queueingThreadSupplier.get(),
forceQueueingSynchronizationWorkaround,
synchronizeCodecInteractionsWithQueueing);
TraceUtil.endSection();
TraceUtil.beginSection("configureCodec");
codecAdapter.configure(
configuration.mediaFormat,
configuration.surface,
configuration.crypto,
configuration.flags);
TraceUtil.endSection();
TraceUtil.beginSection("startCodec");
codecAdapter.start();
TraceUtil.endSection();
return codecAdapter;
} catch (Exception e) {
if (codecAdapter != null) {
codecAdapter.release();
} else if (codec != null) {
codec.release();
}
throw e;
}
} }
} }
...@@ -138,8 +168,7 @@ import java.nio.ByteBuffer; ...@@ -138,8 +168,7 @@ import java.nio.ByteBuffer;
this.state = STATE_CREATED; this.state = STATE_CREATED;
} }
@Override private void configure(
public void configure(
@Nullable MediaFormat mediaFormat, @Nullable MediaFormat mediaFormat,
@Nullable Surface surface, @Nullable Surface surface,
@Nullable MediaCrypto crypto, @Nullable MediaCrypto crypto,
...@@ -149,8 +178,7 @@ import java.nio.ByteBuffer; ...@@ -149,8 +178,7 @@ import java.nio.ByteBuffer;
state = STATE_CONFIGURED; state = STATE_CONFIGURED;
} }
@Override private void start() {
public void start() {
bufferEnqueuer.start(); bufferEnqueuer.start();
codec.start(); codec.start();
state = STATE_STARTED; state = STATE_STARTED;
......
...@@ -26,6 +26,7 @@ import androidx.annotation.Nullable; ...@@ -26,6 +26,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.CryptoInfo; import com.google.android.exoplayer2.decoder.CryptoInfo;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
...@@ -35,6 +36,36 @@ import java.nio.ByteBuffer; ...@@ -35,6 +36,36 @@ import java.nio.ByteBuffer;
* regardless of the mode the {@link MediaCodec} is operating in. * regardless of the mode the {@link MediaCodec} is operating in.
*/ */
public interface MediaCodecAdapter { public interface MediaCodecAdapter {
/** Configuration parameters for a {@link MediaCodecAdapter}. */
class Configuration {
/** Information about the {@link MediaCodec} being configured. */
public final MediaCodecInfo codecInfo;
/** The {@link MediaFormat} for which the codec is being configured. */
public final MediaFormat mediaFormat;
/** For video playbacks, the output where the object will render the decoded frames. */
@Nullable public final Surface surface;
/** For DRM protected playbacks, a {@link MediaCrypto} to use for decryption. */
@Nullable public final MediaCrypto crypto;
/**
* Specify CONFIGURE_FLAG_ENCODE to configure the component as an encoder.
*
* @see MediaCodec#configure
*/
public final int flags;
public Configuration(
MediaCodecInfo codecInfo,
MediaFormat mediaFormat,
@Nullable Surface surface,
@Nullable MediaCrypto crypto,
int flags) {
this.codecInfo = codecInfo;
this.mediaFormat = mediaFormat;
this.surface = surface;
this.crypto = crypto;
this.flags = flags;
}
}
/** A factory for {@link MediaCodecAdapter} instances. */ /** A factory for {@link MediaCodecAdapter} instances. */
interface Factory { interface Factory {
...@@ -42,8 +73,8 @@ public interface MediaCodecAdapter { ...@@ -42,8 +73,8 @@ public interface MediaCodecAdapter {
/** Default factory used in most cases. */ /** Default factory used in most cases. */
Factory DEFAULT = new SynchronousMediaCodecAdapter.Factory(); Factory DEFAULT = new SynchronousMediaCodecAdapter.Factory();
/** Creates an instance wrapping the provided {@link MediaCodec} instance. */ /** Creates a {@link MediaCodecAdapter} instance. */
MediaCodecAdapter createAdapter(MediaCodec codec); MediaCodecAdapter createAdapter(Configuration configuration) throws IOException;
} }
/** /**
...@@ -56,25 +87,6 @@ public interface MediaCodecAdapter { ...@@ -56,25 +87,6 @@ public interface MediaCodecAdapter {
} }
/** /**
* Configures this adapter and the underlying {@link MediaCodec}. Needs to be called before {@link
* #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();
/**
* Returns the next available input buffer index from the underlying {@link MediaCodec} or {@link * Returns the next available input buffer index from the underlying {@link MediaCodec} or {@link
* MediaCodec#INFO_TRY_AGAIN_LATER} if no such buffer exists. * MediaCodec#INFO_TRY_AGAIN_LATER} if no such buffer exists.
* *
...@@ -192,8 +204,7 @@ public interface MediaCodecAdapter { ...@@ -192,8 +204,7 @@ public interface MediaCodecAdapter {
void setParameters(Bundle params); void setParameters(Bundle params);
/** /**
* Specifies the scaling mode to use, if a surface has been specified in a previous call to {@link * Specifies the scaling mode to use, if a surface was specified when the codec was created.
* #configure}.
* *
* @see MediaCodec#setVideoScalingMode(int) * @see MediaCodec#setVideoScalingMode(int)
*/ */
......
...@@ -528,18 +528,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -528,18 +528,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
throws DecoderQueryException; throws DecoderQueryException;
/** /**
* Configures a newly created {@link MediaCodec}. * Returns the {@link MediaCodecAdapter.Configuration} that will be used to create and configure a
* {@link MediaCodec} to decode the given {@link Format} for a playback.
* *
* @param codecInfo Information about the {@link MediaCodec} being configured. * @param codecInfo Information about the {@link MediaCodec} being configured.
* @param codec 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
* no codec operating rate should be set. * no codec operating rate should be set.
* @return The parameters needed to call {@link MediaCodec#configure}.
*/ */
protected abstract void configureCodec( @Nullable
protected abstract MediaCodecAdapter.Configuration getMediaCodecConfiguration(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo,
MediaCodecAdapter codec,
Format format, Format format,
@Nullable MediaCrypto crypto, @Nullable MediaCrypto crypto,
float codecOperatingRate); float codecOperatingRate);
...@@ -1111,7 +1112,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1111,7 +1112,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
long codecInitializedTimestamp; long codecInitializedTimestamp;
@Nullable MediaCodecAdapter codecAdapter = null; @Nullable MediaCodecAdapter codecAdapter = null;
String codecName = codecInfo.name; String codecName = codecInfo.name;
float codecOperatingRate = float codecOperatingRate =
Util.SDK_INT < 23 Util.SDK_INT < 23
? CODEC_OPERATING_RATE_UNSET ? CODEC_OPERATING_RATE_UNSET
...@@ -1119,35 +1119,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1119,35 +1119,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (codecOperatingRate <= assumedMinimumCodecOperatingRate) { if (codecOperatingRate <= assumedMinimumCodecOperatingRate) {
codecOperatingRate = CODEC_OPERATING_RATE_UNSET; codecOperatingRate = CODEC_OPERATING_RATE_UNSET;
} }
codecInitializingTimestamp = SystemClock.elapsedRealtime();
try { TraceUtil.beginSection("createCodec:" + codecName);
codecInitializingTimestamp = SystemClock.elapsedRealtime(); MediaCodecAdapter.Configuration configuration =
TraceUtil.beginSection("createCodec:" + codecName); getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate);
MediaCodec codec = MediaCodec.createByCodecName(codecName); if (enableAsynchronousBufferQueueing && Util.SDK_INT >= 23) {
if (enableAsynchronousBufferQueueing && Util.SDK_INT >= 23) { codecAdapter =
codecAdapter = new AsynchronousMediaCodecAdapter.Factory(
new AsynchronousMediaCodecAdapter.Factory( getTrackType(),
getTrackType(), forceAsyncQueueingSynchronizationWorkaround,
forceAsyncQueueingSynchronizationWorkaround, enableSynchronizeCodecInteractionsWithQueueing)
enableSynchronizeCodecInteractionsWithQueueing) .createAdapter(configuration);
.createAdapter(codec); } else {
} else { codecAdapter = codecAdapterFactory.createAdapter(configuration);
codecAdapter = codecAdapterFactory.createAdapter(codec);
}
TraceUtil.endSection();
TraceUtil.beginSection("configureCodec");
configureCodec(codecInfo, codecAdapter, inputFormat, crypto, codecOperatingRate);
TraceUtil.endSection();
TraceUtil.beginSection("startCodec");
codecAdapter.start();
TraceUtil.endSection();
codecInitializedTimestamp = SystemClock.elapsedRealtime();
} catch (Exception e) {
if (codecAdapter != null) {
codecAdapter.release();
}
throw e;
} }
codecInitializedTimestamp = SystemClock.elapsedRealtime();
this.codec = codecAdapter; this.codec = codecAdapter;
this.codecInfo = codecInfo; this.codecInfo = codecInfo;
......
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
package com.google.android.exoplayer2.mediacodec; package com.google.android.exoplayer2.mediacodec;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
...@@ -28,19 +28,51 @@ import androidx.annotation.Nullable; ...@@ -28,19 +28,51 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.CryptoInfo; import com.google.android.exoplayer2.decoder.CryptoInfo;
import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
* A {@link MediaCodecAdapter} that operates the underlying {@link MediaCodec} in synchronous mode. * A {@link MediaCodecAdapter} that operates the underlying {@link MediaCodec} in synchronous mode.
*/ */
public final class SynchronousMediaCodecAdapter implements MediaCodecAdapter { public class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
/** A factory for {@link SynchronousMediaCodecAdapter} instances. */ /** A factory for {@link SynchronousMediaCodecAdapter} instances. */
public static final class Factory implements MediaCodecAdapter.Factory { public static class Factory implements MediaCodecAdapter.Factory {
@Override @Override
public MediaCodecAdapter createAdapter(MediaCodec codec) { public MediaCodecAdapter createAdapter(Configuration configuration) throws IOException {
return new SynchronousMediaCodecAdapter(codec); @Nullable MediaCodec codec = null;
try {
codec = createCodec(configuration);
TraceUtil.beginSection("configureCodec");
codec.configure(
configuration.mediaFormat,
configuration.surface,
configuration.crypto,
configuration.flags);
TraceUtil.endSection();
TraceUtil.beginSection("startCodec");
codec.start();
TraceUtil.endSection();
return new SynchronousMediaCodecAdapter(codec);
} catch (IOException | RuntimeException e) {
if (codec != null) {
codec.release();
}
throw e;
}
}
/** Creates a new {@link MediaCodec} instance. */
protected MediaCodec createCodec(Configuration configuration) throws IOException {
checkNotNull(configuration.codecInfo);
String codecName = configuration.codecInfo.name;
TraceUtil.beginSection("createCodec:" + codecName);
MediaCodec mediaCodec = MediaCodec.createByCodecName(codecName);
TraceUtil.endSection();
return mediaCodec;
} }
} }
...@@ -50,20 +82,6 @@ public final class SynchronousMediaCodecAdapter implements MediaCodecAdapter { ...@@ -50,20 +82,6 @@ public final class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
private SynchronousMediaCodecAdapter(MediaCodec mediaCodec) { private SynchronousMediaCodecAdapter(MediaCodec mediaCodec) {
this.codec = mediaCodec; this.codec = mediaCodec;
}
@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() {
codec.start();
if (Util.SDK_INT < 21) { if (Util.SDK_INT < 21) {
inputByteBuffers = codec.getInputBuffers(); inputByteBuffers = codec.getInputBuffers();
outputByteBuffers = codec.getOutputBuffers(); outputByteBuffers = codec.getOutputBuffers();
......
...@@ -600,9 +600,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -600,9 +600,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
} }
@Override @Override
protected void configureCodec( protected MediaCodecAdapter.Configuration getMediaCodecConfiguration(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo,
MediaCodecAdapter codec,
Format format, Format format,
@Nullable MediaCrypto crypto, @Nullable MediaCrypto crypto,
float codecOperatingRate) { float codecOperatingRate) {
...@@ -625,10 +624,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -625,10 +624,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
} }
surface = dummySurface; surface = dummySurface;
} }
codec.configure(mediaFormat, surface, crypto, 0); return new MediaCodecAdapter.Configuration(
if (Util.SDK_INT >= 23 && tunneling) { codecInfo, mediaFormat, surface, crypto, /* flags= */ 0);
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);
}
} }
@Override @Override
...@@ -688,6 +685,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -688,6 +685,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
codecNeedsSetOutputSurfaceWorkaround = codecNeedsSetOutputSurfaceWorkaround(name); codecNeedsSetOutputSurfaceWorkaround = codecNeedsSetOutputSurfaceWorkaround(name);
codecHandlesHdr10PlusOutOfBandMetadata = codecHandlesHdr10PlusOutOfBandMetadata =
Assertions.checkNotNull(getCodecInfo()).isHdr10PlusOutOfBandMetadataSupported(); Assertions.checkNotNull(getCodecInfo()).isHdr10PlusOutOfBandMetadataSupported();
if (Util.SDK_INT >= 23 && tunneling) {
tunnelingOnFrameRenderedListener =
new OnFrameRenderedListenerV23(Assertions.checkNotNull(getCodec()));
}
} }
@Override @Override
......
...@@ -27,6 +27,8 @@ import com.google.android.exoplayer2.C; ...@@ -27,6 +27,8 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
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.MediaCodecAdapter;
import com.google.android.exoplayer2.mediacodec.MediaCodecAdapter.Configuration;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.SynchronousMediaCodecAdapter; import com.google.android.exoplayer2.mediacodec.SynchronousMediaCodecAdapter;
import com.google.android.exoplayer2.util.MediaFormatUtil; import com.google.android.exoplayer2.util.MediaFormatUtil;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
...@@ -60,6 +62,36 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -60,6 +62,36 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private boolean inputStreamEnded; private boolean inputStreamEnded;
private boolean outputStreamEnded; private boolean outputStreamEnded;
private static class Factory extends SynchronousMediaCodecAdapter.Factory {
private final boolean decoder;
public Factory(boolean decoder) {
this.decoder = decoder;
}
@Override
protected MediaCodec createCodec(Configuration configuration) throws IOException {
String sampleMimeType =
checkNotNull(configuration.mediaFormat.getString(MediaFormat.KEY_MIME));
return decoder
? MediaCodec.createDecoderByType(checkNotNull(sampleMimeType))
: MediaCodec.createEncoderByType(checkNotNull(sampleMimeType));
}
}
private static MediaCodecInfo createPlaceholderMediaCodecInfo() {
return MediaCodecInfo.newInstance(
/* name= */ "name-placeholder",
/* mimeType= */ "mime-type-placeholder",
/* codecMimeType= */ "mime-type-placeholder",
/* capabilities= */ null,
/* hardwareAccelerated= */ false,
/* softwareOnly= */ false,
/* vendor= */ false,
/* forceDisableAdaptive= */ false,
/* forceSecure= */ false);
}
/** /**
* Returns a {@link MediaCodecAdapterWrapper} for a configured and started {@link * Returns a {@link MediaCodecAdapterWrapper} for a configured and started {@link
* MediaCodecAdapter} audio decoder. * MediaCodecAdapter} audio decoder.
...@@ -70,25 +102,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -70,25 +102,27 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* @throws IOException If the underlying codec cannot be created. * @throws IOException If the underlying codec cannot be created.
*/ */
public static MediaCodecAdapterWrapper createForAudioDecoding(Format format) throws IOException { public static MediaCodecAdapterWrapper createForAudioDecoding(Format format) throws IOException {
@Nullable MediaCodec decoder = null;
@Nullable MediaCodecAdapter adapter = null; @Nullable MediaCodecAdapter adapter = null;
try { try {
decoder = MediaCodec.createDecoderByType(checkNotNull(format.sampleMimeType));
MediaFormat mediaFormat = MediaFormat mediaFormat =
MediaFormat.createAudioFormat( MediaFormat.createAudioFormat(
format.sampleMimeType, format.sampleRate, format.channelCount); checkNotNull(format.sampleMimeType), format.sampleRate, format.channelCount);
MediaFormatUtil.maybeSetInteger( MediaFormatUtil.maybeSetInteger(
mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize); mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData); MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
adapter = new SynchronousMediaCodecAdapter.Factory().createAdapter(decoder); adapter =
adapter.configure(mediaFormat, /* surface= */ null, /* crypto= */ null, /* flags= */ 0); new Factory(/* decoder= */ true)
adapter.start(); .createAdapter(
new MediaCodecAdapter.Configuration(
createPlaceholderMediaCodecInfo(),
mediaFormat,
/* surface= */ null,
/* crypto= */ null,
/* flags= */ 0));
return new MediaCodecAdapterWrapper(adapter); return new MediaCodecAdapterWrapper(adapter);
} catch (Exception e) { } catch (Exception e) {
if (adapter != null) { if (adapter != null) {
adapter.release(); adapter.release();
} else if (decoder != null) {
decoder.release();
} }
throw e; throw e;
} }
...@@ -107,18 +141,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -107,18 +141,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Nullable MediaCodec encoder = null; @Nullable MediaCodec encoder = null;
@Nullable MediaCodecAdapter adapter = null; @Nullable MediaCodecAdapter adapter = null;
try { try {
encoder = MediaCodec.createEncoderByType(checkNotNull(format.sampleMimeType));
MediaFormat mediaFormat = MediaFormat mediaFormat =
MediaFormat.createAudioFormat( MediaFormat.createAudioFormat(
format.sampleMimeType, format.sampleRate, format.channelCount); checkNotNull(format.sampleMimeType), format.sampleRate, format.channelCount);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.bitrate); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.bitrate);
adapter = new SynchronousMediaCodecAdapter.Factory().createAdapter(encoder); adapter =
adapter.configure( new Factory(/* decoder= */ false)
mediaFormat, .createAdapter(
/* surface= */ null, new MediaCodecAdapter.Configuration(
/* crypto= */ null, createPlaceholderMediaCodecInfo(),
/* flags= */ MediaCodec.CONFIGURE_FLAG_ENCODE); mediaFormat,
adapter.start(); /* surface= */ null,
/* crypto= */ null,
/* flags= */ MediaCodec.CONFIGURE_FLAG_ENCODE));
return new MediaCodecAdapterWrapper(adapter); return new MediaCodecAdapterWrapper(adapter);
} catch (Exception e) { } catch (Exception e) {
if (adapter != null) { if (adapter != null) {
......
...@@ -131,19 +131,15 @@ import java.util.ArrayList; ...@@ -131,19 +131,15 @@ import java.util.ArrayList;
} }
@Override @Override
protected void configureCodec( protected MediaCodecAdapter.Configuration getMediaCodecConfiguration(
MediaCodecInfo codecInfo, MediaCodecInfo codecInfo, Format format, MediaCrypto crypto, float operatingRate) {
MediaCodecAdapter codec,
Format format,
MediaCrypto crypto,
float operatingRate) {
// If the codec is being initialized whilst the renderer is started, default behavior is to // If the codec is being initialized whilst the renderer is started, default behavior is to
// render the first frame (i.e. the keyframe before the current position), then drop frames up // render the first frame (i.e. the keyframe before the current position), then drop frames up
// to the current playback position. For test runs that place a maximum limit on the number of // to the current playback position. For test runs that place a maximum limit on the number of
// 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); return super.getMediaCodecConfiguration(codecInfo, format, crypto, operatingRate);
} }
@Override @Override
......
...@@ -20,7 +20,6 @@ import static com.google.android.exoplayer2.util.Assertions.checkState; ...@@ -20,7 +20,6 @@ import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.content.Context; import android.content.Context;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
...@@ -46,6 +45,7 @@ import com.google.android.exoplayer2.text.TextRenderer; ...@@ -46,6 +45,7 @@ import com.google.android.exoplayer2.text.TextRenderer;
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import com.google.android.exoplayer2.video.VideoRendererEventListener; import com.google.android.exoplayer2.video.VideoRendererEventListener;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -121,10 +121,11 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa ...@@ -121,10 +121,11 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
@RequiresApi(18) @RequiresApi(18)
@Override @Override
public MediaCodecAdapter createAdapter(MediaCodec codec) { public MediaCodecAdapter createAdapter(Configuration configuration) throws IOException {
CapturingMediaCodecAdapter adapter = CapturingMediaCodecAdapter adapter =
new CapturingMediaCodecAdapter( new CapturingMediaCodecAdapter(
MediaCodecAdapter.Factory.DEFAULT.createAdapter(codec), codec.getName()); MediaCodecAdapter.Factory.DEFAULT.createAdapter(configuration),
configuration.codecInfo.name);
constructedAdapters.add(adapter); constructedAdapters.add(adapter);
return adapter; return adapter;
} }
...@@ -168,20 +169,6 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa ...@@ -168,20 +169,6 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
// MediaCodecAdapter implementation // MediaCodecAdapter implementation
@Override @Override
public void configure(
@Nullable MediaFormat mediaFormat,
@Nullable Surface surface,
@Nullable MediaCrypto crypto,
int flags) {
delegate.configure(mediaFormat, surface, crypto, flags);
}
@Override
public void start() {
delegate.start();
}
@Override
public int dequeueInputBufferIndex() { public int dequeueInputBufferIndex() {
return delegate.dequeueInputBufferIndex(); return delegate.dequeueInputBufferIndex();
} }
......
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