From 8a758c2ed75c4981da39790756b43a2f8b4e785c Mon Sep 17 00:00:00 2001 From: sheenachhabra Date: Fri, 9 Feb 2024 04:13:28 -0800 Subject: [PATCH] Replace `setModificationTime` API with `setTimestampData` in Mp4Muxer The new API will take both `creation time` and `modification time`. Till now, Mp4Muxer wrote `modification time` in both `creation time` and `modification time` field, which was incorrect. PiperOrigin-RevId: 605590623 --- .../media3/container/Mp4TimestampData.java | 27 ++++++++-- .../androidx/media3/container/Mp4Util.java | 43 ---------------- .../media3/muxer/Mp4MuxerEndToEndTest.java | 21 ++++++-- .../java/androidx/media3/muxer/Boxes.java | 19 ++++--- .../media3/muxer/MetadataCollector.java | 21 ++++---- .../media3/muxer/Mp4MoovStructure.java | 15 ++++-- .../java/androidx/media3/muxer/Mp4Muxer.java | 16 ++++-- .../java/androidx/media3/muxer/BoxesTest.java | 12 +++-- .../media3/muxer/Mp4MuxerEndToEndTest.java | 16 ++++-- .../media3/muxer/Mp4MuxerMetadataTest.java | 51 +++++++++++++++---- .../muxerdumps/audio_track_tkhd_box.dump | 2 +- .../h265_with_metadata_track.mp4.dump | 6 +-- .../assets/muxerdumps/hdr10-720p.mp4.dump | 4 +- ...r10-720p.mp4_fragmented_box_structure.dump | 10 ++-- .../src/test/assets/muxerdumps/mdhd_box.dump | 2 +- .../mp4_with_0_orientation.mp4.dump | 2 +- .../mp4_with_180_orientation.mp4.dump | 2 +- .../mp4_with_270_orientation.mp4.dump | 2 +- .../mp4_with_90_orientation.mp4.dump | 2 +- .../mp4_with_different_tracks_offset.mp4.dump | 4 +- .../mp4_with_float_metadata.mp4.dump | 2 +- .../muxerdumps/mp4_with_frame_rate.mp4.dump | 2 +- .../muxerdumps/mp4_with_location.mp4.dump | 2 +- .../mp4_with_null_location.mp4.dump | 2 +- .../mp4_with_same_tracks_offset.mp4.dump | 4 +- .../mp4_with_string_metadata.mp4.dump | 2 +- .../assets/muxerdumps/mp4_with_xmp.mp4.dump | 6 +-- .../mp4_without_empty_track.mp4.dump | 6 +-- .../src/test/assets/muxerdumps/mvhd_box.dump | 2 +- .../muxerdumps/partial_hdr10-720p.mp4.dump | 4 +- .../assets/muxerdumps/sample_av1.mp4.dump | 4 +- .../muxerdumps/sample_no_bframes.mp4.dump | 4 +- .../muxerdumps/video_track_tkhd_box.dump | 2 +- .../transmuxed_with_inappmuxer.dump | 4 +- .../media3/transformer/InAppMuxer.java | 5 +- ...TransformerWithInAppMuxerEndToEndTest.java | 12 ++--- 36 files changed, 193 insertions(+), 147 deletions(-) delete mode 100644 libraries/container/src/main/java/androidx/media3/container/Mp4Util.java diff --git a/libraries/container/src/main/java/androidx/media3/container/Mp4TimestampData.java b/libraries/container/src/main/java/androidx/media3/container/Mp4TimestampData.java index 92c1ad5b81..26893496ca 100644 --- a/libraries/container/src/main/java/androidx/media3/container/Mp4TimestampData.java +++ b/libraries/container/src/main/java/androidx/media3/container/Mp4TimestampData.java @@ -18,7 +18,6 @@ package androidx.media3.container; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.Nullable; -import androidx.media3.common.C; import androidx.media3.common.Metadata; import androidx.media3.common.util.UnstableApi; import com.google.common.primitives.Longs; @@ -29,6 +28,13 @@ public final class Mp4TimestampData implements Metadata.Entry { /** Represents an unset or unknown timescale. */ public static final int TIMESCALE_UNSET = -1; + /** + * The delta between a Unix epoch timestamp (in milliseconds since midnight, January 1, 1970) and + * an MP4 timestamp (in seconds since midnight, January 1, 1904). + */ + private static final int UNIX_EPOCH_TO_MP4_TIME_DELTA_SECONDS = + ((1970 - 1904) * 365 + 17 /* leap year */) * (24 * 60 * 60); + /** The creation timestamp. */ public final long creationTimestampSeconds; @@ -41,13 +47,16 @@ public final class Mp4TimestampData implements Metadata.Entry { /** * Creates an instance. * + *

The {@link #timescale} is set to {@link Mp4TimestampData#TIMESCALE_UNSET}. + * * @param creationTimestampSeconds The creation time UTC in seconds since midnight, January 1, - * 1904. The {@link #modificationTimestampSeconds} is set to {@link C#TIME_UNSET} and {@link - * #timescale} is set to {@link Mp4TimestampData#TIMESCALE_UNSET}. + * 1904. + * @param modificationTimestampSeconds The modification time UTC in seconds since midnight, + * January 1, 1904. */ - public Mp4TimestampData(long creationTimestampSeconds) { + public Mp4TimestampData(long creationTimestampSeconds, long modificationTimestampSeconds) { this.creationTimestampSeconds = creationTimestampSeconds; - this.modificationTimestampSeconds = C.TIME_UNSET; + this.modificationTimestampSeconds = modificationTimestampSeconds; this.timescale = TIMESCALE_UNSET; } @@ -73,6 +82,14 @@ public final class Mp4TimestampData implements Metadata.Entry { this.timescale = in.readLong(); } + /** + * Returns an MP4 timestamp (in seconds since midnight, January 1, 1904) from a Unix epoch + * timestamp (in milliseconds since midnight, January 1, 1970). + */ + public static long unixTimeToMp4TimeSeconds(long unixTimestampMs) { + return (unixTimestampMs / 1_000L) + UNIX_EPOCH_TO_MP4_TIME_DELTA_SECONDS; + } + @Override public boolean equals(@Nullable Object obj) { if (this == obj) { diff --git a/libraries/container/src/main/java/androidx/media3/container/Mp4Util.java b/libraries/container/src/main/java/androidx/media3/container/Mp4Util.java deleted file mode 100644 index 7963171da1..0000000000 --- a/libraries/container/src/main/java/androidx/media3/container/Mp4Util.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2023 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.container; - -import androidx.media3.common.util.UnstableApi; - -/** Utilities for MP4 container. */ -@UnstableApi -public final class Mp4Util { - private static final int UNIX_EPOCH_TO_MP4_TIME_DELTA_SECONDS = - ((1970 - 1904) * 365 + 17 /* leap year */) * (24 * 60 * 60); - - private Mp4Util() {} - - /** - * Returns an MP4 timestamp (in seconds since midnight, January 1, 1904) from a Unix epoch - * timestamp (in milliseconds since midnight, January 1, 1970). - */ - public static long unixTimeToMp4TimeSeconds(long unixTimestampMs) { - return (unixTimestampMs / 1000L + UNIX_EPOCH_TO_MP4_TIME_DELTA_SECONDS); - } - - /** - * Returns a Unix epoch timestamp (in milliseconds since midnight, January 1, 1970) from an MP4 - * timestamp (in seconds since midnight, January 1, 1904). - */ - public static long mp4TimeToUnixTimeMs(long mp4TimestampSeconds) { - return (mp4TimestampSeconds - UNIX_EPOCH_TO_MP4_TIME_DELTA_SECONDS) * 1000L; - } -} diff --git a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java index 22482bcb2c..a35cb33e6e 100644 --- a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java @@ -23,6 +23,7 @@ import android.media.MediaCodec; import android.media.MediaExtractor; import androidx.annotation.Nullable; import androidx.media3.common.util.MediaFormatUtil; +import androidx.media3.container.Mp4TimestampData; import androidx.media3.extractor.mp4.FragmentedMp4Extractor; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.test.utils.DumpFileAsserts; @@ -85,7 +86,10 @@ public class Mp4MuxerEndToEndTest { try { mp4Muxer = new Mp4Muxer.Builder(checkNotNull(outputStream)).build(); - mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + mp4Muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 100_000_000L, + /* modificationTimestampSeconds= */ 500_000_000L)); feedInputDataToMuxer(mp4Muxer, checkNotNull(inputFile)); } finally { if (mp4Muxer != null) { @@ -106,7 +110,10 @@ public class Mp4MuxerEndToEndTest { // ensure some data has been written after taking all the inputs but before closing the muxer. assumeTrue(checkNotNull(inputFile).equals(H265_HDR10_MP4)); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(checkNotNull(outputStream)).build(); - mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + mp4Muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 100_000_000L, + /* modificationTimestampSeconds= */ 500_000_000L)); feedInputDataToMuxer(mp4Muxer, inputFile); // Muxer not closed. @@ -132,7 +139,10 @@ public class Mp4MuxerEndToEndTest { try { mp4Muxer = new Mp4Muxer.Builder(checkNotNull(outputStream)).setFragmentedMp4Enabled(true).build(); - mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + mp4Muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 100_000_000L, + /* modificationTimestampSeconds= */ 500_000_000L)); feedInputDataToMuxer(mp4Muxer, inputFile); } finally { if (mp4Muxer != null) { @@ -160,7 +170,10 @@ public class Mp4MuxerEndToEndTest { try { mp4Muxer = new Mp4Muxer.Builder(checkNotNull(outputStream)).setFragmentedMp4Enabled(true).build(); - mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + mp4Muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 100_000_000L, + /* modificationTimestampSeconds= */ 500_000_000L)); feedInputDataToMuxer(mp4Muxer, inputFile); } finally { if (mp4Muxer != null) { diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java index de393a5849..62d75056d9 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java @@ -93,14 +93,15 @@ import java.util.Locale; public static ByteBuffer tkhd( int trackId, int trackDurationVu, + int creationTimestampSeconds, int modificationTimestampSeconds, int orientation, Format format) { ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE); contents.putInt(0x00000007); // version and flags; allow presentation, etc. - contents.putInt(modificationTimestampSeconds); // creation_time - contents.putInt(modificationTimestampSeconds); // modification_time + contents.putInt(creationTimestampSeconds); // creation_time; unsigned int(32) + contents.putInt(modificationTimestampSeconds); // modification_time; unsigned int(32) contents.putInt(trackId); contents.putInt(0); // reserved @@ -132,12 +133,15 @@ import java.util.Locale; *

This is the movie header for the entire MP4 file. */ public static ByteBuffer mvhd( - int nextEmptyTrackId, int modificationTimestampSeconds, long videoDurationUs) { + int nextEmptyTrackId, + int creationTimestampSeconds, + int modificationTimestampSeconds, + long videoDurationUs) { ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE); contents.putInt(0); // version and flags - contents.putInt(modificationTimestampSeconds); // creation_time - contents.putInt(modificationTimestampSeconds); // modification_time + contents.putInt(creationTimestampSeconds); // creation_time; unsigned int(32) + contents.putInt(modificationTimestampSeconds); // modification_time; unsigned int(32) contents.putInt((int) MVHD_TIMEBASE); // The per-track timescales might be different. contents.putInt( (int) Mp4Utils.vuFromUs(videoDurationUs, MVHD_TIMEBASE)); // Duration of the entire video. @@ -175,13 +179,14 @@ import java.util.Locale; public static ByteBuffer mdhd( long trackDurationVu, int videoUnitTimebase, + int creationTimestampSeconds, int modificationTimestampSeconds, @Nullable String languageCode) { ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE); contents.putInt(0x0); // version and flags - contents.putInt(modificationTimestampSeconds); // creation_time - contents.putInt(modificationTimestampSeconds); // modification_time + contents.putInt(creationTimestampSeconds); // creation_time; unsigned int(32) + contents.putInt(modificationTimestampSeconds); // modification_time; unsigned int(32) contents.putInt(videoUnitTimebase); diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java b/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java index ed02a57cfe..9bf3f3629f 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java @@ -15,11 +15,10 @@ */ package androidx.media3.muxer; -import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkState; -import static androidx.media3.muxer.Mp4Utils.UNSIGNED_INT_MAX_VALUE; +import static androidx.media3.container.Mp4TimestampData.unixTimeToMp4TimeSeconds; -import androidx.media3.container.Mp4Util; +import androidx.media3.container.Mp4TimestampData; import java.nio.ByteBuffer; import java.util.LinkedHashMap; import java.util.Map; @@ -30,14 +29,17 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public int orientation; public @MonotonicNonNull Mp4Location location; public Map metadataPairs; - public int modificationTimestampSeconds; + public Mp4TimestampData timestampData; public @MonotonicNonNull ByteBuffer xmpData; public MetadataCollector() { orientation = 0; metadataPairs = new LinkedHashMap<>(); - modificationTimestampSeconds = - (int) Mp4Util.unixTimeToMp4TimeSeconds(System.currentTimeMillis()); + long currentTimeInMp4TimeSeconds = unixTimeToMp4TimeSeconds(System.currentTimeMillis()); + timestampData = + new Mp4TimestampData( + /* creationTimestampSeconds= */ currentTimeInMp4TimeSeconds, + /* modificationTimestampSeconds= */ currentTimeInMp4TimeSeconds); } public void addXmp(ByteBuffer xmpData) { @@ -61,10 +63,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; metadataPairs.put(key, value); } - public void setModificationTime(long unixTimestampMs) { - long timestampSeconds = Mp4Util.unixTimeToMp4TimeSeconds(unixTimestampMs); - checkArgument( - timestampSeconds <= UNSIGNED_INT_MAX_VALUE, "Only 32-bit long timestamp supported"); - this.modificationTimestampSeconds = (int) timestampSeconds; + public void setTimestampData(Mp4TimestampData timestampData) { + this.timestampData = timestampData; } } 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 ffacb22326..1f5837aa4e 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java @@ -60,6 +60,12 @@ import org.checkerframework.checker.nullness.qual.PolyNull; @SuppressWarnings("InlinedApi") public ByteBuffer moovMetadataHeader( List 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. + int creationTimestampSeconds = (int) metadataCollector.timestampData.creationTimestampSeconds; + int modificationTimestampSeconds = + (int) metadataCollector.timestampData.modificationTimestampSeconds; List trakBoxes = new ArrayList<>(); List trexBoxes = new ArrayList<>(); @@ -149,14 +155,16 @@ import org.checkerframework.checker.nullness.qual.PolyNull; // Using the time base of the entire file, not that of the track; otherwise, // Quicktime will stretch the audio accordingly, see b/158120042. (int) Mp4Utils.vuFromUs(trackDurationUs, MVHD_TIMEBASE), - metadataCollector.modificationTimestampSeconds, + creationTimestampSeconds, + modificationTimestampSeconds, metadataCollector.orientation, format), Boxes.mdia( Boxes.mdhd( trackDurationInTrackUnitsVu, track.videoUnitTimebase(), - metadataCollector.modificationTimestampSeconds, + creationTimestampSeconds, + modificationTimestampSeconds, languageCode), Boxes.hdlr(handlerType, handlerName), Boxes.minf(mhdBox, Boxes.dinf(Boxes.dref(Boxes.localUrl())), stblBox))); @@ -168,7 +176,8 @@ import org.checkerframework.checker.nullness.qual.PolyNull; } ByteBuffer mvhdBox = - Boxes.mvhd(nextTrackId, metadataCollector.modificationTimestampSeconds, videoDurationUs); + Boxes.mvhd( + nextTrackId, creationTimestampSeconds, modificationTimestampSeconds, videoDurationUs); ByteBuffer udtaBox = Boxes.udta(metadataCollector.location); ByteBuffer metaBox = metadataCollector.metadataPairs.isEmpty() 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 5b277b4f74..577261310c 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java @@ -15,7 +15,9 @@ */ package androidx.media3.muxer; +import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkNotNull; +import static androidx.media3.muxer.Mp4Utils.UNSIGNED_INT_MAX_VALUE; import static java.lang.annotation.ElementType.TYPE_USE; import android.media.MediaCodec.BufferInfo; @@ -25,6 +27,7 @@ import androidx.annotation.Nullable; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; +import androidx.media3.container.Mp4TimestampData; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.FileOutputStream; @@ -233,12 +236,17 @@ public final class Mp4Muxer { } /** - * Sets the file modification time. + * Sets the timestamp data (creation time and modification time) for the output file. * - * @param timestampMs The modification time UTC in milliseconds since the Unix epoch. + *

If this method is not called, the file creation time and modification time will be when the + * {@link Mp4Muxer} was {@linkplain Builder#build() created}. */ - public void setModificationTime(long timestampMs) { - metadataCollector.setModificationTime(timestampMs); + public void setTimestampData(Mp4TimestampData timestampData) { + checkArgument( + timestampData.creationTimestampSeconds <= UNSIGNED_INT_MAX_VALUE + && timestampData.modificationTimestampSeconds <= UNSIGNED_INT_MAX_VALUE, + "Only 32-bit long timestamp is supported"); + metadataCollector.setTimestampData(timestampData); } /** diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java index 2f38b53878..eee73c6dd7 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java @@ -66,7 +66,8 @@ public class BoxesTest { Boxes.tkhd( /* trackId= */ 1, /* trackDurationVu= */ 5_000_000, - /* modificationTimestampSeconds= */ 1_000_000_000, + /* creationTimestampSeconds= */ 1_000_000_000, + /* modificationTimestampSeconds= */ 2_000_000_000, /* orientation= */ 90, FAKE_VIDEO_FORMAT); @@ -81,7 +82,8 @@ public class BoxesTest { Boxes.tkhd( /* trackId= */ 1, /* trackDurationVu= */ 5_000_000, - /* modificationTimestampSeconds= */ 1_000_000_000, + /* creationTimestampSeconds= */ 1_000_000_000, + /* modificationTimestampSeconds= */ 2_000_000_000, /* orientation= */ 90, FAKE_AUDIO_FORMAT); @@ -95,7 +97,8 @@ public class BoxesTest { ByteBuffer mvhdBox = Boxes.mvhd( /* nextEmptyTrackId= */ 3, - /* modificationTimestampSeconds= */ 1_000_000_000, + /* creationTimestampSeconds= */ 1_000_000_000, + /* modificationTimestampSeconds= */ 2_000_000_000, /* videoDurationUs= */ 5_000_000); DumpableMp4Box dumpableBox = new DumpableMp4Box(mvhdBox); @@ -108,7 +111,8 @@ public class BoxesTest { Boxes.mdhd( /* trackDurationVu= */ 5_000_000, VU_TIMEBASE, - /* modificationTimestampSeconds= */ 1_000_000_000, + /* creationTimestampSeconds= */ 1_000_000_000, + /* modificationTimestampSeconds= */ 2_000_000_000, /* languageCode= */ "und"); DumpableMp4Box dumpableBox = new DumpableMp4Box(mdhdBox); 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 430993e75e..43029dc257 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertThrows; import android.media.MediaCodec.BufferInfo; import android.util.Pair; +import androidx.media3.container.Mp4TimestampData; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.muxer.Mp4Muxer.TrackToken; import androidx.media3.test.utils.DumpFileAsserts; @@ -63,7 +64,10 @@ public class Mp4MuxerEndToEndTest { public void createMp4File_withSameTracksOffset_matchesExpected() throws IOException { String outputFilePath = temporaryFolder.newFile().getPath(); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); - mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + mp4Muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 100_000_000L, + /* modificationTimestampSeconds= */ 500_000_000L)); Pair track1Sample1 = MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L); Pair track1Sample2 = @@ -103,7 +107,10 @@ public class Mp4MuxerEndToEndTest { public void createMp4File_withDifferentTracksOffset_matchesExpected() throws IOException { String outputFilePath = temporaryFolder.newFile().getPath(); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); - mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + mp4Muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 100_000_000L, + /* modificationTimestampSeconds= */ 500_000_000L)); Pair track1Sample1 = MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L); Pair track1Sample2 = @@ -162,7 +169,10 @@ public class Mp4MuxerEndToEndTest { public void createMp4File_withOneTrackEmpty_doesNotWriteEmptyTrack() throws Exception { String outputFilePath = temporaryFolder.newFile().getPath(); Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); - mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + mp4Muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 100_000_000L, + /* modificationTimestampSeconds= */ 500_000_000L)); Pair track1Sample1 = MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L); Pair track1Sample2 = diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java index 2b0127ef46..ed5a1e7906 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java @@ -20,6 +20,7 @@ import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT; import android.content.Context; import android.media.MediaCodec.BufferInfo; import android.util.Pair; +import androidx.media3.container.Mp4TimestampData; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.muxer.Mp4Muxer.TrackToken; import androidx.media3.test.utils.DumpFileAsserts; @@ -53,7 +54,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { @@ -75,7 +79,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); @@ -99,7 +106,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); @@ -123,7 +133,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); @@ -147,7 +160,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); muxer.setLocation(33.0f, -120f); @@ -170,7 +186,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { @@ -192,7 +211,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); muxer.setCaptureFps(120.0f); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); @@ -215,7 +237,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); muxer.addMetadata("SomeStringKey", "Some Random String"); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); @@ -238,7 +263,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); muxer.addMetadata("SomeStringKey", 10.0f); TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); @@ -261,7 +289,10 @@ public class Mp4MuxerMetadataTest { Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); try { - muxer.setModificationTime(/* timestampMs= */ 5_000_000L); + muxer.setTimestampData( + new Mp4TimestampData( + /* creationTimestampSeconds= */ 1_000_000L, + /* modificationTimestampSeconds= */ 5_000_000L)); Context context = ApplicationProvider.getApplicationContext(); byte[] xmpBytes = TestUtil.getByteArray(context, XMP_SAMPLE_DATA); ByteBuffer xmp = ByteBuffer.wrap(xmpBytes); diff --git a/libraries/test_data/src/test/assets/muxerdumps/audio_track_tkhd_box.dump b/libraries/test_data/src/test/assets/muxerdumps/audio_track_tkhd_box.dump index 5b1c2f92e7..195989c244 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/audio_track_tkhd_box.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/audio_track_tkhd_box.dump @@ -1,2 +1,2 @@ tkhd (92 bytes): - Data = length 84, hash 8F9E5354 + Data = length 84, hash C3AC4BE9 diff --git a/libraries/test_data/src/test/assets/muxerdumps/h265_with_metadata_track.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/h265_with_metadata_track.mp4.dump index a17d501929..a472ffc0e1 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/h265_with_metadata_track.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/h265_with_metadata_track.mp4.dump @@ -13,7 +13,7 @@ track 0: id = 1 sampleMimeType = application/meta maxInputSize = 161 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] sample 0: time = 0 flags = 1 @@ -39,7 +39,7 @@ track 1: channelCount = 2 sampleRate = 48000 language = ``` - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 2, hash 560 sample 0: @@ -71,7 +71,7 @@ track 2: colorTransfer = 3 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 85, hash 6F3CAA16 sample 0: diff --git a/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4.dump index d62b694803..2707c7a9aa 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4.dump @@ -23,7 +23,7 @@ track 0: colorTransfer = 6 lumaBitdepth = 10 chromaBitdepth = 10 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 99, hash 99842E5A sample 0: @@ -547,7 +547,7 @@ track 1: channelCount = 2 sampleRate = 48000 language = ``` - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 2, hash 560 sample 0: diff --git a/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump b/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump index 737a6b591a..e2baf278d6 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump @@ -2,13 +2,13 @@ ftyp (28 bytes): Data = length 20, hash EF896440 moov (1209 bytes): mvhd (108 bytes): - Data = length 100, hash 5CF3AC6F + Data = length 100, hash 2FE65289 trak (610 bytes): tkhd (92 bytes): - Data = length 84, hash 112173F4 + Data = length 84, hash 7E478E0E mdia (510 bytes): mdhd (32 bytes): - Data = length 24, hash 42753A93 + Data = length 24, hash 87E287AD hdlr (44 bytes): Data = length 36, hash A0852FF2 minf (426 bytes): @@ -31,10 +31,10 @@ moov (1209 bytes): Data = length 8, hash 94446F01 trak (411 bytes): tkhd (92 bytes): - Data = length 84, hash 34D7906B + Data = length 84, hash A1FDAA85 mdia (311 bytes): mdhd (32 bytes): - Data = length 24, hash EA3D1FE6 + Data = length 24, hash 2FAA6D00 hdlr (44 bytes): Data = length 36, hash 49FC755F minf (227 bytes): diff --git a/libraries/test_data/src/test/assets/muxerdumps/mdhd_box.dump b/libraries/test_data/src/test/assets/muxerdumps/mdhd_box.dump index 12a2a4804f..c14ad8b130 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mdhd_box.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mdhd_box.dump @@ -1,2 +1,2 @@ mdhd (32 bytes): - Data = length 24, hash D0792E76 + Data = length 24, hash 71B9FC8B diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_0_orientation.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_0_orientation.mp4.dump index 0022672c9e..c253c89465 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_0_orientation.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_0_orientation.mp4.dump @@ -20,7 +20,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_180_orientation.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_180_orientation.mp4.dump index 16b9c1b912..e873336bb5 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_180_orientation.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_180_orientation.mp4.dump @@ -21,7 +21,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_270_orientation.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_270_orientation.mp4.dump index edd0ab5765..ec6cecc4f0 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_270_orientation.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_270_orientation.mp4.dump @@ -21,7 +21,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_90_orientation.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_90_orientation.mp4.dump index 2bf7d547e3..0b7b8ee4af 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_90_orientation.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_90_orientation.mp4.dump @@ -21,7 +21,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_different_tracks_offset.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_different_tracks_offset.mp4.dump index 0fc8fe0a83..e9c10110cc 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_different_tracks_offset.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_different_tracks_offset.mp4.dump @@ -21,7 +21,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 @@ -48,7 +48,7 @@ track 1: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_float_metadata.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_float_metadata.mp4.dump index f22ab25741..97fb3af1ae 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_float_metadata.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_float_metadata.mp4.dump @@ -20,7 +20,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[mdta: key=SomeStringKey, value=10.0, Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[mdta: key=SomeStringKey, value=10.0, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_frame_rate.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_frame_rate.mp4.dump index 2811d53d40..ff6af8caf2 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_frame_rate.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_frame_rate.mp4.dump @@ -20,7 +20,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[mdta: key=com.android.capture.fps, value=120.0, Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[mdta: key=com.android.capture.fps, value=120.0, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_location.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_location.mp4.dump index 762f6a9037..1464f93898 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_location.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_location.mp4.dump @@ -20,7 +20,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[xyz: latitude=33.0, longitude=-120.0, Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[xyz: latitude=33.0, longitude=-120.0, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_null_location.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_null_location.mp4.dump index 0022672c9e..c253c89465 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_null_location.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_null_location.mp4.dump @@ -20,7 +20,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_same_tracks_offset.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_same_tracks_offset.mp4.dump index 0fc8fe0a83..e9c10110cc 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_same_tracks_offset.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_same_tracks_offset.mp4.dump @@ -21,7 +21,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 @@ -48,7 +48,7 @@ track 1: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_string_metadata.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_string_metadata.mp4.dump index 37551fdca5..413c2b18f9 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_string_metadata.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_string_metadata.mp4.dump @@ -20,7 +20,7 @@ track 0: colorRange = 1 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[mdta: key=SomeStringKey, value=Some Random String, Mp4Timestamp: creation time=2082849800, modification time=2082849800, timescale=10000] + metadata = entries=[mdta: key=SomeStringKey, value=Some Random String, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000] initializationData: data = length 28, hash 410B510 data = length 9, hash FBADD682 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_xmp.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_xmp.mp4.dump index b82a76ff6c..749009974e 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_with_xmp.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_with_xmp.mp4.dump @@ -4,13 +4,13 @@ mdat (71 bytes): Data = length 55, hash 6B19F4A7 moov (658 bytes): mvhd (108 bytes): - Data = length 100, hash A5ADE288 + Data = length 100, hash 2613A5C trak (542 bytes): tkhd (92 bytes): - Data = length 84, hash 8893F5BB + Data = length 84, hash 3D79758F mdia (442 bytes): mdhd (32 bytes): - Data = length 24, hash 50217AD + Data = length 24, hash 41542D81 hdlr (44 bytes): Data = length 36, hash A0852FF2 minf (358 bytes): diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump index 40d8ae50c6..a08fe51c0f 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump @@ -4,13 +4,13 @@ mdat (126 bytes): Data = length 110, hash 48173D41 moov (674 bytes): mvhd (108 bytes): - Data = length 100, hash 3D6D026F + Data = length 100, hash 105FA889 trak (558 bytes): tkhd (92 bytes): - Data = length 84, hash 3EFBEC22 + Data = length 84, hash AC22063C mdia (458 bytes): mdhd (32 bytes): - Data = length 24, hash 42F40E1C + Data = length 24, hash 88615B36 hdlr (44 bytes): Data = length 36, hash A0852FF2 minf (374 bytes): diff --git a/libraries/test_data/src/test/assets/muxerdumps/mvhd_box.dump b/libraries/test_data/src/test/assets/muxerdumps/mvhd_box.dump index 42578f37bd..4f1ac04e00 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mvhd_box.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mvhd_box.dump @@ -1,2 +1,2 @@ mvhd (108 bytes): - Data = length 100, hash 22E47B06 + Data = length 100, hash 1EE0A99B diff --git a/libraries/test_data/src/test/assets/muxerdumps/partial_hdr10-720p.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/partial_hdr10-720p.mp4.dump index 6d5031acc9..6507a08ee5 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/partial_hdr10-720p.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/partial_hdr10-720p.mp4.dump @@ -23,7 +23,7 @@ track 0: colorTransfer = 6 lumaBitdepth = 10 chromaBitdepth = 10 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 99, hash 99842E5A sample 0: @@ -415,7 +415,7 @@ track 1: channelCount = 2 sampleRate = 48000 language = ``` - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 2, hash 560 sample 0: diff --git a/libraries/test_data/src/test/assets/muxerdumps/sample_av1.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/sample_av1.mp4.dump index 6d923bf2df..0c0b8c43ff 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/sample_av1.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/sample_av1.mp4.dump @@ -19,7 +19,7 @@ track 0: colorInfo: lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] sample 0: time = 0 flags = 1 @@ -153,7 +153,7 @@ track 1: channelCount = 1 sampleRate = 44100 language = und - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 5, hash 2B7623A sample 0: diff --git a/libraries/test_data/src/test/assets/muxerdumps/sample_no_bframes.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/sample_no_bframes.mp4.dump index 8a46920b0c..1a3b7e3047 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/sample_no_bframes.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/sample_no_bframes.mp4.dump @@ -17,7 +17,7 @@ track 0: channelCount = 1 sampleRate = 44100 language = und - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 2, hash 5F7 sample 0: @@ -217,7 +217,7 @@ track 1: colorTransfer = 3 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000] + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] initializationData: data = length 23, hash 33E412EE data = length 9, hash FBAFBC0C diff --git a/libraries/test_data/src/test/assets/muxerdumps/video_track_tkhd_box.dump b/libraries/test_data/src/test/assets/muxerdumps/video_track_tkhd_box.dump index acf4f75d5a..080742f716 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/video_track_tkhd_box.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/video_track_tkhd_box.dump @@ -1,2 +1,2 @@ tkhd (92 bytes): - Data = length 84, hash D09E9E0B + Data = length 84, hash 4AC96A0 diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_no_bframes.mp4/transmuxed_with_inappmuxer.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_no_bframes.mp4/transmuxed_with_inappmuxer.dump index afe5517c88..d9678a62bf 100644 --- a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_no_bframes.mp4/transmuxed_with_inappmuxer.dump +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_no_bframes.mp4/transmuxed_with_inappmuxer.dump @@ -23,7 +23,7 @@ track 0: colorTransfer = 3 lumaBitdepth = 8 chromaBitdepth = 8 - metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=2000000000, modification time=2000000000, timescale=10000] + metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=3000000000, modification time=4000000000, timescale=10000] initializationData: data = length 23, hash 33E412EE data = length 9, hash FBAFBC0C @@ -158,7 +158,7 @@ track 1: channelCount = 1 sampleRate = 44100 language = und - metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=2000000000, modification time=2000000000, timescale=10000] + metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=3000000000, modification time=4000000000, timescale=10000] initializationData: data = length 2, hash 5F7 sample 0: 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 c7b670d520..8759071fb2 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java @@ -28,7 +28,6 @@ import androidx.media3.common.util.Util; import androidx.media3.container.MdtaMetadataEntry; import androidx.media3.container.Mp4LocationData; import androidx.media3.container.Mp4TimestampData; -import androidx.media3.container.Mp4Util; import androidx.media3.container.XmpData; import androidx.media3.muxer.Mp4Muxer; import androidx.media3.muxer.Mp4Muxer.TrackToken; @@ -290,9 +289,7 @@ public final class InAppMuxer implements Muxer { } else if (entry instanceof XmpData) { mp4Muxer.addXmp(ByteBuffer.wrap(((XmpData) entry).data)); } else if (entry instanceof Mp4TimestampData) { - // TODO: b/285281716 - Use creation time specific API. - mp4Muxer.setModificationTime( - Mp4Util.mp4TimeToUnixTimeMs(((Mp4TimestampData) entry).creationTimestampSeconds)); + mp4Muxer.setTimestampData((Mp4TimestampData) entry); } else if (entry instanceof MdtaMetadataEntry) { MdtaMetadataEntry mdtaMetadataEntry = (MdtaMetadataEntry) entry; if (mdtaMetadataEntry.key.equals(MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS)) { 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 b957108ba0..3e33519024 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerWithInAppMuxerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerWithInAppMuxerEndToEndTest.java @@ -16,7 +16,6 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkState; -import static androidx.media3.container.Mp4TimestampData.TIMESCALE_UNSET; import static androidx.media3.test.utils.FileUtil.retrieveTrackFormat; import static com.google.common.truth.Truth.assertThat; @@ -70,9 +69,8 @@ public class TransformerWithInAppMuxerEndToEndTest { // Add timestamp to make output file deterministic. metadataEntries.add( new Mp4TimestampData( - /* creationTimestampSeconds= */ 2_000_000_000L, - /* modificationTimestampSeconds= */ 2_000_000_000L, - TIMESCALE_UNSET))) + /* creationTimestampSeconds= */ 3_000_000_000L, + /* modificationTimestampSeconds= */ 4_000_000_000L))) .build(); Transformer transformer = @@ -183,12 +181,10 @@ public class TransformerWithInAppMuxerEndToEndTest { @Test public void transmux_withTimestampData_writesSameTimestampData() throws Exception { - // TODO: b/285281716 - Use different value for modification timestamp. Mp4TimestampData expectedTimestampData = new Mp4TimestampData( - /* creationTimestampSeconds= */ 2_000_000_000L, - /* modificationTimestampSeconds= */ 2_000_000_000L, - TIMESCALE_UNSET); + /* creationTimestampSeconds= */ 3_000_000_000L, + /* modificationTimestampSeconds= */ 4_000_000_000L); Muxer.Factory inAppMuxerFactory = new InAppMuxer.Factory.Builder() .setMetadataProvider(metadataEntries -> metadataEntries.add(expectedTimestampData))