Commit 8e8e53c4 by andrewlewis Committed by Oliver Woodman

Add support for Dolby TrueHD passthrough

Issue: #2147

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=180678595
parent 7314e9bd
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
* DefaultTrackSelector: Support disabling of individual text track selection * DefaultTrackSelector: Support disabling of individual text track selection
flags. flags.
* New Cast extension: Simplifies toggling between local and Cast playbacks. * New Cast extension: Simplifies toggling between local and Cast playbacks.
* Audio: Support TrueHD passthrough for rechunked samples in Matroska files
([#2147](https://github.com/google/ExoPlayer/issues/2147)).
### 2.6.1 ### ### 2.6.1 ###
......
...@@ -122,13 +122,22 @@ public final class C { ...@@ -122,13 +122,22 @@ public final class C {
*/ */
public static final int AUDIO_SESSION_ID_UNSET = AudioManager.AUDIO_SESSION_ID_GENERATE; public static final int AUDIO_SESSION_ID_UNSET = AudioManager.AUDIO_SESSION_ID_GENERATE;
/** /** Represents an audio encoding, or an invalid or unset value. */
* Represents an audio encoding, or an invalid or unset value.
*/
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, @IntDef({
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT, ENCODING_AC3, ENCODING_E_AC3, Format.NO_VALUE,
ENCODING_DTS, ENCODING_DTS_HD}) ENCODING_INVALID,
ENCODING_PCM_8BIT,
ENCODING_PCM_16BIT,
ENCODING_PCM_24BIT,
ENCODING_PCM_32BIT,
ENCODING_PCM_FLOAT,
ENCODING_AC3,
ENCODING_E_AC3,
ENCODING_DTS,
ENCODING_DTS_HD,
ENCODING_DOLBY_TRUEHD
})
public @interface Encoding {} public @interface Encoding {}
/** /**
...@@ -138,46 +147,28 @@ public final class C { ...@@ -138,46 +147,28 @@ public final class C {
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, @IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT}) ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT})
public @interface PcmEncoding {} public @interface PcmEncoding {}
/** /** @see AudioFormat#ENCODING_INVALID */
* @see AudioFormat#ENCODING_INVALID
*/
public static final int ENCODING_INVALID = AudioFormat.ENCODING_INVALID; public static final int ENCODING_INVALID = AudioFormat.ENCODING_INVALID;
/** /** @see AudioFormat#ENCODING_PCM_8BIT */
* @see AudioFormat#ENCODING_PCM_8BIT
*/
public static final int ENCODING_PCM_8BIT = AudioFormat.ENCODING_PCM_8BIT; public static final int ENCODING_PCM_8BIT = AudioFormat.ENCODING_PCM_8BIT;
/** /** @see AudioFormat#ENCODING_PCM_16BIT */
* @see AudioFormat#ENCODING_PCM_16BIT
*/
public static final int ENCODING_PCM_16BIT = AudioFormat.ENCODING_PCM_16BIT; public static final int ENCODING_PCM_16BIT = AudioFormat.ENCODING_PCM_16BIT;
/** /** PCM encoding with 24 bits per sample. */
* PCM encoding with 24 bits per sample.
*/
public static final int ENCODING_PCM_24BIT = 0x80000000; public static final int ENCODING_PCM_24BIT = 0x80000000;
/** /** PCM encoding with 32 bits per sample. */
* PCM encoding with 32 bits per sample.
*/
public static final int ENCODING_PCM_32BIT = 0x40000000; public static final int ENCODING_PCM_32BIT = 0x40000000;
/** /** @see AudioFormat#ENCODING_PCM_FLOAT */
* @see AudioFormat#ENCODING_PCM_FLOAT
*/
public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT; public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT;
/** /** @see AudioFormat#ENCODING_AC3 */
* @see AudioFormat#ENCODING_AC3
*/
public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3; public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3;
/** /** @see AudioFormat#ENCODING_E_AC3 */
* @see AudioFormat#ENCODING_E_AC3
*/
public static final int ENCODING_E_AC3 = AudioFormat.ENCODING_E_AC3; public static final int ENCODING_E_AC3 = AudioFormat.ENCODING_E_AC3;
/** /** @see AudioFormat#ENCODING_DTS */
* @see AudioFormat#ENCODING_DTS
*/
public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS; public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS;
/** /** @see AudioFormat#ENCODING_DTS_HD */
* @see AudioFormat#ENCODING_DTS_HD
*/
public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD; public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD;
/** @see AudioFormat#ENCODING_DOLBY_TRUEHD */
public static final int ENCODING_DOLBY_TRUEHD = AudioFormat.ENCODING_DOLBY_TRUEHD;
/** /**
* @see AudioFormat#CHANNEL_OUT_7POINT1_SURROUND * @see AudioFormat#CHANNEL_OUT_7POINT1_SURROUND
......
...@@ -27,9 +27,7 @@ import com.google.android.exoplayer2.util.ParsableBitArray; ...@@ -27,9 +27,7 @@ import com.google.android.exoplayer2.util.ParsableBitArray;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /** Utility methods for parsing Dolby TrueHD and (E-)AC3 syncframes. */
* Utility methods for parsing (E-)AC-3 syncframes, which are access units in (E-)AC-3 bitstreams.
*/
public final class Ac3Util { public final class Ac3Util {
/** /**
...@@ -94,6 +92,17 @@ public final class Ac3Util { ...@@ -94,6 +92,17 @@ public final class Ac3Util {
} }
/** /**
* The number of samples to store in each output chunk when rechunking TrueHD streams. The number
* of samples extracted from the container corresponding to one syncframe must be an integer
* multiple of this value.
*/
public static final int TRUEHD_RECHUNK_SAMPLE_COUNT = 8;
/**
* The number of bytes that must be parsed from a TrueHD syncframe to calculate the sample count.
*/
public static final int TRUEHD_SYNCFRAME_PREFIX_LENGTH = 12;
/**
* The number of new samples per (E-)AC-3 audio block. * The number of new samples per (E-)AC-3 audio block.
*/ */
private static final int AUDIO_SAMPLES_PER_AUDIO_BLOCK = 256; private static final int AUDIO_SAMPLES_PER_AUDIO_BLOCK = 256;
...@@ -441,6 +450,43 @@ public final class Ac3Util { ...@@ -441,6 +450,43 @@ public final class Ac3Util {
: BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD[(buffer.get(buffer.position() + 4) & 0x30) >> 4]); : BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD[(buffer.get(buffer.position() + 4) & 0x30) >> 4]);
} }
/**
* Returns the number of audio samples represented by the given TrueHD syncframe, or 0 if the
* buffer is not the start of a syncframe.
*
* @param syncframe The bytes from which to read the syncframe. Must be at least {@link
* #TRUEHD_SYNCFRAME_PREFIX_LENGTH} bytes long.
* @return The number of audio samples represented by the syncframe, or 0 if the buffer doesn't
* contain the start of a syncframe.
*/
public static int parseTrueHdSyncframeAudioSampleCount(byte[] syncframe) {
// TODO: Link to specification if available.
if (syncframe[4] != (byte) 0xF8
|| syncframe[5] != (byte) 0x72
|| syncframe[6] != (byte) 0x6F
|| syncframe[7] != (byte) 0xBA) {
return 0;
}
return 40 << (syncframe[8] & 7);
}
/**
* Reads the number of audio samples represented by the given TrueHD syncframe, or 0 if the buffer
* is not the start of a syncframe. The buffer's position is not modified.
*
* @param buffer The {@link ByteBuffer} from which to read the syncframe. Must have at least
* {@link #TRUEHD_SYNCFRAME_PREFIX_LENGTH} bytes remaining.
* @return The number of audio samples represented by the syncframe, or 0 if the buffer is not the
* start of a syncframe.
*/
public static int parseTrueHdSyncframeAudioSampleCount(ByteBuffer buffer) {
// TODO: Link to specification if available.
if (buffer.getInt(buffer.position() + 4) != 0xBA6F72F8) {
return 0;
}
return 40 << (buffer.get(buffer.position() + 8) & 0x07);
}
private static int getAc3SyncframeSize(int fscod, int frmsizecod) { private static int getAc3SyncframeSize(int fscod, int frmsizecod) {
int halfFrmsizecod = frmsizecod / 2; int halfFrmsizecod = frmsizecod / 2;
if (fscod < 0 || fscod >= SAMPLE_RATE_BY_FSCOD.length || frmsizecod < 0 if (fscod < 0 || fscod >= SAMPLE_RATE_BY_FSCOD.length || frmsizecod < 0
......
...@@ -446,9 +446,12 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -446,9 +446,12 @@ public final class DefaultAudioSink implements AudioSink {
if (outputEncoding == C.ENCODING_AC3 || outputEncoding == C.ENCODING_E_AC3) { if (outputEncoding == C.ENCODING_AC3 || outputEncoding == C.ENCODING_E_AC3) {
// AC-3 allows bitrates up to 640 kbit/s. // AC-3 allows bitrates up to 640 kbit/s.
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 80 * 1024 / C.MICROS_PER_SECOND); bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 80 * 1024 / C.MICROS_PER_SECOND);
} else /* (outputEncoding == C.ENCODING_DTS || outputEncoding == C.ENCODING_DTS_HD */ { } else if (outputEncoding == C.ENCODING_DTS) {
// DTS allows an 'open' bitrate, but we assume the maximum listed value: 1536 kbit/s. // DTS allows an 'open' bitrate, but we assume the maximum listed value: 1536 kbit/s.
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 1024 / C.MICROS_PER_SECOND); bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 1024 / C.MICROS_PER_SECOND);
} else /* outputEncoding == C.ENCODING_DTS_HD || outputEncoding == C.ENCODING_DOLBY_TRUEHD*/ {
// HD passthrough requires a larger buffer to avoid underrun.
bufferSize = (int) (PASSTHROUGH_BUFFER_DURATION_US * 192 * 6 * 1024 / C.MICROS_PER_SECOND);
} }
} }
bufferSizeUs = bufferSizeUs =
...@@ -580,6 +583,13 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -580,6 +583,13 @@ public final class DefaultAudioSink implements AudioSink {
if (!isInputPcm && framesPerEncodedSample == 0) { if (!isInputPcm && framesPerEncodedSample == 0) {
// If this is the first encoded sample, calculate the sample size in frames. // If this is the first encoded sample, calculate the sample size in frames.
framesPerEncodedSample = getFramesPerEncodedSample(outputEncoding, buffer); framesPerEncodedSample = getFramesPerEncodedSample(outputEncoding, buffer);
if (framesPerEncodedSample == 0) {
// We still don't know the number of frames per sample, so drop the buffer.
// For TrueHD this can occur after some seek operations, as not every sample starts with
// a syncframe header. If we chunked samples together so the extracted samples always
// started with a syncframe header, the chunks would be too large.
return true;
}
} }
if (drainingPlaybackParameters != null) { if (drainingPlaybackParameters != null) {
...@@ -1225,6 +1235,9 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -1225,6 +1235,9 @@ public final class DefaultAudioSink implements AudioSink {
return Ac3Util.getAc3SyncframeAudioSampleCount(); return Ac3Util.getAc3SyncframeAudioSampleCount();
} else if (encoding == C.ENCODING_E_AC3) { } else if (encoding == C.ENCODING_E_AC3) {
return Ac3Util.parseEAc3SyncframeAudioSampleCount(buffer); return Ac3Util.parseEAc3SyncframeAudioSampleCount(buffer);
} else if (encoding == C.ENCODING_DOLBY_TRUEHD) {
return Ac3Util.parseTrueHdSyncframeAudioSampleCount(buffer)
* Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT;
} else { } else {
throw new IllegalStateException("Unexpected audio encoding: " + encoding); throw new IllegalStateException("Unexpected audio encoding: " + encoding);
} }
......
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
package com.google.android.exoplayer2.extractor.mkv; package com.google.android.exoplayer2.extractor.mkv;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.audio.Ac3Util;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.extractor.ChunkIndex; import com.google.android.exoplayer2.extractor.ChunkIndex;
...@@ -32,6 +34,7 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader; ...@@ -32,6 +34,7 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.LongArray; import com.google.android.exoplayer2.util.LongArray;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.NalUnitUtil; import com.google.android.exoplayer2.util.NalUnitUtil;
...@@ -413,6 +416,9 @@ public final class MatroskaExtractor implements Extractor { ...@@ -413,6 +416,9 @@ public final class MatroskaExtractor implements Extractor {
reader.reset(); reader.reset();
varintReader.reset(); varintReader.reset();
resetSample(); resetSample();
for (int i = 0; i < tracks.size(); i++) {
tracks.valueAt(i).reset();
}
} }
@Override @Override
...@@ -431,7 +437,13 @@ public final class MatroskaExtractor implements Extractor { ...@@ -431,7 +437,13 @@ public final class MatroskaExtractor implements Extractor {
return Extractor.RESULT_SEEK; return Extractor.RESULT_SEEK;
} }
} }
return continueReading ? Extractor.RESULT_CONTINUE : Extractor.RESULT_END_OF_INPUT; if (!continueReading) {
for (int i = 0; i < tracks.size(); i++) {
tracks.valueAt(i).outputPendingSampleMetadata();
}
return Extractor.RESULT_END_OF_INPUT;
}
return Extractor.RESULT_CONTINUE;
} }
/* package */ int getElementType(int id) { /* package */ int getElementType(int id) {
...@@ -1077,14 +1089,26 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1077,14 +1089,26 @@ public final class MatroskaExtractor implements Extractor {
} }
private void commitSampleToOutput(Track track, long timeUs) { private void commitSampleToOutput(Track track, long timeUs) {
if (CODEC_ID_SUBRIP.equals(track.codecId)) { if (track.trueHdSampleRechunker != null) {
commitSubtitleSample(track, SUBRIP_TIMECODE_FORMAT, SUBRIP_PREFIX_END_TIMECODE_OFFSET, track.trueHdSampleRechunker.sampleMetadata(track, timeUs);
SUBRIP_TIMECODE_LAST_VALUE_SCALING_FACTOR, SUBRIP_TIMECODE_EMPTY); } else {
} else if (CODEC_ID_ASS.equals(track.codecId)) { if (CODEC_ID_SUBRIP.equals(track.codecId)) {
commitSubtitleSample(track, SSA_TIMECODE_FORMAT, SSA_PREFIX_END_TIMECODE_OFFSET, commitSubtitleSample(
SSA_TIMECODE_LAST_VALUE_SCALING_FACTOR, SSA_TIMECODE_EMPTY); track,
SUBRIP_TIMECODE_FORMAT,
SUBRIP_PREFIX_END_TIMECODE_OFFSET,
SUBRIP_TIMECODE_LAST_VALUE_SCALING_FACTOR,
SUBRIP_TIMECODE_EMPTY);
} else if (CODEC_ID_ASS.equals(track.codecId)) {
commitSubtitleSample(
track,
SSA_TIMECODE_FORMAT,
SSA_PREFIX_END_TIMECODE_OFFSET,
SSA_TIMECODE_LAST_VALUE_SCALING_FACTOR,
SSA_TIMECODE_EMPTY);
}
track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.cryptoData);
} }
track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.cryptoData);
sampleRead = true; sampleRead = true;
resetSample(); resetSample();
} }
...@@ -1251,6 +1275,10 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1251,6 +1275,10 @@ public final class MatroskaExtractor implements Extractor {
} }
} }
} else { } else {
if (track.trueHdSampleRechunker != null) {
Assertions.checkState(sampleStrippedBytes.limit() == 0);
track.trueHdSampleRechunker.startSample(input, blockFlags, size);
}
while (sampleBytesRead < size) { while (sampleBytesRead < size) {
readToOutput(input, output, size - sampleBytesRead); readToOutput(input, output, size - sampleBytesRead);
} }
...@@ -1510,7 +1538,70 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1510,7 +1538,70 @@ public final class MatroskaExtractor implements Extractor {
throws IOException, InterruptedException { throws IOException, InterruptedException {
MatroskaExtractor.this.binaryElement(id, contentsSize, input); MatroskaExtractor.this.binaryElement(id, contentsSize, input);
} }
}
/**
* Rechunks TrueHD sample data into groups of {@link Ac3Util#TRUEHD_RECHUNK_SAMPLE_COUNT} samples.
*/
private static final class TrueHdSampleRechunker {
private final byte[] syncframePrefix;
private boolean foundSyncframe;
private int sampleCount;
private int chunkSize;
private long timeUs;
private @C.BufferFlags int blockFlags;
public TrueHdSampleRechunker() {
syncframePrefix = new byte[Ac3Util.TRUEHD_SYNCFRAME_PREFIX_LENGTH];
}
public void reset() {
foundSyncframe = false;
}
public void startSample(ExtractorInput input, @C.BufferFlags int blockFlags, int size)
throws IOException, InterruptedException {
if (!foundSyncframe) {
input.peekFully(syncframePrefix, 0, Ac3Util.TRUEHD_SYNCFRAME_PREFIX_LENGTH);
input.resetPeekPosition();
if ((Ac3Util.parseTrueHdSyncframeAudioSampleCount(syncframePrefix) == C.INDEX_UNSET)) {
return;
}
foundSyncframe = true;
sampleCount = 0;
}
if (sampleCount == 0) {
// This is the first sample in the chunk, so reset the block flags and chunk size.
this.blockFlags = blockFlags;
chunkSize = 0;
}
chunkSize += size;
}
public void sampleMetadata(Track track, long timeUs) {
if (!foundSyncframe) {
return;
}
if (sampleCount++ == 0) {
// This is the first sample in the chunk, so update the timestamp.
this.timeUs = timeUs;
}
if (sampleCount < Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT) {
// We haven't read enough samples to output a chunk.
return;
}
track.output.sampleMetadata(this.timeUs, blockFlags, chunkSize, 0, track.cryptoData);
sampleCount = 0;
}
public void outputPendingSampleMetadata(Track track) {
if (foundSyncframe && sampleCount > 0) {
track.output.sampleMetadata(this.timeUs, blockFlags, chunkSize, 0, track.cryptoData);
sampleCount = 0;
}
}
} }
private static final class Track { private static final class Track {
...@@ -1573,6 +1664,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1573,6 +1664,7 @@ public final class MatroskaExtractor implements Extractor {
public int sampleRate = 8000; public int sampleRate = 8000;
public long codecDelayNs = 0; public long codecDelayNs = 0;
public long seekPreRollNs = 0; public long seekPreRollNs = 0;
@Nullable public TrueHdSampleRechunker trueHdSampleRechunker;
// Text elements. // Text elements.
public boolean flagForced; public boolean flagForced;
...@@ -1583,9 +1675,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1583,9 +1675,7 @@ public final class MatroskaExtractor implements Extractor {
public TrackOutput output; public TrackOutput output;
public int nalUnitLengthFieldLength; public int nalUnitLengthFieldLength;
/** /** Initializes the track with an output. */
* Initializes the track with an output.
*/
public void initializeOutput(ExtractorOutput output, int trackId) throws ParserException { public void initializeOutput(ExtractorOutput output, int trackId) throws ParserException {
String mimeType; String mimeType;
int maxInputSize = Format.NO_VALUE; int maxInputSize = Format.NO_VALUE;
...@@ -1669,6 +1759,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1669,6 +1759,7 @@ public final class MatroskaExtractor implements Extractor {
break; break;
case CODEC_ID_TRUEHD: case CODEC_ID_TRUEHD:
mimeType = MimeTypes.AUDIO_TRUEHD; mimeType = MimeTypes.AUDIO_TRUEHD;
trueHdSampleRechunker = new TrueHdSampleRechunker();
break; break;
case CODEC_ID_DTS: case CODEC_ID_DTS:
case CODEC_ID_DTS_EXPRESS: case CODEC_ID_DTS_EXPRESS:
...@@ -1786,9 +1877,21 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1786,9 +1877,21 @@ public final class MatroskaExtractor implements Extractor {
this.output.format(format); this.output.format(format);
} }
/** /** Forces any pending sample metadata to be flushed to the output. */
* Returns the HDR Static Info as defined in CTA-861.3. public void outputPendingSampleMetadata() {
*/ if (trueHdSampleRechunker != null) {
trueHdSampleRechunker.outputPendingSampleMetadata(this);
}
}
/** Resets any state stored in the track in response to a seek. */
public void reset() {
if (trueHdSampleRechunker != null) {
trueHdSampleRechunker.reset();
}
}
/** Returns the HDR Static Info as defined in CTA-861.3. */
private byte[] getHdrStaticInfo() { private byte[] getHdrStaticInfo() {
// Are all fields present. // Are all fields present.
if (primaryRChromaticityX == Format.NO_VALUE || primaryRChromaticityY == Format.NO_VALUE if (primaryRChromaticityX == Format.NO_VALUE || primaryRChromaticityY == Format.NO_VALUE
......
...@@ -264,6 +264,8 @@ public final class MimeTypes { ...@@ -264,6 +264,8 @@ public final class MimeTypes {
return C.ENCODING_DTS; return C.ENCODING_DTS;
case MimeTypes.AUDIO_DTS_HD: case MimeTypes.AUDIO_DTS_HD:
return C.ENCODING_DTS_HD; return C.ENCODING_DTS_HD;
case MimeTypes.AUDIO_TRUEHD:
return C.ENCODING_DOLBY_TRUEHD;
default: default:
return C.ENCODING_INVALID; return C.ENCODING_INVALID;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment