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,51 @@ 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
+ 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
+
1567
1613
TrackOutput output = track .output ;
1568
1614
if (!sampleEncodingHandled ) {
1569
1615
if (track .hasContentEncryption ) {
@@ -2135,6 +2181,7 @@ protected static final class Track {
2135
2181
public long codecDelayNs = 0 ;
2136
2182
public long seekPreRollNs = 0 ;
2137
2183
public @ MonotonicNonNull TrueHdSampleRechunker trueHdSampleRechunker ;
2184
+ public boolean dtsAnalyzed = false ;
2138
2185
2139
2186
// Text elements.
2140
2187
public boolean flagForced ;
@@ -2143,6 +2190,7 @@ protected static final class Track {
2143
2190
2144
2191
// Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265.
2145
2192
public @ MonotonicNonNull TrackOutput output ;
2193
+ public Format .Builder formatBuilder ;
2146
2194
public int nalUnitLengthFieldLength ;
2147
2195
2148
2196
/** Initializes the track with an output. */
@@ -2369,7 +2417,7 @@ public void initializeOutput(ExtractorOutput output, int trackId) throws ParserE
2369
2417
selectionFlags |= flagForced ? C .SELECTION_FLAG_FORCED : 0 ;
2370
2418
2371
2419
int type ;
2372
- Format . Builder formatBuilder = new Format .Builder ();
2420
+ formatBuilder = new Format .Builder ();
2373
2421
// TODO: Consider reading the name elements of the tracks and, if present, incorporating them
2374
2422
// into the trackId passed when creating the formats.
2375
2423
if (MimeTypes .isAudio (mimeType )) {
0 commit comments