Skip to content

Commit 4d408d0

Browse files
nift4rohitjoins
authored andcommitted
Enable accurate mime type assignment for DTS-HD in TS
Read more of the DTS-HD header in order to find out extension substream type, to get correct mime type which is relevant for buffer size decision logic (as DTS Express has way lower maximum bit rate than DTS-HD). Issue: androidx#2487 Issue: androidx#3147
1 parent 38f5c46 commit 4d408d0

6 files changed

Lines changed: 176 additions & 10 deletions

File tree

libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java

Lines changed: 171 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ public static DtsHeader parseDtsHdHeader(byte[] header) throws ParserException {
429429
int assetsCount; // nuNumAssets
430430
int referenceClockCode; // nuRefClockCode
431431
int extensionSubstreamFrameDurationCode; // nuExSSFrameDurationCode
432+
boolean enableMixMetadata = false; // bMixMetadataEnbl
433+
int[] mixerOutChannels = null;
432434

433435
boolean staticFieldsPresent = headerBits.readBit(); // bStaticFieldsPresent
434436
if (staticFieldsPresent) {
@@ -456,13 +458,16 @@ public static DtsHeader parseDtsHdHeader(byte[] header) throws ParserException {
456458
}
457459
}
458460

459-
if (headerBits.readBit()) { // bMixMetadataEnbl
461+
enableMixMetadata = headerBits.readBit();
462+
if (enableMixMetadata) { // bMixMetadataEnbl
460463
headerBits.skipBits(2); // nuMixMetadataAdjLevel
461464
int mixerOutputMaskBits = (headerBits.readBits(2) + 1) << 2; // nuBits4MixOutMask
462465
int mixerOutputConfigurationCount = headerBits.readBits(2) + 1; // nuNumMixOutConfigs
466+
mixerOutChannels = new int[mixerOutputConfigurationCount];
463467
// Output Mixing Configuration Loop
464468
for (int i = 0; i < mixerOutputConfigurationCount; i++) {
465-
headerBits.skipBits(mixerOutputMaskBits); // nuMixOutChMask
469+
int mask = headerBits.readBits(mixerOutputMaskBits); // nuMixOutChMask
470+
mixerOutChannels[i] = getRemapChannelCount(mask);
466471
}
467472
}
468473
} else {
@@ -476,8 +481,11 @@ public static DtsHeader parseDtsHdHeader(byte[] header) throws ParserException {
476481
headerBits.skipBits(extensionSubstreamFrameSizeBits); // nuAssetFsize
477482
int sampleRate = C.RATE_UNSET_INT;
478483
int channelCount = C.LENGTH_UNSET; // nuTotalNumChs
484+
boolean embeddedStereo = false; // bEmbeddedStereoFlag
485+
boolean embedded6ch = false; // bEmbeddedSixChFlag
479486

480-
// Asset descriptor, see ETSI TS 102 114 V1.6.1 (2019-08) Table 7-5.
487+
// Asset descriptor: Size, Index and Per Stream Static Metadata, see ETSI TS 102 114 V1.6.1
488+
// (2019-08) Table 7-5.
481489
headerBits.skipBits(9 + 3); // nuAssetDescriptFsize, nuAssetIndex
482490
if (staticFieldsPresent) {
483491
if (headerBits.readBit()) { // bAssetTypeDescrPresent
@@ -493,9 +501,113 @@ public static DtsHeader parseDtsHdHeader(byte[] header) throws ParserException {
493501
headerBits.skipBits(5); // nuBitResolution
494502
sampleRate = SAMPLE_RATE_BY_INDEX[headerBits.readBits(4)]; // nuMaxSampleRate
495503
channelCount = headerBits.readBits(8) + 1;
496-
// Done reading necessary bits, ignoring the rest.
504+
if (headerBits.readBit()) { // bOne2OneMapChannels2Speakers
505+
if (channelCount > 2) {
506+
embeddedStereo = headerBits.readBit(); // bEmbeddedStereoFlag
507+
}
508+
if (channelCount > 6) {
509+
embedded6ch = headerBits.readBit(); // bEmbeddedSixChFlag
510+
}
511+
int speakerMaskLength = 0;
512+
if (headerBits.readBit()) { // bSpkrMaskEnabled
513+
speakerMaskLength = (headerBits.readBits(2) + 1) << 2; // nuNumBits4SAMask
514+
headerBits.skipBits(speakerMaskLength); // nuSpkrActivityMask
515+
}
516+
int speakerRemapSetsCount = headerBits.readBits(3); // nuNumSpkrRemapSets
517+
int[] speakerRemapSets = new int[speakerRemapSetsCount];
518+
for (int i = 0; i < speakerRemapSetsCount; i++) {
519+
speakerRemapSets[i] = headerBits.readBits(speakerMaskLength); // nuStndrSpkrLayoutMask[ns]
520+
}
521+
for (int i = 0; i < speakerRemapSetsCount; i++) {
522+
int remapChannelCount = getRemapChannelCount(speakerRemapSets[i]);
523+
int remapMaskLength = headerBits.readBits(5) + 1; // nuNumDecCh4Remap[ns]
524+
for (int j = 0; j < remapChannelCount; j++) {
525+
int remapMask = headerBits.readBits(remapMaskLength); // nuRemapDecChMask[ns][nCh]
526+
int coef = Integer.bitCount(remapMask); // nCoef
527+
headerBits.skipBits(coef * 5); // nuSpkrRemapCodes[ns][nCh][nc]
528+
}
529+
}
530+
}
531+
} else {
532+
headerBits.skipBits(3); // nuRepresentationType
497533
}
498534

535+
// Asset descriptor: Dynamic Metadata - DRC, DNC and Mixing Metadata, see ETSI TS 102 114 V1.6.1
536+
// (2019-08) Table 7-6.
537+
boolean hasDrcCoef = headerBits.readBit();
538+
if (hasDrcCoef) { // bDRCCoefPresent
539+
headerBits.skipBits(8); // nuDRCCode
540+
}
541+
if (headerBits.readBit()) { // bDialNormPresent
542+
headerBits.skipBits(5); // nuDialNormCode
543+
}
544+
if (hasDrcCoef && embeddedStereo) {
545+
headerBits.skipBits(8); // nuDRC2ChDmixCode
546+
}
547+
if (enableMixMetadata && headerBits.readBit()) { // bMixMetadataPresent
548+
headerBits.skipBits(1 + 6); // bExternalMixFlag, nuPostMixGainAdjCode
549+
if (headerBits.readBits(2) < 3) { // nuControlMixerDRC
550+
headerBits.skipBits(3); // nuLimit4EmbeddedDRC
551+
} else {
552+
headerBits.skipBits(8); // nuCustomDRCCode
553+
}
554+
boolean audioScalePerChannel = headerBits.readBit(); // bEnblPerChMainAudioScale
555+
for (int mixerOutChannel : mixerOutChannels) {
556+
if (audioScalePerChannel) {
557+
headerBits.skipBits(6 * mixerOutChannel); // nuMainAudioScaleCode[ns][nCh]
558+
} else {
559+
headerBits.skipBits(6); // nuMainAudioScaleCode[ns][0]
560+
}
561+
}
562+
int mixesCount = 1; // nEmDM
563+
int[] channelCountsForDownmixes = new int[3];
564+
channelCountsForDownmixes[0] = channelCount; // nDecCh[0]
565+
if (embedded6ch) {
566+
channelCountsForDownmixes[mixesCount] = 6; // nDecCh[nEmDM]
567+
mixesCount++; // nEmDM
568+
}
569+
if (embeddedStereo) {
570+
channelCountsForDownmixes[mixesCount] = 2; // nDecCh[nEmDM]
571+
mixesCount++; // nEmDM
572+
}
573+
for (int mixerOutChannel : mixerOutChannels) {
574+
for (int downmix = 0; downmix < mixesCount; downmix++) {
575+
int channelCountForDownmix = channelCountsForDownmixes[downmix];
576+
for (int downmixChannel = 0; downmixChannel < channelCountForDownmix; downmixChannel++) {
577+
int mask = headerBits.readBits(mixerOutChannel); // nuMixMapMask[ns][nE][nCh]
578+
int coefficients = Integer.bitCount(mask); // nuNumMixCoefs[ns][nE][nCh]
579+
headerBits.skipBits(coefficients * 6); // nuMixCoeffs[ns][nE][nCh][nC]
580+
}
581+
}
582+
}
583+
}
584+
585+
// Asset descriptor: Decoder Navigation Data, see ETSI TS 102 114 V1.6.1 (2019-08) Table 7-7.
586+
int codingMode = headerBits.readBits(2); // nuCodingMode
587+
String mimeType;
588+
switch (codingMode) {
589+
case 0: // DTS-HD Coding Mode that may contain multiple coding components
590+
int extensionMask = headerBits.readBits(12);
591+
if ((extensionMask & 0x100) != 0) { // Low bit rate component
592+
mimeType = MimeTypes.AUDIO_DTS_EXPRESS;
593+
} else {
594+
mimeType = MimeTypes.AUDIO_DTS_HD;
595+
}
596+
break;
597+
case 1: // DTS-HD Loss-less coding mode without CBR component
598+
mimeType = MimeTypes.AUDIO_DTS_HD;
599+
break;
600+
case 2: // DTS-HD Low bit-rate mode
601+
mimeType = MimeTypes.AUDIO_DTS_EXPRESS;
602+
break;
603+
case 3: // The auxiliary coding mode is reserved for future applications.
604+
default:
605+
throw ParserException.createForMalformedContainer(
606+
/* message= */ "Unsupported coding mode in DTS HD header: " + codingMode,
607+
/* cause= */ null);
608+
}
609+
// Done reading necessary bits, ignoring the rest.
610+
499611
long frameDurationUs = C.TIME_UNSET;
500612
if (staticFieldsPresent) {
501613
int referenceClockFrequency;
@@ -521,14 +633,68 @@ public static DtsHeader parseDtsHdHeader(byte[] header) throws ParserException {
521633
extensionSubstreamFrameDurationCode, C.MICROS_PER_SECOND, referenceClockFrequency);
522634
}
523635
return new DtsHeader(
524-
MimeTypes.AUDIO_DTS_EXPRESS,
636+
mimeType,
525637
channelCount,
526638
sampleRate,
527639
extensionSubstreamFrameSize,
528640
frameDurationUs,
529641
/* bitrate= */ 0);
530642
}
531643

644+
// See Table 7-10 in ETSI TS 102 114 V1.6.1
645+
private static int getRemapChannelCount(int mask) {
646+
int remapChannelCount = 0;
647+
if ((mask & 0x0001) != 0) { // Centre in front of listener
648+
remapChannelCount += 1;
649+
}
650+
if ((mask & 0x0002) != 0) { // Left/Right in front
651+
remapChannelCount += 2;
652+
}
653+
if ((mask & 0x0004) != 0) { // Left/Right surround on side in rear
654+
remapChannelCount += 2;
655+
}
656+
if ((mask & 0x0008) != 0) { // Low frequency effects subwoofer
657+
remapChannelCount += 1;
658+
}
659+
if ((mask & 0x0010) != 0) { // Centre surround in rear
660+
remapChannelCount += 1;
661+
}
662+
if ((mask & 0x0020) != 0) { // Left/Right height in front
663+
remapChannelCount += 2;
664+
}
665+
if ((mask & 0x0040) != 0) { // Left/Right surround in rear
666+
remapChannelCount += 2;
667+
}
668+
if ((mask & 0x0080) != 0) { // Centre Height in front
669+
remapChannelCount += 1;
670+
}
671+
if ((mask & 0x0100) != 0) { // Over the listener's head
672+
remapChannelCount += 1;
673+
}
674+
if ((mask & 0x0200) != 0) { // Between left/right and centre in front
675+
remapChannelCount += 2;
676+
}
677+
if ((mask & 0x0400) != 0) { // Left/Right on side in front
678+
remapChannelCount += 2;
679+
}
680+
if ((mask & 0x0800) != 0) { // Left/Right surround on side
681+
remapChannelCount += 2;
682+
}
683+
if ((mask & 0x1000) != 0) { // Second low frequency effects subwoofer
684+
remapChannelCount += 1;
685+
}
686+
if ((mask & 0x2000) != 0) { // Left/Right height on side
687+
remapChannelCount += 2;
688+
}
689+
if ((mask & 0x4000) != 0) { // Centre height in rear
690+
remapChannelCount += 1;
691+
}
692+
if ((mask & 0x8000) != 0) { // Left/Right height in rear
693+
remapChannelCount += 2;
694+
}
695+
return remapChannelCount;
696+
}
697+
532698
/**
533699
* Returns the size of the extension substream header in a DTS-HD frame according to ETSI TS 102
534700
* 114 V1.6.1 (2019-08), Section 7.5.2.

libraries/test_data/src/test/assets/extractordumps/ts/sample_dts_hd_ma.ts.0.dump

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ track 256:
1313
averageBitrate = 1536000
1414
id = 1/256
1515
containerMimeType = video/mp2t
16-
sampleMimeType = audio/vnd.dts.hd;profile=lbr
16+
sampleMimeType = audio/vnd.dts.hd
1717
channelCount = 8
1818
sampleRate = 48000
1919
language = en

libraries/test_data/src/test/assets/extractordumps/ts/sample_dts_hd_ma.ts.1.dump

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ track 256:
1313
averageBitrate = 1536000
1414
id = 1/256
1515
containerMimeType = video/mp2t
16-
sampleMimeType = audio/vnd.dts.hd;profile=lbr
16+
sampleMimeType = audio/vnd.dts.hd
1717
channelCount = 8
1818
sampleRate = 48000
1919
language = en

libraries/test_data/src/test/assets/extractordumps/ts/sample_dts_hd_ma.ts.2.dump

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ track 256:
1313
averageBitrate = 1536000
1414
id = 1/256
1515
containerMimeType = video/mp2t
16-
sampleMimeType = audio/vnd.dts.hd;profile=lbr
16+
sampleMimeType = audio/vnd.dts.hd
1717
channelCount = 8
1818
sampleRate = 48000
1919
language = en

libraries/test_data/src/test/assets/extractordumps/ts/sample_dts_hd_ma.ts.3.dump

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ track 256:
1313
averageBitrate = 1536000
1414
id = 1/256
1515
containerMimeType = video/mp2t
16-
sampleMimeType = audio/vnd.dts.hd;profile=lbr
16+
sampleMimeType = audio/vnd.dts.hd
1717
channelCount = 8
1818
sampleRate = 48000
1919
language = en

libraries/test_data/src/test/assets/extractordumps/ts/sample_dts_hd_ma.ts.unknown_length.dump

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ track 256:
1010
averageBitrate = 1536000
1111
id = 1/256
1212
containerMimeType = video/mp2t
13-
sampleMimeType = audio/vnd.dts.hd;profile=lbr
13+
sampleMimeType = audio/vnd.dts.hd
1414
channelCount = 8
1515
sampleRate = 48000
1616
language = en

0 commit comments

Comments
 (0)