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
This commit is contained in:
parent
a31a384393
commit
8a758c2ed7
@ -18,7 +18,6 @@ package androidx.media3.container;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
|
||||||
import androidx.media3.common.Metadata;
|
import androidx.media3.common.Metadata;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
@ -29,6 +28,13 @@ public final class Mp4TimestampData implements Metadata.Entry {
|
|||||||
/** Represents an unset or unknown timescale. */
|
/** Represents an unset or unknown timescale. */
|
||||||
public static final int TIMESCALE_UNSET = -1;
|
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. */
|
/** The creation timestamp. */
|
||||||
public final long creationTimestampSeconds;
|
public final long creationTimestampSeconds;
|
||||||
|
|
||||||
@ -41,13 +47,16 @@ public final class Mp4TimestampData implements Metadata.Entry {
|
|||||||
/**
|
/**
|
||||||
* Creates an instance.
|
* Creates an instance.
|
||||||
*
|
*
|
||||||
|
* <p>The {@link #timescale} is set to {@link Mp4TimestampData#TIMESCALE_UNSET}.
|
||||||
|
*
|
||||||
* @param creationTimestampSeconds The creation time UTC in seconds since midnight, January 1,
|
* @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
|
* 1904.
|
||||||
* #timescale} is set to {@link Mp4TimestampData#TIMESCALE_UNSET}.
|
* @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.creationTimestampSeconds = creationTimestampSeconds;
|
||||||
this.modificationTimestampSeconds = C.TIME_UNSET;
|
this.modificationTimestampSeconds = modificationTimestampSeconds;
|
||||||
this.timescale = TIMESCALE_UNSET;
|
this.timescale = TIMESCALE_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +82,14 @@ public final class Mp4TimestampData implements Metadata.Entry {
|
|||||||
this.timescale = in.readLong();
|
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
|
@Override
|
||||||
public boolean equals(@Nullable Object obj) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,6 +23,7 @@ import android.media.MediaCodec;
|
|||||||
import android.media.MediaExtractor;
|
import android.media.MediaExtractor;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.util.MediaFormatUtil;
|
import androidx.media3.common.util.MediaFormatUtil;
|
||||||
|
import androidx.media3.container.Mp4TimestampData;
|
||||||
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
||||||
import androidx.media3.extractor.mp4.Mp4Extractor;
|
import androidx.media3.extractor.mp4.Mp4Extractor;
|
||||||
import androidx.media3.test.utils.DumpFileAsserts;
|
import androidx.media3.test.utils.DumpFileAsserts;
|
||||||
@ -85,7 +86,10 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
mp4Muxer = new Mp4Muxer.Builder(checkNotNull(outputStream)).build();
|
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));
|
feedInputDataToMuxer(mp4Muxer, checkNotNull(inputFile));
|
||||||
} finally {
|
} finally {
|
||||||
if (mp4Muxer != null) {
|
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.
|
// ensure some data has been written after taking all the inputs but before closing the muxer.
|
||||||
assumeTrue(checkNotNull(inputFile).equals(H265_HDR10_MP4));
|
assumeTrue(checkNotNull(inputFile).equals(H265_HDR10_MP4));
|
||||||
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(checkNotNull(outputStream)).build();
|
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);
|
feedInputDataToMuxer(mp4Muxer, inputFile);
|
||||||
|
|
||||||
// Muxer not closed.
|
// Muxer not closed.
|
||||||
@ -132,7 +139,10 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
try {
|
try {
|
||||||
mp4Muxer =
|
mp4Muxer =
|
||||||
new Mp4Muxer.Builder(checkNotNull(outputStream)).setFragmentedMp4Enabled(true).build();
|
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);
|
feedInputDataToMuxer(mp4Muxer, inputFile);
|
||||||
} finally {
|
} finally {
|
||||||
if (mp4Muxer != null) {
|
if (mp4Muxer != null) {
|
||||||
@ -160,7 +170,10 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
try {
|
try {
|
||||||
mp4Muxer =
|
mp4Muxer =
|
||||||
new Mp4Muxer.Builder(checkNotNull(outputStream)).setFragmentedMp4Enabled(true).build();
|
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);
|
feedInputDataToMuxer(mp4Muxer, inputFile);
|
||||||
} finally {
|
} finally {
|
||||||
if (mp4Muxer != null) {
|
if (mp4Muxer != null) {
|
||||||
|
@ -93,14 +93,15 @@ import java.util.Locale;
|
|||||||
public static ByteBuffer tkhd(
|
public static ByteBuffer tkhd(
|
||||||
int trackId,
|
int trackId,
|
||||||
int trackDurationVu,
|
int trackDurationVu,
|
||||||
|
int creationTimestampSeconds,
|
||||||
int modificationTimestampSeconds,
|
int modificationTimestampSeconds,
|
||||||
int orientation,
|
int orientation,
|
||||||
Format format) {
|
Format format) {
|
||||||
ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE);
|
ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE);
|
||||||
contents.putInt(0x00000007); // version and flags; allow presentation, etc.
|
contents.putInt(0x00000007); // version and flags; allow presentation, etc.
|
||||||
|
|
||||||
contents.putInt(modificationTimestampSeconds); // creation_time
|
contents.putInt(creationTimestampSeconds); // creation_time; unsigned int(32)
|
||||||
contents.putInt(modificationTimestampSeconds); // modification_time
|
contents.putInt(modificationTimestampSeconds); // modification_time; unsigned int(32)
|
||||||
|
|
||||||
contents.putInt(trackId);
|
contents.putInt(trackId);
|
||||||
contents.putInt(0); // reserved
|
contents.putInt(0); // reserved
|
||||||
@ -132,12 +133,15 @@ import java.util.Locale;
|
|||||||
* <p>This is the movie header for the entire MP4 file.
|
* <p>This is the movie header for the entire MP4 file.
|
||||||
*/
|
*/
|
||||||
public static ByteBuffer mvhd(
|
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);
|
ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE);
|
||||||
contents.putInt(0); // version and flags
|
contents.putInt(0); // version and flags
|
||||||
|
|
||||||
contents.putInt(modificationTimestampSeconds); // creation_time
|
contents.putInt(creationTimestampSeconds); // creation_time; unsigned int(32)
|
||||||
contents.putInt(modificationTimestampSeconds); // modification_time
|
contents.putInt(modificationTimestampSeconds); // modification_time; unsigned int(32)
|
||||||
contents.putInt((int) MVHD_TIMEBASE); // The per-track timescales might be different.
|
contents.putInt((int) MVHD_TIMEBASE); // The per-track timescales might be different.
|
||||||
contents.putInt(
|
contents.putInt(
|
||||||
(int) Mp4Utils.vuFromUs(videoDurationUs, MVHD_TIMEBASE)); // Duration of the entire video.
|
(int) Mp4Utils.vuFromUs(videoDurationUs, MVHD_TIMEBASE)); // Duration of the entire video.
|
||||||
@ -175,13 +179,14 @@ import java.util.Locale;
|
|||||||
public static ByteBuffer mdhd(
|
public static ByteBuffer mdhd(
|
||||||
long trackDurationVu,
|
long trackDurationVu,
|
||||||
int videoUnitTimebase,
|
int videoUnitTimebase,
|
||||||
|
int creationTimestampSeconds,
|
||||||
int modificationTimestampSeconds,
|
int modificationTimestampSeconds,
|
||||||
@Nullable String languageCode) {
|
@Nullable String languageCode) {
|
||||||
ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE);
|
ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE);
|
||||||
contents.putInt(0x0); // version and flags
|
contents.putInt(0x0); // version and flags
|
||||||
|
|
||||||
contents.putInt(modificationTimestampSeconds); // creation_time
|
contents.putInt(creationTimestampSeconds); // creation_time; unsigned int(32)
|
||||||
contents.putInt(modificationTimestampSeconds); // modification_time
|
contents.putInt(modificationTimestampSeconds); // modification_time; unsigned int(32)
|
||||||
|
|
||||||
contents.putInt(videoUnitTimebase);
|
contents.putInt(videoUnitTimebase);
|
||||||
|
|
||||||
|
@ -15,11 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.muxer;
|
package androidx.media3.muxer;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
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.nio.ByteBuffer;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -30,14 +29,17 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
public int orientation;
|
public int orientation;
|
||||||
public @MonotonicNonNull Mp4Location location;
|
public @MonotonicNonNull Mp4Location location;
|
||||||
public Map<String, Object> metadataPairs;
|
public Map<String, Object> metadataPairs;
|
||||||
public int modificationTimestampSeconds;
|
public Mp4TimestampData timestampData;
|
||||||
public @MonotonicNonNull ByteBuffer xmpData;
|
public @MonotonicNonNull ByteBuffer xmpData;
|
||||||
|
|
||||||
public MetadataCollector() {
|
public MetadataCollector() {
|
||||||
orientation = 0;
|
orientation = 0;
|
||||||
metadataPairs = new LinkedHashMap<>();
|
metadataPairs = new LinkedHashMap<>();
|
||||||
modificationTimestampSeconds =
|
long currentTimeInMp4TimeSeconds = unixTimeToMp4TimeSeconds(System.currentTimeMillis());
|
||||||
(int) Mp4Util.unixTimeToMp4TimeSeconds(System.currentTimeMillis());
|
timestampData =
|
||||||
|
new Mp4TimestampData(
|
||||||
|
/* creationTimestampSeconds= */ currentTimeInMp4TimeSeconds,
|
||||||
|
/* modificationTimestampSeconds= */ currentTimeInMp4TimeSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addXmp(ByteBuffer xmpData) {
|
public void addXmp(ByteBuffer xmpData) {
|
||||||
@ -61,10 +63,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
metadataPairs.put(key, value);
|
metadataPairs.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setModificationTime(long unixTimestampMs) {
|
public void setTimestampData(Mp4TimestampData timestampData) {
|
||||||
long timestampSeconds = Mp4Util.unixTimeToMp4TimeSeconds(unixTimestampMs);
|
this.timestampData = timestampData;
|
||||||
checkArgument(
|
|
||||||
timestampSeconds <= UNSIGNED_INT_MAX_VALUE, "Only 32-bit long timestamp supported");
|
|
||||||
this.modificationTimestampSeconds = (int) timestampSeconds;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,12 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
|
|||||||
@SuppressWarnings("InlinedApi")
|
@SuppressWarnings("InlinedApi")
|
||||||
public ByteBuffer moovMetadataHeader(
|
public ByteBuffer moovMetadataHeader(
|
||||||
List<? extends TrackMetadataProvider> tracks, long minInputPtsUs, boolean isFragmentedMp4) {
|
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.
|
||||||
|
int creationTimestampSeconds = (int) metadataCollector.timestampData.creationTimestampSeconds;
|
||||||
|
int modificationTimestampSeconds =
|
||||||
|
(int) metadataCollector.timestampData.modificationTimestampSeconds;
|
||||||
List<ByteBuffer> trakBoxes = new ArrayList<>();
|
List<ByteBuffer> trakBoxes = new ArrayList<>();
|
||||||
List<ByteBuffer> trexBoxes = new ArrayList<>();
|
List<ByteBuffer> 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,
|
// Using the time base of the entire file, not that of the track; otherwise,
|
||||||
// Quicktime will stretch the audio accordingly, see b/158120042.
|
// Quicktime will stretch the audio accordingly, see b/158120042.
|
||||||
(int) Mp4Utils.vuFromUs(trackDurationUs, MVHD_TIMEBASE),
|
(int) Mp4Utils.vuFromUs(trackDurationUs, MVHD_TIMEBASE),
|
||||||
metadataCollector.modificationTimestampSeconds,
|
creationTimestampSeconds,
|
||||||
|
modificationTimestampSeconds,
|
||||||
metadataCollector.orientation,
|
metadataCollector.orientation,
|
||||||
format),
|
format),
|
||||||
Boxes.mdia(
|
Boxes.mdia(
|
||||||
Boxes.mdhd(
|
Boxes.mdhd(
|
||||||
trackDurationInTrackUnitsVu,
|
trackDurationInTrackUnitsVu,
|
||||||
track.videoUnitTimebase(),
|
track.videoUnitTimebase(),
|
||||||
metadataCollector.modificationTimestampSeconds,
|
creationTimestampSeconds,
|
||||||
|
modificationTimestampSeconds,
|
||||||
languageCode),
|
languageCode),
|
||||||
Boxes.hdlr(handlerType, handlerName),
|
Boxes.hdlr(handlerType, handlerName),
|
||||||
Boxes.minf(mhdBox, Boxes.dinf(Boxes.dref(Boxes.localUrl())), stblBox)));
|
Boxes.minf(mhdBox, Boxes.dinf(Boxes.dref(Boxes.localUrl())), stblBox)));
|
||||||
@ -168,7 +176,8 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer mvhdBox =
|
ByteBuffer mvhdBox =
|
||||||
Boxes.mvhd(nextTrackId, metadataCollector.modificationTimestampSeconds, videoDurationUs);
|
Boxes.mvhd(
|
||||||
|
nextTrackId, creationTimestampSeconds, modificationTimestampSeconds, videoDurationUs);
|
||||||
ByteBuffer udtaBox = Boxes.udta(metadataCollector.location);
|
ByteBuffer udtaBox = Boxes.udta(metadataCollector.location);
|
||||||
ByteBuffer metaBox =
|
ByteBuffer metaBox =
|
||||||
metadataCollector.metadataPairs.isEmpty()
|
metadataCollector.metadataPairs.isEmpty()
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.muxer;
|
package androidx.media3.muxer;
|
||||||
|
|
||||||
|
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
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 static java.lang.annotation.ElementType.TYPE_USE;
|
||||||
|
|
||||||
import android.media.MediaCodec.BufferInfo;
|
import android.media.MediaCodec.BufferInfo;
|
||||||
@ -25,6 +27,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import androidx.media3.container.Mp4TimestampData;
|
||||||
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.FileOutputStream;
|
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.
|
* <p>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) {
|
public void setTimestampData(Mp4TimestampData timestampData) {
|
||||||
metadataCollector.setModificationTime(timestampMs);
|
checkArgument(
|
||||||
|
timestampData.creationTimestampSeconds <= UNSIGNED_INT_MAX_VALUE
|
||||||
|
&& timestampData.modificationTimestampSeconds <= UNSIGNED_INT_MAX_VALUE,
|
||||||
|
"Only 32-bit long timestamp is supported");
|
||||||
|
metadataCollector.setTimestampData(timestampData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,7 +66,8 @@ public class BoxesTest {
|
|||||||
Boxes.tkhd(
|
Boxes.tkhd(
|
||||||
/* trackId= */ 1,
|
/* trackId= */ 1,
|
||||||
/* trackDurationVu= */ 5_000_000,
|
/* trackDurationVu= */ 5_000_000,
|
||||||
/* modificationTimestampSeconds= */ 1_000_000_000,
|
/* creationTimestampSeconds= */ 1_000_000_000,
|
||||||
|
/* modificationTimestampSeconds= */ 2_000_000_000,
|
||||||
/* orientation= */ 90,
|
/* orientation= */ 90,
|
||||||
FAKE_VIDEO_FORMAT);
|
FAKE_VIDEO_FORMAT);
|
||||||
|
|
||||||
@ -81,7 +82,8 @@ public class BoxesTest {
|
|||||||
Boxes.tkhd(
|
Boxes.tkhd(
|
||||||
/* trackId= */ 1,
|
/* trackId= */ 1,
|
||||||
/* trackDurationVu= */ 5_000_000,
|
/* trackDurationVu= */ 5_000_000,
|
||||||
/* modificationTimestampSeconds= */ 1_000_000_000,
|
/* creationTimestampSeconds= */ 1_000_000_000,
|
||||||
|
/* modificationTimestampSeconds= */ 2_000_000_000,
|
||||||
/* orientation= */ 90,
|
/* orientation= */ 90,
|
||||||
FAKE_AUDIO_FORMAT);
|
FAKE_AUDIO_FORMAT);
|
||||||
|
|
||||||
@ -95,7 +97,8 @@ public class BoxesTest {
|
|||||||
ByteBuffer mvhdBox =
|
ByteBuffer mvhdBox =
|
||||||
Boxes.mvhd(
|
Boxes.mvhd(
|
||||||
/* nextEmptyTrackId= */ 3,
|
/* nextEmptyTrackId= */ 3,
|
||||||
/* modificationTimestampSeconds= */ 1_000_000_000,
|
/* creationTimestampSeconds= */ 1_000_000_000,
|
||||||
|
/* modificationTimestampSeconds= */ 2_000_000_000,
|
||||||
/* videoDurationUs= */ 5_000_000);
|
/* videoDurationUs= */ 5_000_000);
|
||||||
|
|
||||||
DumpableMp4Box dumpableBox = new DumpableMp4Box(mvhdBox);
|
DumpableMp4Box dumpableBox = new DumpableMp4Box(mvhdBox);
|
||||||
@ -108,7 +111,8 @@ public class BoxesTest {
|
|||||||
Boxes.mdhd(
|
Boxes.mdhd(
|
||||||
/* trackDurationVu= */ 5_000_000,
|
/* trackDurationVu= */ 5_000_000,
|
||||||
VU_TIMEBASE,
|
VU_TIMEBASE,
|
||||||
/* modificationTimestampSeconds= */ 1_000_000_000,
|
/* creationTimestampSeconds= */ 1_000_000_000,
|
||||||
|
/* modificationTimestampSeconds= */ 2_000_000_000,
|
||||||
/* languageCode= */ "und");
|
/* languageCode= */ "und");
|
||||||
|
|
||||||
DumpableMp4Box dumpableBox = new DumpableMp4Box(mdhdBox);
|
DumpableMp4Box dumpableBox = new DumpableMp4Box(mdhdBox);
|
||||||
|
@ -21,6 +21,7 @@ import static org.junit.Assert.assertThrows;
|
|||||||
|
|
||||||
import android.media.MediaCodec.BufferInfo;
|
import android.media.MediaCodec.BufferInfo;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import androidx.media3.container.Mp4TimestampData;
|
||||||
import androidx.media3.extractor.mp4.Mp4Extractor;
|
import androidx.media3.extractor.mp4.Mp4Extractor;
|
||||||
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
||||||
import androidx.media3.test.utils.DumpFileAsserts;
|
import androidx.media3.test.utils.DumpFileAsserts;
|
||||||
@ -63,7 +64,10 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
public void createMp4File_withSameTracksOffset_matchesExpected() throws IOException {
|
public void createMp4File_withSameTracksOffset_matchesExpected() throws IOException {
|
||||||
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.setModificationTime(/* timestampMs= */ 500_000_000L);
|
mp4Muxer.setTimestampData(
|
||||||
|
new Mp4TimestampData(
|
||||||
|
/* creationTimestampSeconds= */ 100_000_000L,
|
||||||
|
/* modificationTimestampSeconds= */ 500_000_000L));
|
||||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||||
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
||||||
@ -103,7 +107,10 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
public void createMp4File_withDifferentTracksOffset_matchesExpected() throws IOException {
|
public void createMp4File_withDifferentTracksOffset_matchesExpected() throws IOException {
|
||||||
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.setModificationTime(/* timestampMs= */ 500_000_000L);
|
mp4Muxer.setTimestampData(
|
||||||
|
new Mp4TimestampData(
|
||||||
|
/* creationTimestampSeconds= */ 100_000_000L,
|
||||||
|
/* modificationTimestampSeconds= */ 500_000_000L));
|
||||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||||
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
||||||
@ -162,7 +169,10 @@ public class Mp4MuxerEndToEndTest {
|
|||||||
public void createMp4File_withOneTrackEmpty_doesNotWriteEmptyTrack() throws Exception {
|
public void createMp4File_withOneTrackEmpty_doesNotWriteEmptyTrack() 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.setModificationTime(/* timestampMs= */ 500_000_000L);
|
mp4Muxer.setTimestampData(
|
||||||
|
new Mp4TimestampData(
|
||||||
|
/* creationTimestampSeconds= */ 100_000_000L,
|
||||||
|
/* modificationTimestampSeconds= */ 500_000_000L));
|
||||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||||
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
||||||
|
@ -20,6 +20,7 @@ import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.MediaCodec.BufferInfo;
|
import android.media.MediaCodec.BufferInfo;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import androidx.media3.container.Mp4TimestampData;
|
||||||
import androidx.media3.extractor.mp4.Mp4Extractor;
|
import androidx.media3.extractor.mp4.Mp4Extractor;
|
||||||
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
||||||
import androidx.media3.test.utils.DumpFileAsserts;
|
import androidx.media3.test.utils.DumpFileAsserts;
|
||||||
@ -53,7 +54,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
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);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
} finally {
|
} finally {
|
||||||
@ -75,7 +79,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
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);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
|
|
||||||
@ -99,7 +106,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
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);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
|
|
||||||
@ -123,7 +133,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
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);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
|
|
||||||
@ -147,7 +160,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
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);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
muxer.setLocation(33.0f, -120f);
|
muxer.setLocation(33.0f, -120f);
|
||||||
@ -170,7 +186,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
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);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
} finally {
|
} finally {
|
||||||
@ -192,7 +211,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
muxer.setModificationTime(/* timestampMs= */ 5_000_000L);
|
muxer.setTimestampData(
|
||||||
|
new Mp4TimestampData(
|
||||||
|
/* creationTimestampSeconds= */ 1_000_000L,
|
||||||
|
/* modificationTimestampSeconds= */ 5_000_000L));
|
||||||
muxer.setCaptureFps(120.0f);
|
muxer.setCaptureFps(120.0f);
|
||||||
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
@ -215,7 +237,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
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");
|
muxer.addMetadata("SomeStringKey", "Some Random String");
|
||||||
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
@ -238,7 +263,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
muxer.setModificationTime(/* timestampMs= */ 5_000_000L);
|
muxer.setTimestampData(
|
||||||
|
new Mp4TimestampData(
|
||||||
|
/* creationTimestampSeconds= */ 1_000_000L,
|
||||||
|
/* modificationTimestampSeconds= */ 5_000_000L));
|
||||||
muxer.addMetadata("SomeStringKey", 10.0f);
|
muxer.addMetadata("SomeStringKey", 10.0f);
|
||||||
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||||
@ -261,7 +289,10 @@ public class Mp4MuxerMetadataTest {
|
|||||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
muxer.setModificationTime(/* timestampMs= */ 5_000_000L);
|
muxer.setTimestampData(
|
||||||
|
new Mp4TimestampData(
|
||||||
|
/* creationTimestampSeconds= */ 1_000_000L,
|
||||||
|
/* modificationTimestampSeconds= */ 5_000_000L));
|
||||||
Context context = ApplicationProvider.getApplicationContext();
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
byte[] xmpBytes = TestUtil.getByteArray(context, XMP_SAMPLE_DATA);
|
byte[] xmpBytes = TestUtil.getByteArray(context, XMP_SAMPLE_DATA);
|
||||||
ByteBuffer xmp = ByteBuffer.wrap(xmpBytes);
|
ByteBuffer xmp = ByteBuffer.wrap(xmpBytes);
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
tkhd (92 bytes):
|
tkhd (92 bytes):
|
||||||
Data = length 84, hash 8F9E5354
|
Data = length 84, hash C3AC4BE9
|
||||||
|
@ -13,7 +13,7 @@ track 0:
|
|||||||
id = 1
|
id = 1
|
||||||
sampleMimeType = application/meta
|
sampleMimeType = application/meta
|
||||||
maxInputSize = 161
|
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:
|
sample 0:
|
||||||
time = 0
|
time = 0
|
||||||
flags = 1
|
flags = 1
|
||||||
@ -39,7 +39,7 @@ track 1:
|
|||||||
channelCount = 2
|
channelCount = 2
|
||||||
sampleRate = 48000
|
sampleRate = 48000
|
||||||
language = ```
|
language = ```
|
||||||
metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000]
|
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 2, hash 560
|
data = length 2, hash 560
|
||||||
sample 0:
|
sample 0:
|
||||||
@ -71,7 +71,7 @@ track 2:
|
|||||||
colorTransfer = 3
|
colorTransfer = 3
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 85, hash 6F3CAA16
|
data = length 85, hash 6F3CAA16
|
||||||
sample 0:
|
sample 0:
|
||||||
|
@ -23,7 +23,7 @@ track 0:
|
|||||||
colorTransfer = 6
|
colorTransfer = 6
|
||||||
lumaBitdepth = 10
|
lumaBitdepth = 10
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 99, hash 99842E5A
|
data = length 99, hash 99842E5A
|
||||||
sample 0:
|
sample 0:
|
||||||
@ -547,7 +547,7 @@ track 1:
|
|||||||
channelCount = 2
|
channelCount = 2
|
||||||
sampleRate = 48000
|
sampleRate = 48000
|
||||||
language = ```
|
language = ```
|
||||||
metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000]
|
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 2, hash 560
|
data = length 2, hash 560
|
||||||
sample 0:
|
sample 0:
|
||||||
|
@ -2,13 +2,13 @@ ftyp (28 bytes):
|
|||||||
Data = length 20, hash EF896440
|
Data = length 20, hash EF896440
|
||||||
moov (1209 bytes):
|
moov (1209 bytes):
|
||||||
mvhd (108 bytes):
|
mvhd (108 bytes):
|
||||||
Data = length 100, hash 5CF3AC6F
|
Data = length 100, hash 2FE65289
|
||||||
trak (610 bytes):
|
trak (610 bytes):
|
||||||
tkhd (92 bytes):
|
tkhd (92 bytes):
|
||||||
Data = length 84, hash 112173F4
|
Data = length 84, hash 7E478E0E
|
||||||
mdia (510 bytes):
|
mdia (510 bytes):
|
||||||
mdhd (32 bytes):
|
mdhd (32 bytes):
|
||||||
Data = length 24, hash 42753A93
|
Data = length 24, hash 87E287AD
|
||||||
hdlr (44 bytes):
|
hdlr (44 bytes):
|
||||||
Data = length 36, hash A0852FF2
|
Data = length 36, hash A0852FF2
|
||||||
minf (426 bytes):
|
minf (426 bytes):
|
||||||
@ -31,10 +31,10 @@ moov (1209 bytes):
|
|||||||
Data = length 8, hash 94446F01
|
Data = length 8, hash 94446F01
|
||||||
trak (411 bytes):
|
trak (411 bytes):
|
||||||
tkhd (92 bytes):
|
tkhd (92 bytes):
|
||||||
Data = length 84, hash 34D7906B
|
Data = length 84, hash A1FDAA85
|
||||||
mdia (311 bytes):
|
mdia (311 bytes):
|
||||||
mdhd (32 bytes):
|
mdhd (32 bytes):
|
||||||
Data = length 24, hash EA3D1FE6
|
Data = length 24, hash 2FAA6D00
|
||||||
hdlr (44 bytes):
|
hdlr (44 bytes):
|
||||||
Data = length 36, hash 49FC755F
|
Data = length 36, hash 49FC755F
|
||||||
minf (227 bytes):
|
minf (227 bytes):
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
mdhd (32 bytes):
|
mdhd (32 bytes):
|
||||||
Data = length 24, hash D0792E76
|
Data = length 24, hash 71B9FC8B
|
||||||
|
@ -20,7 +20,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -21,7 +21,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -21,7 +21,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -21,7 +21,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -21,7 +21,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
@ -48,7 +48,7 @@ track 1:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -20,7 +20,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -20,7 +20,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -20,7 +20,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -20,7 +20,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -21,7 +21,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
@ -48,7 +48,7 @@ track 1:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -20,7 +20,7 @@ track 0:
|
|||||||
colorRange = 1
|
colorRange = 1
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 28, hash 410B510
|
data = length 28, hash 410B510
|
||||||
data = length 9, hash FBADD682
|
data = length 9, hash FBADD682
|
||||||
|
@ -4,13 +4,13 @@ mdat (71 bytes):
|
|||||||
Data = length 55, hash 6B19F4A7
|
Data = length 55, hash 6B19F4A7
|
||||||
moov (658 bytes):
|
moov (658 bytes):
|
||||||
mvhd (108 bytes):
|
mvhd (108 bytes):
|
||||||
Data = length 100, hash A5ADE288
|
Data = length 100, hash 2613A5C
|
||||||
trak (542 bytes):
|
trak (542 bytes):
|
||||||
tkhd (92 bytes):
|
tkhd (92 bytes):
|
||||||
Data = length 84, hash 8893F5BB
|
Data = length 84, hash 3D79758F
|
||||||
mdia (442 bytes):
|
mdia (442 bytes):
|
||||||
mdhd (32 bytes):
|
mdhd (32 bytes):
|
||||||
Data = length 24, hash 50217AD
|
Data = length 24, hash 41542D81
|
||||||
hdlr (44 bytes):
|
hdlr (44 bytes):
|
||||||
Data = length 36, hash A0852FF2
|
Data = length 36, hash A0852FF2
|
||||||
minf (358 bytes):
|
minf (358 bytes):
|
||||||
|
@ -4,13 +4,13 @@ mdat (126 bytes):
|
|||||||
Data = length 110, hash 48173D41
|
Data = length 110, hash 48173D41
|
||||||
moov (674 bytes):
|
moov (674 bytes):
|
||||||
mvhd (108 bytes):
|
mvhd (108 bytes):
|
||||||
Data = length 100, hash 3D6D026F
|
Data = length 100, hash 105FA889
|
||||||
trak (558 bytes):
|
trak (558 bytes):
|
||||||
tkhd (92 bytes):
|
tkhd (92 bytes):
|
||||||
Data = length 84, hash 3EFBEC22
|
Data = length 84, hash AC22063C
|
||||||
mdia (458 bytes):
|
mdia (458 bytes):
|
||||||
mdhd (32 bytes):
|
mdhd (32 bytes):
|
||||||
Data = length 24, hash 42F40E1C
|
Data = length 24, hash 88615B36
|
||||||
hdlr (44 bytes):
|
hdlr (44 bytes):
|
||||||
Data = length 36, hash A0852FF2
|
Data = length 36, hash A0852FF2
|
||||||
minf (374 bytes):
|
minf (374 bytes):
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
mvhd (108 bytes):
|
mvhd (108 bytes):
|
||||||
Data = length 100, hash 22E47B06
|
Data = length 100, hash 1EE0A99B
|
||||||
|
@ -23,7 +23,7 @@ track 0:
|
|||||||
colorTransfer = 6
|
colorTransfer = 6
|
||||||
lumaBitdepth = 10
|
lumaBitdepth = 10
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 99, hash 99842E5A
|
data = length 99, hash 99842E5A
|
||||||
sample 0:
|
sample 0:
|
||||||
@ -415,7 +415,7 @@ track 1:
|
|||||||
channelCount = 2
|
channelCount = 2
|
||||||
sampleRate = 48000
|
sampleRate = 48000
|
||||||
language = ```
|
language = ```
|
||||||
metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000]
|
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
|
||||||
initializationData:
|
initializationData:
|
||||||
data = length 2, hash 560
|
data = length 2, hash 560
|
||||||
sample 0:
|
sample 0:
|
||||||
|
@ -19,7 +19,7 @@ track 0:
|
|||||||
colorInfo:
|
colorInfo:
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
sample 0:
|
||||||
time = 0
|
time = 0
|
||||||
flags = 1
|
flags = 1
|
||||||
@ -153,7 +153,7 @@ track 1:
|
|||||||
channelCount = 1
|
channelCount = 1
|
||||||
sampleRate = 44100
|
sampleRate = 44100
|
||||||
language = und
|
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:
|
initializationData:
|
||||||
data = length 5, hash 2B7623A
|
data = length 5, hash 2B7623A
|
||||||
sample 0:
|
sample 0:
|
||||||
|
@ -17,7 +17,7 @@ track 0:
|
|||||||
channelCount = 1
|
channelCount = 1
|
||||||
sampleRate = 44100
|
sampleRate = 44100
|
||||||
language = und
|
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:
|
initializationData:
|
||||||
data = length 2, hash 5F7
|
data = length 2, hash 5F7
|
||||||
sample 0:
|
sample 0:
|
||||||
@ -217,7 +217,7 @@ track 1:
|
|||||||
colorTransfer = 3
|
colorTransfer = 3
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 23, hash 33E412EE
|
data = length 23, hash 33E412EE
|
||||||
data = length 9, hash FBAFBC0C
|
data = length 9, hash FBAFBC0C
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
tkhd (92 bytes):
|
tkhd (92 bytes):
|
||||||
Data = length 84, hash D09E9E0B
|
Data = length 84, hash 4AC96A0
|
||||||
|
@ -23,7 +23,7 @@ track 0:
|
|||||||
colorTransfer = 3
|
colorTransfer = 3
|
||||||
lumaBitdepth = 8
|
lumaBitdepth = 8
|
||||||
chromaBitdepth = 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:
|
initializationData:
|
||||||
data = length 23, hash 33E412EE
|
data = length 23, hash 33E412EE
|
||||||
data = length 9, hash FBAFBC0C
|
data = length 9, hash FBAFBC0C
|
||||||
@ -158,7 +158,7 @@ track 1:
|
|||||||
channelCount = 1
|
channelCount = 1
|
||||||
sampleRate = 44100
|
sampleRate = 44100
|
||||||
language = und
|
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:
|
initializationData:
|
||||||
data = length 2, hash 5F7
|
data = length 2, hash 5F7
|
||||||
sample 0:
|
sample 0:
|
||||||
|
@ -28,7 +28,6 @@ import androidx.media3.common.util.Util;
|
|||||||
import androidx.media3.container.MdtaMetadataEntry;
|
import androidx.media3.container.MdtaMetadataEntry;
|
||||||
import androidx.media3.container.Mp4LocationData;
|
import androidx.media3.container.Mp4LocationData;
|
||||||
import androidx.media3.container.Mp4TimestampData;
|
import androidx.media3.container.Mp4TimestampData;
|
||||||
import androidx.media3.container.Mp4Util;
|
|
||||||
import androidx.media3.container.XmpData;
|
import androidx.media3.container.XmpData;
|
||||||
import androidx.media3.muxer.Mp4Muxer;
|
import androidx.media3.muxer.Mp4Muxer;
|
||||||
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
||||||
@ -290,9 +289,7 @@ public final class InAppMuxer implements Muxer {
|
|||||||
} else if (entry instanceof XmpData) {
|
} else if (entry instanceof XmpData) {
|
||||||
mp4Muxer.addXmp(ByteBuffer.wrap(((XmpData) entry).data));
|
mp4Muxer.addXmp(ByteBuffer.wrap(((XmpData) entry).data));
|
||||||
} else if (entry instanceof Mp4TimestampData) {
|
} else if (entry instanceof Mp4TimestampData) {
|
||||||
// TODO: b/285281716 - Use creation time specific API.
|
mp4Muxer.setTimestampData((Mp4TimestampData) entry);
|
||||||
mp4Muxer.setModificationTime(
|
|
||||||
Mp4Util.mp4TimeToUnixTimeMs(((Mp4TimestampData) entry).creationTimestampSeconds));
|
|
||||||
} else if (entry instanceof MdtaMetadataEntry) {
|
} else if (entry instanceof MdtaMetadataEntry) {
|
||||||
MdtaMetadataEntry mdtaMetadataEntry = (MdtaMetadataEntry) entry;
|
MdtaMetadataEntry mdtaMetadataEntry = (MdtaMetadataEntry) entry;
|
||||||
if (mdtaMetadataEntry.key.equals(MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS)) {
|
if (mdtaMetadataEntry.key.equals(MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS)) {
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
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 androidx.media3.test.utils.FileUtil.retrieveTrackFormat;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@ -70,9 +69,8 @@ public class TransformerWithInAppMuxerEndToEndTest {
|
|||||||
// Add timestamp to make output file deterministic.
|
// Add timestamp to make output file deterministic.
|
||||||
metadataEntries.add(
|
metadataEntries.add(
|
||||||
new Mp4TimestampData(
|
new Mp4TimestampData(
|
||||||
/* creationTimestampSeconds= */ 2_000_000_000L,
|
/* creationTimestampSeconds= */ 3_000_000_000L,
|
||||||
/* modificationTimestampSeconds= */ 2_000_000_000L,
|
/* modificationTimestampSeconds= */ 4_000_000_000L)))
|
||||||
TIMESCALE_UNSET)))
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
@ -183,12 +181,10 @@ public class TransformerWithInAppMuxerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transmux_withTimestampData_writesSameTimestampData() throws Exception {
|
public void transmux_withTimestampData_writesSameTimestampData() throws Exception {
|
||||||
// TODO: b/285281716 - Use different value for modification timestamp.
|
|
||||||
Mp4TimestampData expectedTimestampData =
|
Mp4TimestampData expectedTimestampData =
|
||||||
new Mp4TimestampData(
|
new Mp4TimestampData(
|
||||||
/* creationTimestampSeconds= */ 2_000_000_000L,
|
/* creationTimestampSeconds= */ 3_000_000_000L,
|
||||||
/* modificationTimestampSeconds= */ 2_000_000_000L,
|
/* modificationTimestampSeconds= */ 4_000_000_000L);
|
||||||
TIMESCALE_UNSET);
|
|
||||||
Muxer.Factory inAppMuxerFactory =
|
Muxer.Factory inAppMuxerFactory =
|
||||||
new InAppMuxer.Factory.Builder()
|
new InAppMuxer.Factory.Builder()
|
||||||
.setMetadataProvider(metadataEntries -> metadataEntries.add(expectedTimestampData))
|
.setMetadataProvider(metadataEntries -> metadataEntries.add(expectedTimestampData))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user