Replace Transformer.Muxer interface with Muxer.Muxer
PiperOrigin-RevId: 633193701
This commit is contained in:
parent
5950e884f6
commit
3a3145521b
@ -32,6 +32,9 @@
|
|||||||
at stereo when handling PCM input.
|
at stereo when handling PCM input.
|
||||||
* When selecting tracks in `ExoPlayerAssetLoader`, ignore audio channel
|
* When selecting tracks in `ExoPlayerAssetLoader`, ignore audio channel
|
||||||
count constraints as they only apply for playback.
|
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:
|
* Track Selection:
|
||||||
* Extractors:
|
* Extractors:
|
||||||
* MPEG-TS: Roll forward the change ensuring the last frame is rendered by
|
* MPEG-TS: Roll forward the change ensuring the last frame is rendered by
|
||||||
|
@ -83,6 +83,7 @@ dependencies {
|
|||||||
implementation project(modulePrefix + 'lib-exoplayer')
|
implementation project(modulePrefix + 'lib-exoplayer')
|
||||||
implementation project(modulePrefix + 'lib-exoplayer-dash')
|
implementation project(modulePrefix + 'lib-exoplayer-dash')
|
||||||
implementation project(modulePrefix + 'lib-transformer')
|
implementation project(modulePrefix + 'lib-transformer')
|
||||||
|
implementation project(modulePrefix + 'lib-muxer')
|
||||||
implementation project(modulePrefix + 'lib-ui')
|
implementation project(modulePrefix + 'lib-ui')
|
||||||
|
|
||||||
// For MediaPipe and its dependencies:
|
// For MediaPipe and its dependencies:
|
||||||
|
@ -80,6 +80,7 @@ import androidx.media3.effect.TextureOverlay;
|
|||||||
import androidx.media3.exoplayer.ExoPlayer;
|
import androidx.media3.exoplayer.ExoPlayer;
|
||||||
import androidx.media3.exoplayer.audio.SilenceSkippingAudioProcessor;
|
import androidx.media3.exoplayer.audio.SilenceSkippingAudioProcessor;
|
||||||
import androidx.media3.exoplayer.util.DebugTextViewHelper;
|
import androidx.media3.exoplayer.util.DebugTextViewHelper;
|
||||||
|
import androidx.media3.muxer.Muxer;
|
||||||
import androidx.media3.transformer.Composition;
|
import androidx.media3.transformer.Composition;
|
||||||
import androidx.media3.transformer.DefaultEncoderFactory;
|
import androidx.media3.transformer.DefaultEncoderFactory;
|
||||||
import androidx.media3.transformer.DefaultMuxer;
|
import androidx.media3.transformer.DefaultMuxer;
|
||||||
@ -90,7 +91,6 @@ import androidx.media3.transformer.ExportException;
|
|||||||
import androidx.media3.transformer.ExportResult;
|
import androidx.media3.transformer.ExportResult;
|
||||||
import androidx.media3.transformer.InAppMuxer;
|
import androidx.media3.transformer.InAppMuxer;
|
||||||
import androidx.media3.transformer.JsonUtil;
|
import androidx.media3.transformer.JsonUtil;
|
||||||
import androidx.media3.transformer.Muxer;
|
|
||||||
import androidx.media3.transformer.ProgressHolder;
|
import androidx.media3.transformer.ProgressHolder;
|
||||||
import androidx.media3.transformer.Transformer;
|
import androidx.media3.transformer.Transformer;
|
||||||
import androidx.media3.ui.AspectRatioFrameLayout;
|
import androidx.media3.ui.AspectRatioFrameLayout;
|
||||||
|
@ -19,6 +19,7 @@ import android.content.Context;
|
|||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.media.MediaExtractor;
|
import android.media.MediaExtractor;
|
||||||
import androidx.media3.common.util.MediaFormatUtil;
|
import androidx.media3.common.util.MediaFormatUtil;
|
||||||
|
import androidx.media3.muxer.Muxer.MuxerException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -37,7 +38,7 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void feedInputDataToMuxer(Context context, Muxer muxer, String inputFileName)
|
public static void feedInputDataToMuxer(Context context, Muxer muxer, String inputFileName)
|
||||||
throws IOException {
|
throws IOException, MuxerException {
|
||||||
MediaExtractor extractor = new MediaExtractor();
|
MediaExtractor extractor = new MediaExtractor();
|
||||||
extractor.setDataSource(
|
extractor.setDataSource(
|
||||||
context.getResources().getAssets().openFd(MP4_FILE_ASSET_DIRECTORY + inputFileName));
|
context.getResources().getAssets().openFd(MP4_FILE_ASSET_DIRECTORY + inputFileName));
|
||||||
|
@ -62,7 +62,7 @@ public class FragmentedMp4MuxerEndToEndAndroidTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createFragmentedMp4File_fromInputFileSampleData_matchesExpected() throws IOException {
|
public void createFragmentedMp4File_fromInputFileSampleData_matchesExpected() throws Exception {
|
||||||
@Nullable Muxer fragmentedMp4Muxer = null;
|
@Nullable Muxer fragmentedMp4Muxer = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -89,7 +89,7 @@ public class FragmentedMp4MuxerEndToEndAndroidTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createFragmentedMp4File_fromInputFileSampleData_matchesExpectedBoxStructure()
|
public void createFragmentedMp4File_fromInputFileSampleData_matchesExpectedBoxStructure()
|
||||||
throws IOException {
|
throws Exception {
|
||||||
@Nullable Muxer fragmentedMp4Muxer = null;
|
@Nullable Muxer fragmentedMp4Muxer = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -73,7 +73,7 @@ public class Mp4MuxerEndToEndAndroidTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createMp4File_fromInputFileSampleData_matchesExpected() throws IOException {
|
public void createMp4File_fromInputFileSampleData_matchesExpected() throws Exception {
|
||||||
@Nullable Mp4Muxer mp4Muxer = null;
|
@Nullable Mp4Muxer mp4Muxer = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -96,7 +96,7 @@ public class Mp4MuxerEndToEndAndroidTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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
|
// 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
|
// 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.
|
// ensure some data has been written after taking all the inputs but before closing the muxer.
|
||||||
|
@ -156,12 +156,21 @@ public final class FragmentedMp4Muxer implements Muxer {
|
|||||||
* Builder#setSampleCopyEnabled(boolean) sample copying} is disabled. Otherwise, the position
|
* Builder#setSampleCopyEnabled(boolean) sample copying} is disabled. Otherwise, the position
|
||||||
* of the buffer is updated but the caller retains ownership.
|
* of the buffer is updated but the caller retains ownership.
|
||||||
* @param bufferInfo The {@link BufferInfo} related to this sample.
|
* @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
|
@Override
|
||||||
public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||||
throws IOException {
|
throws MuxerException {
|
||||||
fragmentedMp4Writer.writeSampleData(trackToken, byteBuffer, bufferInfo);
|
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
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws MuxerException {
|
||||||
fragmentedMp4Writer.close();
|
try {
|
||||||
|
fragmentedMp4Writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new MuxerException("Failed to close the muxer", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,12 +221,21 @@ public final class Mp4Muxer implements Muxer {
|
|||||||
* Builder#setSampleCopyEnabled(boolean) sample copying} is disabled. Otherwise, the position
|
* Builder#setSampleCopyEnabled(boolean) sample copying} is disabled. Otherwise, the position
|
||||||
* of the buffer is updated but the caller retains ownership.
|
* of the buffer is updated but the caller retains ownership.
|
||||||
* @param bufferInfo The {@link BufferInfo} related to this sample.
|
* @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
|
@Override
|
||||||
public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||||
throws IOException {
|
throws MuxerException {
|
||||||
mp4Writer.writeSampleData(trackToken, byteBuffer, bufferInfo);
|
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
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws MuxerException {
|
||||||
mp4Writer.close();
|
try {
|
||||||
|
mp4Writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new MuxerException("Failed to close the muxer", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,28 +16,81 @@
|
|||||||
package androidx.media3.muxer;
|
package androidx.media3.muxer;
|
||||||
|
|
||||||
import android.media.MediaCodec.BufferInfo;
|
import android.media.MediaCodec.BufferInfo;
|
||||||
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.Metadata;
|
import androidx.media3.common.Metadata;
|
||||||
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import java.io.IOException;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/** The muxer for producing media container files. */
|
/** The muxer for producing media container files. */
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public interface Muxer {
|
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<String> getSupportedSampleMimeTypes(@C.TrackType int trackType);
|
||||||
|
}
|
||||||
|
|
||||||
/** A token representing an added track. */
|
/** A token representing an added track. */
|
||||||
interface TrackToken {}
|
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)
|
void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||||
throws IOException;
|
throws MuxerException;
|
||||||
|
|
||||||
/** Adds {@linkplain Metadata.Entry metadata} about the output file. */
|
/** Adds {@linkplain Metadata.Entry metadata} about the output file. */
|
||||||
void addMetadataEntry(Metadata.Entry metadataEntry);
|
void addMetadataEntry(Metadata.Entry metadataEntry);
|
||||||
|
|
||||||
/** Closes the file. */
|
/**
|
||||||
void close() throws IOException;
|
* Closes the file.
|
||||||
|
*
|
||||||
|
* <p>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;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ import androidx.media3.test.utils.TestUtil;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -54,7 +53,7 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createMp4File_addTrackAndMetadataButNoSamples_createsEmptyFile() throws IOException {
|
public void createMp4File_addTrackAndMetadataButNoSamples_createsEmptyFile() throws Exception {
|
||||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||||
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
@ -75,7 +74,7 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createMp4File_withSameTracksOffset_matchesExpected() throws IOException {
|
public void createMp4File_withSameTracksOffset_matchesExpected() throws Exception {
|
||||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||||
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
mp4Muxer.addMetadataEntry(
|
mp4Muxer.addMetadataEntry(
|
||||||
@ -118,7 +117,7 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createMp4File_withDifferentTracksOffset_matchesExpected() throws IOException {
|
public void createMp4File_withDifferentTracksOffset_matchesExpected() throws Exception {
|
||||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||||
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
mp4Muxer.addMetadataEntry(
|
mp4Muxer.addMetadataEntry(
|
||||||
@ -157,7 +156,7 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeSampleData_withOutOfOrderSampleTimestamps_throws() throws IOException {
|
public void writeSampleData_withOutOfOrderSampleTimestamps_throws() throws Exception {
|
||||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||||
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||||
|
@ -36,7 +36,8 @@ import androidx.media3.common.audio.AudioProcessor;
|
|||||||
import androidx.media3.common.audio.SonicAudioProcessor;
|
import androidx.media3.common.audio.SonicAudioProcessor;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.effect.RgbFilter;
|
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.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
import com.google.common.base.Ascii;
|
import com.google.common.base.Ascii;
|
||||||
@ -418,7 +419,7 @@ public class TransformerPauseResumeTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Muxer create(String path) throws Muxer.MuxerException {
|
public Muxer create(String path) throws MuxerException {
|
||||||
return new FrameBlockingMuxer(wrappedMuxerFactory.create(path), listener);
|
return new FrameBlockingMuxer(wrappedMuxerFactory.create(path), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,8 +474,8 @@ public class TransformerPauseResumeTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() throws MuxerException {
|
public void close() throws MuxerException {
|
||||||
wrappedMuxer.release();
|
wrappedMuxer.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import androidx.media3.common.C;
|
|||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.Metadata;
|
import androidx.media3.common.Metadata;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import androidx.media3.muxer.Muxer;
|
||||||
import androidx.media3.muxer.Muxer.TrackToken;
|
import androidx.media3.muxer.Muxer.TrackToken;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -71,9 +72,9 @@ public final class DefaultMuxer implements Muxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
|
public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||||
throws MuxerException {
|
throws MuxerException {
|
||||||
muxer.writeSampleData(trackToken, data, bufferInfo);
|
muxer.writeSampleData(trackToken, byteBuffer, bufferInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,7 +83,7 @@ public final class DefaultMuxer implements Muxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() throws MuxerException {
|
public void close() throws MuxerException {
|
||||||
muxer.release();
|
muxer.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ import androidx.media3.common.MimeTypes;
|
|||||||
import androidx.media3.common.util.MediaFormatUtil;
|
import androidx.media3.common.util.MediaFormatUtil;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.container.Mp4LocationData;
|
import androidx.media3.container.Mp4LocationData;
|
||||||
import androidx.media3.muxer.Muxer.TrackToken;
|
import androidx.media3.muxer.Muxer;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@ -199,7 +199,7 @@ import java.util.Map;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() throws MuxerException {
|
public void close() throws MuxerException {
|
||||||
if (isReleased) {
|
if (isReleased) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,12 @@ import androidx.media3.container.Mp4OrientationData;
|
|||||||
import androidx.media3.muxer.FragmentedMp4Muxer;
|
import androidx.media3.muxer.FragmentedMp4Muxer;
|
||||||
import androidx.media3.muxer.Mp4Muxer;
|
import androidx.media3.muxer.Mp4Muxer;
|
||||||
import androidx.media3.muxer.Mp4Utils;
|
import androidx.media3.muxer.Mp4Utils;
|
||||||
|
import androidx.media3.muxer.Muxer;
|
||||||
import androidx.media3.muxer.Muxer.TrackToken;
|
import androidx.media3.muxer.Muxer.TrackToken;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -170,7 +170,7 @@ public final class InAppMuxer implements Muxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackToken addTrack(Format format) {
|
public TrackToken addTrack(Format format) throws MuxerException {
|
||||||
TrackToken trackToken = muxer.addTrack(format);
|
TrackToken trackToken = muxer.addTrack(format);
|
||||||
if (MimeTypes.isVideo(format.sampleMimeType)) {
|
if (MimeTypes.isVideo(format.sampleMimeType)) {
|
||||||
muxer.addMetadataEntry(new Mp4OrientationData(format.rotationDegrees));
|
muxer.addMetadataEntry(new Mp4OrientationData(format.rotationDegrees));
|
||||||
@ -179,19 +179,9 @@ public final class InAppMuxer implements Muxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
|
public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||||
throws MuxerException {
|
throws MuxerException {
|
||||||
|
muxer.writeSampleData(trackToken, byteBuffer, bufferInfo);
|
||||||
try {
|
|
||||||
muxer.writeSampleData(trackToken, data, bufferInfo);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new MuxerException(
|
|
||||||
"Failed to write sample for presentationTimeUs="
|
|
||||||
+ bufferInfo.presentationTimeUs
|
|
||||||
+ ", size="
|
|
||||||
+ bufferInfo.size,
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -202,14 +192,9 @@ public final class InAppMuxer implements Muxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() throws MuxerException {
|
public void close() throws MuxerException {
|
||||||
writeMetadata();
|
writeMetadata();
|
||||||
|
muxer.close();
|
||||||
try {
|
|
||||||
muxer.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new MuxerException("Error closing muxer", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeMetadata() {
|
private void writeMetadata() {
|
||||||
|
@ -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.
|
|
||||||
*
|
|
||||||
* <p>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<String> 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.
|
|
||||||
*
|
|
||||||
* <p>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;
|
|
||||||
}
|
|
@ -48,6 +48,8 @@ import androidx.media3.common.MimeTypes;
|
|||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.container.NalUnitUtil;
|
import androidx.media3.container.NalUnitUtil;
|
||||||
import androidx.media3.effect.DebugTraceUtil;
|
import androidx.media3.effect.DebugTraceUtil;
|
||||||
|
import androidx.media3.muxer.Muxer;
|
||||||
|
import androidx.media3.muxer.Muxer.MuxerException;
|
||||||
import androidx.media3.muxer.Muxer.TrackToken;
|
import androidx.media3.muxer.Muxer.TrackToken;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.File;
|
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
|
* @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
|
* #setTrackCount track count}, if {@link #setTrackCount(int)} has not been called or if there
|
||||||
* is already a track of that {@link C.TrackType}.
|
* is already a track of that {@link C.TrackType}.
|
||||||
* @throws Muxer.MuxerException If the underlying {@link Muxer} encounters a problem while adding
|
* @throws MuxerException If the underlying {@link Muxer} encounters a problem while adding the
|
||||||
* the track.
|
* track.
|
||||||
*/
|
*/
|
||||||
public void addTrackFormat(Format format)
|
public void addTrackFormat(Format format) throws AppendTrackFormatException, MuxerException {
|
||||||
throws AppendTrackFormatException, Muxer.MuxerException {
|
|
||||||
@Nullable String sampleMimeType = format.sampleMimeType;
|
@Nullable String sampleMimeType = format.sampleMimeType;
|
||||||
@C.TrackType int trackType = MimeTypes.getTrackType(sampleMimeType);
|
@C.TrackType int trackType = MimeTypes.getTrackType(sampleMimeType);
|
||||||
checkArgument(
|
checkArgument(
|
||||||
@ -521,11 +522,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
* received a format} for every {@linkplain #setTrackCount(int) track}.
|
* received a format} for every {@linkplain #setTrackCount(int) track}.
|
||||||
* @throws IllegalArgumentException If the muxer doesn't have a {@linkplain #endTrack(int)
|
* @throws IllegalArgumentException If the muxer doesn't have a {@linkplain #endTrack(int)
|
||||||
* non-ended} track of the given {@link C.TrackType}.
|
* 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(
|
public boolean writeSample(
|
||||||
@C.TrackType int trackType, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs)
|
@C.TrackType int trackType, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs)
|
||||||
throws Muxer.MuxerException {
|
throws MuxerException {
|
||||||
checkArgument(contains(trackTypeToInfo, trackType));
|
checkArgument(contains(trackTypeToInfo, trackType));
|
||||||
TrackInfo trackInfo = trackTypeToInfo.get(trackType);
|
TrackInfo trackInfo = trackTypeToInfo.get(trackType);
|
||||||
boolean canWriteSample = canWriteSample(trackType, presentationTimeUs);
|
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}.
|
* #MUXER_RELEASE_REASON_CANCELLED} or {@link #MUXER_RELEASE_REASON_ERROR}.
|
||||||
*
|
*
|
||||||
* @param releaseReason The reason to release the muxer.
|
* @param releaseReason The reason to release the muxer.
|
||||||
* @throws Muxer.MuxerException If the underlying {@link Muxer} fails to finish writing the output
|
* @throws MuxerException If the underlying {@link Muxer} fails to finish writing the output and
|
||||||
* and the {@code releaseReason} is not {@link #MUXER_RELEASE_REASON_CANCELLED}.
|
* the {@code releaseReason} is not {@link #MUXER_RELEASE_REASON_CANCELLED}.
|
||||||
*/
|
*/
|
||||||
public void finishWritingAndMaybeRelease(@MuxerReleaseReason int releaseReason)
|
public void finishWritingAndMaybeRelease(@MuxerReleaseReason int releaseReason)
|
||||||
throws Muxer.MuxerException {
|
throws MuxerException {
|
||||||
if (releaseReason == MUXER_RELEASE_REASON_COMPLETED && muxerMode == MUXER_MODE_MUX_PARTIAL) {
|
if (releaseReason == MUXER_RELEASE_REASON_COMPLETED && muxerMode == MUXER_MODE_MUX_PARTIAL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -665,8 +666,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
abortScheduledExecutorService.shutdownNow();
|
abortScheduledExecutorService.shutdownNow();
|
||||||
if (muxer != null) {
|
if (muxer != null) {
|
||||||
try {
|
try {
|
||||||
muxer.release();
|
muxer.close();
|
||||||
} catch (Muxer.MuxerException e) {
|
} catch (MuxerException e) {
|
||||||
if (releaseReason == MUXER_RELEASE_REASON_CANCELLED
|
if (releaseReason == MUXER_RELEASE_REASON_CANCELLED
|
||||||
&& checkNotNull(e.getMessage())
|
&& checkNotNull(e.getMessage())
|
||||||
.equals(FrameworkMuxer.MUXER_STOPPING_FAILED_ERROR_MESSAGE)) {
|
.equals(FrameworkMuxer.MUXER_STOPPING_FAILED_ERROR_MESSAGE)) {
|
||||||
@ -736,7 +737,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@EnsuresNonNull("muxer")
|
@EnsuresNonNull("muxer")
|
||||||
private void ensureMuxerInitialized() throws Muxer.MuxerException {
|
private void ensureMuxerInitialized() throws MuxerException {
|
||||||
if (muxer == null) {
|
if (muxer == null) {
|
||||||
muxer = muxerFactory.create(outputPath);
|
muxer = muxerFactory.create(outputPath);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import androidx.media3.common.Format;
|
|||||||
import androidx.media3.common.Metadata;
|
import androidx.media3.common.Metadata;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.decoder.DecoderInputBuffer;
|
import androidx.media3.decoder.DecoderInputBuffer;
|
||||||
|
import androidx.media3.muxer.Muxer.MuxerException;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -110,7 +111,7 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
muxerWrapper.addTrackFormat(inputFormat);
|
muxerWrapper.addTrackFormat(inputFormat);
|
||||||
} catch (Muxer.MuxerException e) {
|
} catch (MuxerException e) {
|
||||||
throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED);
|
throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED);
|
||||||
} catch (MuxerWrapper.AppendTrackFormatException e) {
|
} catch (MuxerWrapper.AppendTrackFormatException e) {
|
||||||
throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_APPEND);
|
throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_APPEND);
|
||||||
@ -136,7 +137,7 @@ import java.util.List;
|
|||||||
muxerInputBuffer.timeUs)) {
|
muxerInputBuffer.timeUs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Muxer.MuxerException e) {
|
} catch (MuxerException e) {
|
||||||
throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED);
|
throw ExportException.createForMuxer(e, ExportException.ERROR_CODE_MUXING_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ import androidx.media3.effect.DebugTraceUtil;
|
|||||||
import androidx.media3.effect.DefaultVideoFrameProcessor;
|
import androidx.media3.effect.DefaultVideoFrameProcessor;
|
||||||
import androidx.media3.effect.Presentation;
|
import androidx.media3.effect.Presentation;
|
||||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
||||||
|
import androidx.media3.muxer.Muxer;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
@ -62,6 +62,7 @@ import androidx.media3.common.util.Clock;
|
|||||||
import androidx.media3.common.util.ConditionVariable;
|
import androidx.media3.common.util.ConditionVariable;
|
||||||
import androidx.media3.common.util.HandlerWrapper;
|
import androidx.media3.common.util.HandlerWrapper;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import androidx.media3.muxer.Muxer.MuxerException;
|
||||||
import androidx.media3.transformer.AssetLoader.CompositionSettings;
|
import androidx.media3.transformer.AssetLoader.CompositionSettings;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
@ -436,7 +437,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
muxerWrapper.finishWritingAndMaybeRelease(getMuxerReleaseReason(endReason));
|
muxerWrapper.finishWritingAndMaybeRelease(getMuxerReleaseReason(endReason));
|
||||||
} catch (Muxer.MuxerException e) {
|
} catch (MuxerException e) {
|
||||||
if (releaseExportException == null) {
|
if (releaseExportException == null) {
|
||||||
releaseExportException = ExportException.createForMuxer(e, ERROR_CODE_MUXING_FAILED);
|
releaseExportException = ExportException.createForMuxer(e, ERROR_CODE_MUXING_FAILED);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import androidx.media3.common.C;
|
|||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.Metadata;
|
import androidx.media3.common.Metadata;
|
||||||
import androidx.media3.common.util.Util;
|
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.DumpableFormat;
|
||||||
import androidx.media3.test.utils.Dumper;
|
import androidx.media3.test.utils.Dumper;
|
||||||
import androidx.media3.test.utils.Dumper.Dumpable;
|
import androidx.media3.test.utils.Dumper.Dumpable;
|
||||||
@ -72,7 +72,7 @@ public final class CapturingMuxer implements Muxer, Dumpable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Muxer create(String path) throws Muxer.MuxerException {
|
public Muxer create(String path) throws MuxerException {
|
||||||
muxer = new CapturingMuxer(wrappedFactory.create(path), handleAudioAsPcm);
|
muxer = new CapturingMuxer(wrappedFactory.create(path), handleAudioAsPcm);
|
||||||
return muxer;
|
return muxer;
|
||||||
}
|
}
|
||||||
@ -142,9 +142,9 @@ public final class CapturingMuxer implements Muxer, Dumpable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() throws MuxerException {
|
public void close() throws MuxerException {
|
||||||
released = true;
|
released = true;
|
||||||
wrappedMuxer.release();
|
wrappedMuxer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dumper.Dumpable implementation.
|
// Dumper.Dumpable implementation.
|
||||||
|
@ -30,6 +30,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.ColorInfo;
|
import androidx.media3.common.ColorInfo;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
|
import androidx.media3.muxer.Muxer.MuxerException;
|
||||||
import androidx.media3.test.utils.DumpFileAsserts;
|
import androidx.media3.test.utils.DumpFileAsserts;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@ -74,7 +75,7 @@ public class MuxerWrapperTest {
|
|||||||
@Nullable private MuxerWrapper muxerWrapper;
|
@Nullable private MuxerWrapper muxerWrapper;
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Muxer.MuxerException {
|
public void tearDown() throws MuxerException {
|
||||||
if (muxerWrapper != null) {
|
if (muxerWrapper != null) {
|
||||||
// Release with reason cancellation so that underlying resources are always released.
|
// Release with reason cancellation so that underlying resources are always released.
|
||||||
muxerWrapper.finishWritingAndMaybeRelease(MuxerWrapper.MUXER_RELEASE_REASON_CANCELLED);
|
muxerWrapper.finishWritingAndMaybeRelease(MuxerWrapper.MUXER_RELEASE_REASON_CANCELLED);
|
||||||
|
@ -24,6 +24,7 @@ import androidx.media3.common.audio.ChannelMixingMatrix;
|
|||||||
import androidx.media3.common.audio.SonicAudioProcessor;
|
import androidx.media3.common.audio.SonicAudioProcessor;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import androidx.media3.muxer.Muxer;
|
||||||
import androidx.media3.test.utils.FakeClock;
|
import androidx.media3.test.utils.FakeClock;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
@ -34,6 +34,7 @@ import androidx.media3.container.Mp4TimestampData;
|
|||||||
import androidx.media3.container.XmpData;
|
import androidx.media3.container.XmpData;
|
||||||
import androidx.media3.extractor.mp4.Mp4Extractor;
|
import androidx.media3.extractor.mp4.Mp4Extractor;
|
||||||
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||||
|
import androidx.media3.muxer.Muxer;
|
||||||
import androidx.media3.test.utils.DumpFileAsserts;
|
import androidx.media3.test.utils.DumpFileAsserts;
|
||||||
import androidx.media3.test.utils.FakeClock;
|
import androidx.media3.test.utils.FakeClock;
|
||||||
import androidx.media3.test.utils.FakeExtractorOutput;
|
import androidx.media3.test.utils.FakeExtractorOutput;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user