Add support to MPEG4 codec in Mp4Muxer.
Add support for MPEG4 codec to enable muxing video encoded with the mp4v-es codec. Use esdsBox method to generate esds box required for Mp4v box. PiperOrigin-RevId: 651000744
This commit is contained in:
parent
cf90d2624d
commit
34a802ef38
@ -52,6 +52,7 @@ public class Mp4MuxerEndToEndParameterizedAndroidTest {
|
||||
private static final String H265_WITH_METADATA_TRACK_MP4 = "h265_with_metadata_track.mp4";
|
||||
private static final String AV1_MP4 = "sample_av1.mp4";
|
||||
private static final String AMR_WB = "bbb_mono_16kHz_23.05kbps_amrwb.3gp";
|
||||
private static final String MPEG4_MP4 = "bbb_176x144_192kbps_15fps_mpeg4.mp4";
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static ImmutableList<String> mediaSamples() {
|
||||
@ -62,7 +63,8 @@ public class Mp4MuxerEndToEndParameterizedAndroidTest {
|
||||
H265_HDR10_MP4,
|
||||
H265_WITH_METADATA_TRACK_MP4,
|
||||
AV1_MP4,
|
||||
AMR_WB);
|
||||
AMR_WB,
|
||||
MPEG4_MP4);
|
||||
}
|
||||
|
||||
@Parameter public @MonotonicNonNull String inputFile;
|
||||
|
@ -542,6 +542,7 @@ import java.util.List;
|
||||
String mimeType = checkNotNull(format.sampleMimeType);
|
||||
switch (mimeType) {
|
||||
case MimeTypes.AUDIO_AAC:
|
||||
case MimeTypes.VIDEO_MP4V:
|
||||
return esdsBox(format);
|
||||
case MimeTypes.AUDIO_AMR_WB:
|
||||
return damrBox(/* mode= */ (short) 0x83FF); // mode set: all enabled
|
||||
@ -1329,6 +1330,8 @@ import java.util.List;
|
||||
return "hvc1";
|
||||
case MimeTypes.VIDEO_AV1:
|
||||
return "av01";
|
||||
case MimeTypes.VIDEO_MP4V:
|
||||
return "mp4v-es";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported format: " + mimeType);
|
||||
}
|
||||
@ -1344,6 +1347,7 @@ import java.util.List;
|
||||
ByteBuffer csd0ByteBuffer = ByteBuffer.wrap(csd0);
|
||||
int peakBitrate = format.peakBitrate;
|
||||
int averageBitrate = format.averageBitrate;
|
||||
boolean isVideo = MimeTypes.isVideo(format.sampleMimeType);
|
||||
|
||||
int csd0Size = csd0ByteBuffer.limit();
|
||||
ByteBuffer dsiSizeBuffer = getSizeBuffer(csd0Size);
|
||||
@ -1358,17 +1362,18 @@ import java.util.List;
|
||||
contents.put(esdSizeBuffer);
|
||||
|
||||
contents.putShort((short) 0x0000); // First 16 bits of ES_ID.
|
||||
contents.put((byte) 0x00); // Last 8 bits of ES_ID.
|
||||
contents.put(isVideo ? (byte) 0x1f : (byte) 0x00); // Last 8 bits of ES_ID.
|
||||
|
||||
contents.put((byte) 0x04); // DecoderConfigDescrTag
|
||||
contents.put(dcdSizeBuffer);
|
||||
|
||||
contents.put((byte) 0x40); // objectTypeIndication
|
||||
contents.put(isVideo ? (byte) 0x20 : (byte) 0x40); // objectTypeIndication
|
||||
// streamType (6 bits) | upStream (1 bit) | reserved = 1 (1 bit)
|
||||
contents.put((byte) ((0x05 << 2) | 0x01)); // streamType AudioStream
|
||||
contents.put((byte) ((isVideo ? (0x04 << 2) : (0x05 << 2)) | 0x01)); // streamType
|
||||
|
||||
contents.putShort((short) 0x03); // First 16 bits of buffer size (0x300).
|
||||
contents.put((byte) 0x00); // Last 8 bits of buffer size (0x300).
|
||||
int size = isVideo ? 0x017700 : 0x000300;
|
||||
contents.putShort((short) ((size >> 8) & 0xFFFF)); // First 16 bits of buffer size.
|
||||
contents.put((byte) 0x00); // Last 8 bits of buffer size.
|
||||
|
||||
contents.putInt(peakBitrate != Format.NO_VALUE ? peakBitrate : 0);
|
||||
contents.putInt(averageBitrate != Format.NO_VALUE ? averageBitrate : 0);
|
||||
|
@ -30,6 +30,7 @@ import android.media.MediaCodec;
|
||||
import androidx.media3.common.C;
|
||||
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;
|
||||
@ -396,6 +397,35 @@ public class BoxesTest {
|
||||
context, dumpableBox, MuxerTestUtil.getExpectedDumpFilePath("video_sample_entry_box_av1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVideoSampleEntryBox_forMPEG4_matchesExpected() throws IOException {
|
||||
Format format =
|
||||
new Format.Builder()
|
||||
.setId(1)
|
||||
.setSampleMimeType(MimeTypes.VIDEO_MP4V)
|
||||
.setAverageBitrate(9200)
|
||||
.setPeakBitrate(9200)
|
||||
.setLanguage("und")
|
||||
.setWidth(10)
|
||||
.setMaxInputSize(49)
|
||||
.setFrameRate(25)
|
||||
.setHeight(12)
|
||||
.setInitializationData(
|
||||
ImmutableList.of(
|
||||
BaseEncoding.base16()
|
||||
.decode(
|
||||
"000001B001000001B58913000001000000012000C48D88007D0584121443000001B24C61766335382E35342E313030")))
|
||||
.build();
|
||||
|
||||
ByteBuffer videoSampleEntryBox = Boxes.videoSampleEntry(format);
|
||||
|
||||
DumpableMp4Box dumpableBox = new DumpableMp4Box(videoSampleEntryBox);
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
dumpableBox,
|
||||
MuxerTestUtil.getExpectedDumpFilePath("video_sample_entry_box_mpeg4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVideoSampleEntryBox_withUnknownVideoFormat_throws() {
|
||||
// The video format contains an unknown MIME type.
|
||||
|
Binary file not shown.
@ -0,0 +1,87 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 933300
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(466650) = [[timeUs=0, position=400052]]
|
||||
getPosition(933300) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 45694
|
||||
sample count = 15
|
||||
format 0:
|
||||
averageBitrate = 365552
|
||||
peakBitrate = 365552
|
||||
id = 1
|
||||
sampleMimeType = video/mp4v-es
|
||||
maxInputSize = 9256
|
||||
width = 176
|
||||
height = 144
|
||||
frameRate = 16.072002
|
||||
colorInfo:
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 47, hash DC4DD041
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 9226, hash 7C636E69
|
||||
sample 1:
|
||||
time = 66655
|
||||
flags = 0
|
||||
data = length 2560, hash C7A69F47
|
||||
sample 2:
|
||||
time = 133322
|
||||
flags = 0
|
||||
data = length 1720, hash 32B683D
|
||||
sample 3:
|
||||
time = 200000
|
||||
flags = 0
|
||||
data = length 2684, hash A77F20B0
|
||||
sample 4:
|
||||
time = 266655
|
||||
flags = 0
|
||||
data = length 2966, hash CDB6D380
|
||||
sample 5:
|
||||
time = 333322
|
||||
flags = 0
|
||||
data = length 3160, hash 5A1455FB
|
||||
sample 6:
|
||||
time = 400000
|
||||
flags = 0
|
||||
data = length 3128, hash 8F3EA8F2
|
||||
sample 7:
|
||||
time = 466655
|
||||
flags = 0
|
||||
data = length 3164, hash 40A33F45
|
||||
sample 8:
|
||||
time = 533322
|
||||
flags = 0
|
||||
data = length 3309, hash 4ACFEBD1
|
||||
sample 9:
|
||||
time = 600000
|
||||
flags = 0
|
||||
data = length 3332, hash 7902F5A6
|
||||
sample 10:
|
||||
time = 666655
|
||||
flags = 0
|
||||
data = length 3082, hash 57E4EBB9
|
||||
sample 11:
|
||||
time = 733322
|
||||
flags = 0
|
||||
data = length 3210, hash FDA3CC0F
|
||||
sample 12:
|
||||
time = 800000
|
||||
flags = 0
|
||||
data = length 981, hash FA98FC90
|
||||
sample 13:
|
||||
time = 866655
|
||||
flags = 0
|
||||
data = length 1611, hash 3F58EEE9
|
||||
sample 14:
|
||||
time = 933322
|
||||
flags = 536870912
|
||||
data = length 1561, hash 24FA5A54
|
||||
tracksEnded = true
|
@ -0,0 +1,2 @@
|
||||
mp4v (186 bytes):
|
||||
Data = length 178, hash DE771E7E
|
Loading…
x
Reference in New Issue
Block a user