Add support for amr-wb audio codec.

Implement damrBox to provide support for amr-wb audio codec.

Add unit test and an Android end to end test.

PiperOrigin-RevId: 650210732
This commit is contained in:
Googler 2024-07-08 05:10:39 -07:00 committed by Copybara-Service
parent d0a29400ea
commit 6e18cb0053
6 changed files with 666 additions and 1 deletions

View File

@ -51,6 +51,7 @@ public class Mp4MuxerEndToEndParameterizedAndroidTest {
private static final String H265_HDR10_MP4 = "hdr10-720p.mp4";
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";
@Parameters(name = "{0}")
public static ImmutableList<String> mediaSamples() {
@ -60,7 +61,8 @@ public class Mp4MuxerEndToEndParameterizedAndroidTest {
H264_WITH_PYRAMID_B_FRAMES_MP4,
H265_HDR10_MP4,
H265_WITH_METADATA_TRACK_MP4,
AV1_MP4);
AV1_MP4,
AMR_WB);
}
@Parameter public @MonotonicNonNull String inputFile;

View File

@ -21,6 +21,7 @@ import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.muxer.ColorUtils.MEDIAFORMAT_STANDARD_TO_PRIMARIES_AND_MATRIX;
import static androidx.media3.muxer.ColorUtils.MEDIAFORMAT_TRANSFER_TO_MP4_TRANSFER;
import static androidx.media3.muxer.Mp4Utils.UNSIGNED_INT_MAX_VALUE;
import static java.nio.charset.StandardCharsets.UTF_8;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
@ -541,6 +542,8 @@ import java.util.List;
switch (mimeType) {
case MimeTypes.AUDIO_AAC:
return esdsBox(format);
case MimeTypes.AUDIO_AMR_WB:
return damrBox(/* mode= */ (short) 0x83FF); // mode set: all enabled
case MimeTypes.VIDEO_H264:
return avcCBox(format);
case MimeTypes.VIDEO_H265:
@ -1317,6 +1320,8 @@ import java.util.List;
switch (mimeType) {
case MimeTypes.AUDIO_AAC:
return "mp4a";
case MimeTypes.AUDIO_AMR_WB:
return "sawb";
case MimeTypes.VIDEO_H264:
return "avc1";
case MimeTypes.VIDEO_H265:
@ -1380,6 +1385,21 @@ import java.util.List;
return BoxUtils.wrapIntoBox("esds", contents);
}
/** Returns the audio damr box. */
private static ByteBuffer damrBox(short mode) {
ByteBuffer contents = ByteBuffer.allocate(MAX_FIXED_LEAF_BOX_SIZE);
contents.put(" ".getBytes(UTF_8)); // vendor: 4 bytes
contents.put((byte) 0); // decoder version
contents.putShort(mode);
contents.put((byte) 0); // mode change period
contents.put((byte) 1); // frames per sample
contents.flip();
return BoxUtils.wrapIntoBox("damr", contents);
}
/** Packs a three-letter language code into a short, packing 3x5 bits. */
private static short languageCodeFromString(@Nullable String code) {
if (code == null) {

View File

@ -253,6 +253,27 @@ public class BoxesTest {
context, dumpableBox, getExpectedDumpFilePath("audio_sample_entry_box_mp4a"));
}
@Test
public void createAudioSampleEntryBox_forSawb_matchesExpected() throws Exception {
Format format =
new Format.Builder()
.setPeakBitrate(128000)
.setSampleRate(48000)
.setId(3)
.setSampleMimeType("audio/amr-wb")
.setChannelCount(2)
.setAverageBitrate(128000)
.setLanguage("```")
.setMaxInputSize(502)
.build();
ByteBuffer audioSampleEntryBox = Boxes.audioSampleEntry(format);
DumpableMp4Box dumpableBox = new DumpableMp4Box(audioSampleEntryBox);
DumpFileAsserts.assertOutput(
context, dumpableBox, getExpectedDumpFilePath("audio_sample_entry_box_sawb"));
}
@Test
public void createAudioSampleEntryBox_withUnknownAudioFormat_throws() {
// The audio format contains an unknown MIME type.

View File

@ -0,0 +1,2 @@
sawb (53 bytes):
Data = length 45, hash 7F064471

View File

@ -0,0 +1,620 @@
seekMap:
isSeekable = true
duration = 2980000
getPosition(0) = [[timeUs=0, position=400052]]
getPosition(1) = [[timeUs=1, position=400052]]
getPosition(1490000) = [[timeUs=1490000, position=404418]]
getPosition(2980000) = [[timeUs=2980000, position=408843]]
numberOfTracks = 1
track 0:
total output bytes = 8850
sample count = 150
format 0:
id = 1
sampleMimeType = audio/amr-wb
maxInputSize = 89
channelCount = 1
sampleRate = 16000
language = und
metadata = entries=[Mp4Timestamp: creation time=100000000, modification time=500000000, timescale=10000]
sample 0:
time = 0
flags = 1
data = length 59, hash 7CD1831D
sample 1:
time = 20000
flags = 1
data = length 59, hash D3770C4A
sample 2:
time = 40000
flags = 1
data = length 59, hash 9FE1F1DC
sample 3:
time = 60000
flags = 1
data = length 59, hash E01D2E94
sample 4:
time = 80000
flags = 1
data = length 59, hash 9F0F1148
sample 5:
time = 100000
flags = 1
data = length 59, hash 84844FC5
sample 6:
time = 120000
flags = 1
data = length 59, hash E1BA9151
sample 7:
time = 140000
flags = 1
data = length 59, hash 809C53C7
sample 8:
time = 160000
flags = 1
data = length 59, hash CF7C326C
sample 9:
time = 180000
flags = 1
data = length 59, hash 9493FCC5
sample 10:
time = 200000
flags = 1
data = length 59, hash 7E1C0B55
sample 11:
time = 220000
flags = 1
data = length 59, hash 590CE70F
sample 12:
time = 240000
flags = 1
data = length 59, hash AE96EA
sample 13:
time = 260000
flags = 1
data = length 59, hash 101B6F1F
sample 14:
time = 280000
flags = 1
data = length 59, hash A7B53E8
sample 15:
time = 300000
flags = 1
data = length 59, hash ADFF0186
sample 16:
time = 320000
flags = 1
data = length 59, hash 62429AE2
sample 17:
time = 340000
flags = 1
data = length 59, hash C0DE98C4
sample 18:
time = 360000
flags = 1
data = length 59, hash 38248344
sample 19:
time = 380000
flags = 1
data = length 59, hash 6FA9C78D
sample 20:
time = 400000
flags = 1
data = length 59, hash 70E62506
sample 21:
time = 420000
flags = 1
data = length 59, hash C5852B4D
sample 22:
time = 440000
flags = 1
data = length 59, hash 3963835
sample 23:
time = 460000
flags = 1
data = length 59, hash 12332285
sample 24:
time = 480000
flags = 1
data = length 59, hash 6992A084
sample 25:
time = 500000
flags = 1
data = length 59, hash 5F571FDF
sample 26:
time = 520000
flags = 1
data = length 59, hash 3897B324
sample 27:
time = 540000
flags = 1
data = length 59, hash E55F2655
sample 28:
time = 560000
flags = 1
data = length 59, hash 2EEF8B7B
sample 29:
time = 580000
flags = 1
data = length 59, hash 5C36A7D6
sample 30:
time = 600000
flags = 1
data = length 59, hash EA18CD8F
sample 31:
time = 620000
flags = 1
data = length 59, hash 2C2702ED
sample 32:
time = 640000
flags = 1
data = length 59, hash 31438CAF
sample 33:
time = 660000
flags = 1
data = length 59, hash 5F8FD154
sample 34:
time = 680000
flags = 1
data = length 59, hash 9D352097
sample 35:
time = 700000
flags = 1
data = length 59, hash D7EA644
sample 36:
time = 720000
flags = 1
data = length 59, hash 8905564B
sample 37:
time = 740000
flags = 1
data = length 59, hash 8FCB240C
sample 38:
time = 760000
flags = 1
data = length 59, hash B74A9E26
sample 39:
time = 780000
flags = 1
data = length 59, hash EA79D25B
sample 40:
time = 800000
flags = 1
data = length 59, hash 798EC537
sample 41:
time = 820000
flags = 1
data = length 59, hash F4D614DE
sample 42:
time = 840000
flags = 1
data = length 59, hash 9F3F5B91
sample 43:
time = 860000
flags = 1
data = length 59, hash B04F058
sample 44:
time = 880000
flags = 1
data = length 59, hash 8758EDC0
sample 45:
time = 900000
flags = 1
data = length 59, hash DFBCAE27
sample 46:
time = 920000
flags = 1
data = length 59, hash BF6AF6FD
sample 47:
time = 940000
flags = 1
data = length 59, hash 319B3149
sample 48:
time = 960000
flags = 1
data = length 59, hash 8CA30C36
sample 49:
time = 980000
flags = 1
data = length 59, hash 74CD82DA
sample 50:
time = 1000000
flags = 1
data = length 59, hash 8123D422
sample 51:
time = 1020000
flags = 1
data = length 59, hash 697DFCCA
sample 52:
time = 1040000
flags = 1
data = length 59, hash 40EC178E
sample 53:
time = 1060000
flags = 1
data = length 59, hash C8418BE1
sample 54:
time = 1080000
flags = 1
data = length 59, hash 7AC2CF25
sample 55:
time = 1100000
flags = 1
data = length 59, hash BCCEFF19
sample 56:
time = 1120000
flags = 1
data = length 59, hash 975A96
sample 57:
time = 1140000
flags = 1
data = length 59, hash 8F187C30
sample 58:
time = 1160000
flags = 1
data = length 59, hash D7797178
sample 59:
time = 1180000
flags = 1
data = length 59, hash CE6E8CA6
sample 60:
time = 1200000
flags = 1
data = length 59, hash 5A50B1A8
sample 61:
time = 1220000
flags = 1
data = length 59, hash ADDECF9A
sample 62:
time = 1240000
flags = 1
data = length 59, hash C5F376FF
sample 63:
time = 1260000
flags = 1
data = length 59, hash 1A83DF9A
sample 64:
time = 1280000
flags = 1
data = length 59, hash AC44CC85
sample 65:
time = 1300000
flags = 1
data = length 59, hash FE8D7E6D
sample 66:
time = 1320000
flags = 1
data = length 59, hash 50269ED4
sample 67:
time = 1340000
flags = 1
data = length 59, hash 1CC6FC25
sample 68:
time = 1360000
flags = 1
data = length 59, hash 6A4092A7
sample 69:
time = 1380000
flags = 1
data = length 59, hash 68C46314
sample 70:
time = 1400000
flags = 1
data = length 59, hash 5964275A
sample 71:
time = 1420000
flags = 1
data = length 59, hash 3130A785
sample 72:
time = 1440000
flags = 1
data = length 59, hash 83F2D996
sample 73:
time = 1460000
flags = 1
data = length 59, hash 515A062A
sample 74:
time = 1480000
flags = 1
data = length 59, hash 1D64DD8B
sample 75:
time = 1500000
flags = 1
data = length 59, hash 63587E3
sample 76:
time = 1520000
flags = 1
data = length 59, hash 68DCB927
sample 77:
time = 1540000
flags = 1
data = length 59, hash CDBA3C67
sample 78:
time = 1560000
flags = 1
data = length 59, hash 12A67F90
sample 79:
time = 1580000
flags = 1
data = length 59, hash 61159E34
sample 80:
time = 1600000
flags = 1
data = length 59, hash 45A73FB9
sample 81:
time = 1620000
flags = 1
data = length 59, hash 5A841075
sample 82:
time = 1640000
flags = 1
data = length 59, hash EBCDC2CA
sample 83:
time = 1660000
flags = 1
data = length 59, hash F751E192
sample 84:
time = 1680000
flags = 1
data = length 59, hash 5F8907C6
sample 85:
time = 1700000
flags = 1
data = length 59, hash FC73C275
sample 86:
time = 1720000
flags = 1
data = length 59, hash 2D4154EB
sample 87:
time = 1740000
flags = 1
data = length 59, hash ECA668E1
sample 88:
time = 1760000
flags = 1
data = length 59, hash 8C27620A
sample 89:
time = 1780000
flags = 1
data = length 59, hash 8D8BC449
sample 90:
time = 1800000
flags = 1
data = length 59, hash 332FDB24
sample 91:
time = 1820000
flags = 1
data = length 59, hash 33C2F5AF
sample 92:
time = 1840000
flags = 1
data = length 59, hash E08089D5
sample 93:
time = 1860000
flags = 1
data = length 59, hash A0A51B67
sample 94:
time = 1880000
flags = 1
data = length 59, hash 14B84283
sample 95:
time = 1900000
flags = 1
data = length 59, hash BB7F61C6
sample 96:
time = 1920000
flags = 1
data = length 59, hash C870B629
sample 97:
time = 1940000
flags = 1
data = length 59, hash DA557DDA
sample 98:
time = 1960000
flags = 1
data = length 59, hash 4E7D8042
sample 99:
time = 1980000
flags = 1
data = length 59, hash 91060D4A
sample 100:
time = 2000000
flags = 1
data = length 59, hash 676F457A
sample 101:
time = 2020000
flags = 1
data = length 59, hash 8BE7A3E2
sample 102:
time = 2040000
flags = 1
data = length 59, hash 8B5F28E4
sample 103:
time = 2060000
flags = 1
data = length 59, hash 88288529
sample 104:
time = 2080000
flags = 1
data = length 59, hash 52EF420D
sample 105:
time = 2100000
flags = 1
data = length 59, hash DA4DA53B
sample 106:
time = 2120000
flags = 1
data = length 59, hash CC3284E
sample 107:
time = 2140000
flags = 1
data = length 59, hash 371BB544
sample 108:
time = 2160000
flags = 1
data = length 59, hash E40EE9CA
sample 109:
time = 2180000
flags = 1
data = length 59, hash C070679F
sample 110:
time = 2200000
flags = 1
data = length 59, hash F62B5F23
sample 111:
time = 2220000
flags = 1
data = length 59, hash 1C265EC6
sample 112:
time = 2240000
flags = 1
data = length 59, hash AF49562
sample 113:
time = 2260000
flags = 1
data = length 59, hash F3E1441B
sample 114:
time = 2280000
flags = 1
data = length 59, hash 808BA758
sample 115:
time = 2300000
flags = 1
data = length 59, hash 17931F4C
sample 116:
time = 2320000
flags = 1
data = length 59, hash 59EBFB2C
sample 117:
time = 2340000
flags = 1
data = length 59, hash 48CBD767
sample 118:
time = 2360000
flags = 1
data = length 59, hash 37F0E68C
sample 119:
time = 2380000
flags = 1
data = length 59, hash 78D9C594
sample 120:
time = 2400000
flags = 1
data = length 59, hash BC29DE1A
sample 121:
time = 2420000
flags = 1
data = length 59, hash 30D57FD8
sample 122:
time = 2440000
flags = 1
data = length 59, hash 11EBFCA7
sample 123:
time = 2460000
flags = 1
data = length 59, hash 4A073D0
sample 124:
time = 2480000
flags = 1
data = length 59, hash AAE23356
sample 125:
time = 2500000
flags = 1
data = length 59, hash 8CD60F62
sample 126:
time = 2520000
flags = 1
data = length 59, hash 413DF0E5
sample 127:
time = 2540000
flags = 1
data = length 59, hash E0A6E95
sample 128:
time = 2560000
flags = 1
data = length 59, hash 3E41A79F
sample 129:
time = 2580000
flags = 1
data = length 59, hash 74E52392
sample 130:
time = 2600000
flags = 1
data = length 59, hash 4730E2F8
sample 131:
time = 2620000
flags = 1
data = length 59, hash F76800F3
sample 132:
time = 2640000
flags = 1
data = length 59, hash 6EAFD6A7
sample 133:
time = 2660000
flags = 1
data = length 59, hash F22E2D70
sample 134:
time = 2680000
flags = 1
data = length 59, hash 70229933
sample 135:
time = 2700000
flags = 1
data = length 59, hash 6FF33D1C
sample 136:
time = 2720000
flags = 1
data = length 59, hash 83EC00FE
sample 137:
time = 2740000
flags = 1
data = length 59, hash 292A2AFD
sample 138:
time = 2760000
flags = 1
data = length 59, hash A4ECB34E
sample 139:
time = 2780000
flags = 1
data = length 59, hash 7B1A9983
sample 140:
time = 2800000
flags = 1
data = length 59, hash 486E9059
sample 141:
time = 2820000
flags = 1
data = length 59, hash 2255918
sample 142:
time = 2840000
flags = 1
data = length 59, hash 33DC9432
sample 143:
time = 2860000
flags = 1
data = length 59, hash 41D0A458
sample 144:
time = 2880000
flags = 1
data = length 59, hash DBA9CED6
sample 145:
time = 2900000
flags = 1
data = length 59, hash FA055524
sample 146:
time = 2920000
flags = 1
data = length 59, hash A4146B9E
sample 147:
time = 2940000
flags = 1
data = length 59, hash 2DC246A0
sample 148:
time = 2960000
flags = 1
data = length 59, hash 4A8B5F2A
sample 149:
time = 2980000
flags = 536870913
data = length 59, hash D3223AAC
tracksEnded = true