Allocate correct size for keys and ilst boxes in Mp4Muxer

The keys and ilst boxes in the MP4 muxer were allocated
with a fixed size of 200 bytes. This was not enough to
store the keys and values of large metadata entries, which
could cause the muxer to throw an exception. This CL allocates
the correct size for the keys and ilst boxes based on the size of the metadata entries.

PiperOrigin-RevId: 630331680
This commit is contained in:
sheenachhabra 2024-05-03 02:44:21 -07:00 committed by Copybara-Service
parent 620cb32667
commit 10e29be8b6
2 changed files with 38 additions and 3 deletions

View File

@ -415,7 +415,12 @@ import java.util.Locale;
* <p>This box contains a list of metadata keys.
*/
public static ByteBuffer keys(List<MdtaMetadataEntry> mdtaMetadataEntries) {
ByteBuffer contents = ByteBuffer.allocate(MAX_FIXED_LEAF_BOX_SIZE);
int totalSizeToStoreKeys = 0;
for (int i = 0; i < mdtaMetadataEntries.size(); i++) {
// Add header size to wrap each key into a "mdta" box.
totalSizeToStoreKeys += mdtaMetadataEntries.get(i).key.length() + BOX_HEADER_SIZE;
}
ByteBuffer contents = ByteBuffer.allocate(2 * BYTES_PER_INTEGER + totalSizeToStoreKeys);
contents.putInt(0x0); // version and flags
contents.putInt(mdtaMetadataEntries.size()); // Entry count
@ -434,7 +439,15 @@ import java.util.Locale;
* <p>This box contains a list of metadata values.
*/
public static ByteBuffer ilst(List<MdtaMetadataEntry> mdtaMetadataEntries) {
ByteBuffer contents = ByteBuffer.allocate(MAX_FIXED_LEAF_BOX_SIZE);
int totalSizeToStoreValues = 0;
for (int i = 0; i < mdtaMetadataEntries.size(); i++) {
// Add additional 16 bytes for writing metadata associated to each value.
// Add header size to wrap each value into a "data" box.
totalSizeToStoreValues +=
mdtaMetadataEntries.get(i).value.length + 4 * BYTES_PER_INTEGER + BOX_HEADER_SIZE;
}
ByteBuffer contents = ByteBuffer.allocate(totalSizeToStoreValues);
for (int i = 0; i < mdtaMetadataEntries.size(); i++) {
int keyId = i + 1;
@ -448,7 +461,7 @@ import java.util.Locale;
valueContents.flip();
ByteBuffer valueBox = BoxUtils.wrapIntoBox("data", valueContents);
contents.putInt(valueBox.remaining() + 8);
contents.putInt(valueBox.remaining() + BOX_HEADER_SIZE);
contents.putInt(keyId);
contents.put(valueBox);
}

View File

@ -20,6 +20,7 @@ import static androidx.media3.container.MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32
import static androidx.media3.container.MdtaMetadataEntry.TYPE_INDICATOR_STRING;
import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
import static androidx.media3.muxer.MuxerTestUtil.XMP_SAMPLE_DATA;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.media.MediaCodec.BufferInfo;
@ -277,6 +278,27 @@ public class Mp4MuxerMetadataTest {
MuxerTestUtil.getExpectedDumpFilePath("mp4_with_string_metadata.mp4"));
}
@Test
public void writeMp4File_addManyLargeStringMetadata_doesNotThrow() throws Exception {
String outputFilePath = temporaryFolder.newFile().getPath();
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
String metadataKey = "SomeStringKey";
byte[] metadataValue = Util.getUtf8Bytes("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
for (int i = 0; i < 100; i++) {
muxer.addMetadataEntry(
new MdtaMetadataEntry(metadataKey, metadataValue, TYPE_INDICATOR_STRING));
}
TrackToken token = muxer.addTrack(FAKE_VIDEO_FORMAT);
try {
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
assertThat(sampleAndSampleInfo.first.remaining()).isEqualTo(0);
} finally {
muxer.close();
}
}
@Test
public void writeMp4File_addFloatMetadata_matchesExpected() throws Exception {
String outputFilePath = temporaryFolder.newFile().getPath();