From a52df6d29e74187cf6a7372869704f6a93943357 Mon Sep 17 00:00:00 2001 From: sheenachhabra Date: Thu, 18 Jul 2024 06:47:56 -0700 Subject: [PATCH] Make Mp4MoovStructure.moov() method static Creating a moov box is same as creating any other box so there is no particular need to have a separate class for this. In a follow up CL the method will be moved into Boxes.java along with other box creation methods. Made nit changes in the final fields ordering to match with constructor parameter ordering. PiperOrigin-RevId: 653602558 --- .../media3/muxer/FragmentedMp4Muxer.java | 5 +--- .../media3/muxer/FragmentedMp4Writer.java | 26 ++++++++++++------- .../media3/muxer/Mp4MoovStructure.java | 22 +++++++--------- .../java/androidx/media3/muxer/Mp4Muxer.java | 10 +++---- .../java/androidx/media3/muxer/Mp4Writer.java | 24 ++++++++++++----- 5 files changed, 47 insertions(+), 40 deletions(-) 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 fc56869723..b0137b4271 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java @@ -124,13 +124,10 @@ public final class FragmentedMp4Muxer implements Muxer { FileOutputStream fileOutputStream, long fragmentDurationMs, boolean sampleCopyEnabled) { checkNotNull(fileOutputStream); metadataCollector = new MetadataCollector(); - Mp4MoovStructure moovStructure = - new Mp4MoovStructure( - metadataCollector, Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION); fragmentedMp4Writer = new FragmentedMp4Writer( fileOutputStream, - moovStructure, + metadataCollector, AnnexBToAvccConverter.DEFAULT, fragmentDurationMs, sampleCopyEnabled); diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java index 474133b2f9..2f7f1485e3 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java @@ -64,11 +64,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private final FileOutputStream outputStream; private final FileChannel output; - private final Mp4MoovStructure moovGenerator; + private final MetadataCollector metadataCollector; private final AnnexBToAvccConverter annexBToAvccConverter; - private final List tracks; private final long fragmentDurationUs; private final boolean sampleCopyEnabled; + private final @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior; + private final List tracks; private @MonotonicNonNull Track videoTrack; private int currentFragmentSequenceNumber; @@ -80,7 +81,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * Creates an instance. * * @param outputStream The {@link FileOutputStream} to write the data to. - * @param moovGenerator An {@link Mp4MoovStructure} instance to generate the moov box. + * @param metadataCollector A {@link MetadataCollector}. * @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 * AVCC format (which uses length prefixes). @@ -89,17 +90,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; */ public FragmentedMp4Writer( FileOutputStream outputStream, - Mp4MoovStructure moovGenerator, + MetadataCollector metadataCollector, AnnexBToAvccConverter annexBToAvccConverter, long fragmentDurationMs, boolean sampleCopyEnabled) { this.outputStream = outputStream; - this.output = outputStream.getChannel(); - this.moovGenerator = moovGenerator; + output = outputStream.getChannel(); + this.metadataCollector = metadataCollector; this.annexBToAvccConverter = annexBToAvccConverter; - this.sampleCopyEnabled = sampleCopyEnabled; - tracks = new ArrayList<>(); this.fragmentDurationUs = fragmentDurationMs * 1_000; + this.sampleCopyEnabled = sampleCopyEnabled; + lastFrameDurationBehavior = Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION; + tracks = new ArrayList<>(); minInputPresentationTimeUs = Long.MAX_VALUE; currentFragmentSequenceNumber = 1; } @@ -200,8 +202,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; output.write(Boxes.ftyp()); // The minInputPtsUs is actually ignored as there are no pending samples to write. output.write( - moovGenerator.moovMetadataHeader( - tracks, /* minInputPtsUs= */ 0L, /* isFragmentedMp4= */ true)); + Mp4MoovStructure.moov( + tracks, + metadataCollector, + /* minInputPtsUs= */ 0L, + /* isFragmentedMp4= */ true, + lastFrameDurationBehavior)); } private boolean shouldFlushPendingSamples( diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java index 0e03392eeb..054b72ce09 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java @@ -30,7 +30,7 @@ import java.util.Locale; import org.checkerframework.checker.nullness.qual.PolyNull; /** Builds the moov box structure of an MP4 file. */ -/* package */ class Mp4MoovStructure { +/* package */ final class Mp4MoovStructure { /** Provides track's metadata like media format, written samples. */ public interface TrackMetadataProvider { Format format(); @@ -44,20 +44,16 @@ import org.checkerframework.checker.nullness.qual.PolyNull; ImmutableList writtenChunkSampleCounts(); } - private final MetadataCollector metadataCollector; - private final @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior; + private Mp4MoovStructure() {} - public Mp4MoovStructure( - MetadataCollector metadataCollector, - @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior) { - this.metadataCollector = metadataCollector; - this.lastFrameDurationBehavior = lastFrameDurationBehavior; - } - - /** Generates a mdat header. */ + /** Returns the moov box. */ @SuppressWarnings("InlinedApi") - public ByteBuffer moovMetadataHeader( - List tracks, long minInputPtsUs, boolean isFragmentedMp4) { + public static ByteBuffer moov( + List tracks, + MetadataCollector metadataCollector, + long minInputPtsUs, + boolean isFragmentedMp4, + @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior) { // The timestamp will always fit into a 32-bit integer. This is already validated in the // Mp4Muxer.setTimestampData() API. The value after type casting might be negative, but it is // still valid because it is meant to be read as an unsigned integer. 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 2877a9eac7..3ed66cf536 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java @@ -296,13 +296,12 @@ public final class Mp4Muxer implements Muxer { this.outputFileFormat = outputFileFormat; this.cacheFileProvider = cacheFileProvider; metadataCollector = new MetadataCollector(); - Mp4MoovStructure moovStructure = - new Mp4MoovStructure(metadataCollector, lastFrameDurationBehavior); mp4Writer = new Mp4Writer( outputChannel, - moovStructure, + metadataCollector, annexBToAvccConverter, + lastFrameDurationBehavior, sampleCopyEnabled, attemptStreamableOutputEnabled); editableVideoTracks = new ArrayList<>(); @@ -465,13 +464,12 @@ public final class Mp4Muxer implements Muxer { cacheFilePath = checkNotNull(cacheFileProvider).getCacheFilePath(); cacheFileOutputStream = new FileOutputStream(cacheFilePath); editableVideoMetadataCollector = new MetadataCollector(); - Mp4MoovStructure mp4MoovStructure = - new Mp4MoovStructure(editableVideoMetadataCollector, lastFrameDurationBehavior); editableVideoMp4Writer = new Mp4Writer( cacheFileOutputStream.getChannel(), - mp4MoovStructure, + checkNotNull(editableVideoMetadataCollector), annexBToAvccConverter, + lastFrameDurationBehavior, sampleCopyEnabled, attemptStreamableOutputEnabled); } diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java index 03f7f57232..949ba92ffd 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java @@ -43,11 +43,12 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final String FREE_BOX_TYPE = "free"; private final FileChannel outputFileChannel; - private final Mp4MoovStructure moovGenerator; + private final MetadataCollector metadataCollector; private final AnnexBToAvccConverter annexBToAvccConverter; + private final @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior; + private final boolean sampleCopyEnabled; private final List tracks; private final AtomicBoolean hasWrittenSamples; - private final boolean sampleCopyEnabled; // Stores location of the space reserved for the moov box at the beginning of the file (after ftyp // box) @@ -67,26 +68,30 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param fileChannel The {@link FileChannel} to write the data to. The {@link FileChannel} can be * closed after {@linkplain #finishWritingSamplesAndFinalizeMoovBox() finishing writing * samples}. - * @param moovGenerator An {@link Mp4MoovStructure} instance to generate the moov box. + * @param metadataCollector A {@link MetadataCollector}. * @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 * AVCC format (which uses length prefixes). + * @param lastFrameDurationBehavior The {@link Mp4Muxer.LastFrameDurationBehavior} for the video + * track. * @param sampleCopyEnabled Whether sample copying is enabled. * @param attemptStreamableOutputEnabled Whether to attempt to write a streamable output. */ public Mp4Writer( FileChannel fileChannel, - Mp4MoovStructure moovGenerator, + MetadataCollector metadataCollector, AnnexBToAvccConverter annexBToAvccConverter, + @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior, boolean sampleCopyEnabled, boolean attemptStreamableOutputEnabled) { this.outputFileChannel = fileChannel; - this.moovGenerator = moovGenerator; + this.metadataCollector = metadataCollector; this.annexBToAvccConverter = annexBToAvccConverter; + this.lastFrameDurationBehavior = lastFrameDurationBehavior; this.sampleCopyEnabled = sampleCopyEnabled; - canWriteMoovAtStart = attemptStreamableOutputEnabled; tracks = new ArrayList<>(); hasWrittenSamples = new AtomicBoolean(false); + canWriteMoovAtStart = attemptStreamableOutputEnabled; lastMoovWritten = Range.closed(0L, 0L); } @@ -239,7 +244,12 @@ import java.util.concurrent.atomic.AtomicBoolean; ByteBuffer moovHeader; if (minInputPtsUs != Long.MAX_VALUE) { moovHeader = - moovGenerator.moovMetadataHeader(tracks, minInputPtsUs, /* isFragmentedMp4= */ false); + Mp4MoovStructure.moov( + tracks, + metadataCollector, + minInputPtsUs, + /* isFragmentedMp4= */ false, + lastFrameDurationBehavior); } else { // Skip moov box, if there are no samples. moovHeader = ByteBuffer.allocate(0);