46
46
import androidx .media3 .extractor .AacUtil ;
47
47
import androidx .media3 .extractor .AvcConfig ;
48
48
import androidx .media3 .extractor .ChunkIndex ;
49
+ import androidx .media3 .extractor .DtsUtil ;
49
50
import androidx .media3 .extractor .Extractor ;
50
51
import androidx .media3 .extractor .ExtractorInput ;
51
52
import androidx .media3 .extractor .ExtractorOutput ;
@@ -1564,6 +1565,53 @@ private int writeSampleData(ExtractorInput input, Track track, int size, boolean
1564
1565
return finishWriteSampleData ();
1565
1566
}
1566
1567
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
+ // header starts immediately after the 4‐byte sync
1586
+ int headerStart = idx + 4 ;
1587
+ if (headerStart + 10 > buf .length ) {
1588
+ break ;
1589
+ }
1590
+
1591
+ bb .mark ();
1592
+ bb .position (headerStart );
1593
+ byte [] header = new byte [10 ];
1594
+ bb .get (header );
1595
+ bb .reset ();
1596
+ int fsize = DtsUtil .getDtsFrameSize (header );
1597
+ if (fsize <= 0 || idx + fsize + 4 > buf .length ) {
1598
+ break ;
1599
+ }
1600
+
1601
+ word = bb .getInt (idx + fsize );
1602
+
1603
+ if (DtsUtil .getFrameType (word ) == DtsUtil .FRAME_TYPE_EXTENSION_SUBSTREAM ) {
1604
+ track .formatBuilder .setSampleMimeType (MimeTypes .AUDIO_DTS_HD );
1605
+ track .output .format (track .formatBuilder .build ());
1606
+ }
1607
+
1608
+ // After finding a valid DTS core frame we can break the loop, there is no
1609
+ // need to evaluate the rest of the buffer.
1610
+ break ;
1611
+ }
1612
+ }
1613
+ }
1614
+
1567
1615
TrackOutput output = track .output ;
1568
1616
if (!sampleEncodingHandled ) {
1569
1617
if (track .hasContentEncryption ) {
@@ -2135,6 +2183,7 @@ protected static final class Track {
2135
2183
public long codecDelayNs = 0 ;
2136
2184
public long seekPreRollNs = 0 ;
2137
2185
public @ MonotonicNonNull TrueHdSampleRechunker trueHdSampleRechunker ;
2186
+ public boolean dtsAnalyzed = false ;
2138
2187
2139
2188
// Text elements.
2140
2189
public boolean flagForced ;
@@ -2143,6 +2192,7 @@ protected static final class Track {
2143
2192
2144
2193
// Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265.
2145
2194
public @ MonotonicNonNull TrackOutput output ;
2195
+ public Format .Builder formatBuilder ;
2146
2196
public int nalUnitLengthFieldLength ;
2147
2197
2148
2198
/** Initializes the track with an output. */
@@ -2369,7 +2419,7 @@ public void initializeOutput(ExtractorOutput output, int trackId) throws ParserE
2369
2419
selectionFlags |= flagForced ? C .SELECTION_FLAG_FORCED : 0 ;
2370
2420
2371
2421
int type ;
2372
- Format . Builder formatBuilder = new Format .Builder ();
2422
+ formatBuilder = new Format .Builder ();
2373
2423
// TODO: Consider reading the name elements of the tracks and, if present, incorporating them
2374
2424
// into the trackId passed when creating the formats.
2375
2425
if (MimeTypes .isAudio (mimeType )) {
0 commit comments