diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java
index 737e1285f5..fc5b65891d 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java
@@ -42,7 +42,7 @@ import java.nio.ByteBuffer;
@Override
public FrameworkMuxer create(String path, String outputMimeType) throws IOException {
MediaMuxer mediaMuxer = new MediaMuxer(path, mimeTypeToMuxerOutputFormat(outputMimeType));
- return new FrameworkMuxer(mediaMuxer, outputMimeType);
+ return new FrameworkMuxer(mediaMuxer);
}
@RequiresApi(26)
@@ -53,7 +53,7 @@ import java.nio.ByteBuffer;
new MediaMuxer(
parcelFileDescriptor.getFileDescriptor(),
mimeTypeToMuxerOutputFormat(outputMimeType));
- return new FrameworkMuxer(mediaMuxer, outputMimeType);
+ return new FrameworkMuxer(mediaMuxer);
}
@Override
@@ -65,47 +65,46 @@ import java.nio.ByteBuffer;
}
return true;
}
+
+ @Override
+ public boolean supportsSampleMimeType(
+ @Nullable String sampleMimeType, String containerMimeType) {
+ // MediaMuxer supported sample formats are documented in MediaMuxer.addTrack(MediaFormat).
+ boolean isAudio = MimeTypes.isAudio(sampleMimeType);
+ boolean isVideo = MimeTypes.isVideo(sampleMimeType);
+ if (containerMimeType.equals(MimeTypes.VIDEO_MP4)) {
+ if (isVideo) {
+ return MimeTypes.VIDEO_H263.equals(sampleMimeType)
+ || MimeTypes.VIDEO_H264.equals(sampleMimeType)
+ || MimeTypes.VIDEO_MP4V.equals(sampleMimeType)
+ || (Util.SDK_INT >= 24 && MimeTypes.VIDEO_H265.equals(sampleMimeType));
+ } else if (isAudio) {
+ return MimeTypes.AUDIO_AAC.equals(sampleMimeType)
+ || MimeTypes.AUDIO_AMR_NB.equals(sampleMimeType)
+ || MimeTypes.AUDIO_AMR_WB.equals(sampleMimeType);
+ }
+ } else if (containerMimeType.equals(MimeTypes.VIDEO_WEBM) && SDK_INT >= 21) {
+ if (isVideo) {
+ return MimeTypes.VIDEO_VP8.equals(sampleMimeType)
+ || (Util.SDK_INT >= 24 && MimeTypes.VIDEO_VP9.equals(sampleMimeType));
+ } else if (isAudio) {
+ return MimeTypes.AUDIO_VORBIS.equals(sampleMimeType);
+ }
+ }
+ return false;
+ }
}
private final MediaMuxer mediaMuxer;
- private final String outputMimeType;
private final MediaCodec.BufferInfo bufferInfo;
private boolean isStarted;
- private FrameworkMuxer(MediaMuxer mediaMuxer, String outputMimeType) {
+ private FrameworkMuxer(MediaMuxer mediaMuxer) {
this.mediaMuxer = mediaMuxer;
- this.outputMimeType = outputMimeType;
bufferInfo = new MediaCodec.BufferInfo();
}
- @Override
- public boolean supportsSampleMimeType(@Nullable String mimeType) {
- // MediaMuxer supported sample formats are documented in MediaMuxer.addTrack(MediaFormat).
- boolean isAudio = MimeTypes.isAudio(mimeType);
- boolean isVideo = MimeTypes.isVideo(mimeType);
- if (outputMimeType.equals(MimeTypes.VIDEO_MP4)) {
- if (isVideo) {
- return MimeTypes.VIDEO_H263.equals(mimeType)
- || MimeTypes.VIDEO_H264.equals(mimeType)
- || MimeTypes.VIDEO_MP4V.equals(mimeType)
- || (Util.SDK_INT >= 24 && MimeTypes.VIDEO_H265.equals(mimeType));
- } else if (isAudio) {
- return MimeTypes.AUDIO_AAC.equals(mimeType)
- || MimeTypes.AUDIO_AMR_NB.equals(mimeType)
- || MimeTypes.AUDIO_AMR_WB.equals(mimeType);
- }
- } else if (outputMimeType.equals(MimeTypes.VIDEO_WEBM) && SDK_INT >= 21) {
- if (isVideo) {
- return MimeTypes.VIDEO_VP8.equals(mimeType)
- || (Util.SDK_INT >= 24 && MimeTypes.VIDEO_VP9.equals(mimeType));
- } else if (isAudio) {
- return MimeTypes.AUDIO_VORBIS.equals(mimeType);
- }
- }
- return false;
- }
-
@Override
public int addTrack(Format format) {
String sampleMimeType = checkNotNull(format.sampleMimeType);
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Muxer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Muxer.java
index b00fbadfd5..20a868edb2 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Muxer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Muxer.java
@@ -25,11 +25,12 @@ import java.nio.ByteBuffer;
/**
* Abstracts media muxing operations.
*
- *
Query whether {@link #supportsSampleMimeType(String) sample MIME types are supported} and
- * {@link #addTrack(Format) add all tracks}, then {@link #writeSampleData(int, ByteBuffer, boolean,
- * long) write sample data} to mux samples. Once any sample data has been written, it is not
- * possible to add tracks. After writing all sample data, {@link #release(boolean) release} the
- * instance to finish writing to the output and return any resources to the system.
+ *
Query whether {@link Factory#supportsOutputMimeType(String) container MIME type} and {@link
+ * Factory#supportsSampleMimeType(String, String) sample MIME types} are supported and {@link
+ * #addTrack(Format) add all tracks}, then {@link #writeSampleData(int, ByteBuffer, boolean, long)
+ * write sample data} to mux samples. Once any sample data has been written, it is not possible to
+ * add tracks. After writing all sample data, {@link #release(boolean) release} the instance to
+ * finish writing to the output and return any resources to the system.
*/
/* package */ interface Muxer {
@@ -62,10 +63,13 @@ import java.nio.ByteBuffer;
/** Returns whether the {@link MimeTypes MIME type} provided is a supported output format. */
boolean supportsOutputMimeType(String mimeType);
- }
- /** Returns whether the sample {@link MimeTypes MIME type} is supported. */
- boolean supportsSampleMimeType(@Nullable String mimeType);
+ /**
+ * Returns whether the sample {@link MimeTypes MIME type} is supported with the given container
+ * {@link MimeTypes MIME type}.
+ */
+ boolean supportsSampleMimeType(@Nullable String sampleMimeType, String containerMimeType);
+ }
/**
* Adds a track with the specified format, and returns its index (to be passed in subsequent calls
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/MuxerWrapper.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/MuxerWrapper.java
index 6127fd567a..e8a217f645 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/MuxerWrapper.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/MuxerWrapper.java
@@ -45,8 +45,10 @@ import java.nio.ByteBuffer;
private static final long MAX_TRACK_WRITE_AHEAD_US = C.msToUs(500);
private final Muxer muxer;
+ private final Muxer.Factory muxerFactory;
private final SparseIntArray trackTypeToIndex;
private final SparseLongArray trackTypeToTimeUs;
+ private final String containerMimeType;
private int trackCount;
private int trackFormatCount;
@@ -54,8 +56,10 @@ import java.nio.ByteBuffer;
private @C.TrackType int previousTrackType;
private long minTrackTimeUs;
- public MuxerWrapper(Muxer muxer) {
+ public MuxerWrapper(Muxer muxer, Muxer.Factory muxerFactory, String containerMimeType) {
this.muxer = muxer;
+ this.muxerFactory = muxerFactory;
+ this.containerMimeType = containerMimeType;
trackTypeToIndex = new SparseIntArray();
trackTypeToTimeUs = new SparseLongArray();
previousTrackType = C.TRACK_TYPE_NONE;
@@ -78,7 +82,7 @@ import java.nio.ByteBuffer;
/** Returns whether the sample {@link MimeTypes MIME type} is supported. */
public boolean supportsSampleMimeType(@Nullable String mimeType) {
- return muxer.supportsSampleMimeType(mimeType);
+ return muxerFactory.supportsSampleMimeType(mimeType, containerMimeType);
}
/**
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java
index 02db36c6ad..61feaf5dd0 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java
@@ -100,6 +100,7 @@ public final class TranscodingTransformer {
private boolean removeVideo;
private boolean flattenForSlowMotion;
private String outputMimeType;
+ @Nullable private String audioMimeType;
private TranscodingTransformer.Listener listener;
private Looper looper;
private Clock clock;
@@ -122,6 +123,7 @@ public final class TranscodingTransformer {
this.removeVideo = transcodingTransformer.transformation.removeVideo;
this.flattenForSlowMotion = transcodingTransformer.transformation.flattenForSlowMotion;
this.outputMimeType = transcodingTransformer.transformation.outputMimeType;
+ this.audioMimeType = transcodingTransformer.transformation.audioMimeType;
this.listener = transcodingTransformer.listener;
this.looper = transcodingTransformer.looper;
this.clock = transcodingTransformer.clock;
@@ -212,10 +214,8 @@ public final class TranscodingTransformer {
}
/**
- * Sets the MIME type of the output. The default value is {@link MimeTypes#VIDEO_MP4}. The
- * output MIME type should be supported by the {@link
- * Muxer.Factory#supportsOutputMimeType(String) muxer}. Values supported by the default {@link
- * FrameworkMuxer} are:
+ * Sets the MIME type of the output. The default value is {@link MimeTypes#VIDEO_MP4}. Supported
+ * values are:
*
*
* - {@link MimeTypes#VIDEO_MP4}
@@ -230,6 +230,31 @@ public final class TranscodingTransformer {
return this;
}
+ /**
+ * Sets the audio MIME type of the output. The default value is to use the same MIME type as the
+ * input. Supported values are:
+ *
+ *
+ * - when the container MIME type is {@link MimeTypes#VIDEO_MP4}:
+ *
+ * - {@link MimeTypes#AUDIO_AAC}
+ *
- {@link MimeTypes#AUDIO_AMR_NB}
+ *
- {@link MimeTypes#AUDIO_AMR_WB}
+ *
+ * - when the container MIME type is {@link MimeTypes#VIDEO_WEBM}:
+ *
+ * - {@link MimeTypes#AUDIO_VORBIS}
+ *
+ *
+ *
+ * @param audioMimeType The MIME type of the audio samples in the output.
+ * @return This builder.
+ */
+ public Builder setAudioMimeType(String audioMimeType) {
+ this.audioMimeType = audioMimeType;
+ return this;
+ }
+
/**
* Sets the {@link TranscodingTransformer.Listener} to listen to the transformation events.
*
@@ -290,6 +315,7 @@ public final class TranscodingTransformer {
* @throws IllegalStateException If both audio and video have been removed (otherwise the output
* would not contain any samples).
* @throws IllegalStateException If the muxer doesn't support the requested output MIME type.
+ * @throws IllegalStateException If the muxer doesn't support the requested audio MIME type.
*/
public TranscodingTransformer build() {
checkStateNotNull(context);
@@ -303,8 +329,17 @@ public final class TranscodingTransformer {
checkState(
muxerFactory.supportsOutputMimeType(outputMimeType),
"Unsupported output MIME type: " + outputMimeType);
+ if (audioMimeType != null) {
+ checkState(
+ muxerFactory.supportsSampleMimeType(audioMimeType, outputMimeType),
+ "Unsupported sample MIME type "
+ + audioMimeType
+ + " for container MIME type "
+ + outputMimeType);
+ }
Transformation transformation =
- new Transformation(removeAudio, removeVideo, flattenForSlowMotion, outputMimeType);
+ new Transformation(
+ removeAudio, removeVideo, flattenForSlowMotion, outputMimeType, audioMimeType);
return new TranscodingTransformer(
context, mediaSourceFactory, muxerFactory, transformation, listener, looper, clock);
}
@@ -469,7 +504,8 @@ public final class TranscodingTransformer {
throw new IllegalStateException("There is already a transformation in progress.");
}
- MuxerWrapper muxerWrapper = new MuxerWrapper(muxer);
+ MuxerWrapper muxerWrapper =
+ new MuxerWrapper(muxer, muxerFactory, transformation.outputMimeType);
this.muxerWrapper = muxerWrapper;
DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
trackSelector.setParameters(
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java
index b0c9e8d2cc..a224fe3a93 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java
@@ -16,6 +16,8 @@
package com.google.android.exoplayer2.transformer;
+import androidx.annotation.Nullable;
+
/** A media transformation configuration. */
/* package */ final class Transformation {
@@ -23,15 +25,18 @@ package com.google.android.exoplayer2.transformer;
public final boolean removeVideo;
public final boolean flattenForSlowMotion;
public final String outputMimeType;
+ @Nullable public final String audioMimeType;
public Transformation(
boolean removeAudio,
boolean removeVideo,
boolean flattenForSlowMotion,
- String outputMimeType) {
+ String outputMimeType,
+ @Nullable String audioMimeType) {
this.removeAudio = removeAudio;
this.removeVideo = removeVideo;
this.flattenForSlowMotion = flattenForSlowMotion;
this.outputMimeType = outputMimeType;
+ this.audioMimeType = audioMimeType;
}
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
index f300f66aa3..34d10137b8 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
@@ -209,10 +209,8 @@ public final class Transformer {
}
/**
- * Sets the MIME type of the output. The default value is {@link MimeTypes#VIDEO_MP4}. The
- * output MIME type should be supported by the {@link
- * Muxer.Factory#supportsOutputMimeType(String) muxer}. Values supported by the default {@link
- * FrameworkMuxer} are:
+ * Sets the MIME type of the output. The default value is {@link MimeTypes#VIDEO_MP4}. Supported
+ * values are:
*
*
* - {@link MimeTypes#VIDEO_MP4}
@@ -301,7 +299,12 @@ public final class Transformer {
muxerFactory.supportsOutputMimeType(outputMimeType),
"Unsupported output MIME type: " + outputMimeType);
Transformation transformation =
- new Transformation(removeAudio, removeVideo, flattenForSlowMotion, outputMimeType);
+ new Transformation(
+ removeAudio,
+ removeVideo,
+ flattenForSlowMotion,
+ outputMimeType,
+ /* audioMimeType= */ null);
return new Transformer(
context, mediaSourceFactory, muxerFactory, transformation, listener, looper, clock);
}
@@ -464,7 +467,8 @@ public final class Transformer {
throw new IllegalStateException("There is already a transformation in progress.");
}
- MuxerWrapper muxerWrapper = new MuxerWrapper(muxer);
+ MuxerWrapper muxerWrapper =
+ new MuxerWrapper(muxer, muxerFactory, transformation.outputMimeType);
this.muxerWrapper = muxerWrapper;
DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
trackSelector.setParameters(
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java
index 6b1d0f3b90..64dc53d58c 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java
@@ -350,11 +350,15 @@ import java.nio.ByteBuffer;
throw createRendererException(e, PlaybackException.ERROR_CODE_UNSPECIFIED);
}
}
+ String audioMimeType =
+ transformation.audioMimeType == null
+ ? checkNotNull(inputFormat).sampleMimeType
+ : transformation.audioMimeType;
try {
encoder =
MediaCodecAdapterWrapper.createForAudioEncoding(
new Format.Builder()
- .setSampleMimeType(checkNotNull(inputFormat).sampleMimeType)
+ .setSampleMimeType(audioMimeType)
.setSampleRate(outputAudioFormat.sampleRate)
.setChannelCount(outputAudioFormat.channelCount)
.setAverageBitrate(DEFAULT_ENCODER_BITRATE)
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java
index 724790b8c6..4f2243000d 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java
@@ -52,7 +52,13 @@ import com.google.android.exoplayer2.util.MimeTypes;
@Nullable String sampleMimeType = format.sampleMimeType;
if (MimeTypes.getTrackType(sampleMimeType) != getTrackType()) {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
- } else if (muxerWrapper.supportsSampleMimeType(sampleMimeType)) {
+ } else if ((MimeTypes.isAudio(sampleMimeType)
+ && muxerWrapper.supportsSampleMimeType(
+ transformation.audioMimeType == null
+ ? sampleMimeType
+ : transformation.audioMimeType))
+ || (MimeTypes.isVideo(sampleMimeType)
+ && muxerWrapper.supportsSampleMimeType(sampleMimeType))) {
return RendererCapabilities.create(C.FORMAT_HANDLED);
} else {
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java
index e4835274c2..d47dd0d32f 100644
--- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java
@@ -26,30 +26,27 @@ import java.util.List;
/**
* An implementation of {@link Muxer} that supports dumping information about all interactions (for
- * testing purposes) and delegates the actual muxing operations to a {@link FrameworkMuxer}.
+ * testing purposes) and delegates the actual muxing operations to another {@link Muxer} created
+ * using the factory provided.
*/
public final class TestMuxer implements Muxer, Dumper.Dumpable {
- private final Muxer frameworkMuxer;
+ private final Muxer muxer;
private final List dumpables;
/** Creates a new test muxer. */
- public TestMuxer(String path, String outputMimeType) throws IOException {
- frameworkMuxer = new FrameworkMuxer.Factory().create(path, outputMimeType);
+ public TestMuxer(String path, String outputMimeType, Muxer.Factory muxerFactory)
+ throws IOException {
+ muxer = muxerFactory.create(path, outputMimeType);
dumpables = new ArrayList<>();
dumpables.add(dumper -> dumper.add("containerMimeType", outputMimeType));
}
// Muxer implementation.
- @Override
- public boolean supportsSampleMimeType(String mimeType) {
- return frameworkMuxer.supportsSampleMimeType(mimeType);
- }
-
@Override
public int addTrack(Format format) {
- int trackIndex = frameworkMuxer.addTrack(format);
+ int trackIndex = muxer.addTrack(format);
dumpables.add(new DumpableFormat(format, trackIndex));
return trackIndex;
}
@@ -58,13 +55,13 @@ public final class TestMuxer implements Muxer, Dumper.Dumpable {
public void writeSampleData(
int trackIndex, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) {
dumpables.add(new DumpableSample(trackIndex, data, isKeyFrame, presentationTimeUs));
- frameworkMuxer.writeSampleData(trackIndex, data, isKeyFrame, presentationTimeUs);
+ muxer.writeSampleData(trackIndex, data, isKeyFrame, presentationTimeUs);
}
@Override
public void release(boolean forCancellation) {
dumpables.add(dumper -> dumper.add("released", true));
- frameworkMuxer.release(forCancellation);
+ muxer.release(forCancellation);
}
// Dumper.Dumpable implementation.
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
index a99b4a369b..690b6fe2bb 100644
--- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
@@ -562,16 +562,25 @@ public final class TransformerTest {
}
private final class TestMuxerFactory implements Muxer.Factory {
+
+ private final Muxer.Factory frameworkMuxerFactory;
+
+ public TestMuxerFactory() {
+ frameworkMuxerFactory = new FrameworkMuxer.Factory();
+ }
+
@Override
public Muxer create(String path, String outputMimeType) throws IOException {
- testMuxer = new TestMuxer(path, outputMimeType);
+ testMuxer = new TestMuxer(path, outputMimeType, frameworkMuxerFactory);
return testMuxer;
}
@Override
public Muxer create(ParcelFileDescriptor parcelFileDescriptor, String outputMimeType)
throws IOException {
- testMuxer = new TestMuxer("FD:" + parcelFileDescriptor.getFd(), outputMimeType);
+ testMuxer =
+ new TestMuxer(
+ "FD:" + parcelFileDescriptor.getFd(), outputMimeType, frameworkMuxerFactory);
return testMuxer;
}
@@ -579,5 +588,10 @@ public final class TransformerTest {
public boolean supportsOutputMimeType(String mimeType) {
return true;
}
+
+ @Override
+ public boolean supportsSampleMimeType(String sampleMimeType, String outputMimeType) {
+ return frameworkMuxerFactory.supportsSampleMimeType(sampleMimeType, outputMimeType);
+ }
}
}