Use 4 Byte size field in fMP4 mdat boxes

Since mdat box can be huge so there is a provision to use 64 bit size field.
In case of fragmented MP4, individual fragments should not have large mdat box
so a 32 bit size field should be sufficient.

PiperOrigin-RevId: 599219041
This commit is contained in:
sheenachhabra 2024-01-17 10:34:16 -08:00 committed by Copybara-Service
parent 406c0a15be
commit 666685bd85
4 changed files with 21 additions and 17 deletions

View file

@ -17,6 +17,7 @@ package androidx.media3.muxer;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.muxer.Mp4Utils.UNSIGNED_INT_MAX_VALUE;
import static java.lang.Math.max;
import static java.lang.Math.min;
@ -174,13 +175,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private void writeMdatBox() throws IOException {
long mdatStartPosition = output.position();
// 4 bytes (indicating a 64-bit length field) + 4 bytes (box name) + 8 bytes (the actual length)
ByteBuffer header = ByteBuffer.allocate(16);
// This 32-bit integer in general contains the total length of the box. Here value 1 indicates
// that the actual length is stored as 64-bit integer after the box name.
header.putInt(1);
int mdatHeaderSize = 8; // 4 bytes (box size) + 4 bytes (box name)
ByteBuffer header = ByteBuffer.allocate(mdatHeaderSize);
header.putInt(mdatHeaderSize); // The total box size so far.
header.put(Util.getUtf8Bytes("mdat"));
header.putLong(16); // The total box length so far.
header.flip();
output.write(header);
@ -201,13 +199,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
long currentPosition = output.position();
// Skip 4 bytes (64-bit length indication) + 4 bytes (box name).
output.position(mdatStartPosition + 8);
ByteBuffer mdatSize = ByteBuffer.allocate(8); // 64-bit length.
// Additional 4 bytes (64-bit length indication) + 4 bytes (box name) + 8 bytes (actual length).
mdatSize.putLong(bytesWritten + 16);
mdatSize.flip();
output.write(mdatSize);
output.position(mdatStartPosition);
ByteBuffer mdatSizeByteBuffer = ByteBuffer.allocate(4);
long mdatSize = bytesWritten + mdatHeaderSize;
checkArgument(
mdatSize <= UNSIGNED_INT_MAX_VALUE,
"Only 32-bit long mdat size supported in the fragmented MP4");
mdatSizeByteBuffer.putInt((int) mdatSize);
mdatSizeByteBuffer.flip();
output.write(mdatSizeByteBuffer);
output.position(currentPosition);
}

View file

@ -17,6 +17,7 @@ package androidx.media3.muxer;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.muxer.Mp4Utils.UNSIGNED_INT_MAX_VALUE;
import androidx.media3.container.Mp4Util;
import java.nio.ByteBuffer;
@ -61,9 +62,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
public void setModificationTime(long unixTimestampMs) {
long maxUnsignedInt = 4294967295L;
long timestampSeconds = Mp4Util.unixTimeToMp4TimeSeconds(unixTimestampMs);
checkArgument(timestampSeconds <= maxUnsignedInt, "Only 32-bit long timestamp supported");
checkArgument(
timestampSeconds <= UNSIGNED_INT_MAX_VALUE, "Only 32-bit long timestamp supported");
this.modificationTimestampSeconds = (int) timestampSeconds;
}
}

View file

@ -25,6 +25,9 @@ package androidx.media3.muxer;
*/
public static final int MAX_FIXED_LEAF_BOX_SIZE = 200;
/** The maximum value of a 32-bit unsigned int. */
public static final long UNSIGNED_INT_MAX_VALUE = 4_294_967_295L;
/**
* The per-video timebase, used for durations in MVHD and TKHD even if the per-track timebase is
* different (e.g. typically the sample rate for audio).

View file

@ -71,7 +71,7 @@ moof (2852 bytes):
Data = length 8, hash 94446F03
trun (1684 bytes):
Data = length 1676, hash 46E974DC
mdat (5712395 bytes):
mdat (5712387 bytes):
Data = length 5712379, hash 86B2819D
moof (1220 bytes):
mfhd (16 bytes):
@ -86,5 +86,5 @@ moof (1220 bytes):
Data = length 8, hash 94446F03
trun (688 bytes):
Data = length 680, hash 4E3D2F16
mdat (2364929 bytes):
mdat (2364921 bytes):
Data = length 2364913, hash D363A845