diff --git a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndParameterizedAndroidTest.java b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndParameterizedAndroidTest.java index 47256c06a1..5055f88009 100644 --- a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndParameterizedAndroidTest.java +++ b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/Mp4MuxerEndToEndParameterizedAndroidTest.java @@ -43,6 +43,7 @@ import org.junit.runners.Parameterized.Parameters; /** End to end parameterized instrumentation tests for {@link Mp4Muxer}. */ @RunWith(Parameterized.class) public class Mp4MuxerEndToEndParameterizedAndroidTest { + private static final String H263_GPP = "bbb_176x144_128kbps_15fps_h263.3gp"; private static final String H264_MP4 = "sample_no_bframes.mp4"; private static final String H264_WITH_NON_REFERENCE_B_FRAMES_MP4 = "bbb_800x640_768kbps_30fps_avc_non_reference_3b.mp4"; @@ -58,6 +59,7 @@ public class Mp4MuxerEndToEndParameterizedAndroidTest { @Parameters(name = "{0}") public static ImmutableList mediaSamples() { return ImmutableList.of( + H263_GPP, H264_MP4, H264_WITH_NON_REFERENCE_B_FRAMES_MP4, H264_WITH_PYRAMID_B_FRAMES_MP4, 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 43420ed066..cae311bdb3 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java @@ -548,6 +548,8 @@ import java.util.List; return damrBox(/* mode= */ (short) 0x81FF); // mode set: all enabled for AMR-NB case MimeTypes.AUDIO_AMR_WB: return damrBox(/* mode= */ (short) 0x83FF); // mode set: all enabled for AMR-WB + case MimeTypes.VIDEO_H263: + return d263Box(); case MimeTypes.VIDEO_H264: return avcCBox(format); case MimeTypes.VIDEO_H265: @@ -1095,6 +1097,19 @@ import java.util.List; } } + /** Returns the d263Box box as per 3GPP ETSI TS 126 244: 6.8. */ + private static ByteBuffer d263Box() { + ByteBuffer d263Box = ByteBuffer.allocate(7); + d263Box.put(" ".getBytes(UTF_8)); // 4 spaces (vendor) + d263Box.put((byte) 0x00); // decoder version + // TODO: b/352000778 - Get profile and level from format. + d263Box.put((byte) 0x10); // level + d263Box.put((byte) 0x00); // profile + + d263Box.flip(); + return BoxUtils.wrapIntoBox("d263", d263Box); + } + /** Returns the avcC box as per ISO/IEC 14496-15: 5.3.3.1.2. */ private static ByteBuffer avcCBox(Format format) { checkArgument( @@ -1328,6 +1343,8 @@ import java.util.List; return "samr"; case MimeTypes.AUDIO_AMR_WB: return "sawb"; + case MimeTypes.VIDEO_H263: + return "s263"; case MimeTypes.VIDEO_H264: return "avc1"; case MimeTypes.VIDEO_H265: diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java index 97e4682cf4..5ab501fd31 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java @@ -35,7 +35,7 @@ import java.nio.ByteBuffer; /** * A muxer for creating a fragmented MP4 file. * - *

The muxer supports writing H264, H265 and AV1 video, AAC audio and metadata. + *

The muxer supports writing H263, H264, H265 and AV1 video, AAC audio and metadata. * *

All the operations are performed on the caller thread. * 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 5a619172fd..6f2172eddc 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java @@ -54,7 +54,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; /** * A muxer for creating an MP4 container file. * - *

The muxer supports writing H264, H265 and AV1 video, AAC audio and metadata. + *

The muxer supports writing H263, H264, H265 and AV1 video, AAC audio and metadata. * *

All the operations are performed on the caller thread. * 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 a5902031bc..0d6062bc39 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java @@ -375,6 +375,26 @@ public class BoxesTest { MuxerTestUtil.getExpectedDumpFilePath("video_sample_entry_box_h265_hdr10")); } + @Test + public void createVideoSampleEntryBox_forH263_matchesExpected() throws Exception { + Format format = + new Format.Builder() + .setId(1) + .setSampleMimeType(MimeTypes.VIDEO_H263) + .setLanguage("und") + .setWidth(10) + .setMaxInputSize(39) + .setFrameRate(25) + .setHeight(12) + .build(); + + ByteBuffer videoSampleEntryBox = Boxes.videoSampleEntry(format); + + DumpableMp4Box dumpableBox = new DumpableMp4Box(videoSampleEntryBox); + DumpFileAsserts.assertOutput( + context, dumpableBox, MuxerTestUtil.getExpectedDumpFilePath("video_sample_entry_box_h263")); + } + @Test public void createVideoSampleEntryBox_forH264_matchesExpected() throws Exception { Format format = diff --git a/libraries/test_data/src/test/assets/media/mp4/bbb_176x144_128kbps_15fps_h263.3gp b/libraries/test_data/src/test/assets/media/mp4/bbb_176x144_128kbps_15fps_h263.3gp new file mode 100644 index 0000000000..717ffb8470 Binary files /dev/null and b/libraries/test_data/src/test/assets/media/mp4/bbb_176x144_128kbps_15fps_h263.3gp differ diff --git a/libraries/test_data/src/test/assets/muxerdumps/bbb_176x144_128kbps_15fps_h263.3gp.dump b/libraries/test_data/src/test/assets/muxerdumps/bbb_176x144_128kbps_15fps_h263.3gp.dump new file mode 100644 index 0000000000..11ba771b68 --- /dev/null +++ b/libraries/test_data/src/test/assets/muxerdumps/bbb_176x144_128kbps_15fps_h263.3gp.dump @@ -0,0 +1,83 @@ +seekMap: + isSeekable = true + duration = 933300 + getPosition(0) = [[timeUs=0, position=400052]] + getPosition(1) = [[timeUs=0, position=400052], [timeUs=533322, position=428455]] + getPosition(466650) = [[timeUs=0, position=400052], [timeUs=533322, position=428455]] + getPosition(933300) = [[timeUs=533322, position=428455]] +numberOfTracks = 1 +track 0: + total output bytes = 50100 + sample count = 15 + format 0: + id = 1 + sampleMimeType = video/3gpp + maxInputSize = 10464 + width = 176 + height = 144 + frameRate = 16.072002 + colorInfo: + lumaBitdepth = 8 + chromaBitdepth = 8 + metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000] + sample 0: + time = 0 + flags = 1 + data = length 10434, hash AE44B225 + sample 1: + time = 66655 + flags = 0 + data = length 2615, hash A0DA11FE + sample 2: + time = 133322 + flags = 0 + data = length 1812, hash 7088FD15 + sample 3: + time = 200000 + flags = 0 + data = length 2812, hash C8A9745F + sample 4: + time = 266655 + flags = 0 + data = length 3127, hash 15B392C5 + sample 5: + time = 333322 + flags = 0 + data = length 3362, hash 77B8F06A + sample 6: + time = 400000 + flags = 0 + data = length 3295, hash 24A31310 + sample 7: + time = 466655 + flags = 0 + data = length 946, hash B1E4247C + sample 8: + time = 533322 + flags = 1 + data = length 10399, hash 65BB0623 + sample 9: + time = 600000 + flags = 0 + data = length 3373, hash 6884A84C + sample 10: + time = 666655 + flags = 0 + data = length 878, hash BFC0DD04 + sample 11: + time = 733322 + flags = 0 + data = length 1530, hash 55CB846F + sample 12: + time = 800000 + flags = 0 + data = length 1834, hash ECF4E9AA + sample 13: + time = 866655 + flags = 0 + data = length 1776, hash 63A892E4 + sample 14: + time = 933322 + flags = 536870912 + data = length 1907, hash 99D43466 +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/muxerdumps/video_sample_entry_box_h263.dump b/libraries/test_data/src/test/assets/muxerdumps/video_sample_entry_box_h263.dump new file mode 100644 index 0000000000..2f9865ae4d --- /dev/null +++ b/libraries/test_data/src/test/assets/muxerdumps/video_sample_entry_box_h263.dump @@ -0,0 +1,2 @@ +s263 (117 bytes): + Data = length 109, hash B820D1F5