diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 83c3c0af6c..4f4bb2d851 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -32,6 +32,9 @@ at stereo when handling PCM input. * When selecting tracks in `ExoPlayerAssetLoader`, ignore audio channel count constraints as they only apply for playback. + * Replace `androidx.media3.transformer.Muxer` interface with + `androidx.media3.muxer.Muxer` and remove + `androidx.media3.transformer.Muxer`. * Track Selection: * Extractors: * MPEG-TS: Roll forward the change ensuring the last frame is rendered by diff --git a/demos/transformer/build.gradle b/demos/transformer/build.gradle index 279fcc7476..1d6f779cfd 100644 --- a/demos/transformer/build.gradle +++ b/demos/transformer/build.gradle @@ -83,6 +83,7 @@ dependencies { implementation project(modulePrefix + 'lib-exoplayer') implementation project(modulePrefix + 'lib-exoplayer-dash') implementation project(modulePrefix + 'lib-transformer') + implementation project(modulePrefix + 'lib-muxer') implementation project(modulePrefix + 'lib-ui') // For MediaPipe and its dependencies: diff --git a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java index 44b5650445..0ef03f7602 100644 --- a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java +++ b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java @@ -80,6 +80,7 @@ import androidx.media3.effect.TextureOverlay; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.audio.SilenceSkippingAudioProcessor; import androidx.media3.exoplayer.util.DebugTextViewHelper; +import androidx.media3.muxer.Muxer; import androidx.media3.transformer.Composition; import androidx.media3.transformer.DefaultEncoderFactory; import androidx.media3.transformer.DefaultMuxer; @@ -90,7 +91,6 @@ import androidx.media3.transformer.ExportException; import androidx.media3.transformer.ExportResult; import androidx.media3.transformer.InAppMuxer; import androidx.media3.transformer.JsonUtil; -import androidx.media3.transformer.Muxer; import androidx.media3.transformer.ProgressHolder; import androidx.media3.transformer.Transformer; import androidx.media3.ui.AspectRatioFrameLayout; diff --git a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java index 5b79492e41..470e73cf34 100644 --- a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java +++ b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java @@ -19,6 +19,7 @@ import android.content.Context; import android.media.MediaCodec; import android.media.MediaExtractor; import androidx.media3.common.util.MediaFormatUtil; +import androidx.media3.muxer.Muxer.MuxerException; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -37,7 +38,7 @@ import java.util.List; } public static void feedInputDataToMuxer(Context context, Muxer muxer, String inputFileName) - throws IOException { + throws IOException, MuxerException { MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource( context.getResources().getAssets().openFd(MP4_FILE_ASSET_DIRECTORY + inputFileName)); diff --git a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java index 43ea39acd3..b203748cb1 100644 --- a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java +++ b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java @@ -62,7 +62,7 @@ public class FragmentedMp4MuxerEndToEndAndroidTest { } @Test - public void createFragmentedMp4File_fromInputFileSampleData_matchesExpected() throws IOException { + public void createFragmentedMp4File_fromInputFileSampleData_matchesExpected() throws Exception { @Nullable Muxer fragmentedMp4Muxer = null; try { @@ -89,7 +89,7 @@ public class FragmentedMp4MuxerEndToEndAndroidTest { @Test public void createFragmentedMp4File_fromInputFileSampleData_matchesExpectedBoxStructure() - throws IOException { + throws Exception { @Nullable Muxer fragmentedMp4Muxer = null; try { diff --git a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndAndroidTest.java b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndAndroidTest.java index e4810beb62..59a7d32a7e 100644 --- a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndAndroidTest.java +++ b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndAndroidTest.java @@ -73,7 +73,7 @@ public class Mp4MuxerEndToEndAndroidTest { } @Test - public void createMp4File_fromInputFileSampleData_matchesExpected() throws IOException { + public void createMp4File_fromInputFileSampleData_matchesExpected() throws Exception { @Nullable Mp4Muxer mp4Muxer = null; try { @@ -96,7 +96,7 @@ public class Mp4MuxerEndToEndAndroidTest { } @Test - public void createMp4File_muxerNotClosed_createsPartiallyWrittenValidFile() throws IOException { + public void createMp4File_muxerNotClosed_createsPartiallyWrittenValidFile() throws Exception { // Skip for all parameter values except when the input is a large file. The muxer writes samples // in batches (and flushes data only when it's closed), so a large input file is needed to // ensure some data has been written after taking all the inputs but before closing the muxer. diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java index 4dfe921d5e..97e4682cf4 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java @@ -156,12 +156,21 @@ public final class FragmentedMp4Muxer implements Muxer { * Builder#setSampleCopyEnabled(boolean) sample copying} is disabled. Otherwise, the position * of the buffer is updated but the caller retains ownership. * @param bufferInfo The {@link BufferInfo} related to this sample. - * @throws IOException If there is any error while writing data to the disk. + * @throws MuxerException If there is any error while writing data to the disk. */ @Override public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) - throws IOException { - fragmentedMp4Writer.writeSampleData(trackToken, byteBuffer, bufferInfo); + throws MuxerException { + try { + fragmentedMp4Writer.writeSampleData(trackToken, byteBuffer, bufferInfo); + } catch (IOException e) { + throw new MuxerException( + "Failed to write sample for presentationTimeUs=" + + bufferInfo.presentationTimeUs + + ", size=" + + bufferInfo.size, + e); + } } /** @@ -190,7 +199,11 @@ public final class FragmentedMp4Muxer implements Muxer { } @Override - public void close() throws IOException { - fragmentedMp4Writer.close(); + public void close() throws MuxerException { + try { + fragmentedMp4Writer.close(); + } catch (IOException e) { + throw new MuxerException("Failed to close the muxer", e); + } } } diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java index e0735d3df1..a658a058e6 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java @@ -221,12 +221,21 @@ public final class Mp4Muxer implements Muxer { * Builder#setSampleCopyEnabled(boolean) sample copying} is disabled. Otherwise, the position * of the buffer is updated but the caller retains ownership. * @param bufferInfo The {@link BufferInfo} related to this sample. - * @throws IOException If there is any error while writing data to the disk. + * @throws MuxerException If there is any error while writing data to the disk. */ @Override public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) - throws IOException { - mp4Writer.writeSampleData(trackToken, byteBuffer, bufferInfo); + throws MuxerException { + try { + mp4Writer.writeSampleData(trackToken, byteBuffer, bufferInfo); + } catch (IOException e) { + throw new MuxerException( + "Failed to write sample for presentationTimeUs=" + + bufferInfo.presentationTimeUs + + ", size=" + + bufferInfo.size, + e); + } } /** @@ -255,7 +264,11 @@ public final class Mp4Muxer implements Muxer { } @Override - public void close() throws IOException { - mp4Writer.close(); + public void close() throws MuxerException { + try { + mp4Writer.close(); + } catch (IOException e) { + throw new MuxerException("Failed to close the muxer", e); + } } } diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java index 0a731adfc7..7b8f0b0fb1 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java @@ -16,28 +16,81 @@ package androidx.media3.muxer; import android.media.MediaCodec.BufferInfo; +import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.Metadata; +import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; -import java.io.IOException; +import com.google.common.collect.ImmutableList; import java.nio.ByteBuffer; /** The muxer for producing media container files. */ @UnstableApi public interface Muxer { + /** Thrown when a muxer failure occurs. */ + final class MuxerException extends Exception { + /** + * Creates an instance. + * + * @param message See {@link #getMessage()}. + * @param cause See {@link #getCause()}. + */ + public MuxerException(String message, Throwable cause) { + super(message, cause); + } + } + + /** Factory for muxers. */ + interface Factory { + /** + * Returns a new {@link Muxer}. + * + * @param path The path to the output file. + * @throws MuxerException If an error occurs opening the output file for writing. + */ + Muxer create(String path) throws MuxerException; + + /** + * Returns the supported sample {@linkplain MimeTypes MIME types} for the given {@link + * C.TrackType}. + */ + ImmutableList getSupportedSampleMimeTypes(@C.TrackType int trackType); + } + /** A token representing an added track. */ interface TrackToken {} - /** Adds a track of the given media format. */ - TrackToken addTrack(Format format); + /** + * Adds a track of the given media format. + * + * @param format The {@link Format} of the track. + * @return The {@link TrackToken} for this track, which should be passed to {@link + * #writeSampleData}. + * @throws MuxerException If the muxer encounters a problem while adding the track. + */ + TrackToken addTrack(Format format) throws MuxerException; - /** Writes encoded sample data. */ + /** + * Writes encoded sample data. + * + * @param trackToken The {@link TrackToken} of the track, previously returned by {@link + * #addTrack(Format)}. + * @param byteBuffer A buffer containing the sample data to write to the container. + * @param bufferInfo The {@link BufferInfo} of the sample. + * @throws MuxerException If the muxer fails to write the sample. + */ void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) - throws IOException; + throws MuxerException; /** Adds {@linkplain Metadata.Entry metadata} about the output file. */ void addMetadataEntry(Metadata.Entry metadataEntry); - /** Closes the file. */ - void close() throws IOException; + /** + * Closes the file. + * + *

The muxer cannot be used anymore once this method returns. + * + * @throws MuxerException If the muxer fails to finish writing the output. + */ + void close() throws MuxerException; } diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java index 2624cd5f33..0cb763ff40 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java @@ -39,7 +39,6 @@ import androidx.media3.test.utils.TestUtil; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.FileOutputStream; -import java.io.IOException; import java.nio.ByteBuffer; import org.junit.Rule; import org.junit.Test; @@ -54,7 +53,7 @@ public class Mp4MuxerEndToEndTest { private final Context context = ApplicationProvider.getApplicationContext(); @Test - public void createMp4File_addTrackAndMetadataButNoSamples_createsEmptyFile() throws IOException { + public void createMp4File_addTrackAndMetadataButNoSamples_createsEmptyFile() throws Exception { String outputFilePath = temporaryFolder.newFile().getPath(); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); @@ -75,7 +74,7 @@ public class Mp4MuxerEndToEndTest { } @Test - public void createMp4File_withSameTracksOffset_matchesExpected() throws IOException { + public void createMp4File_withSameTracksOffset_matchesExpected() throws Exception { String outputFilePath = temporaryFolder.newFile().getPath(); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); mp4Muxer.addMetadataEntry( @@ -118,7 +117,7 @@ public class Mp4MuxerEndToEndTest { } @Test - public void createMp4File_withDifferentTracksOffset_matchesExpected() throws IOException { + public void createMp4File_withDifferentTracksOffset_matchesExpected() throws Exception { String outputFilePath = temporaryFolder.newFile().getPath(); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); mp4Muxer.addMetadataEntry( @@ -157,7 +156,7 @@ public class Mp4MuxerEndToEndTest { } @Test - public void writeSampleData_withOutOfOrderSampleTimestamps_throws() throws IOException { + public void writeSampleData_withOutOfOrderSampleTimestamps_throws() throws Exception { String outputFilePath = temporaryFolder.newFile().getPath(); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); Pair track1Sample1 = diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java index ab00e4f137..cecb42b874 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java @@ -36,7 +36,8 @@ import androidx.media3.common.audio.AudioProcessor; import androidx.media3.common.audio.SonicAudioProcessor; import androidx.media3.common.util.Util; import androidx.media3.effect.RgbFilter; -import androidx.media3.muxer.Muxer.TrackToken; +import androidx.media3.muxer.Muxer; +import androidx.media3.muxer.Muxer.MuxerException; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import com.google.common.base.Ascii; @@ -418,7 +419,7 @@ public class TransformerPauseResumeTest { } @Override - public Muxer create(String path) throws Muxer.MuxerException { + public Muxer create(String path) throws MuxerException { return new FrameBlockingMuxer(wrappedMuxerFactory.create(path), listener); } @@ -473,8 +474,8 @@ public class TransformerPauseResumeTest { } @Override - public void release() throws MuxerException { - wrappedMuxer.release(); + public void close() throws MuxerException { + wrappedMuxer.close(); } } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java index 9273446c12..34d74c8d5c 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java @@ -20,6 +20,7 @@ import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.Metadata; import androidx.media3.common.util.UnstableApi; +import androidx.media3.muxer.Muxer; import androidx.media3.muxer.Muxer.TrackToken; import com.google.common.collect.ImmutableList; import java.nio.ByteBuffer; @@ -71,9 +72,9 @@ public final class DefaultMuxer implements Muxer { } @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) + public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws MuxerException { - muxer.writeSampleData(trackToken, data, bufferInfo); + muxer.writeSampleData(trackToken, byteBuffer, bufferInfo); } @Override @@ -82,7 +83,7 @@ public final class DefaultMuxer implements Muxer { } @Override - public void release() throws MuxerException { - muxer.release(); + public void close() throws MuxerException { + muxer.close(); } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java index 1d2aed93f4..85c8bbb467 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java @@ -32,7 +32,7 @@ import androidx.media3.common.MimeTypes; import androidx.media3.common.util.MediaFormatUtil; import androidx.media3.common.util.Util; import androidx.media3.container.Mp4LocationData; -import androidx.media3.muxer.Muxer.TrackToken; +import androidx.media3.muxer.Muxer; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.lang.reflect.Field; @@ -199,7 +199,7 @@ import java.util.Map; } @Override - public void release() throws MuxerException { + public void close() throws MuxerException { if (isReleased) { return; } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java index aec85a5769..a876d416b5 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java @@ -25,12 +25,12 @@ import androidx.media3.container.Mp4OrientationData; import androidx.media3.muxer.FragmentedMp4Muxer; import androidx.media3.muxer.Mp4Muxer; import androidx.media3.muxer.Mp4Utils; +import androidx.media3.muxer.Muxer; import androidx.media3.muxer.Muxer.TrackToken; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.IOException; import java.nio.ByteBuffer; import java.util.LinkedHashSet; import java.util.Set; @@ -170,7 +170,7 @@ public final class InAppMuxer implements Muxer { } @Override - public TrackToken addTrack(Format format) { + public TrackToken addTrack(Format format) throws MuxerException { TrackToken trackToken = muxer.addTrack(format); if (MimeTypes.isVideo(format.sampleMimeType)) { muxer.addMetadataEntry(new Mp4OrientationData(format.rotationDegrees)); @@ -179,19 +179,9 @@ public final class InAppMuxer implements Muxer { } @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) + public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws MuxerException { - - try { - muxer.writeSampleData(trackToken, data, bufferInfo); - } catch (IOException e) { - throw new MuxerException( - "Failed to write sample for presentationTimeUs=" - + bufferInfo.presentationTimeUs - + ", size=" - + bufferInfo.size, - e); - } + muxer.writeSampleData(trackToken, byteBuffer, bufferInfo); } @Override @@ -202,14 +192,9 @@ public final class InAppMuxer implements Muxer { } @Override - public void release() throws MuxerException { + public void close() throws MuxerException { writeMetadata(); - - try { - muxer.close(); - } catch (IOException e) { - throw new MuxerException("Error closing muxer", e); - } + muxer.close(); } private void writeMetadata() { diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Muxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Muxer.java deleted file mode 100644 index ddc5e787c9..0000000000 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Muxer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package androidx.media3.transformer; - -import android.media.MediaCodec.BufferInfo; -import androidx.media3.common.C; -import androidx.media3.common.Format; -import androidx.media3.common.Metadata; -import androidx.media3.common.MimeTypes; -import androidx.media3.common.util.UnstableApi; -import androidx.media3.muxer.Muxer.TrackToken; -import com.google.common.collect.ImmutableList; -import java.nio.ByteBuffer; - -/** - * Abstracts media muxing operations. - * - *

Query whether {@linkplain Factory#getSupportedSampleMimeTypes(int) sample MIME types} are - * supported and {@linkplain #addTrack(Format) add all tracks}, then {@linkplain #writeSampleData - * 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, {@linkplain #release() release} the instance to finish - * writing to the output and return any resources to the system. - */ -@UnstableApi -// TODO: b/330695864 - Replace with the Muxer interface from the Muxer module. -public interface Muxer { - - /** Thrown when a muxing failure occurs. */ - final class MuxerException extends Exception { - /** - * Creates an instance. - * - * @param message See {@link #getMessage()}. - * @param cause See {@link #getCause()}. - */ - public MuxerException(String message, Throwable cause) { - super(message, cause); - } - } - - /** Factory for muxers. */ - interface Factory { - /** - * Returns a new muxer writing to a file. - * - * @param path The path to the output file. - * @throws IllegalArgumentException If the path is invalid. - * @throws MuxerException If an error occurs opening the output file for writing. - */ - Muxer create(String path) throws MuxerException; - - /** - * Returns the supported sample {@linkplain MimeTypes MIME types} for the given {@link - * C.TrackType}. - */ - ImmutableList getSupportedSampleMimeTypes(@C.TrackType int trackType); - } - - /** - * Adds a track with the specified format. - * - * @param format The {@link Format} of the track. - * @return The {@link TrackToken} for this track, which should be passed to {@link - * #writeSampleData}. - * @throws MuxerException If the muxer encounters a problem while adding the track. - */ - TrackToken addTrack(Format format) throws MuxerException; - - /** - * Writes the specified sample. - * - * @param trackToken The {@link TrackToken} of the track, previously returned by {@link - * #addTrack(Format)}. - * @param data A buffer containing the sample data to write to the container. - * @param bufferInfo The {@link BufferInfo} of the sample. - * @throws MuxerException If the muxer fails to write the sample. - */ - void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) - throws MuxerException; - - /** Adds {@linkplain Metadata.Entry metadata} about the output file. */ - void addMetadataEntry(Metadata.Entry metadataEntry); - - /** - * Finishes writing the output and releases any resources associated with muxing. - * - *

The muxer cannot be used anymore once this method has been called. - * - * @throws MuxerException If the muxer fails to finish writing the output and {@code - * forCancellation} is false. - */ - void release() throws MuxerException; -} diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java index 53fab1172d..ce001e972c 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java @@ -48,6 +48,8 @@ import androidx.media3.common.MimeTypes; import androidx.media3.common.util.Util; import androidx.media3.container.NalUnitUtil; import androidx.media3.effect.DebugTraceUtil; +import androidx.media3.muxer.Muxer; +import androidx.media3.muxer.Muxer.MuxerException; import androidx.media3.muxer.Muxer.TrackToken; import com.google.common.collect.ImmutableList; import java.io.File; @@ -374,11 +376,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * @throws IllegalStateException If the number of formats added exceeds the {@linkplain * #setTrackCount track count}, if {@link #setTrackCount(int)} has not been called or if there * is already a track of that {@link C.TrackType}. - * @throws Muxer.MuxerException If the underlying {@link Muxer} encounters a problem while adding - * the track. + * @throws MuxerException If the underlying {@link Muxer} encounters a problem while adding the + * track. */ - public void addTrackFormat(Format format) - throws AppendTrackFormatException, Muxer.MuxerException { + public void addTrackFormat(Format format) throws AppendTrackFormatException, MuxerException { @Nullable String sampleMimeType = format.sampleMimeType; @C.TrackType int trackType = MimeTypes.getTrackType(sampleMimeType); checkArgument( @@ -521,11 +522,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * received a format} for every {@linkplain #setTrackCount(int) track}. * @throws IllegalArgumentException If the muxer doesn't have a {@linkplain #endTrack(int) * non-ended} track of the given {@link C.TrackType}. - * @throws Muxer.MuxerException If the underlying {@link Muxer} fails to write the sample. + * @throws MuxerException If the underlying {@link Muxer} fails to write the sample. */ public boolean writeSample( @C.TrackType int trackType, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) - throws Muxer.MuxerException { + throws MuxerException { checkArgument(contains(trackTypeToInfo, trackType)); TrackInfo trackInfo = trackTypeToInfo.get(trackType); boolean canWriteSample = canWriteSample(trackType, presentationTimeUs); @@ -653,11 +654,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * #MUXER_RELEASE_REASON_CANCELLED} or {@link #MUXER_RELEASE_REASON_ERROR}. * * @param releaseReason The reason to release the muxer. - * @throws Muxer.MuxerException If the underlying {@link Muxer} fails to finish writing the output - * and the {@code releaseReason} is not {@link #MUXER_RELEASE_REASON_CANCELLED}. + * @throws MuxerException If the underlying {@link Muxer} fails to finish writing the output and + * the {@code releaseReason} is not {@link #MUXER_RELEASE_REASON_CANCELLED}. */ public void finishWritingAndMaybeRelease(@MuxerReleaseReason int releaseReason) - throws Muxer.MuxerException { + throws MuxerException { if (releaseReason == MUXER_RELEASE_REASON_COMPLETED && muxerMode == MUXER_MODE_MUX_PARTIAL) { return; } @@ -665,8 +666,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; abortScheduledExecutorService.shutdownNow(); if (muxer != null) { try { - muxer.release(); - } catch (Muxer.MuxerException e) { + muxer.close(); + } catch (MuxerException e) { if (releaseReason == MUXER_RELEASE_REASON_CANCELLED && checkNotNull(e.getMessage()) .equals(FrameworkMuxer.MUXER_STOPPING_FAILED_ERROR_MESSAGE)) { @@ -736,7 +737,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } @EnsuresNonNull("muxer") - private void ensureMuxerInitialized() throws Muxer.MuxerException { + private void ensureMuxerInitialized() throws MuxerException { if (muxer == null) { muxer = muxerFactory.create(outputPath); } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/SampleExporter.java b/libraries/transformer/src/main/java/androidx/media3/transformer/SampleExporter.java index cafc939a5d..d65dd64059 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/SampleExporter.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/SampleExporter.java @@ -30,6 +30,7 @@ import androidx.media3.common.Format; import androidx.media3.common.Metadata; import androidx.media3.common.MimeTypes; import androidx.media3.decoder.DecoderInputBuffer; +import androidx.media3.muxer.Muxer.MuxerException; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import java.util.List; @@ -110,7 +111,7 @@ import java.util.List; } try { muxerWrapper.addTrackFormat(inputFormat); - } catch (Muxer.MuxerException e) { + } catch (MuxerException e) { throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED); } catch (MuxerWrapper.AppendTrackFormatException e) { throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_APPEND); @@ -136,7 +137,7 @@ import java.util.List; muxerInputBuffer.timeUs)) { return false; } - } catch (Muxer.MuxerException e) { + } catch (MuxerException e) { throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED); } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java index b5d9489bf5..de4667715c 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -59,6 +59,7 @@ import androidx.media3.effect.DebugTraceUtil; import androidx.media3.effect.DefaultVideoFrameProcessor; import androidx.media3.effect.Presentation; import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; +import androidx.media3.muxer.Muxer; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java index f840801b26..ab655c40b1 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java @@ -62,6 +62,7 @@ import androidx.media3.common.util.Clock; import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.HandlerWrapper; import androidx.media3.common.util.Util; +import androidx.media3.muxer.Muxer.MuxerException; import androidx.media3.transformer.AssetLoader.CompositionSettings; import com.google.common.collect.ImmutableList; import java.lang.annotation.Documented; @@ -436,7 +437,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } try { muxerWrapper.finishWritingAndMaybeRelease(getMuxerReleaseReason(endReason)); - } catch (Muxer.MuxerException e) { + } catch (MuxerException e) { if (releaseExportException == null) { releaseExportException = ExportException.createForMuxer(e, ERROR_CODE_MUXING_FAILED); } diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java b/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java index 5748c9f44b..c424ef1a50 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java @@ -26,7 +26,7 @@ import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.Metadata; import androidx.media3.common.util.Util; -import androidx.media3.muxer.Muxer.TrackToken; +import androidx.media3.muxer.Muxer; import androidx.media3.test.utils.DumpableFormat; import androidx.media3.test.utils.Dumper; import androidx.media3.test.utils.Dumper.Dumpable; @@ -72,7 +72,7 @@ public final class CapturingMuxer implements Muxer, Dumpable { } @Override - public Muxer create(String path) throws Muxer.MuxerException { + public Muxer create(String path) throws MuxerException { muxer = new CapturingMuxer(wrappedFactory.create(path), handleAudioAsPcm); return muxer; } @@ -142,9 +142,9 @@ public final class CapturingMuxer implements Muxer, Dumpable { } @Override - public void release() throws MuxerException { + public void close() throws MuxerException { released = true; - wrappedMuxer.release(); + wrappedMuxer.close(); } // Dumper.Dumpable implementation. diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/MuxerWrapperTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/MuxerWrapperTest.java index 223fc84076..ea83abdf90 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/MuxerWrapperTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/MuxerWrapperTest.java @@ -30,6 +30,7 @@ import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.ColorInfo; import androidx.media3.common.Format; +import androidx.media3.muxer.Muxer.MuxerException; import androidx.media3.test.utils.DumpFileAsserts; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -74,7 +75,7 @@ public class MuxerWrapperTest { @Nullable private MuxerWrapper muxerWrapper; @After - public void tearDown() throws Muxer.MuxerException { + public void tearDown() throws MuxerException { if (muxerWrapper != null) { // Release with reason cancellation so that underlying resources are always released. muxerWrapper.finishWritingAndMaybeRelease(MuxerWrapper.MUXER_RELEASE_REASON_CANCELLED); diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TestUtil.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TestUtil.java index 4ea80d70d6..e8147a22e3 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TestUtil.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TestUtil.java @@ -24,6 +24,7 @@ import androidx.media3.common.audio.ChannelMixingMatrix; import androidx.media3.common.audio.SonicAudioProcessor; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; +import androidx.media3.muxer.Muxer; import androidx.media3.test.utils.FakeClock; import androidx.test.core.app.ApplicationProvider; import com.google.common.collect.ImmutableList; diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerWithInAppMuxerEndToEndTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerWithInAppMuxerEndToEndTest.java index 0f86a6323b..ecd33c019f 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerWithInAppMuxerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerWithInAppMuxerEndToEndTest.java @@ -34,6 +34,7 @@ import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.XmpData; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.extractor.text.DefaultSubtitleParserFactory; +import androidx.media3.muxer.Muxer; import androidx.media3.test.utils.DumpFileAsserts; import androidx.media3.test.utils.FakeClock; import androidx.media3.test.utils.FakeExtractorOutput;