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 90edc5622f..f741a51c56 100644
--- a/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java
+++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java
@@ -32,6 +32,7 @@ import androidx.media3.common.ColorInfo;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util;
+import androidx.media3.container.MdtaMetadataEntry;
import androidx.media3.container.Mp4LocationData;
import androidx.media3.container.NalUnitUtil;
import androidx.media3.muxer.FragmentedMp4Writer.SampleMetadata;
@@ -395,14 +396,13 @@ import java.util.Locale;
*
*
This box contains a list of metadata keys.
*/
- public static ByteBuffer keys(List keyNames) {
- // This should be an adaptive size here; we don't yet care since it's usually small.
+ public static ByteBuffer keys(List mdtaMetadataEntries) {
ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE);
- contents.putInt(0x0); // version and flags.
- contents.putInt(keyNames.size()); // num of entries
+ contents.putInt(0x0); // version and flags
+ contents.putInt(mdtaMetadataEntries.size()); // Entry count
- for (int i = 0; i < keyNames.size(); i++) {
- ByteBuffer keyNameBuffer = ByteBuffer.wrap(Util.getUtf8Bytes(keyNames.get(i)));
+ for (int i = 0; i < mdtaMetadataEntries.size(); i++) {
+ ByteBuffer keyNameBuffer = ByteBuffer.wrap(Util.getUtf8Bytes(mdtaMetadataEntries.get(i).key));
contents.put(BoxUtils.wrapIntoBox("mdta", keyNameBuffer));
}
@@ -415,31 +415,18 @@ import java.util.Locale;
*
* This box contains a list of metadata values.
*/
- public static ByteBuffer ilst(List values) {
- // This should be an adaptive size here; we don't yet care since it's usually small.
+ public static ByteBuffer ilst(List mdtaMetadataEntries) {
ByteBuffer contents = ByteBuffer.allocate(Mp4Utils.MAX_FIXED_LEAF_BOX_SIZE);
- for (int i = 0; i < values.size(); i++) {
+ for (int i = 0; i < mdtaMetadataEntries.size(); i++) {
int keyId = i + 1;
- Object value = values.get(i);
+ MdtaMetadataEntry currentMdtaMetadataEntry = mdtaMetadataEntries.get(i);
- ByteBuffer valueContents;
- if (value instanceof String) {
- String valueString = (String) value;
- byte[] valueBytes = Util.getUtf8Bytes(valueString);
- valueContents = ByteBuffer.allocate(valueBytes.length + 8);
- valueContents.putInt(1); // type code for UTF-8 string
- valueContents.putInt(0); // default country / language
- valueContents.put(valueBytes);
-
- } else if (value instanceof Float) {
- valueContents = ByteBuffer.allocate(12);
- valueContents.putInt(23); // float32
- valueContents.putInt(0); // language / country
- valueContents.putFloat((float) value);
- } else {
- throw new IllegalArgumentException("Unknown metadata type: " + value.getClass());
- }
+ ByteBuffer valueContents =
+ ByteBuffer.allocate(2 * BYTES_PER_INTEGER + currentMdtaMetadataEntry.value.length);
+ valueContents.putInt(currentMdtaMetadataEntry.typeIndicator);
+ valueContents.putInt(currentMdtaMetadataEntry.localeIndicator);
+ valueContents.put(currentMdtaMetadataEntry.value);
valueContents.flip();
ByteBuffer valueBox = BoxUtils.wrapIntoBox("data", valueContents);
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 66021a31d8..b4ecad0631 100644
--- a/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java
+++ b/libraries/muxer/src/main/java/androidx/media3/muxer/MetadataCollector.java
@@ -15,27 +15,28 @@
*/
package androidx.media3.muxer;
-import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.container.Mp4TimestampData.unixTimeToMp4TimeSeconds;
+import androidx.media3.common.Metadata;
+import androidx.media3.container.MdtaMetadataEntry;
import androidx.media3.container.Mp4LocationData;
import androidx.media3.container.Mp4TimestampData;
-import java.nio.ByteBuffer;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import androidx.media3.container.XmpData;
+import java.util.ArrayList;
+import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Collects and provides metadata: location, FPS, XMP data, etc. */
/* package */ final class MetadataCollector {
public int orientation;
public @MonotonicNonNull Mp4LocationData locationData;
- public Map metadataPairs;
+ public List metadataEntries;
public Mp4TimestampData timestampData;
- public @MonotonicNonNull ByteBuffer xmpData;
+ public @MonotonicNonNull XmpData xmpData;
public MetadataCollector() {
orientation = 0;
- metadataPairs = new LinkedHashMap<>();
+ metadataEntries = new ArrayList<>();
long currentTimeInMp4TimeSeconds = unixTimeToMp4TimeSeconds(System.currentTimeMillis());
timestampData =
new Mp4TimestampData(
@@ -43,28 +44,21 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* modificationTimestampSeconds= */ currentTimeInMp4TimeSeconds);
}
- public void addXmp(ByteBuffer xmpData) {
- checkState(this.xmpData == null);
- this.xmpData = xmpData;
- }
-
public void setOrientation(int orientation) {
this.orientation = orientation;
}
- public void setLocation(float latitude, float longitude) {
- locationData = new Mp4LocationData(latitude, longitude);
- }
-
- public void setCaptureFps(float captureFps) {
- metadataPairs.put("com.android.capture.fps", captureFps);
- }
-
- public void addMetadata(String key, Object value) {
- metadataPairs.put(key, value);
- }
-
- public void setTimestampData(Mp4TimestampData timestampData) {
- this.timestampData = timestampData;
+ public void addMetadata(Metadata.Entry metadata) {
+ if (metadata instanceof Mp4LocationData) {
+ locationData = (Mp4LocationData) metadata;
+ } else if (metadata instanceof Mp4TimestampData) {
+ timestampData = (Mp4TimestampData) metadata;
+ } else if (metadata instanceof MdtaMetadataEntry) {
+ metadataEntries.add((MdtaMetadataEntry) metadata);
+ } else if (metadata instanceof XmpData) {
+ xmpData = (XmpData) metadata;
+ } else {
+ throw new IllegalArgumentException("Unsupported metadata");
+ }
}
}
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 cf154a9c48..ec71e235cc 100644
--- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java
+++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4MoovStructure.java
@@ -180,12 +180,12 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
nextTrackId, creationTimestampSeconds, modificationTimestampSeconds, videoDurationUs);
ByteBuffer udtaBox = Boxes.udta(metadataCollector.locationData);
ByteBuffer metaBox =
- metadataCollector.metadataPairs.isEmpty()
+ metadataCollector.metadataEntries.isEmpty()
? ByteBuffer.allocate(0)
: Boxes.meta(
Boxes.hdlr(/* handlerType= */ "mdta", /* handlerName= */ ""),
- Boxes.keys(Lists.newArrayList(metadataCollector.metadataPairs.keySet())),
- Boxes.ilst(Lists.newArrayList(metadataCollector.metadataPairs.values())));
+ Boxes.keys(Lists.newArrayList(metadataCollector.metadataEntries)),
+ Boxes.ilst(Lists.newArrayList(metadataCollector.metadataEntries)));
ByteBuffer moovBox;
moovBox =
@@ -199,7 +199,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
// Also add XMP if needed
if (metadataCollector.xmpData != null) {
return BoxUtils.concatenateBuffers(
- moovBox, Boxes.uuid(Boxes.XMP_UUID, metadataCollector.xmpData.duplicate()));
+ moovBox, Boxes.uuid(Boxes.XMP_UUID, ByteBuffer.wrap(metadataCollector.xmpData.data)));
} else {
// No need for another copy if there is no XMP to be appended.
return moovBox;
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 577261310c..47096b6484 100644
--- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java
+++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java
@@ -25,9 +25,14 @@ import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.Format;
+import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.UnstableApi;
+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.XmpData;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.FileOutputStream;
@@ -205,6 +210,20 @@ public final class Mp4Muxer {
this.metadataCollector = metadataCollector;
}
+ /**
+ * Returns whether a given {@link Metadata.Entry metadata} is supported.
+ *
+ * For the list of supported metadata refer to {@link Mp4Muxer#addMetadata(Metadata.Entry)}.
+ */
+ public static boolean isMetadataSupported(Metadata.Entry metadata) {
+ return metadata instanceof Mp4LocationData
+ || (metadata instanceof Mp4TimestampData
+ && isMp4TimestampDataSupported((Mp4TimestampData) metadata))
+ || (metadata instanceof MdtaMetadataEntry
+ && isMdtaMetadataEntrySupported((MdtaMetadataEntry) metadata))
+ || metadata instanceof XmpData;
+ }
+
/**
* Sets the orientation hint for the video playback.
*
@@ -215,57 +234,85 @@ public final class Mp4Muxer {
}
/**
- * Sets the location.
- *
- * @param latitude The latitude, in degrees. Its value must be in the range [-90, 90].
- * @param longitude The longitude, in degrees. Its value must be in the range [-180, 180].
+ * @deprecated Use {@link #addMetadata(Metadata.Entry)} with {@link Mp4LocationData} instead.
*/
+ @Deprecated
public void setLocation(
@FloatRange(from = -90.0, to = 90.0) float latitude,
@FloatRange(from = -180.0, to = 180.0) float longitude) {
- metadataCollector.setLocation(latitude, longitude);
+ addMetadata(new Mp4LocationData(latitude, longitude));
}
/**
- * Sets the capture frame rate.
- *
- * @param captureFps The frame rate.
+ * @deprecated Use {@link #addMetadata(Metadata.Entry)} with {@link MdtaMetadataEntry} instead.
*/
+ @Deprecated
public void setCaptureFps(float captureFps) {
- metadataCollector.setCaptureFps(captureFps);
+ addMetadata(
+ new MdtaMetadataEntry(
+ MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS,
+ Util.toByteArray(captureFps),
+ MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32));
}
/**
- * Sets the timestamp data (creation time and modification time) for the output file.
- *
- *
If this method is not called, the file creation time and modification time will be when the
- * {@link Mp4Muxer} was {@linkplain Builder#build() created}.
+ * @deprecated Use {@link #addMetadata(Metadata.Entry)} with {@link Mp4TimestampData} instead.
*/
+ @Deprecated
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);
+ addMetadata(timestampData);
}
/**
- * Adds custom metadata.
- *
- * @param key The metadata key in {@link String} format.
- * @param value The metadata value in {@link String} or {@link Float} format.
+ * @deprecated Use {@link #addMetadata(Metadata.Entry)} with {@link MdtaMetadataEntry} instead.
*/
+ @Deprecated
public void addMetadata(String key, Object value) {
- metadataCollector.addMetadata(key, value);
+ MdtaMetadataEntry mdtaMetadataEntry = null;
+ if (value instanceof String) {
+ mdtaMetadataEntry =
+ new MdtaMetadataEntry(
+ key, Util.getUtf8Bytes((String) value), MdtaMetadataEntry.TYPE_INDICATOR_STRING);
+ } else if (value instanceof Float) {
+ mdtaMetadataEntry =
+ new MdtaMetadataEntry(
+ key, Util.toByteArray((Float) value), MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32);
+ } else {
+ throw new IllegalArgumentException("Unsupported metadata");
+ }
+ addMetadata(mdtaMetadataEntry);
}
/**
- * Adds xmp data.
+ * Adds metadata for the output file.
*
- * @param xmp The xmp {@link ByteBuffer}.
+ *
List of supported {@linkplain Metadata.Entry metadata entries}:
+ *
+ *
+ * {@link Mp4LocationData}
+ * {@link Mp4TimestampData}
+ * {@link MdtaMetadataEntry}: Only {@linkplain MdtaMetadataEntry#TYPE_INDICATOR_STRING
+ * string type} or {@linkplain MdtaMetadataEntry#TYPE_INDICATOR_FLOAT32 float type} value is
+ * supported.
+ * {@link XmpData}
+ *
+ *
+ * @param metadata The {@linkplain Metadata.Entry metadata}. An {@link IllegalArgumentException}
+ * is throw if the {@linkplain Metadata.Entry metadata} is not supported.
*/
+ public void addMetadata(Metadata.Entry metadata) {
+ checkArgument(isMetadataSupported(metadata), "Unsupported metadata");
+ metadataCollector.addMetadata(metadata);
+ }
+
+ /**
+ * @deprecated Use {@link #addMetadata(Metadata.Entry)} with {@link XmpData} instead.
+ */
+ @Deprecated
public void addXmp(ByteBuffer xmp) {
- metadataCollector.addXmp(xmp);
+ byte[] xmpData = new byte[xmp.remaining()];
+ xmp.get(xmpData, 0, xmpData.length);
+ addMetadata(new XmpData(xmpData));
}
/**
@@ -308,4 +355,14 @@ public final class Mp4Muxer {
public void close() throws IOException {
mp4Writer.close();
}
+
+ private static boolean isMdtaMetadataEntrySupported(MdtaMetadataEntry mdtaMetadataEntry) {
+ return mdtaMetadataEntry.typeIndicator == MdtaMetadataEntry.TYPE_INDICATOR_STRING
+ || mdtaMetadataEntry.typeIndicator == MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32;
+ }
+
+ private static boolean isMp4TimestampDataSupported(Mp4TimestampData timestampData) {
+ return timestampData.creationTimestampSeconds <= UNSIGNED_INT_MAX_VALUE
+ && timestampData.modificationTimestampSeconds <= UNSIGNED_INT_MAX_VALUE;
+ }
}
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 7bf34c440f..f84e55d01f 100644
--- a/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java
+++ b/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java
@@ -30,6 +30,8 @@ import android.media.MediaCodec;
import androidx.media3.common.C;
import androidx.media3.common.ColorInfo;
import androidx.media3.common.Format;
+import androidx.media3.common.util.Util;
+import androidx.media3.container.MdtaMetadataEntry;
import androidx.media3.container.Mp4LocationData;
import androidx.media3.muxer.FragmentedMp4Writer.SampleMetadata;
import androidx.media3.test.utils.DumpFileAsserts;
@@ -173,9 +175,19 @@ public class BoxesTest {
@Test
public void createKeysBox_matchesExpected() throws Exception {
- List keyNames = ImmutableList.of("com.android.version", "com.android.capture.fps");
+ List metadataEntries = new ArrayList<>();
+ metadataEntries.add(
+ new MdtaMetadataEntry(
+ "com.android.version",
+ Util.getUtf8Bytes("11"),
+ MdtaMetadataEntry.TYPE_INDICATOR_STRING));
+ metadataEntries.add(
+ new MdtaMetadataEntry(
+ "com.android.capture.fps",
+ Util.toByteArray(120.0f),
+ MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32));
- ByteBuffer keysBox = Boxes.keys(keyNames);
+ ByteBuffer keysBox = Boxes.keys(metadataEntries);
DumpableMp4Box dumpableBox = new DumpableMp4Box(keysBox);
DumpFileAsserts.assertOutput(context, dumpableBox, getExpectedDumpFilePath("keys_box"));
@@ -183,9 +195,19 @@ public class BoxesTest {
@Test
public void createIlstBox_matchesExpected() throws Exception {
- List values = ImmutableList.of("11", 120.0f);
+ List metadataEntries = new ArrayList<>();
+ metadataEntries.add(
+ new MdtaMetadataEntry(
+ "com.android.version",
+ Util.getUtf8Bytes("11"),
+ MdtaMetadataEntry.TYPE_INDICATOR_STRING));
+ metadataEntries.add(
+ new MdtaMetadataEntry(
+ "com.android.capture.fps",
+ Util.toByteArray(120.0f),
+ MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32));
- ByteBuffer ilstBox = Boxes.ilst(values);
+ ByteBuffer ilstBox = Boxes.ilst(metadataEntries);
DumpableMp4Box dumpableBox = new DumpableMp4Box(ilstBox);
DumpFileAsserts.assertOutput(context, dumpableBox, getExpectedDumpFilePath("ilst_box"));
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 ae69dd8aa8..daaef7a59c 100644
--- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java
+++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java
@@ -24,7 +24,11 @@ import static org.junit.Assert.assertThrows;
import android.content.Context;
import android.media.MediaCodec.BufferInfo;
import android.util.Pair;
+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.XmpData;
import androidx.media3.extractor.mp4.Mp4Extractor;
import androidx.media3.muxer.Mp4Muxer.TrackToken;
import androidx.media3.test.utils.DumpFileAsserts;
@@ -56,7 +60,11 @@ public class Mp4MuxerEndToEndTest {
try {
mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
mp4Muxer.setOrientation(90);
- mp4Muxer.addMetadata("key", "value");
+ mp4Muxer.addMetadata(
+ new MdtaMetadataEntry(
+ "key",
+ /* value= */ Util.getUtf8Bytes("value"),
+ MdtaMetadataEntry.TYPE_INDICATOR_STRING));
} finally {
mp4Muxer.close();
}
@@ -69,7 +77,7 @@ 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.setTimestampData(
+ mp4Muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
@@ -112,7 +120,7 @@ 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.setTimestampData(
+ mp4Muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
@@ -174,7 +182,7 @@ 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.setTimestampData(
+ mp4Muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
@@ -209,18 +217,26 @@ public class Mp4MuxerEndToEndTest {
Pair sampleAndSampleInfo =
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
byte[] xmpBytes = TestUtil.getByteArray(context, XMP_SAMPLE_DATA);
- ByteBuffer xmp = ByteBuffer.wrap(xmpBytes);
try {
muxer.setOrientation(90);
- muxer.setLocation(/* latitude= */ 33.0f, /* longitude= */ -120f);
- muxer.setCaptureFps(120.0f);
- muxer.setTimestampData(
+ muxer.addMetadata(new Mp4LocationData(/* latitude= */ 33.0f, /* longitude= */ -120f));
+ float captureFps = 120.0f;
+ muxer.addMetadata(
+ new MdtaMetadataEntry(
+ MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS,
+ /* value= */ Util.toByteArray(captureFps),
+ MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32));
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
- muxer.addMetadata("StringKey1", "StringValue");
- muxer.addXmp(xmp);
+ muxer.addMetadata(
+ new MdtaMetadataEntry(
+ "StringKey1",
+ /* value= */ Util.getUtf8Bytes("StringValue"),
+ MdtaMetadataEntry.TYPE_INDICATOR_STRING));
+ muxer.addMetadata(new XmpData(xmpBytes));
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
} finally {
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 a766352542..dc51f165ae 100644
--- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java
+++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java
@@ -52,7 +52,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -77,7 +77,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -104,7 +104,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -131,7 +131,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -158,7 +158,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -184,7 +184,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -209,7 +209,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -235,7 +235,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
@@ -261,7 +261,7 @@ public class Mp4MuxerMetadataTest {
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
try {
- muxer.setTimestampData(
+ muxer.addMetadata(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 1_000_000L,
/* modificationTimestampSeconds= */ 5_000_000L));
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 8759071fb2..8ad031574a 100644
--- a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java
+++ b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java
@@ -24,11 +24,6 @@ import androidx.media3.common.Format;
import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.UnstableApi;
-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.XmpData;
import androidx.media3.muxer.Mp4Muxer;
import androidx.media3.muxer.Mp4Muxer.TrackToken;
import com.google.common.collect.ImmutableList;
@@ -56,14 +51,7 @@ public final class InAppMuxer implements Muxer {
* A {@link Metadata.Entry} can be added or removed. To modify an existing {@link
* Metadata.Entry}, first remove it and then add a new one.
*
- *
List of supported {@linkplain Metadata.Entry metadata entries}:
- *
- *
- * {@link Mp4LocationData}
- * {@link XmpData}
- * {@link Mp4TimestampData}
- * {@link MdtaMetadataEntry}
- *
+ * For the list of supported metadata refer to {@link Mp4Muxer#addMetadata(Metadata.Entry)}.
*/
void updateMetadataEntries(Set metadataEntries);
}
@@ -241,17 +229,7 @@ public final class InAppMuxer implements Muxer {
public void addMetadata(Metadata metadata) {
for (int i = 0; i < metadata.length(); i++) {
Metadata.Entry entry = metadata.get(i);
- // Keep only supported metadata.
- // LINT.IfChange(added_metadata)
- if (entry instanceof Mp4LocationData
- || entry instanceof XmpData
- || entry instanceof Mp4TimestampData
- || (entry instanceof MdtaMetadataEntry
- && (((MdtaMetadataEntry) entry).key.equals(MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS)
- || ((MdtaMetadataEntry) entry).typeIndicator
- == MdtaMetadataEntry.TYPE_INDICATOR_STRING
- || ((MdtaMetadataEntry) entry).typeIndicator
- == MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32))) {
+ if (Mp4Muxer.isMetadataSupported(entry)) {
metadataEntries.add(entry);
}
}
@@ -282,29 +260,7 @@ public final class InAppMuxer implements Muxer {
}
for (Metadata.Entry entry : metadataEntries) {
- // LINT.IfChange(written_metadata)
- if (entry instanceof Mp4LocationData) {
- mp4Muxer.setLocation(
- ((Mp4LocationData) entry).latitude, ((Mp4LocationData) entry).longitude);
- } else if (entry instanceof XmpData) {
- mp4Muxer.addXmp(ByteBuffer.wrap(((XmpData) entry).data));
- } else if (entry instanceof Mp4TimestampData) {
- mp4Muxer.setTimestampData((Mp4TimestampData) entry);
- } else if (entry instanceof MdtaMetadataEntry) {
- MdtaMetadataEntry mdtaMetadataEntry = (MdtaMetadataEntry) entry;
- if (mdtaMetadataEntry.key.equals(MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS)) {
- byte[] captureFps = mdtaMetadataEntry.value;
- mp4Muxer.setCaptureFps(ByteBuffer.wrap(captureFps).getFloat());
- } else if (mdtaMetadataEntry.typeIndicator == MdtaMetadataEntry.TYPE_INDICATOR_STRING) {
- mp4Muxer.addMetadata(mdtaMetadataEntry.key, Util.fromUtf8Bytes(mdtaMetadataEntry.value));
- } else if (mdtaMetadataEntry.typeIndicator == MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32) {
- mp4Muxer.addMetadata(mdtaMetadataEntry.key, Util.toFloat(mdtaMetadataEntry.value));
- } else {
- throw new IllegalStateException("Unsupported MdtaMetadataEntry " + mdtaMetadataEntry.key);
- }
- } else {
- throw new IllegalStateException("Unsupported Metadata.Entry " + entry.getClass().getName());
- }
+ mp4Muxer.addMetadata(entry);
}
}
}