From ed977d1429cf05414264579ef5ac0dc35f6d9be7 Mon Sep 17 00:00:00 2001 From: kimvde Date: Wed, 15 Apr 2020 18:49:16 +0100 Subject: [PATCH] Test and fix H265Reader - Update H265Reader to output the same samples after a seek to 0. - Add a TsExtractor test for H.265. PiperOrigin-RevId: 306675050 --- .../exoplayer2/extractor/ts/H265Reader.java | 26 ++-- .../extractor/ts/TsExtractorTest.java | 5 + testdata/src/test/assets/ts/sample_h265.ts | Bin 0 -> 24440 bytes .../src/test/assets/ts/sample_h265.ts.0.dump | 141 ++++++++++++++++++ .../src/test/assets/ts/sample_h265.ts.1.dump | 105 +++++++++++++ .../src/test/assets/ts/sample_h265.ts.2.dump | 69 +++++++++ .../src/test/assets/ts/sample_h265.ts.3.dump | 33 ++++ .../ts/sample_h265.ts.unknown_length.dump | 138 +++++++++++++++++ 8 files changed, 504 insertions(+), 13 deletions(-) create mode 100644 testdata/src/test/assets/ts/sample_h265.ts create mode 100644 testdata/src/test/assets/ts/sample_h265.ts.0.dump create mode 100644 testdata/src/test/assets/ts/sample_h265.ts.1.dump create mode 100644 testdata/src/test/assets/ts/sample_h265.ts.2.dump create mode 100644 testdata/src/test/assets/ts/sample_h265.ts.3.dump create mode 100644 testdata/src/test/assets/ts/sample_h265.ts.unknown_length.dump diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java index 4369ff7ca0..dcf64d9198 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java @@ -172,9 +172,8 @@ public final class H265Reader implements ElementaryStreamReader { @RequiresNonNull("sampleReader") private void startNalUnit(long position, int offset, int nalUnitType, long pesTimeUs) { - if (hasOutputFormat) { - sampleReader.startNalUnit(position, offset, nalUnitType, pesTimeUs); - } else { + sampleReader.startNalUnit(position, offset, nalUnitType, pesTimeUs, hasOutputFormat); + if (!hasOutputFormat) { vps.startNalUnit(nalUnitType); sps.startNalUnit(nalUnitType); pps.startNalUnit(nalUnitType); @@ -185,9 +184,8 @@ public final class H265Reader implements ElementaryStreamReader { @RequiresNonNull("sampleReader") private void nalUnitData(byte[] dataArray, int offset, int limit) { - if (hasOutputFormat) { - sampleReader.readNalUnitData(dataArray, offset, limit); - } else { + sampleReader.readNalUnitData(dataArray, offset, limit); + if (!hasOutputFormat) { vps.appendToNalUnit(dataArray, offset, limit); sps.appendToNalUnit(dataArray, offset, limit); pps.appendToNalUnit(dataArray, offset, limit); @@ -198,9 +196,8 @@ public final class H265Reader implements ElementaryStreamReader { @RequiresNonNull({"output", "sampleReader"}) private void endNalUnit(long position, int offset, int discardPadding, long pesTimeUs) { - if (hasOutputFormat) { - sampleReader.endNalUnit(position, offset); - } else { + sampleReader.endNalUnit(position, offset, hasOutputFormat); + if (!hasOutputFormat) { vps.endNalUnit(discardPadding); sps.endNalUnit(discardPadding); pps.endNalUnit(discardPadding); @@ -454,7 +451,8 @@ public final class H265Reader implements ElementaryStreamReader { writingParameterSets = false; } - public void startNalUnit(long position, int offset, int nalUnitType, long pesTimeUs) { + public void startNalUnit( + long position, int offset, int nalUnitType, long pesTimeUs, boolean hasOutputFormat) { isFirstSlice = false; isFirstParameterSet = false; nalUnitTimeUs = pesTimeUs; @@ -464,7 +462,9 @@ public final class H265Reader implements ElementaryStreamReader { if (nalUnitType >= VPS_NUT) { if (!writingParameterSets && readingSample) { // This is a non-VCL NAL unit, so flush the previous sample. - outputSample(offset); + if (hasOutputFormat) { + outputSample(offset); + } readingSample = false; } if (nalUnitType <= PPS_NUT) { @@ -491,14 +491,14 @@ public final class H265Reader implements ElementaryStreamReader { } } - public void endNalUnit(long position, int offset) { + public void endNalUnit(long position, int offset, boolean hasOutputFormat) { if (writingParameterSets && isFirstSlice) { // This sample has parameter sets. Reset the key-frame flag based on the first slice. sampleIsKeyframe = nalUnitHasKeyframeData; writingParameterSets = false; } else if (isFirstParameterSet || isFirstSlice) { // This NAL unit is at the start of a new sample (access unit). - if (readingSample) { + if (hasOutputFormat && readingSample) { // Output the sample ending before this NAL unit. int nalUnitLength = (int) (position - nalUnitStartPosition); outputSample(offset + nalUnitLength); diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java index 23f8e91009..d040c22286 100644 --- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java @@ -54,6 +54,11 @@ public final class TsExtractorTest { ExtractorAsserts.assertBehavior(TsExtractor::new, "ts/sample_h264_mpeg_audio.ts"); } + @Test + public void sampleWithH265() throws Exception { + ExtractorAsserts.assertBehavior(TsExtractor::new, "ts/sample_h265.ts"); + } + @Test @Ignore // TODO(internal: b/153539929) Re-enable when ExtractorAsserts is less strict around repeated diff --git a/testdata/src/test/assets/ts/sample_h265.ts b/testdata/src/test/assets/ts/sample_h265.ts new file mode 100644 index 0000000000000000000000000000000000000000..483010fd86545dfe17cfb02ff0114b00ca18329e GIT binary patch literal 24440 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