Move muxer closing logic from Mp4Writer to Mp4Muxer

PiperOrigin-RevId: 646134522
This commit is contained in:
sheenachhabra 2024-06-24 10:06:32 -07:00 committed by Copybara-Service
parent b026271c84
commit 327f728010
2 changed files with 49 additions and 21 deletions

View File

@ -24,6 +24,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
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.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.container.MdtaMetadataEntry; import androidx.media3.container.MdtaMetadataEntry;
import androidx.media3.container.Mp4LocationData; import androidx.media3.container.Mp4LocationData;
@ -38,6 +39,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/** /**
* A muxer for creating an MP4 container file. * A muxer for creating an MP4 container file.
@ -176,6 +178,10 @@ public final class Mp4Muxer implements Muxer {
} }
} }
private static final String TAG = "Mp4Muxer";
private final FileOutputStream fileOutputStream;
private final FileChannel fileChannel;
private final MetadataCollector metadataCollector; private final MetadataCollector metadataCollector;
private final Mp4Writer mp4Writer; private final Mp4Writer mp4Writer;
@ -185,12 +191,14 @@ public final class Mp4Muxer implements Muxer {
AnnexBToAvccConverter annexBToAvccConverter, AnnexBToAvccConverter annexBToAvccConverter,
boolean sampleCopyEnabled, boolean sampleCopyEnabled,
boolean attemptStreamableOutputEnabled) { boolean attemptStreamableOutputEnabled) {
this.fileOutputStream = fileOutputStream;
this.fileChannel = fileOutputStream.getChannel();
metadataCollector = new MetadataCollector(); metadataCollector = new MetadataCollector();
Mp4MoovStructure moovStructure = Mp4MoovStructure moovStructure =
new Mp4MoovStructure(metadataCollector, lastFrameDurationBehavior); new Mp4MoovStructure(metadataCollector, lastFrameDurationBehavior);
mp4Writer = mp4Writer =
new Mp4Writer( new Mp4Writer(
fileOutputStream, fileChannel,
moovStructure, moovStructure,
annexBToAvccConverter, annexBToAvccConverter,
sampleCopyEnabled, sampleCopyEnabled,
@ -288,10 +296,32 @@ public final class Mp4Muxer implements Muxer {
@Override @Override
public void close() throws MuxerException { public void close() throws MuxerException {
@Nullable MuxerException exception = null;
try { try {
mp4Writer.close(); mp4Writer.finishWritingSamples();
} catch (IOException e) { } catch (IOException e) {
throw new MuxerException("Failed to close the muxer", e); exception = new MuxerException("Failed to finish writing samples", e);
}
try {
fileChannel.close();
} catch (IOException e) {
if (exception == null) {
exception = new MuxerException("Failed to close output channel", e);
} else {
Log.e(TAG, "Failed to close output channel", e);
}
}
try {
fileOutputStream.close();
} catch (IOException e) {
if (exception == null) {
exception = new MuxerException("Failed to close output stream", e);
} else {
Log.e(TAG, "Failed to close output stream", e);
}
}
if (exception != null) {
throw exception;
} }
} }
} }

View File

@ -28,7 +28,6 @@ import androidx.media3.common.Format;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.muxer.Muxer.TrackToken; import androidx.media3.muxer.Muxer.TrackToken;
import com.google.common.collect.Range; import com.google.common.collect.Range;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
@ -43,7 +42,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int DEFAULT_MOOV_BOX_SIZE_BYTES = 400_000; private static final int DEFAULT_MOOV_BOX_SIZE_BYTES = 400_000;
private static final String FREE_BOX_TYPE = "free"; private static final String FREE_BOX_TYPE = "free";
private final FileOutputStream outputStream;
private final FileChannel output; private final FileChannel output;
private final Mp4MoovStructure moovGenerator; private final Mp4MoovStructure moovGenerator;
private final AnnexBToAvccConverter annexBToAvccConverter; private final AnnexBToAvccConverter annexBToAvccConverter;
@ -66,7 +64,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* Creates an instance. * Creates an instance.
* *
* @param outputStream The {@link FileOutputStream} to write the data to. * @param fileChannel The {@link FileChannel} to write the data to. The {@link FileChannel} can be
* closed after {@link #finishWritingSamples() finishing writing samples}.
* @param moovGenerator An {@link Mp4MoovStructure} instance to generate the moov box. * @param moovGenerator An {@link Mp4MoovStructure} instance to generate the moov box.
* @param annexBToAvccConverter The {@link AnnexBToAvccConverter} to be used to convert H.264 and * @param annexBToAvccConverter The {@link AnnexBToAvccConverter} to be used to convert H.264 and
* H.265 NAL units from the Annex-B format (using start codes to delineate NAL units) to the * H.265 NAL units from the Annex-B format (using start codes to delineate NAL units) to the
@ -75,13 +74,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @param attemptStreamableOutputEnabled Whether to attempt to write a streamable output. * @param attemptStreamableOutputEnabled Whether to attempt to write a streamable output.
*/ */
public Mp4Writer( public Mp4Writer(
FileOutputStream outputStream, FileChannel fileChannel,
Mp4MoovStructure moovGenerator, Mp4MoovStructure moovGenerator,
AnnexBToAvccConverter annexBToAvccConverter, AnnexBToAvccConverter annexBToAvccConverter,
boolean sampleCopyEnabled, boolean sampleCopyEnabled,
boolean attemptStreamableOutputEnabled) { boolean attemptStreamableOutputEnabled) {
this.outputStream = outputStream; this.output = fileChannel;
this.output = outputStream.getChannel();
this.moovGenerator = moovGenerator; this.moovGenerator = moovGenerator;
this.annexBToAvccConverter = annexBToAvccConverter; this.annexBToAvccConverter = annexBToAvccConverter;
this.sampleCopyEnabled = sampleCopyEnabled; this.sampleCopyEnabled = sampleCopyEnabled;
@ -105,19 +103,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
doInterleave(); doInterleave();
} }
public void close() throws IOException { /**
try { * Writes all the pending samples and the final moov box to the disk.
for (int i = 0; i < tracks.size(); i++) { *
flushPending(tracks.get(i)); * <p>The output {@link FileChannel} can be closed after calling this method.
} */
public void finishWritingSamples() throws IOException {
for (int i = 0; i < tracks.size(); i++) {
flushPending(tracks.get(i));
}
// Leave the file empty if no samples are written. // Leave the file empty if no samples are written.
if (hasWrittenSamples.get()) { if (hasWrittenSamples.get()) {
writeMoovAndTrim(); writeMoovAndTrim();
}
} finally {
output.close();
outputStream.close();
} }
} }