Skip to content

Commit

Permalink
Support parsing MPEG-H 3D Audio
Browse files Browse the repository at this point in the history
First intention to support parsing MPEG-H 3D Audio in ExoPlayer is to
take advantage of parsing capability from MediaParser API in AOSP.
Just with this change ExoPlayer does't support decoding MPEG-H 3D Audio
but can support decoding either by adding decoder with an extension or
by using Android OS which has decoder capability with MediaCodec API.
  • Loading branch information
KeiMurayamaS committed May 10, 2021
1 parent 7f2922d commit f05197c
Show file tree
Hide file tree
Showing 16 changed files with 1,994 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public final class MimeTypes {
public static final String AUDIO_MSGSM = BASE_TYPE_AUDIO + "/gsm";
public static final String AUDIO_OGG = BASE_TYPE_AUDIO + "/ogg";
public static final String AUDIO_WAV = BASE_TYPE_AUDIO + "/wav";
public static final String AUDIO_MPEGH_MHA1 = BASE_TYPE_AUDIO + "/mha1";
public static final String AUDIO_MPEGH_MHM1 = BASE_TYPE_AUDIO + "/mhm1";
public static final String AUDIO_UNKNOWN = BASE_TYPE_AUDIO + "/x-unknown";

public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt";
Expand Down Expand Up @@ -391,6 +393,10 @@ public static String getMediaMimeType(@Nullable String codec) {
return MimeTypes.APPLICATION_CEA708;
} else if (codec.contains("eia608") || codec.contains("cea608")) {
return MimeTypes.APPLICATION_CEA608;
} else if (codec.startsWith("mha1")) {
return MimeTypes.AUDIO_MPEGH_MHA1;
} else if (codec.startsWith("mhm1")) {
return MimeTypes.AUDIO_MPEGH_MHM1;
} else {
return getCustomMimeTypeForCodec(codec);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,15 @@
@SuppressWarnings("ConstantCaseForConstants")
public static final int TYPE_twos = 0x74776f73;

@SuppressWarnings("ConstantCaseForConstants")
public static final int TYPE_mha1 = 0x6d686131;

@SuppressWarnings("ConstantCaseForConstants")
public static final int TYPE_mhm1 = 0x6d686d31;

@SuppressWarnings("ConstantCaseForConstants")
public static final int TYPE_mhaC = 0x6d686143;

public final int type;

public Atom(int type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,9 @@ private static StsdData parseStsd(
|| childAtomType == Atom.TYPE_alaw
|| childAtomType == Atom.TYPE_ulaw
|| childAtomType == Atom.TYPE_Opus
|| childAtomType == Atom.TYPE_fLaC) {
|| childAtomType == Atom.TYPE_fLaC
|| childAtomType == Atom.TYPE_mha1
|| childAtomType == Atom.TYPE_mhm1) {
parseAudioSampleEntry(
stsd,
childAtomType,
Expand Down Expand Up @@ -1358,6 +1360,10 @@ private static void parseAudioSampleEntry(
mimeType = MimeTypes.AUDIO_OPUS;
} else if (atomType == Atom.TYPE_fLaC) {
mimeType = MimeTypes.AUDIO_FLAC;
} else if (atomType == Atom.TYPE_mha1) {
mimeType = MimeTypes.AUDIO_MPEGH_MHA1;
} else if (atomType == Atom.TYPE_mhm1) {
mimeType = MimeTypes.AUDIO_MPEGH_MHM1;
}

@Nullable List<byte[]> initializationData = null;
Expand Down Expand Up @@ -1440,6 +1446,16 @@ private static void parseAudioSampleEntry(
sampleRate = audioSpecificConfig.first;
channelCount = audioSpecificConfig.second;
initializationData = ImmutableList.of(initializationDataBytes);
} else if (childAtomType == Atom.TYPE_mhaC) {
// See ISO_IEC_23008-3;2019 MHADecoderConfigurationRecord
int mhacHeaderSize = 4 /* size */ + 4 /* boxtype 'mhaC' */
+ 1 /* configurationVersion */ + 1 /* mpegh3daProfileLevelIndication */
+ 1 /* referenceChannelLayout */ + 2 /* mpegh3daConfigLength */;
int childAtomBodySize = childAtomSize - mhacHeaderSize;
byte[] initializationDataBytes = new byte[childAtomBodySize];
parent.setPosition(childPosition + mhacHeaderSize);
parent.readBytes(initializationDataBytes, 0, childAtomBodySize);
initializationData = ImmutableList.of(initializationDataBytes);
}
childPosition += childAtomSize;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,16 @@ public void mp4SampleWithOpusTrack() throws Exception {
ExtractorAsserts.assertBehavior(
Mp4Extractor::new, "media/mp4/sample_opus.mp4", simulationConfig);
}

@Test
public void mp4SampleWithMha1Track() throws Exception {
ExtractorAsserts.assertBehavior(
Mp4Extractor::new, "media/mp4/sample_mpegh_mha1.mp4", simulationConfig);
}

@Test
public void mp4SampleWithMhm1Track() throws Exception {
ExtractorAsserts.assertBehavior(
Mp4Extractor::new, "media/mp4/sample_mpegh_mhm1.mp4", simulationConfig);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
seekMap:
isSeekable = true
duration = 1168020
getPosition(0) = [[timeUs=0, position=1256]]
getPosition(1) = [[timeUs=1, position=1256]]
getPosition(584010) = [[timeUs=584010, position=46570]]
getPosition(1168020) = [[timeUs=1168020, position=91172]]
numberOfTracks = 1
track 0:
total output bytes = 104853
sample count = 58
format 0:
id = 1
sampleMimeType = audio/mha1
maxInputSize = 3528
channelCount = 0
sampleRate = 48000
encoderDelay = 3072
encoderPadding = 255
language = und
initializationData:
data = length 26, hash 4E58F6C7
sample 0:
time = 0
flags = 1
data = length 1706, hash F69B88EF
sample 1:
time = 21333
flags = 0
data = length 1705, hash 20F7927C
sample 2:
time = 42666
flags = 0
data = length 1900, hash D986BAA7
sample 3:
time = 64000
flags = 0
data = length 2224, hash DC056DA8
sample 4:
time = 85333
flags = 0
data = length 2157, hash D9587B29
sample 5:
time = 106666
flags = 0
data = length 2252, hash 9935FAC5
sample 6:
time = 128000
flags = 0
data = length 2025, hash 388EC449
sample 7:
time = 149333
flags = 0
data = length 1818, hash 148B1B72
sample 8:
time = 170666
flags = 0
data = length 1844, hash E997B535
sample 9:
time = 192000
flags = 0
data = length 1717, hash 2A9D93FB
sample 10:
time = 213333
flags = 0
data = length 1701, hash 40238DB5
sample 11:
time = 234666
flags = 0
data = length 1684, hash C46763BF
sample 12:
time = 256000
flags = 0
data = length 1747, hash 5FC3C86E
sample 13:
time = 277333
flags = 0
data = length 1750, hash 7F164780
sample 14:
time = 298666
flags = 0
data = length 1742, hash B853D24D
sample 15:
time = 320000
flags = 0
data = length 1839, hash FBFCDC4A
sample 16:
time = 341333
flags = 0
data = length 1809, hash C4722031
sample 17:
time = 362666
flags = 0
data = length 1746, hash 5990EC1F
sample 18:
time = 384000
flags = 0
data = length 1657, hash 1973E3C4
sample 19:
time = 405333
flags = 0
data = length 1862, hash 47500487
sample 20:
time = 426666
flags = 0
data = length 1687, hash 6789C2B4
sample 21:
time = 448000
flags = 0
data = length 1661, hash 26AB63E4
sample 22:
time = 469333
flags = 0
data = length 1671, hash 85AA94AD
sample 23:
time = 490666
flags = 0
data = length 1666, hash 60AF02C
sample 24:
time = 512000
flags = 0
data = length 1744, hash 93B89CC9
sample 25:
time = 533333
flags = 1
data = length 3498, hash 3013997F
sample 26:
time = 554666
flags = 0
data = length 1645, hash 912C7F11
sample 27:
time = 576000
flags = 0
data = length 1679, hash 5C1D5E4B
sample 28:
time = 597333
flags = 0
data = length 1653, hash AAFDF0C4
sample 29:
time = 618666
flags = 0
data = length 1793, hash 7DEDF0E7
sample 30:
time = 640000
flags = 0
data = length 1673, hash 5123A069
sample 31:
time = 661333
flags = 0
data = length 1631, hash 668D073B
sample 32:
time = 682666
flags = 0
data = length 1645, hash 4BA09D58
sample 33:
time = 704000
flags = 0
data = length 1715, hash 6696D08A
sample 34:
time = 725333
flags = 0
data = length 1913, hash F22841A5
sample 35:
time = 746666
flags = 0
data = length 1808, hash 3EB2EF9A
sample 36:
time = 768000
flags = 0
data = length 1703, hash A76E92E6
sample 37:
time = 789333
flags = 0
data = length 1663, hash D60564B6
sample 38:
time = 810666
flags = 0
data = length 1691, hash 3E9DB1D0
sample 39:
time = 832000
flags = 0
data = length 1682, hash 66EF509A
sample 40:
time = 853333
flags = 0
data = length 1661, hash 1F1114BE
sample 41:
time = 874666
flags = 0
data = length 1651, hash 37C9B7B6
sample 42:
time = 896000
flags = 0
data = length 1675, hash 94616355
sample 43:
time = 917333
flags = 0
data = length 1671, hash DA7F4549
sample 44:
time = 938666
flags = 0
data = length 1799, hash 49EF8B35
sample 45:
time = 960000
flags = 0
data = length 1807, hash C8BDF3C1
sample 46:
time = 981333
flags = 0
data = length 1674, hash 36EA2B2F
sample 47:
time = 1002666
flags = 0
data = length 1662, hash A865F92C
sample 48:
time = 1024000
flags = 0
data = length 1856, hash D20294BC
sample 49:
time = 1045333
flags = 0
data = length 1754, hash 54C7681A
sample 50:
time = 1066666
flags = 1
data = length 3408, hash 48774BB2
sample 51:
time = 1088000
flags = 0
data = length 1602, hash 8E895F43
sample 52:
time = 1109333
flags = 0
data = length 1624, hash 9E0AD8CF
sample 53:
time = 1130666
flags = 0
data = length 1616, hash 1F123433
sample 54:
time = 1152000
flags = 0
data = length 1671, hash 29644955
sample 55:
time = 1173333
flags = 0
data = length 1641, hash 55E8050C
sample 56:
time = 1194666
flags = 0
data = length 1670, hash CC133185
sample 57:
time = 1216000
flags = 536870912
data = length 1705, hash 35C3F104
tracksEnded = true
Loading

0 comments on commit f05197c

Please sign in to comment.