From 7ec61f13cecb821c50e020969f856bc0b12b1f6a Mon Sep 17 00:00:00 2001 From: rohks Date: Tue, 29 Oct 2024 04:16:10 -0700 Subject: [PATCH] Fix handling of cues that exceed total duration in `MatroskaExtractor` Adjusted logic to accurately calculate sizes and durations for the last valid cue point when cue timestamps are greater than the total duration. Fixes the issue where the reported duration of the MKV file was greater than the total duration specified by the duration element. Verified this using `mkvinfo` and `mediainfo` tools. PiperOrigin-RevId: 690961276 (cherry picked from commit b1f2efd218c80a0c6b3134a3d57fdff0a16e64b1) --- .../extractor/mkv/MatroskaExtractor.java | 28 ++++++---- .../extractordumps/mkv/sample.mkv.0.dump | 6 +- .../extractordumps/mkv/sample.mkv.1.dump | 56 +++++++++++-------- .../extractordumps/mkv/sample.mkv.2.dump | 34 ++++++----- .../extractordumps/mkv/sample.mkv.3.dump | 6 +- .../mkv/sample.mkv.unknown_length.dump | 6 +- 6 files changed, 80 insertions(+), 56 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mkv/MatroskaExtractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mkv/MatroskaExtractor.java index 6519eb1891..9e500dfc88 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mkv/MatroskaExtractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mkv/MatroskaExtractor.java @@ -1898,17 +1898,25 @@ public class MatroskaExtractor implements Extractor { sizes[i] = (int) (offsets[i + 1] - offsets[i]); durationsUs[i] = timesUs[i + 1] - timesUs[i]; } - sizes[cuePointsSize - 1] = - (int) (segmentContentPosition + segmentContentSize - offsets[cuePointsSize - 1]); - durationsUs[cuePointsSize - 1] = durationUs - timesUs[cuePointsSize - 1]; - long lastDurationUs = durationsUs[cuePointsSize - 1]; - if (lastDurationUs <= 0) { - Log.w(TAG, "Discarding last cue point with unexpected duration: " + lastDurationUs); - sizes = Arrays.copyOf(sizes, sizes.length - 1); - offsets = Arrays.copyOf(offsets, offsets.length - 1); - durationsUs = Arrays.copyOf(durationsUs, durationsUs.length - 1); - timesUs = Arrays.copyOf(timesUs, timesUs.length - 1); + // Start from the last cue point and move backward until a valid duration is found. + int lastValidIndex = cuePointsSize - 1; + while (lastValidIndex > 0 && timesUs[lastValidIndex] > durationUs) { + lastValidIndex--; + } + + // Calculate sizes and durations for the last valid index + sizes[lastValidIndex] = + (int) (segmentContentPosition + segmentContentSize - offsets[lastValidIndex]); + durationsUs[lastValidIndex] = durationUs - timesUs[lastValidIndex]; + + // If the last valid index is not the last cue point, truncate the arrays + if (lastValidIndex < cuePointsSize - 1) { + Log.w(TAG, "Discarding trailing cue points with timestamps greater than total duration"); + sizes = Arrays.copyOf(sizes, lastValidIndex + 1); + offsets = Arrays.copyOf(offsets, lastValidIndex + 1); + durationsUs = Arrays.copyOf(durationsUs, lastValidIndex + 1); + timesUs = Arrays.copyOf(timesUs, lastValidIndex + 1); } return new ChunkIndex(sizes, offsets, durationsUs, timesUs); diff --git a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.0.dump b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.0.dump index d31f181dd0..0f80782c2a 100644 --- a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.0.dump +++ b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.0.dump @@ -1,10 +1,10 @@ seekMap: isSeekable = true - duration = 1104000 + duration = 1072000 getPosition(0) = [[timeUs=67000, position=5576]] getPosition(1) = [[timeUs=67000, position=5576]] - getPosition(552000) = [[timeUs=547000, position=77334], [timeUs=567000, position=84155]] - getPosition(1104000) = [[timeUs=1035000, position=106570]] + getPosition(536000) = [[timeUs=534000, position=84155], [timeUs=547000, position=77334]] + getPosition(1072000) = [[timeUs=1035000, position=106570]] numberOfTracks = 2 track 1: total output bytes = 89502 diff --git a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.1.dump b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.1.dump index 749aee4faa..c8a800aee8 100644 --- a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.1.dump +++ b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.1.dump @@ -1,14 +1,14 @@ seekMap: isSeekable = true - duration = 1104000 + duration = 1072000 getPosition(0) = [[timeUs=67000, position=5576]] getPosition(1) = [[timeUs=67000, position=5576]] - getPosition(552000) = [[timeUs=547000, position=77334], [timeUs=567000, position=84155]] - getPosition(1104000) = [[timeUs=1035000, position=106570]] + getPosition(536000) = [[timeUs=534000, position=84155], [timeUs=547000, position=77334]] + getPosition(1072000) = [[timeUs=1035000, position=106570]] numberOfTracks = 2 track 1: - total output bytes = 29422 - sample count = 20 + total output bytes = 30995 + sample count = 22 format 0: id = 1 sampleMimeType = video/avc @@ -21,82 +21,90 @@ track 1: data = length 30, hash F6F3D010 data = length 10, hash 7A0D0F2B sample 0: + time = 334000 + flags = 0 + data = length 953, hash 7160C661 + sample 1: + time = 300000 + flags = 0 + data = length 620, hash 7A7AE07C + sample 2: time = 367000 flags = 0 data = length 405, hash 5CC7F4E7 - sample 1: + sample 3: time = 500000 flags = 0 data = length 4852, hash 9DB6979D - sample 2: + sample 4: time = 467000 flags = 0 data = length 547, hash E31A6979 - sample 3: + sample 5: time = 434000 flags = 0 data = length 570, hash FEC40D00 - sample 4: + sample 6: time = 634000 flags = 0 data = length 5525, hash 7C478F7E - sample 5: + sample 7: time = 567000 flags = 0 data = length 1082, hash DA07059A - sample 6: + sample 8: time = 534000 flags = 0 data = length 807, hash 93478E6B - sample 7: + sample 9: time = 600000 flags = 0 data = length 744, hash 9A8E6026 - sample 8: + sample 10: time = 767000 flags = 0 data = length 4732, hash C73B23C0 - sample 9: + sample 11: time = 700000 flags = 0 data = length 1004, hash 8A19A228 - sample 10: + sample 12: time = 667000 flags = 0 data = length 794, hash 8126022C - sample 11: + sample 13: time = 734000 flags = 0 data = length 645, hash F08300E5 - sample 12: + sample 14: time = 900000 flags = 0 data = length 2684, hash 727FE378 - sample 13: + sample 15: time = 834000 flags = 0 data = length 787, hash 419A7821 - sample 14: + sample 16: time = 800000 flags = 0 data = length 649, hash 5C159346 - sample 15: + sample 17: time = 867000 flags = 0 data = length 509, hash F912D655 - sample 16: + sample 18: time = 1034000 flags = 0 data = length 1226, hash 29815C21 - sample 17: + sample 19: time = 967000 flags = 0 data = length 898, hash D997AD0A - sample 18: + sample 20: time = 934000 flags = 0 data = length 476, hash A0423645 - sample 19: + sample 21: time = 1000000 flags = 0 data = length 486, hash DDF32CBB diff --git a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.2.dump b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.2.dump index d7bbab9459..c6769bb5ca 100644 --- a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.2.dump +++ b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.2.dump @@ -1,14 +1,14 @@ seekMap: isSeekable = true - duration = 1104000 + duration = 1072000 getPosition(0) = [[timeUs=67000, position=5576]] getPosition(1) = [[timeUs=67000, position=5576]] - getPosition(552000) = [[timeUs=547000, position=77334], [timeUs=567000, position=84155]] - getPosition(1104000) = [[timeUs=1035000, position=106570]] + getPosition(536000) = [[timeUs=534000, position=84155], [timeUs=547000, position=77334]] + getPosition(1072000) = [[timeUs=1035000, position=106570]] numberOfTracks = 2 track 1: - total output bytes = 8360 - sample count = 9 + total output bytes = 10158 + sample count = 11 format 0: id = 1 sampleMimeType = video/avc @@ -21,38 +21,46 @@ track 1: data = length 30, hash F6F3D010 data = length 10, hash 7A0D0F2B sample 0: + time = 700000 + flags = 0 + data = length 1004, hash 8A19A228 + sample 1: + time = 667000 + flags = 0 + data = length 794, hash 8126022C + sample 2: time = 734000 flags = 0 data = length 645, hash F08300E5 - sample 1: + sample 3: time = 900000 flags = 0 data = length 2684, hash 727FE378 - sample 2: + sample 4: time = 834000 flags = 0 data = length 787, hash 419A7821 - sample 3: + sample 5: time = 800000 flags = 0 data = length 649, hash 5C159346 - sample 4: + sample 6: time = 867000 flags = 0 data = length 509, hash F912D655 - sample 5: + sample 7: time = 1034000 flags = 0 data = length 1226, hash 29815C21 - sample 6: + sample 8: time = 967000 flags = 0 data = length 898, hash D997AD0A - sample 7: + sample 9: time = 934000 flags = 0 data = length 476, hash A0423645 - sample 8: + sample 10: time = 1000000 flags = 0 data = length 486, hash DDF32CBB diff --git a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.3.dump b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.3.dump index f99f632e2f..32dfc5b576 100644 --- a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.3.dump +++ b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.3.dump @@ -1,10 +1,10 @@ seekMap: isSeekable = true - duration = 1104000 + duration = 1072000 getPosition(0) = [[timeUs=67000, position=5576]] getPosition(1) = [[timeUs=67000, position=5576]] - getPosition(552000) = [[timeUs=547000, position=77334], [timeUs=567000, position=84155]] - getPosition(1104000) = [[timeUs=1035000, position=106570]] + getPosition(536000) = [[timeUs=534000, position=84155], [timeUs=547000, position=77334]] + getPosition(1072000) = [[timeUs=1035000, position=106570]] numberOfTracks = 2 track 1: total output bytes = 0 diff --git a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.unknown_length.dump b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.unknown_length.dump index d31f181dd0..0f80782c2a 100644 --- a/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.unknown_length.dump +++ b/libraries/test_data/src/test/assets/extractordumps/mkv/sample.mkv.unknown_length.dump @@ -1,10 +1,10 @@ seekMap: isSeekable = true - duration = 1104000 + duration = 1072000 getPosition(0) = [[timeUs=67000, position=5576]] getPosition(1) = [[timeUs=67000, position=5576]] - getPosition(552000) = [[timeUs=547000, position=77334], [timeUs=567000, position=84155]] - getPosition(1104000) = [[timeUs=1035000, position=106570]] + getPosition(536000) = [[timeUs=534000, position=84155], [timeUs=547000, position=77334]] + getPosition(1072000) = [[timeUs=1035000, position=106570]] numberOfTracks = 2 track 1: total output bytes = 89502