Skip to content

Commit 130ac1e

Browse files
committed
Add detection for DTS-HD audio tracks in MatroskaExtractor
Distinguish between DTS and DTS-HD formats by analyzing the frame data in matroska containers. This enables accurate MIME type assignment for DTS-HD content.
1 parent 9df933f commit 130ac1e

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

libraries/extractor/src/main/java/androidx/media3/extractor/mkv/MatroskaExtractor.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import androidx.media3.extractor.AacUtil;
4747
import androidx.media3.extractor.AvcConfig;
4848
import androidx.media3.extractor.ChunkIndex;
49+
import androidx.media3.extractor.DtsUtil;
4950
import androidx.media3.extractor.Extractor;
5051
import androidx.media3.extractor.ExtractorInput;
5152
import androidx.media3.extractor.ExtractorOutput;
@@ -1564,6 +1565,51 @@ private int writeSampleData(ExtractorInput input, Track track, int size, boolean
15641565
return finishWriteSampleData();
15651566
}
15661567

1568+
if (CODEC_ID_DTS.equals(track.codecId) && !track.dtsAnalyzed) {
1569+
long remaining = input.getLength() - input.getPosition();
1570+
// Limit the peek ahead to be up to the max frame size (16383) plus the
1571+
// sync word of the second frame
1572+
int scanLength = (int)Math.min(16383 + 95, remaining);
1573+
byte[] buf = new byte[scanLength];
1574+
track.dtsAnalyzed = true;
1575+
1576+
input.advancePeekPosition(0);
1577+
input.peekFully(buf, 0, buf.length);
1578+
input.resetPeekPosition();
1579+
1580+
final ByteBuffer bb = ByteBuffer.wrap(buf);
1581+
for (int idx = 0; idx + 4 <= buf.length; idx += 4) {
1582+
int word = bb.getInt(idx);
1583+
1584+
if (DtsUtil.getFrameType(word) == DtsUtil.FRAME_TYPE_CORE) {
1585+
if (idx + 10 > buf.length) {
1586+
break;
1587+
}
1588+
1589+
bb.mark();
1590+
bb.position(idx);
1591+
byte[] header = new byte[10];
1592+
bb.get(header);
1593+
bb.reset();
1594+
int fsize = DtsUtil.getDtsFrameSize(header);
1595+
if (fsize <= 0 || idx + fsize + 4 > buf.length) {
1596+
break;
1597+
}
1598+
1599+
word = bb.getInt(idx + fsize);
1600+
1601+
if (DtsUtil.getFrameType(word) == DtsUtil.FRAME_TYPE_EXTENSION_SUBSTREAM) {
1602+
track.formatBuilder.setSampleMimeType(MimeTypes.AUDIO_DTS_HD);
1603+
track.output.format(track.formatBuilder.build());
1604+
}
1605+
1606+
// After finding a valid DTS core frame we can break the loop, there is no
1607+
// need to evaluate the rest of the buffer.
1608+
break;
1609+
}
1610+
}
1611+
}
1612+
15671613
TrackOutput output = track.output;
15681614
if (!sampleEncodingHandled) {
15691615
if (track.hasContentEncryption) {
@@ -2135,6 +2181,7 @@ protected static final class Track {
21352181
public long codecDelayNs = 0;
21362182
public long seekPreRollNs = 0;
21372183
public @MonotonicNonNull TrueHdSampleRechunker trueHdSampleRechunker;
2184+
public boolean dtsAnalyzed = false;
21382185

21392186
// Text elements.
21402187
public boolean flagForced;
@@ -2143,6 +2190,7 @@ protected static final class Track {
21432190

21442191
// Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265.
21452192
public @MonotonicNonNull TrackOutput output;
2193+
public Format.Builder formatBuilder;
21462194
public int nalUnitLengthFieldLength;
21472195

21482196
/** Initializes the track with an output. */
@@ -2369,7 +2417,7 @@ public void initializeOutput(ExtractorOutput output, int trackId) throws ParserE
23692417
selectionFlags |= flagForced ? C.SELECTION_FLAG_FORCED : 0;
23702418

23712419
int type;
2372-
Format.Builder formatBuilder = new Format.Builder();
2420+
formatBuilder = new Format.Builder();
23732421
// TODO: Consider reading the name elements of the tracks and, if present, incorporating them
23742422
// into the trackId passed when creating the formats.
23752423
if (MimeTypes.isAudio(mimeType)) {

0 commit comments

Comments
 (0)