Skip to content

Commit

Permalink
Make Mp4MoovStructure.moov() method static
Browse files Browse the repository at this point in the history
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
  • Loading branch information
SheenaChhabra authored and copybara-github committed Jul 18, 2024
1 parent 570be36 commit a52df6d
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,10 @@ private FragmentedMp4Muxer(
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ public SampleMetadata(int durationsVu, int size, int flags, int compositionTimeO

private final FileOutputStream outputStream;
private final FileChannel output;
private final Mp4MoovStructure moovGenerator;
private final MetadataCollector metadataCollector;
private final AnnexBToAvccConverter annexBToAvccConverter;
private final List<Track> tracks;
private final long fragmentDurationUs;
private final boolean sampleCopyEnabled;
private final @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior;
private final List<Track> tracks;

private @MonotonicNonNull Track videoTrack;
private int currentFragmentSequenceNumber;
Expand All @@ -80,7 +81,7 @@ public SampleMetadata(int durationsVu, int size, int flags, int compositionTimeO
* 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).
Expand All @@ -89,17 +90,18 @@ public SampleMetadata(int durationsVu, int size, int flags, int compositionTimeO
*/
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.fragmentDurationUs = fragmentDurationMs * 1_000;
this.sampleCopyEnabled = sampleCopyEnabled;
lastFrameDurationBehavior = Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION;
tracks = new ArrayList<>();
this.fragmentDurationUs = fragmentDurationMs * 1_000;
minInputPresentationTimeUs = Long.MAX_VALUE;
currentFragmentSequenceNumber = 1;
}
Expand Down Expand Up @@ -200,8 +202,12 @@ private void createHeader() throws IOException {
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
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();
Expand All @@ -44,20 +44,16 @@ public interface TrackMetadataProvider {
ImmutableList<Integer> writtenChunkSampleCounts();
}

private final MetadataCollector metadataCollector;
private final @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior;
private Mp4MoovStructure() {}

public Mp4MoovStructure(
/** Returns the moov box. */
@SuppressWarnings("InlinedApi")
public static ByteBuffer moov(
List<? extends TrackMetadataProvider> tracks,
MetadataCollector metadataCollector,
long minInputPtsUs,
boolean isFragmentedMp4,
@Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior) {
this.metadataCollector = metadataCollector;
this.lastFrameDurationBehavior = lastFrameDurationBehavior;
}

/** Generates a mdat header. */
@SuppressWarnings("InlinedApi")
public ByteBuffer moovMetadataHeader(
List<? extends TrackMetadataProvider> tracks, long minInputPtsUs, boolean isFragmentedMp4) {
// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,12 @@ private Mp4Muxer(
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<>();
Expand Down Expand Up @@ -465,13 +464,12 @@ private void ensureSetupForEditableVideoTracks() throws FileNotFoundException {
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);
}
Expand Down
24 changes: 17 additions & 7 deletions libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@
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<Track> 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)
Expand All @@ -67,26 +68,30 @@
* @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);
}

Expand Down Expand Up @@ -239,7 +244,12 @@ private ByteBuffer assembleCurrentMoovData() {
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);
Expand Down

0 comments on commit a52df6d

Please sign in to comment.