From d4af13803a44adfb9eb17af895826740855529f6 Mon Sep 17 00:00:00 2001 From: Daniele Sparano Date: Wed, 29 Nov 2023 13:09:27 +0000 Subject: [PATCH 1/4] Fix H264 reader key frame detection --- .../java/androidx/media3/extractor/ts/H264Reader.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java index c6cb9376162..795f9743dc0 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java @@ -183,7 +183,7 @@ private void startNalUnit(long position, int nalUnitType, long pesTimeUs) { pps.startNalUnit(nalUnitType); } sei.startNalUnit(nalUnitType); - sampleReader.startNalUnit(position, nalUnitType, pesTimeUs); + sampleReader.startNalUnit(position, nalUnitType, pesTimeUs, randomAccessIndicator); } @RequiresNonNull("sampleReader") @@ -254,7 +254,7 @@ private void endNalUnit(long position, int offset, int discardPadding, long pesT seiReader.consume(pesTimeUs, seiWrapper); } boolean sampleIsKeyFrame = - sampleReader.endNalUnit(position, offset, hasOutputFormat, randomAccessIndicator); + sampleReader.endNalUnit(position, offset, hasOutputFormat); if (sampleIsKeyFrame) { // This is either an IDR frame or the first I-frame since the random access indicator, so mark // it as a keyframe. Clear the flag so that subsequent non-IDR I-frames are not marked as @@ -297,6 +297,7 @@ private static final class SampleReader { private long samplePosition; private long sampleTimeUs; private boolean sampleIsKeyframe; + private boolean randomAccessIndicator; public SampleReader( TrackOutput output, boolean allowNonIdrKeyframes, boolean detectAccessUnits) { @@ -330,10 +331,11 @@ public void reset() { sliceHeader.clear(); } - public void startNalUnit(long position, int type, long pesTimeUs) { + public void startNalUnit(long position, int type, long pesTimeUs, boolean rai) { nalUnitType = type; nalUnitTimeUs = pesTimeUs; nalUnitStartPosition = position; + randomAccessIndicator = rai; if ((allowNonIdrKeyframes && nalUnitType == NalUnitUtil.NAL_UNIT_TYPE_NON_IDR) || (detectAccessUnits && (nalUnitType == NalUnitUtil.NAL_UNIT_TYPE_IDR @@ -482,7 +484,7 @@ public void appendToNalUnit(byte[] data, int offset, int limit) { } public boolean endNalUnit( - long position, int offset, boolean hasOutputFormat, boolean randomAccessIndicator) { + long position, int offset, boolean hasOutputFormat) { if (nalUnitType == NalUnitUtil.NAL_UNIT_TYPE_AUD || (detectAccessUnits && sliceHeader.isFirstVclNalUnitOfPicture(previousSliceHeader))) { // If the NAL unit ending is the start of a new sample, output the previous one. From 4a17ca760023d400861c69ca2b55b86acf770d20 Mon Sep 17 00:00:00 2001 From: Daniele Sparano Date: Tue, 5 Dec 2023 14:36:42 +0000 Subject: [PATCH 2/4] Add basic h264 sample unit test to ensure correct sample flags, including key frames --- .../media3/extractor/ts/TsExtractorTest.java | 4 + .../extractordumps/ts/sample_h264.ts.0.dump | 144 ++++++++++++++++++ .../extractordumps/ts/sample_h264.ts.1.dump | 108 +++++++++++++ .../extractordumps/ts/sample_h264.ts.2.dump | 72 +++++++++ .../extractordumps/ts/sample_h264.ts.3.dump | 36 +++++ .../ts/sample_h264.ts.unknown_length.dump | 141 +++++++++++++++++ .../src/test/assets/media/ts/sample_h264.ts | Bin 0 -> 48880 bytes 7 files changed, 505 insertions(+) create mode 100644 libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.0.dump create mode 100644 libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.1.dump create mode 100644 libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.2.dump create mode 100644 libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.3.dump create mode 100644 libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.unknown_length.dump create mode 100644 libraries/test_data/src/test/assets/media/ts/sample_h264.ts diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java index c0d4a00ec97..b29cd3ca766 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java @@ -66,6 +66,10 @@ public void sampleWithH263() throws Exception { } @Test + public void sampleWithH264() throws Exception { + ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_h264.ts", simulationConfig); + } + public void sampleWithH264AndMpegAudio() throws Exception { ExtractorAsserts.assertBehavior( TsExtractor::new, "media/ts/sample_h264_mpeg_audio.ts", simulationConfig); diff --git a/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.0.dump b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.0.dump new file mode 100644 index 00000000000..366338fe96c --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.0.dump @@ -0,0 +1,144 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=23030]] + getPosition(900000) = [[timeUs=900000, position=46248]] +numberOfTracks = 1 +track 256: + total output bytes = 41614 + sample count = 30 + format 0: + id = 1/256 + sampleMimeType = video/avc + codecs = avc1.64001F + width = 854 + height = 480 + colorInfo: + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 29, hash A220FDE0 + data = length 9, hash D971CD89 + sample 0: + time = 66666 + flags = 1 + data = length 856, hash E3FC14FA + sample 1: + time = 100000 + flags = 0 + data = length 3330, hash ACE433CC + sample 2: + time = 166666 + flags = 0 + data = length 6849, hash 2762E298 + sample 3: + time = 133333 + flags = 0 + data = length 794, hash 16489833 + sample 4: + time = 233333 + flags = 0 + data = length 1874, hash 24DF8A2D + sample 5: + time = 200000 + flags = 0 + data = length 1209, hash B137200F + sample 6: + time = 366666 + flags = 0 + data = length 476, hash 1D70B27E + sample 7: + time = 300000 + flags = 0 + data = length 325, hash D3FB2CC2 + sample 8: + time = 266666 + flags = 0 + data = length 89, hash F66C5D60 + sample 9: + time = 333333 + flags = 0 + data = length 177, hash 7E6DB5B7 + sample 10: + time = 400000 + flags = 1 + data = length 11054, hash 1FC7442D + sample 11: + time = 533333 + flags = 0 + data = length 302, hash 5432E85C + sample 12: + time = 466666 + flags = 0 + data = length 302, hash 95A21C90 + sample 13: + time = 433333 + flags = 0 + data = length 96, hash 8C98DBB8 + sample 14: + time = 500000 + flags = 0 + data = length 198, hash 114E22D9 + sample 15: + time = 666666 + flags = 0 + data = length 303, hash C2C45716 + sample 16: + time = 600000 + flags = 0 + data = length 168, hash 1B048DCA + sample 17: + time = 566666 + flags = 0 + data = length 98, hash 3AA3B8B4 + sample 18: + time = 633333 + flags = 0 + data = length 108, hash 4F67E6F8 + sample 19: + time = 700000 + flags = 0 + data = length 110, hash 625A9B91 + sample 20: + time = 733333 + flags = 1 + data = length 11235, hash 8EDDEB9 + sample 21: + time = 866666 + flags = 0 + data = length 358, hash 797276E4 + sample 22: + time = 800000 + flags = 0 + data = length 336, hash B92DBED9 + sample 23: + time = 766666 + flags = 0 + data = length 105, hash 223F3D12 + sample 24: + time = 833333 + flags = 0 + data = length 106, hash DF8D1552 + sample 25: + time = 1000000 + flags = 0 + data = length 235, hash 6127527D + sample 26: + time = 933333 + flags = 0 + data = length 109, hash E8E69F9F + sample 27: + time = 900000 + flags = 0 + data = length 84, hash 54E55CB4 + sample 28: + time = 966666 + flags = 0 + data = length 93, hash B6B6263C + sample 29: + time = 1033333 + flags = 0 + data = length 234, hash A48D3D90 +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.1.dump b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.1.dump new file mode 100644 index 00000000000..afbcb23e5d1 --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.1.dump @@ -0,0 +1,108 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=23030]] + getPosition(900000) = [[timeUs=900000, position=46248]] +numberOfTracks = 1 +track 256: + total output bytes = 25812 + sample count = 21 + format 0: + id = 1/256 + sampleMimeType = video/avc + codecs = avc1.64001F + width = 854 + height = 480 + colorInfo: + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 29, hash A220FDE0 + data = length 9, hash D971CD89 + sample 0: + time = 333333 + flags = 0 + data = length 177, hash 7E6DB5B7 + sample 1: + time = 400000 + flags = 1 + data = length 11054, hash 1FC7442D + sample 2: + time = 533333 + flags = 0 + data = length 302, hash 5432E85C + sample 3: + time = 466666 + flags = 0 + data = length 302, hash 95A21C90 + sample 4: + time = 433333 + flags = 0 + data = length 96, hash 8C98DBB8 + sample 5: + time = 500000 + flags = 0 + data = length 198, hash 114E22D9 + sample 6: + time = 666666 + flags = 0 + data = length 303, hash C2C45716 + sample 7: + time = 600000 + flags = 0 + data = length 168, hash 1B048DCA + sample 8: + time = 566666 + flags = 0 + data = length 98, hash 3AA3B8B4 + sample 9: + time = 633333 + flags = 0 + data = length 108, hash 4F67E6F8 + sample 10: + time = 700000 + flags = 0 + data = length 110, hash 625A9B91 + sample 11: + time = 733333 + flags = 1 + data = length 11235, hash 8EDDEB9 + sample 12: + time = 866666 + flags = 0 + data = length 358, hash 797276E4 + sample 13: + time = 800000 + flags = 0 + data = length 336, hash B92DBED9 + sample 14: + time = 766666 + flags = 0 + data = length 105, hash 223F3D12 + sample 15: + time = 833333 + flags = 0 + data = length 106, hash DF8D1552 + sample 16: + time = 1000000 + flags = 0 + data = length 235, hash 6127527D + sample 17: + time = 933333 + flags = 0 + data = length 109, hash E8E69F9F + sample 18: + time = 900000 + flags = 0 + data = length 84, hash 54E55CB4 + sample 19: + time = 966666 + flags = 0 + data = length 93, hash B6B6263C + sample 20: + time = 1033333 + flags = 0 + data = length 234, hash A48D3D90 +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.2.dump b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.2.dump new file mode 100644 index 00000000000..ce18263dd80 --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.2.dump @@ -0,0 +1,72 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=23030]] + getPosition(900000) = [[timeUs=900000, position=46248]] +numberOfTracks = 1 +track 256: + total output bytes = 13114 + sample count = 12 + format 0: + id = 1/256 + sampleMimeType = video/avc + codecs = avc1.64001F + width = 854 + height = 480 + colorInfo: + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 29, hash A220FDE0 + data = length 9, hash D971CD89 + sample 0: + time = 633333 + flags = 0 + data = length 108, hash 4F67E6F8 + sample 1: + time = 700000 + flags = 0 + data = length 110, hash 625A9B91 + sample 2: + time = 733333 + flags = 1 + data = length 11235, hash 8EDDEB9 + sample 3: + time = 866666 + flags = 0 + data = length 358, hash 797276E4 + sample 4: + time = 800000 + flags = 0 + data = length 336, hash B92DBED9 + sample 5: + time = 766666 + flags = 0 + data = length 105, hash 223F3D12 + sample 6: + time = 833333 + flags = 0 + data = length 106, hash DF8D1552 + sample 7: + time = 1000000 + flags = 0 + data = length 235, hash 6127527D + sample 8: + time = 933333 + flags = 0 + data = length 109, hash E8E69F9F + sample 9: + time = 900000 + flags = 0 + data = length 84, hash 54E55CB4 + sample 10: + time = 966666 + flags = 0 + data = length 93, hash B6B6263C + sample 11: + time = 1033333 + flags = 0 + data = length 234, hash A48D3D90 +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.3.dump b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.3.dump new file mode 100644 index 00000000000..f8372491d6e --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.3.dump @@ -0,0 +1,36 @@ +seekMap: + isSeekable = true + duration = 900000 + getPosition(0) = [[timeUs=0, position=0]] + getPosition(1) = [[timeUs=1, position=0]] + getPosition(450000) = [[timeUs=450000, position=23030]] + getPosition(900000) = [[timeUs=900000, position=46248]] +numberOfTracks = 1 +track 256: + total output bytes = 412 + sample count = 3 + format 0: + id = 1/256 + sampleMimeType = video/avc + codecs = avc1.64001F + width = 854 + height = 480 + colorInfo: + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 29, hash A220FDE0 + data = length 9, hash D971CD89 + sample 0: + time = 900000 + flags = 0 + data = length 84, hash 54E55CB4 + sample 1: + time = 966666 + flags = 0 + data = length 93, hash B6B6263C + sample 2: + time = 1033333 + flags = 0 + data = length 234, hash A48D3D90 +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.unknown_length.dump b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.unknown_length.dump new file mode 100644 index 00000000000..8406fb34de5 --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/ts/sample_h264.ts.unknown_length.dump @@ -0,0 +1,141 @@ +seekMap: + isSeekable = false + duration = UNSET TIME + getPosition(0) = [[timeUs=0, position=0]] +numberOfTracks = 1 +track 256: + total output bytes = 41614 + sample count = 30 + format 0: + id = 1/256 + sampleMimeType = video/avc + codecs = avc1.64001F + width = 854 + height = 480 + colorInfo: + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 29, hash A220FDE0 + data = length 9, hash D971CD89 + sample 0: + time = 66666 + flags = 1 + data = length 856, hash E3FC14FA + sample 1: + time = 100000 + flags = 0 + data = length 3330, hash ACE433CC + sample 2: + time = 166666 + flags = 0 + data = length 6849, hash 2762E298 + sample 3: + time = 133333 + flags = 0 + data = length 794, hash 16489833 + sample 4: + time = 233333 + flags = 0 + data = length 1874, hash 24DF8A2D + sample 5: + time = 200000 + flags = 0 + data = length 1209, hash B137200F + sample 6: + time = 366666 + flags = 0 + data = length 476, hash 1D70B27E + sample 7: + time = 300000 + flags = 0 + data = length 325, hash D3FB2CC2 + sample 8: + time = 266666 + flags = 0 + data = length 89, hash F66C5D60 + sample 9: + time = 333333 + flags = 0 + data = length 177, hash 7E6DB5B7 + sample 10: + time = 400000 + flags = 1 + data = length 11054, hash 1FC7442D + sample 11: + time = 533333 + flags = 0 + data = length 302, hash 5432E85C + sample 12: + time = 466666 + flags = 0 + data = length 302, hash 95A21C90 + sample 13: + time = 433333 + flags = 0 + data = length 96, hash 8C98DBB8 + sample 14: + time = 500000 + flags = 0 + data = length 198, hash 114E22D9 + sample 15: + time = 666666 + flags = 0 + data = length 303, hash C2C45716 + sample 16: + time = 600000 + flags = 0 + data = length 168, hash 1B048DCA + sample 17: + time = 566666 + flags = 0 + data = length 98, hash 3AA3B8B4 + sample 18: + time = 633333 + flags = 0 + data = length 108, hash 4F67E6F8 + sample 19: + time = 700000 + flags = 0 + data = length 110, hash 625A9B91 + sample 20: + time = 733333 + flags = 1 + data = length 11235, hash 8EDDEB9 + sample 21: + time = 866666 + flags = 0 + data = length 358, hash 797276E4 + sample 22: + time = 800000 + flags = 0 + data = length 336, hash B92DBED9 + sample 23: + time = 766666 + flags = 0 + data = length 105, hash 223F3D12 + sample 24: + time = 833333 + flags = 0 + data = length 106, hash DF8D1552 + sample 25: + time = 1000000 + flags = 0 + data = length 235, hash 6127527D + sample 26: + time = 933333 + flags = 0 + data = length 109, hash E8E69F9F + sample 27: + time = 900000 + flags = 0 + data = length 84, hash 54E55CB4 + sample 28: + time = 966666 + flags = 0 + data = length 93, hash B6B6263C + sample 29: + time = 1033333 + flags = 0 + data = length 234, hash A48D3D90 +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/media/ts/sample_h264.ts b/libraries/test_data/src/test/assets/media/ts/sample_h264.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e4becd3a9af4f3f5b89caf3e7bb4c7650aba0ea GIT binary patch literal 48880 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

oatWl4j1WJM^Qg@r7r7b>iI0E% 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 literal 0 HcmV?d00001 From 6f5187a34badf5d0c510ecbf033eff1b178e9027 Mon Sep 17 00:00:00 2001 From: Daniele Sparano Date: Tue, 5 Dec 2023 14:57:00 +0000 Subject: [PATCH 3/4] Format to wake up PR --- .../main/java/androidx/media3/extractor/ts/H264Reader.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java index 795f9743dc0..99ad187b05d 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java @@ -253,8 +253,7 @@ private void endNalUnit(long position, int offset, int discardPadding, long pesT seiWrapper.setPosition(4); // NAL prefix and nal_unit() header. seiReader.consume(pesTimeUs, seiWrapper); } - boolean sampleIsKeyFrame = - sampleReader.endNalUnit(position, offset, hasOutputFormat); + boolean sampleIsKeyFrame = sampleReader.endNalUnit(position, offset, hasOutputFormat); if (sampleIsKeyFrame) { // This is either an IDR frame or the first I-frame since the random access indicator, so mark // it as a keyframe. Clear the flag so that subsequent non-IDR I-frames are not marked as @@ -483,8 +482,7 @@ public void appendToNalUnit(byte[] data, int offset, int limit) { isFilling = false; } - public boolean endNalUnit( - long position, int offset, boolean hasOutputFormat) { + public boolean endNalUnit(long position, int offset, boolean hasOutputFormat) { if (nalUnitType == NalUnitUtil.NAL_UNIT_TYPE_AUD || (detectAccessUnits && sliceHeader.isFirstVclNalUnitOfPicture(previousSliceHeader))) { // If the NAL unit ending is the start of a new sample, output the previous one. From eb2092bc8bc07c04aa7f59c66604e7e35ddd18e9 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 11 Dec 2023 14:36:59 +0000 Subject: [PATCH 4/4] Formatting fixes and release notes --- RELEASENOTES.md | 2 ++ .../main/java/androidx/media3/extractor/ts/H264Reader.java | 5 +++-- .../java/androidx/media3/extractor/ts/TsExtractorTest.java | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 62a0143a876..5e9ea278126 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -50,6 +50,8 @@ `ColorInfo.colorSpace`, `ColorInfo.colorTransfer`, and `ColorInfo.colorRange` values ([#692](https://github.com/androidx/media/pull/692)). + * Fix wrong keyframe detection for TS H264 streams + ([#864](https://github.com/androidx/media/pull/864)). * Audio: * Video: * Add workaround for a device issue on Galaxy Tab S7 FE, Chromecast with diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java index 99ad187b05d..07786a4ba5e 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java @@ -330,11 +330,12 @@ public void reset() { sliceHeader.clear(); } - public void startNalUnit(long position, int type, long pesTimeUs, boolean rai) { + public void startNalUnit( + long position, int type, long pesTimeUs, boolean randomAccessIndicator) { nalUnitType = type; nalUnitTimeUs = pesTimeUs; nalUnitStartPosition = position; - randomAccessIndicator = rai; + this.randomAccessIndicator = randomAccessIndicator; if ((allowNonIdrKeyframes && nalUnitType == NalUnitUtil.NAL_UNIT_TYPE_NON_IDR) || (detectAccessUnits && (nalUnitType == NalUnitUtil.NAL_UNIT_TYPE_IDR diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java index b29cd3ca766..4ee83354a39 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/ts/TsExtractorTest.java @@ -70,6 +70,7 @@ public void sampleWithH264() throws Exception { ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_h264.ts", simulationConfig); } + @Test public void sampleWithH264AndMpegAudio() throws Exception { ExtractorAsserts.assertBehavior( TsExtractor::new, "media/ts/sample_h264_mpeg_audio.ts", simulationConfig);