Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@ public static ImmutableList<String> mediaSamples() {
"sample_with_htc_rotation_track_name.mkv",
"sample_with_pgs_subtitles.mkv",
"sample_with_ssa_subtitles.mkv",
"sample_with_zlib_ass_subtitles.mkv",
"sample_with_null_terminated_ssa_subtitles.mkv",
"sample_with_overlapping_ssa_subtitles.mkv",
"sample_with_srt.mkv",
"sample_with_null_terminated_srt.mkv",
"sample_with_zlib_null_terminated_srt.mkv",
"sample_with_overlapping_srt.mkv",
"sample_with_vtt_subtitles.mkv",
"sample_with_null_terminated_vtt_subtitles.mkv",
"sample_with_zlib_null_terminated_vtt_subtitles.mkv",
"sample_with_vobsub.mkv");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.zip.Inflater;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
Expand Down Expand Up @@ -463,6 +464,7 @@ public static ExtractorsFactory newFactory(SubtitleParser.Factory subtitleParser
private final ParsableByteArray seekEntryIdBytes;
private final ParsableByteArray sampleStrippedBytes;
private final ParsableByteArray subtitleSample;
private final ParsableByteArray inflatedSubtitleSample;
private final ParsableByteArray encryptionInitializationVector;
private final ParsableByteArray encryptionSubsampleData;
private final ParsableByteArray supplementalData;
Expand All @@ -476,6 +478,9 @@ public static ExtractorsFactory newFactory(SubtitleParser.Factory subtitleParser
private boolean isWebm;
private boolean pendingEndTracks;

// Inflater for zlib compressed tracks
@Nullable private Inflater inflater;

// The chapter corresponding to the current EditionEntry element, or null.
@Nullable private ChapterEntry currentChapter;

Expand Down Expand Up @@ -591,6 +596,7 @@ public MatroskaExtractor(SubtitleParser.Factory subtitleParserFactory, @Flags in
nalLength = new ParsableByteArray(4);
sampleStrippedBytes = new ParsableByteArray();
subtitleSample = new ParsableByteArray();
inflatedSubtitleSample = new ParsableByteArray();
encryptionInitializationVector = new ParsableByteArray(ENCRYPTION_IV_SIZE);
encryptionSubsampleData = new ParsableByteArray();
supplementalData = new ParsableByteArray();
Expand Down Expand Up @@ -863,6 +869,9 @@ protected void startMasterElement(int id, long contentPosition, long contentSize
case ID_CONTENT_ENCODING:
// TODO: check and fail if more than one content encoding is present.
break;
case ID_CONTENT_COMPRESSION:
getCurrentTrack(id).hasContentCompression = true;
break;
case ID_CONTENT_ENCRYPTION:
getCurrentTrack(id).hasContentEncryption = true;
break;
Expand Down Expand Up @@ -1256,8 +1265,8 @@ protected void integerElement(int id, long value) throws ParserException {
}
break;
case ID_CONTENT_COMPRESSION_ALGORITHM:
// This extractor only supports header stripping.
if (value != 3) {
// This extractor only supports header stripping and zlib compressed text tracks.
if (value != 3 && (value != 0 || getCurrentTrack(id).type != C.TRACK_TYPE_TEXT)) {
throw ParserException.createForMalformedContainer(
"ContentCompAlgo " + value + " not supported", /* cause= */ null);
}
Expand Down Expand Up @@ -1834,13 +1843,13 @@ private void readScratch(ExtractorInput input, int requiredLength) throws IOExce
private int writeSampleData(ExtractorInput input, Track track, int size, boolean isBlockGroup)
throws IOException {
if (CODEC_ID_SUBRIP.equals(track.codecId)) {
writeSubtitleSampleData(input, SUBRIP_PREFIX, size);
writeSubtitleSampleData(input, SUBRIP_PREFIX, size, track.hasContentCompression);
return finishWriteSampleData();
} else if (CODEC_ID_ASS.equals(track.codecId) || CODEC_ID_SSA.equals(track.codecId)) {
writeSubtitleSampleData(input, SSA_PREFIX, size);
writeSubtitleSampleData(input, SSA_PREFIX, size, track.hasContentCompression);
return finishWriteSampleData();
} else if (CODEC_ID_VTT.equals(track.codecId)) {
writeSubtitleSampleData(input, VTT_PREFIX, size);
writeSubtitleSampleData(input, VTT_PREFIX, size, track.hasContentCompression);
return finishWriteSampleData();
}

Expand Down Expand Up @@ -2055,7 +2064,8 @@ private void resetWriteSampleData() {
sampleStrippedBytes.reset(/* limit= */ 0);
}

private void writeSubtitleSampleData(ExtractorInput input, byte[] samplePrefix, int size)
private void writeSubtitleSampleData(
ExtractorInput input, byte[] samplePrefix, int size, boolean hasContentCompression)
throws IOException {
int sizeWithPrefix = samplePrefix.length + size;
if (subtitleSample.capacity() < sizeWithPrefix) {
Expand All @@ -2066,6 +2076,25 @@ private void writeSubtitleSampleData(ExtractorInput input, byte[] samplePrefix,
System.arraycopy(samplePrefix, 0, subtitleSample.getData(), 0, samplePrefix.length);
}
input.readFully(subtitleSample.getData(), samplePrefix.length, size);

if (hasContentCompression) {
if (inflater == null) {
inflater = new Inflater();
}
subtitleSample.setPosition(samplePrefix.length);
subtitleSample.setLimit(sizeWithPrefix);
if (Util.maybeInflate(subtitleSample, inflatedSubtitleSample, inflater)) {
sizeWithPrefix = samplePrefix.length + inflatedSubtitleSample.limit();
subtitleSample.ensureCapacity(sizeWithPrefix);
System.arraycopy(
inflatedSubtitleSample.getData(),
0,
subtitleSample.getData(),
samplePrefix.length,
inflatedSubtitleSample.limit());
}
}

subtitleSample.setPosition(0);
subtitleSample.setLimit(sizeWithPrefix);
// Defer writing the data to the track output. We need to modify the sample data by setting
Expand Down Expand Up @@ -2359,6 +2388,7 @@ protected static final class Track {
public int defaultSampleDurationNs;
public int maxBlockAdditionId;
private int blockAddIdType;
public boolean hasContentCompression;
public boolean hasContentEncryption;
public byte @MonotonicNonNull [] sampleStrippedBytes;
public TrackOutput.@MonotonicNonNull CryptoData cryptoData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,19 @@ public void mkvSample_withNullTerminatedSubripSubtitles() throws Exception {
simulationConfig);
}

@Test
// TODO: b/507050745 - Suppressed due to failure with subtitlesParsedDuringExtraction=true on SDK
// >= 32.
@Config(maxSdk = 31)
public void mkvSample_withZlibNullTerminatedSubripSubtitles() throws Exception {
ExtractorAsserts.assertBehavior(
getExtractorFactory(subtitlesParsedDuringExtraction),
"media/mkv/sample_with_zlib_null_terminated_srt.mkv",
getAssertionConfigWithPrefix(
"media/mkv/sample_with_zlib_null_terminated_srt.mkv", subtitlesParsedDuringExtraction),
simulationConfig);
}

@Test
// TODO: b/507050745 - Suppressed due to failure with subtitlesParsedDuringExtraction=true on SDK
// >= 32.
Expand Down Expand Up @@ -143,6 +156,19 @@ public void mkvSample_withAssSubtitles() throws Exception {
simulationConfig);
}

@Test
// TODO: b/507050745 - Suppressed due to failure with subtitlesParsedDuringExtraction=true on SDK
// >= 32.
@Config(maxSdk = 31)
public void mkvSample_withZlibAssSubtitles() throws Exception {
ExtractorAsserts.assertBehavior(
getExtractorFactory(subtitlesParsedDuringExtraction),
"media/mkv/sample_with_zlib_ass_subtitles.mkv",
getAssertionConfigWithPrefix(
"media/mkv/sample_with_zlib_ass_subtitles.mkv", subtitlesParsedDuringExtraction),
simulationConfig);
}

// https://github.com/google/ExoPlayer/pull/8265
@Test
// TODO: b/507050745 - Suppressed due to failure with subtitlesParsedDuringExtraction=true on SDK
Expand Down Expand Up @@ -198,6 +224,20 @@ public void mkvSample_withNullTerminatedVttSubtitles() throws Exception {
simulationConfig);
}

@Test
// TODO: b/507050745 - Suppressed due to failure with subtitlesParsedDuringExtraction=true on SDK
// >= 32.
@Config(maxSdk = 31)
public void mkvSample_withZlibNullTerminatedVttSubtitles() throws Exception {
ExtractorAsserts.assertBehavior(
getExtractorFactory(subtitlesParsedDuringExtraction),
"media/mkv/sample_with_zlib_null_terminated_vtt_subtitles.mkv",
getAssertionConfigWithPrefix(
"media/mkv/sample_with_zlib_null_terminated_vtt_subtitles.mkv",
subtitlesParsedDuringExtraction),
simulationConfig);
}

@Test
public void mkvSample_withVorbisAudio() throws Exception {
ExtractorAsserts.assertBehavior(
Expand Down
Loading