diff --git a/library/common/src/main/java/com/google/android/exoplayer2/audio/MlpUtil.java b/library/common/src/main/java/com/google/android/exoplayer2/audio/MlpUtil.java new file mode 100644 index 00000000000..a8fa37e81ff --- /dev/null +++ b/library/common/src/main/java/com/google/android/exoplayer2/audio/MlpUtil.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.audio; + +import androidx.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.drm.DrmInitData; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; + +/** Utility methods for parsing MLP frames, which are access units in MLP bitstreams. */ +public final class MlpUtil { + + /** a MLP stream can carry simultaneously multiple representations of the same audio : + * stereo as well as multichannel and object based immersive audio, + * so just consider stereo by default */ + private static final int CHANNEL_COUNT_2 = 2; + + /** + * Returns the MLP format given {@code data} containing the MLPSpecificBox according to + * dolbytruehdbitstreamswithintheisobasemediafileformat.pdf + * The reading position of {@code data} will be modified. + * + * @param data The MLPSpecificBox to parse. + * @param trackId The track identifier to set on the format. + * @param sampleRate The sample rate to be included in the format. + * @param language The language to set on the format. + * @param drmInitData {@link DrmInitData} to be included in the format. + * @return The MLP format parsed from data in the header. + */ + public static Format parseMlpFormat( + ParsableByteArray data, String trackId, int sampleRate, + String language, @Nullable DrmInitData drmInitData) { + + return new Format.Builder() + .setId(trackId) + .setSampleMimeType(MimeTypes.AUDIO_TRUEHD) + .setChannelCount(CHANNEL_COUNT_2) + .setSampleRate(sampleRate) + .setDrmInitData(drmInitData) + .setLanguage(language) + .build(); + } + + private MlpUtil() {} + + /** + * 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 = 16; + + /** + * Rechunks TrueHD sample data into groups of {@link #TRUEHD_RECHUNK_SAMPLE_COUNT} samples. + */ + public static class TrueHdSampleRechunker { + + private int sampleCount; + public long timeUs; + public @C.BufferFlags int flags; + public int sampleSize; + + public TrueHdSampleRechunker() { + reset(); + } + + public void reset() { + sampleCount = 0; + sampleSize = 0; + } + + /** Returns true when enough samples have been appended. */ + public boolean appendSampleMetadata(long timeUs, @C.BufferFlags int flags, int size) { + + if (sampleCount++ == 0) { + // This is the first sample in the chunk. + this.timeUs = timeUs; + this.flags = flags; + this.sampleSize = 0; + } + this.sampleSize += size; + if (sampleCount >= TRUEHD_RECHUNK_SAMPLE_COUNT) { + sampleCount = 0; + return true; + } + return false; + } + } +} diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java index a85d928f04d..bc8633acc8e 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java @@ -152,6 +152,12 @@ @SuppressWarnings("ConstantCaseForConstants") public static final int TYPE_dac4 = 0x64616334; + @SuppressWarnings("ConstantCaseForConstants") + public static final int TYPE_mlpa = 0x6d6c7061; + + @SuppressWarnings("ConstantCaseForConstants") + public static final int TYPE_dmlp = 0x646d6c70; + @SuppressWarnings("ConstantCaseForConstants") public static final int TYPE_dtsc = 0x64747363; diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 067d53ebfe3..e739694dca7 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -28,6 +28,7 @@ import com.google.android.exoplayer2.audio.AacUtil; import com.google.android.exoplayer2.audio.Ac3Util; import com.google.android.exoplayer2.audio.Ac4Util; +import com.google.android.exoplayer2.audio.MlpUtil; import com.google.android.exoplayer2.audio.OpusUtil; import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.extractor.ExtractorUtil; @@ -962,6 +963,7 @@ private static StsdData parseStsd( || childAtomType == Atom.TYPE_ac_3 || childAtomType == Atom.TYPE_ec_3 || childAtomType == Atom.TYPE_ac_4 + || childAtomType == Atom.TYPE_mlpa || childAtomType == Atom.TYPE_dtsc || childAtomType == Atom.TYPE_dtse || childAtomType == Atom.TYPE_dtsh @@ -1312,14 +1314,20 @@ private static void parseAudioSampleEntry( parent.skipBytes(8); } - int channelCount; - int sampleRate; + int channelCount; + int sampleRate; + int sampleRate32 = 0; @C.PcmEncoding int pcmEncoding = Format.NO_VALUE; @Nullable String codecs = null; if (quickTimeSoundDescriptionVersion == 0 || quickTimeSoundDescriptionVersion == 1) { channelCount = parent.readUnsignedShort(); - parent.skipBytes(6); // sampleSize, compressionId, packetSize. + parent.skipBytes(6); // sampleSize, compressionId, packetSize. + + int pos = parent.getPosition(); + sampleRate32 = (int) parent.readUnsignedInt(); + + parent.setPosition(pos); sampleRate = parent.readUnsignedFixedPoint1616(); if (quickTimeSoundDescriptionVersion == 1) { @@ -1401,6 +1409,8 @@ private static void parseAudioSampleEntry( mimeType = MimeTypes.AUDIO_OPUS; } else if (atomType == Atom.TYPE_fLaC) { mimeType = MimeTypes.AUDIO_FLAC; + } else if (atomType == Atom.TYPE_mlpa) { + mimeType = MimeTypes.AUDIO_TRUEHD; } @Nullable List initializationData = null; @@ -1442,6 +1452,10 @@ private static void parseAudioSampleEntry( initializationData = ImmutableList.of(initializationDataBytes); } } + } else if (childAtomType == Atom.TYPE_dmlp) { + parent.setPosition(Atom.HEADER_SIZE + childPosition); + out.format = MlpUtil.parseMlpFormat(parent, Integer.toString(trackId), + sampleRate32, language, drmInitData); } else if (childAtomType == Atom.TYPE_dac3) { parent.setPosition(Atom.HEADER_SIZE + childPosition); out.format = diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java index d542fa85450..11e11898e89 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java @@ -30,6 +30,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.audio.Ac4Util; +import com.google.android.exoplayer2.audio.MlpUtil; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorOutput; @@ -501,11 +502,17 @@ private void processMoovAtom(ContainerAtom moov) throws ParserException { track.durationUs != C.TIME_UNSET ? track.durationUs : trackSampleTable.durationUs; durationUs = max(durationUs, trackDurationUs); Mp4Track mp4Track = - new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type)); + new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type), track.format.sampleMimeType); // Each sample has up to three bytes of overhead for the start code that replaces its length. // Allow ten source samples per output sample, like the platform extractor. int maxInputSize = trackSampleTable.maximumSize + 3 * 10; + + if ((track.format.sampleMimeType != null) && (track.format.sampleMimeType.equals(MimeTypes.AUDIO_TRUEHD))) { + // TrueHD collates 16 source samples per output + maxInputSize = trackSampleTable.maximumSize * MlpUtil.TRUEHD_RECHUNK_SAMPLE_COUNT; + } + Format.Builder formatBuilder = track.format.buildUpon(); formatBuilder.setMaxInputSize(maxInputSize); if (track.type == C.TRACK_TYPE_VIDEO @@ -540,7 +547,8 @@ private void processMoovAtom(ContainerAtom moov) throws ParserException { } /** - * Attempts to extract the next sample in the current mdat atom for the specified track. + * Attempts to extract the next sample or the next 16 samples in case of Dolby TrueHD audio + * in the current mdat atom for the specified track. * *

Returns {@link #RESULT_SEEK} if the source should be reloaded from the position in {@code * positionHolder}. @@ -632,12 +640,9 @@ private int readSample(ExtractorInput input, PositionHolder positionHolder) thro sampleCurrentNalBytesRemaining -= writtenBytes; } } - trackOutput.sampleMetadata( - track.sampleTable.timestampsUs[sampleIndex], - track.sampleTable.flags[sampleIndex], - sampleSize, - 0, - null); + + track.sampleMetadata(sampleIndex, sampleSize, 0, null); + track.sampleIndex++; sampleTrackIndex = C.INDEX_UNSET; sampleBytesRead = 0; @@ -904,11 +909,40 @@ private static final class Mp4Track { public final TrackOutput trackOutput; public int sampleIndex; + @Nullable public MlpUtil.TrueHdSampleRechunker trueHdSampleRechunker; - public Mp4Track(Track track, TrackSampleTable sampleTable, TrackOutput trackOutput) { + public Mp4Track(Track track, TrackSampleTable sampleTable, TrackOutput trackOutput, @Nullable String mimeType) { this.track = track; this.sampleTable = sampleTable; this.trackOutput = trackOutput; + this.trueHdSampleRechunker = null; + + if ((mimeType != null) && mimeType.equals(MimeTypes.AUDIO_TRUEHD)) { + this.trueHdSampleRechunker = new MlpUtil.TrueHdSampleRechunker(); + } + } + + public void sampleMetadata( int sampleIndex, int sampleSize, int offset, + @Nullable TrackOutput.CryptoData cryptoData) { + + long timeUs = sampleTable.timestampsUs[sampleIndex]; + @C.BufferFlags int flags = sampleTable.flags[sampleIndex]; + + if (trueHdSampleRechunker != null) { + boolean fullChunk = trueHdSampleRechunker.appendSampleMetadata(timeUs,flags,sampleSize); + + if (fullChunk || (sampleIndex+1 == sampleTable.sampleCount)) { + timeUs = trueHdSampleRechunker.timeUs; + flags = trueHdSampleRechunker.flags; + sampleSize = trueHdSampleRechunker.sampleSize; + + trackOutput.sampleMetadata( timeUs, flags, sampleSize, offset, cryptoData); + trueHdSampleRechunker.reset(); + } + } else { + trackOutput.sampleMetadata( timeUs, flags, sampleSize, offset, cryptoData); + } } } + } diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java index 4408ffab832..9c41d361ad1 100644 --- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java @@ -102,4 +102,10 @@ public void mp4SampleWithColorInfo() throws Exception { ExtractorAsserts.assertBehavior( Mp4Extractor::new, "media/mp4/sample_with_color_info.mp4", simulationConfig); } + + @Test + public void mp4SampleWithDolbyTrueHDTrack() throws Exception { + ExtractorAsserts.assertBehavior( + Mp4Extractor::new, "media/mp4/sample_dthd.mp4", simulationConfig); + } } diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.0.dump b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.0.dump new file mode 100644 index 00000000000..d05b05b2cc0 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.0.dump @@ -0,0 +1,147 @@ +seekMap: + isSeekable = true + duration = 418333 + getPosition(0) = [[timeUs=0, position=3447]] + getPosition(1) = [[timeUs=1, position=3447]] + getPosition(209166) = [[timeUs=209166, position=27035]] + getPosition(418333) = [[timeUs=418333, position=75365]] +numberOfTracks = 1 +track 0: + total output bytes = 94656 + sample count = 32 + format 0: + id = 1 + sampleMimeType = audio/true-hd + maxInputSize = 12480 + channelCount = 2 + sampleRate = 48000 + language = und + sample 0: + time = 0 + flags = 1 + data = length 3512, hash B77F1117 + sample 1: + time = 13333 + flags = 0 + data = length 2830, hash 4B19B7D5 + sample 2: + time = 26666 + flags = 0 + data = length 2868, hash BC04A38E + sample 3: + time = 40000 + flags = 0 + data = length 2834, hash D2AF8AF9 + sample 4: + time = 53333 + flags = 0 + data = length 2898, hash 5C9B3119 + sample 5: + time = 66666 + flags = 0 + data = length 2800, hash 31B9C93F + sample 6: + time = 80000 + flags = 0 + data = length 2866, hash 7FCABDBC + sample 7: + time = 93333 + flags = 0 + data = length 2980, hash FC2CCBDA + sample 8: + time = 106666 + flags = 1 + data = length 3432, hash 17F43166 + sample 9: + time = 120000 + flags = 0 + data = length 2974, hash 69EDFD38 + sample 10: + time = 133333 + flags = 0 + data = length 2898, hash 60E09542 + sample 11: + time = 146666 + flags = 0 + data = length 2896, hash 94A43D4A + sample 12: + time = 160000 + flags = 0 + data = length 3008, hash 82D706BB + sample 13: + time = 173333 + flags = 0 + data = length 2918, hash 22DE72A8 + sample 14: + time = 186666 + flags = 0 + data = length 2990, hash E478A008 + sample 15: + time = 200000 + flags = 0 + data = length 2860, hash B5C3DE40 + sample 16: + time = 213333 + flags = 1 + data = length 3638, hash 3FCD885B + sample 17: + time = 226666 + flags = 0 + data = length 2968, hash A3692382 + sample 18: + time = 240000 + flags = 0 + data = length 2940, hash 72A71C81 + sample 19: + time = 253333 + flags = 0 + data = length 3010, hash A826B2C3 + sample 20: + time = 266666 + flags = 0 + data = length 2952, hash BCEA8C02 + sample 21: + time = 280000 + flags = 0 + data = length 3018, hash C313A53F + sample 22: + time = 293333 + flags = 0 + data = length 2930, hash 4AAB358 + sample 23: + time = 306666 + flags = 0 + data = length 2898, hash C2C22662 + sample 24: + time = 320000 + flags = 1 + data = length 3680, hash 354DF989 + sample 25: + time = 333333 + flags = 0 + data = length 2970, hash 3191F764 + sample 26: + time = 346666 + flags = 0 + data = length 3044, hash 9E115802 + sample 27: + time = 360000 + flags = 0 + data = length 2946, hash B1341399 + sample 28: + time = 373333 + flags = 0 + data = length 2992, hash 4DA27845 + sample 29: + time = 386666 + flags = 0 + data = length 2930, hash 140DC44C + sample 30: + time = 400000 + flags = 0 + data = length 2960, hash 5287EBF8 + sample 31: + time = 413333 + flags = 0 + data = length 1216, hash B83FE151 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.1.dump b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.1.dump new file mode 100644 index 00000000000..47ac8e4b972 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.1.dump @@ -0,0 +1,115 @@ +seekMap: + isSeekable = true + duration = 418333 + getPosition(0) = [[timeUs=0, position=3447]] + getPosition(1) = [[timeUs=1, position=3447]] + getPosition(209166) = [[timeUs=209166, position=27035]] + getPosition(418333) = [[timeUs=418333, position=75365]] +numberOfTracks = 1 +track 0: + total output bytes = 71068 + sample count = 24 + format 0: + id = 1 + sampleMimeType = audio/true-hd + maxInputSize = 12480 + channelCount = 2 + sampleRate = 48000 + language = und + sample 0: + time = 106666 + flags = 1 + data = length 3432, hash 17F43166 + sample 1: + time = 120000 + flags = 0 + data = length 2974, hash 69EDFD38 + sample 2: + time = 133333 + flags = 0 + data = length 2898, hash 60E09542 + sample 3: + time = 146666 + flags = 0 + data = length 2896, hash 94A43D4A + sample 4: + time = 160000 + flags = 0 + data = length 3008, hash 82D706BB + sample 5: + time = 173333 + flags = 0 + data = length 2918, hash 22DE72A8 + sample 6: + time = 186666 + flags = 0 + data = length 2990, hash E478A008 + sample 7: + time = 200000 + flags = 0 + data = length 2860, hash B5C3DE40 + sample 8: + time = 213333 + flags = 1 + data = length 3638, hash 3FCD885B + sample 9: + time = 226666 + flags = 0 + data = length 2968, hash A3692382 + sample 10: + time = 240000 + flags = 0 + data = length 2940, hash 72A71C81 + sample 11: + time = 253333 + flags = 0 + data = length 3010, hash A826B2C3 + sample 12: + time = 266666 + flags = 0 + data = length 2952, hash BCEA8C02 + sample 13: + time = 280000 + flags = 0 + data = length 3018, hash C313A53F + sample 14: + time = 293333 + flags = 0 + data = length 2930, hash 4AAB358 + sample 15: + time = 306666 + flags = 0 + data = length 2898, hash C2C22662 + sample 16: + time = 320000 + flags = 1 + data = length 3680, hash 354DF989 + sample 17: + time = 333333 + flags = 0 + data = length 2970, hash 3191F764 + sample 18: + time = 346666 + flags = 0 + data = length 3044, hash 9E115802 + sample 19: + time = 360000 + flags = 0 + data = length 2946, hash B1341399 + sample 20: + time = 373333 + flags = 0 + data = length 2992, hash 4DA27845 + sample 21: + time = 386666 + flags = 0 + data = length 2930, hash 140DC44C + sample 22: + time = 400000 + flags = 0 + data = length 2960, hash 5287EBF8 + sample 23: + time = 413333 + flags = 0 + data = length 1216, hash B83FE151 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.2.dump b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.2.dump new file mode 100644 index 00000000000..c52bcbffed3 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.2.dump @@ -0,0 +1,83 @@ +seekMap: + isSeekable = true + duration = 418333 + getPosition(0) = [[timeUs=0, position=3447]] + getPosition(1) = [[timeUs=1, position=3447]] + getPosition(209166) = [[timeUs=209166, position=27035]] + getPosition(418333) = [[timeUs=418333, position=75365]] +numberOfTracks = 1 +track 0: + total output bytes = 47092 + sample count = 16 + format 0: + id = 1 + sampleMimeType = audio/true-hd + maxInputSize = 12480 + channelCount = 2 + sampleRate = 48000 + language = und + sample 0: + time = 213333 + flags = 1 + data = length 3638, hash 3FCD885B + sample 1: + time = 226666 + flags = 0 + data = length 2968, hash A3692382 + sample 2: + time = 240000 + flags = 0 + data = length 2940, hash 72A71C81 + sample 3: + time = 253333 + flags = 0 + data = length 3010, hash A826B2C3 + sample 4: + time = 266666 + flags = 0 + data = length 2952, hash BCEA8C02 + sample 5: + time = 280000 + flags = 0 + data = length 3018, hash C313A53F + sample 6: + time = 293333 + flags = 0 + data = length 2930, hash 4AAB358 + sample 7: + time = 306666 + flags = 0 + data = length 2898, hash C2C22662 + sample 8: + time = 320000 + flags = 1 + data = length 3680, hash 354DF989 + sample 9: + time = 333333 + flags = 0 + data = length 2970, hash 3191F764 + sample 10: + time = 346666 + flags = 0 + data = length 3044, hash 9E115802 + sample 11: + time = 360000 + flags = 0 + data = length 2946, hash B1341399 + sample 12: + time = 373333 + flags = 0 + data = length 2992, hash 4DA27845 + sample 13: + time = 386666 + flags = 0 + data = length 2930, hash 140DC44C + sample 14: + time = 400000 + flags = 0 + data = length 2960, hash 5287EBF8 + sample 15: + time = 413333 + flags = 0 + data = length 1216, hash B83FE151 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.3.dump b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.3.dump new file mode 100644 index 00000000000..1d226c257ae --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.3.dump @@ -0,0 +1,51 @@ +seekMap: + isSeekable = true + duration = 418333 + getPosition(0) = [[timeUs=0, position=3447]] + getPosition(1) = [[timeUs=1, position=3447]] + getPosition(209166) = [[timeUs=209166, position=27035]] + getPosition(418333) = [[timeUs=418333, position=75365]] +numberOfTracks = 1 +track 0: + total output bytes = 22738 + sample count = 8 + format 0: + id = 1 + sampleMimeType = audio/true-hd + maxInputSize = 12480 + channelCount = 2 + sampleRate = 48000 + language = und + sample 0: + time = 320000 + flags = 1 + data = length 3680, hash 354DF989 + sample 1: + time = 333333 + flags = 0 + data = length 2970, hash 3191F764 + sample 2: + time = 346666 + flags = 0 + data = length 3044, hash 9E115802 + sample 3: + time = 360000 + flags = 0 + data = length 2946, hash B1341399 + sample 4: + time = 373333 + flags = 0 + data = length 2992, hash 4DA27845 + sample 5: + time = 386666 + flags = 0 + data = length 2930, hash 140DC44C + sample 6: + time = 400000 + flags = 0 + data = length 2960, hash 5287EBF8 + sample 7: + time = 413333 + flags = 0 + data = length 1216, hash B83FE151 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.unknown_length.dump b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.unknown_length.dump new file mode 100644 index 00000000000..d05b05b2cc0 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_dthd.mp4.unknown_length.dump @@ -0,0 +1,147 @@ +seekMap: + isSeekable = true + duration = 418333 + getPosition(0) = [[timeUs=0, position=3447]] + getPosition(1) = [[timeUs=1, position=3447]] + getPosition(209166) = [[timeUs=209166, position=27035]] + getPosition(418333) = [[timeUs=418333, position=75365]] +numberOfTracks = 1 +track 0: + total output bytes = 94656 + sample count = 32 + format 0: + id = 1 + sampleMimeType = audio/true-hd + maxInputSize = 12480 + channelCount = 2 + sampleRate = 48000 + language = und + sample 0: + time = 0 + flags = 1 + data = length 3512, hash B77F1117 + sample 1: + time = 13333 + flags = 0 + data = length 2830, hash 4B19B7D5 + sample 2: + time = 26666 + flags = 0 + data = length 2868, hash BC04A38E + sample 3: + time = 40000 + flags = 0 + data = length 2834, hash D2AF8AF9 + sample 4: + time = 53333 + flags = 0 + data = length 2898, hash 5C9B3119 + sample 5: + time = 66666 + flags = 0 + data = length 2800, hash 31B9C93F + sample 6: + time = 80000 + flags = 0 + data = length 2866, hash 7FCABDBC + sample 7: + time = 93333 + flags = 0 + data = length 2980, hash FC2CCBDA + sample 8: + time = 106666 + flags = 1 + data = length 3432, hash 17F43166 + sample 9: + time = 120000 + flags = 0 + data = length 2974, hash 69EDFD38 + sample 10: + time = 133333 + flags = 0 + data = length 2898, hash 60E09542 + sample 11: + time = 146666 + flags = 0 + data = length 2896, hash 94A43D4A + sample 12: + time = 160000 + flags = 0 + data = length 3008, hash 82D706BB + sample 13: + time = 173333 + flags = 0 + data = length 2918, hash 22DE72A8 + sample 14: + time = 186666 + flags = 0 + data = length 2990, hash E478A008 + sample 15: + time = 200000 + flags = 0 + data = length 2860, hash B5C3DE40 + sample 16: + time = 213333 + flags = 1 + data = length 3638, hash 3FCD885B + sample 17: + time = 226666 + flags = 0 + data = length 2968, hash A3692382 + sample 18: + time = 240000 + flags = 0 + data = length 2940, hash 72A71C81 + sample 19: + time = 253333 + flags = 0 + data = length 3010, hash A826B2C3 + sample 20: + time = 266666 + flags = 0 + data = length 2952, hash BCEA8C02 + sample 21: + time = 280000 + flags = 0 + data = length 3018, hash C313A53F + sample 22: + time = 293333 + flags = 0 + data = length 2930, hash 4AAB358 + sample 23: + time = 306666 + flags = 0 + data = length 2898, hash C2C22662 + sample 24: + time = 320000 + flags = 1 + data = length 3680, hash 354DF989 + sample 25: + time = 333333 + flags = 0 + data = length 2970, hash 3191F764 + sample 26: + time = 346666 + flags = 0 + data = length 3044, hash 9E115802 + sample 27: + time = 360000 + flags = 0 + data = length 2946, hash B1341399 + sample 28: + time = 373333 + flags = 0 + data = length 2992, hash 4DA27845 + sample 29: + time = 386666 + flags = 0 + data = length 2930, hash 140DC44C + sample 30: + time = 400000 + flags = 0 + data = length 2960, hash 5287EBF8 + sample 31: + time = 413333 + flags = 0 + data = length 1216, hash B83FE151 +tracksEnded = true diff --git a/testdata/src/test/assets/media/mp4/sample_dthd.mp4 b/testdata/src/test/assets/media/mp4/sample_dthd.mp4 new file mode 100644 index 00000000000..c5d3eb2a390 Binary files /dev/null and b/testdata/src/test/assets/media/mp4/sample_dthd.mp4 differ