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 0000000000..483010fd86 Binary files /dev/null and b/testdata/src/test/assets/ts/sample_h265.ts differ diff --git a/testdata/src/test/assets/ts/sample_h265.ts.0.dump b/testdata/src/test/assets/ts/sample_h265.ts.0.dump new file mode 100644 index 0000000000..1c06207b75 --- /dev/null +++ b/testdata/src/test/assets/ts/sample_h265.ts.0.dump @@ -0,0 +1,141 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=11421]] + getPosition(900000) = [[timeUs=900000, position=23030]] +numberOfTracks = 2 +track 256: + total output bytes = 19364 + sample count = 29 + format 0: + id = 1/256 + sampleMimeType = video/hevc + width = 854 + height = 480 + initializationData: + data = length 83, hash 7F428 + sample 0: + time = 66666 + flags = 1 + data = length 2510, hash 796A98BE + sample 1: + time = 100000 + flags = 0 + data = length 1219, hash 131AA4E4 + sample 2: + time = 266666 + flags = 0 + data = length 7810, hash 3F881DB9 + sample 3: + time = 200000 + flags = 0 + data = length 2306, hash 9A77959C + sample 4: + time = 133333 + flags = 0 + data = length 1058, hash B887F7EF + sample 5: + time = 166666 + flags = 0 + data = length 98, hash D95BF6E3 + sample 6: + time = 233333 + flags = 0 + data = length 61, hash 574C41C3 + sample 7: + time = 433333 + flags = 0 + data = length 296, hash E92DB288 + sample 8: + time = 366666 + flags = 0 + data = length 137, hash 586DADD6 + sample 9: + time = 300000 + flags = 0 + data = length 218, hash 91E82C9F + sample 10: + time = 333333 + flags = 0 + data = length 177, hash 4A4FEEC0 + sample 11: + time = 400000 + flags = 0 + data = length 82, hash 2E2ADD8 + sample 12: + time = 533333 + flags = 0 + data = length 290, hash 63CF7D90 + sample 13: + time = 500000 + flags = 0 + data = length 268, hash E8CBAC11 + sample 14: + time = 466666 + flags = 0 + data = length 178, hash C5B1613E + sample 15: + time = 566666 + flags = 0 + data = length 271, hash 76652FC5 + sample 16: + time = 733333 + flags = 0 + data = length 257, hash 960B5DF4 + sample 17: + time = 666666 + flags = 0 + data = length 206, hash 87358D00 + sample 18: + time = 600000 + flags = 0 + data = length 130, hash 4D7A038D + sample 19: + time = 633333 + flags = 0 + data = length 114, hash 2B3C616E + sample 20: + time = 700000 + flags = 0 + data = length 95, hash 37D79559 + sample 21: + time = 900000 + flags = 0 + data = length 233, hash 80308C9E + sample 22: + time = 833333 + flags = 0 + data = length 203, hash E70BA5F2 + sample 23: + time = 766666 + flags = 0 + data = length 95, hash BA6FA2D3 + sample 24: + time = 800000 + flags = 0 + data = length 103, hash 51291041 + sample 25: + time = 866666 + flags = 0 + data = length 111, hash EE9DCFC9 + sample 26: + time = 1033333 + flags = 0 + data = length 253, hash D0CEFBA7 + sample 27: + time = 966666 + flags = 0 + data = length 134, hash 8802EEF0 + sample 28: + time = 933333 + flags = 0 + data = length 80, hash C635D9C2 +track 8448: + total output bytes = 0 + sample count = 0 + format 0: + id = 1/8448 + sampleMimeType = application/cea-608 +tracksEnded = true diff --git a/testdata/src/test/assets/ts/sample_h265.ts.1.dump b/testdata/src/test/assets/ts/sample_h265.ts.1.dump new file mode 100644 index 0000000000..95d8d9b73d --- /dev/null +++ b/testdata/src/test/assets/ts/sample_h265.ts.1.dump @@ -0,0 +1,105 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=11421]] + getPosition(900000) = [[timeUs=900000, position=23030]] +numberOfTracks = 2 +track 256: + total output bytes = 3806 + sample count = 20 + format 0: + id = 1/256 + sampleMimeType = video/hevc + width = 854 + height = 480 + initializationData: + data = length 83, hash 7F428 + sample 0: + time = 300000 + flags = 0 + data = length 218, hash 91E82C9F + sample 1: + time = 333333 + flags = 0 + data = length 177, hash 4A4FEEC0 + sample 2: + time = 400000 + flags = 0 + data = length 82, hash 2E2ADD8 + sample 3: + time = 533333 + flags = 0 + data = length 290, hash 63CF7D90 + sample 4: + time = 500000 + flags = 0 + data = length 268, hash E8CBAC11 + sample 5: + time = 466666 + flags = 0 + data = length 178, hash C5B1613E + sample 6: + time = 566666 + flags = 0 + data = length 271, hash 76652FC5 + sample 7: + time = 733333 + flags = 0 + data = length 257, hash 960B5DF4 + sample 8: + time = 666666 + flags = 0 + data = length 206, hash 87358D00 + sample 9: + time = 600000 + flags = 0 + data = length 130, hash 4D7A038D + sample 10: + time = 633333 + flags = 0 + data = length 114, hash 2B3C616E + sample 11: + time = 700000 + flags = 0 + data = length 95, hash 37D79559 + sample 12: + time = 900000 + flags = 0 + data = length 233, hash 80308C9E + sample 13: + time = 833333 + flags = 0 + data = length 203, hash E70BA5F2 + sample 14: + time = 766666 + flags = 0 + data = length 95, hash BA6FA2D3 + sample 15: + time = 800000 + flags = 0 + data = length 103, hash 51291041 + sample 16: + time = 866666 + flags = 0 + data = length 111, hash EE9DCFC9 + sample 17: + time = 1033333 + flags = 0 + data = length 253, hash D0CEFBA7 + sample 18: + time = 966666 + flags = 0 + data = length 134, hash 8802EEF0 + sample 19: + time = 933333 + flags = 0 + data = length 80, hash C635D9C2 +track 8448: + total output bytes = 0 + sample count = 0 + format 0: + id = 1/8448 + sampleMimeType = application/cea-608 +tracksEnded = true diff --git a/testdata/src/test/assets/ts/sample_h265.ts.2.dump b/testdata/src/test/assets/ts/sample_h265.ts.2.dump new file mode 100644 index 0000000000..9080f5c17f --- /dev/null +++ b/testdata/src/test/assets/ts/sample_h265.ts.2.dump @@ -0,0 +1,69 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=11421]] + getPosition(900000) = [[timeUs=900000, position=23030]] +numberOfTracks = 2 +track 256: + total output bytes = 1796 + sample count = 11 + format 0: + id = 1/256 + sampleMimeType = video/hevc + width = 854 + height = 480 + initializationData: + data = length 83, hash 7F428 + sample 0: + time = 600000 + flags = 0 + data = length 130, hash 4D7A038D + sample 1: + time = 633333 + flags = 0 + data = length 114, hash 2B3C616E + sample 2: + time = 700000 + flags = 0 + data = length 95, hash 37D79559 + sample 3: + time = 900000 + flags = 0 + data = length 233, hash 80308C9E + sample 4: + time = 833333 + flags = 0 + data = length 203, hash E70BA5F2 + sample 5: + time = 766666 + flags = 0 + data = length 95, hash BA6FA2D3 + sample 6: + time = 800000 + flags = 0 + data = length 103, hash 51291041 + sample 7: + time = 866666 + flags = 0 + data = length 111, hash EE9DCFC9 + sample 8: + time = 1033333 + flags = 0 + data = length 253, hash D0CEFBA7 + sample 9: + time = 966666 + flags = 0 + data = length 134, hash 8802EEF0 + sample 10: + time = 933333 + flags = 0 + data = length 80, hash C635D9C2 +track 8448: + total output bytes = 0 + sample count = 0 + format 0: + id = 1/8448 + sampleMimeType = application/cea-608 +tracksEnded = true diff --git a/testdata/src/test/assets/ts/sample_h265.ts.3.dump b/testdata/src/test/assets/ts/sample_h265.ts.3.dump new file mode 100644 index 0000000000..5fe7bcede4 --- /dev/null +++ b/testdata/src/test/assets/ts/sample_h265.ts.3.dump @@ -0,0 +1,33 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=11421]] + getPosition(900000) = [[timeUs=900000, position=23030]] +numberOfTracks = 2 +track 256: + total output bytes = 396 + sample count = 2 + format 0: + id = 1/256 + sampleMimeType = video/hevc + width = 854 + height = 480 + initializationData: + data = length 83, hash 7F428 + sample 0: + time = 966666 + flags = 0 + data = length 134, hash 8802EEF0 + sample 1: + time = 933333 + flags = 0 + data = length 80, hash C635D9C2 +track 8448: + total output bytes = 0 + sample count = 0 + format 0: + id = 1/8448 + sampleMimeType = application/cea-608 +tracksEnded = true diff --git a/testdata/src/test/assets/ts/sample_h265.ts.unknown_length.dump b/testdata/src/test/assets/ts/sample_h265.ts.unknown_length.dump new file mode 100644 index 0000000000..733be6f01e --- /dev/null +++ b/testdata/src/test/assets/ts/sample_h265.ts.unknown_length.dump @@ -0,0 +1,138 @@ +seekMap: + isSeekable = false + duration = UNSET TIME + getPosition(0) = [[timeUs=0, position=0]] +numberOfTracks = 2 +track 256: + total output bytes = 19364 + sample count = 29 + format 0: + id = 1/256 + sampleMimeType = video/hevc + width = 854 + height = 480 + initializationData: + data = length 83, hash 7F428 + sample 0: + time = 66666 + flags = 1 + data = length 2510, hash 796A98BE + sample 1: + time = 100000 + flags = 0 + data = length 1219, hash 131AA4E4 + sample 2: + time = 266666 + flags = 0 + data = length 7810, hash 3F881DB9 + sample 3: + time = 200000 + flags = 0 + data = length 2306, hash 9A77959C + sample 4: + time = 133333 + flags = 0 + data = length 1058, hash B887F7EF + sample 5: + time = 166666 + flags = 0 + data = length 98, hash D95BF6E3 + sample 6: + time = 233333 + flags = 0 + data = length 61, hash 574C41C3 + sample 7: + time = 433333 + flags = 0 + data = length 296, hash E92DB288 + sample 8: + time = 366666 + flags = 0 + data = length 137, hash 586DADD6 + sample 9: + time = 300000 + flags = 0 + data = length 218, hash 91E82C9F + sample 10: + time = 333333 + flags = 0 + data = length 177, hash 4A4FEEC0 + sample 11: + time = 400000 + flags = 0 + data = length 82, hash 2E2ADD8 + sample 12: + time = 533333 + flags = 0 + data = length 290, hash 63CF7D90 + sample 13: + time = 500000 + flags = 0 + data = length 268, hash E8CBAC11 + sample 14: + time = 466666 + flags = 0 + data = length 178, hash C5B1613E + sample 15: + time = 566666 + flags = 0 + data = length 271, hash 76652FC5 + sample 16: + time = 733333 + flags = 0 + data = length 257, hash 960B5DF4 + sample 17: + time = 666666 + flags = 0 + data = length 206, hash 87358D00 + sample 18: + time = 600000 + flags = 0 + data = length 130, hash 4D7A038D + sample 19: + time = 633333 + flags = 0 + data = length 114, hash 2B3C616E + sample 20: + time = 700000 + flags = 0 + data = length 95, hash 37D79559 + sample 21: + time = 900000 + flags = 0 + data = length 233, hash 80308C9E + sample 22: + time = 833333 + flags = 0 + data = length 203, hash E70BA5F2 + sample 23: + time = 766666 + flags = 0 + data = length 95, hash BA6FA2D3 + sample 24: + time = 800000 + flags = 0 + data = length 103, hash 51291041 + sample 25: + time = 866666 + flags = 0 + data = length 111, hash EE9DCFC9 + sample 26: + time = 1033333 + flags = 0 + data = length 253, hash D0CEFBA7 + sample 27: + time = 966666 + flags = 0 + data = length 134, hash 8802EEF0 + sample 28: + time = 933333 + flags = 0 + data = length 80, hash C635D9C2 +track 8448: + total output bytes = 0 + sample count = 0 + format 0: + id = 1/8448 + sampleMimeType = application/cea-608 +tracksEnded = true