From 23b3c42baf2cd5da0c3ff9e8b4afde2c06cc65ff Mon Sep 17 00:00:00 2001 From: Aman Gautam Date: Sun, 22 Mar 2026 16:43:29 +0530 Subject: [PATCH 1/4] Fix audio-video sync issue in DASH MP4 muxer by normalizing composition timestamps --- .../newpipe/streams/Mp4FromDashWriter.java | 54 ++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java index 807f190b4ad..cd2a4c58233 100644 --- a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java +++ b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java @@ -162,6 +162,12 @@ public void build(final SharpStream output) throws IOException { final int[] defaultMediaTime = new int[readers.length]; final int[] defaultSampleDuration = new int[readers.length]; final int[] sampleCount = new int[readers.length]; + long[] firstPts = new long[readers.length]; + boolean[] firstPtsSet = new boolean[readers.length]; + boolean minPtsComputed = false; + long minPts = 0; + long[] basePts = new long[readers.length]; + boolean[] basePtsSet = new boolean[readers.length]; final TablesInfo[] tablesInfo = new TablesInfo[tracks.length]; for (int i = 0; i < tablesInfo.length; i++) { @@ -317,7 +323,7 @@ public void build(final SharpStream output) throws IOException { for (int i = 0; i < readers.length; i++) { if (sampleIndex[i] < 0) { - continue; // track is done + continue; } final long chunkOffset = writeOffset; @@ -336,26 +342,62 @@ public void build(final SharpStream output) throws IOException { if (sample == null) { if (tablesInfo[i].ctts > 0 && sampleExtra[i] >= 0) { writeEntryArray(tablesInfo[i].ctts, 1, sampleCount[i], - sampleExtra[i]); // flush last entries + sampleExtra[i]); outRestore(); } sampleIndex[i] = -1; break; } + // Normalize composition timestamps to align audio and video timelines + long pts = sample.info.sampleCompositionTimeOffset; + if (!firstPtsSet[i]) { + firstPts[i] = pts; + firstPtsSet[i] = true; + } + + if (!minPtsComputed) { + boolean allSet = true; + for (int k = 0; k < readers.length; k++) { + if (!firstPtsSet[k]) { + allSet = false; + break; + } + } + + if (allSet) { + minPts = firstPts[0]; + for (int k = 1; k < readers.length; k++) { + minPts = Math.min(minPts, firstPts[k]); + } + minPtsComputed = true; + } + } + sampleIndex[i]++; + if (!basePtsSet[i]) { + if (minPtsComputed) { + basePts[i] = minPts; + } else { + basePts[i] = firstPts[i]; + } + basePtsSet[i] = true; + } + + int correctedOffset = (int) (pts - basePts[i]); if (tablesInfo[i].ctts > 0) { - if (sample.info.sampleCompositionTimeOffset == sampleExtra[i]) { + if (correctedOffset == sampleExtra[i]) { sampleCount[i]++; } else { if (sampleExtra[i] >= 0) { - tablesInfo[i].ctts = writeEntryArray(tablesInfo[i].ctts, 2, - sampleCount[i], sampleExtra[i]); + tablesInfo[i].ctts = writeEntryArray( + tablesInfo[i].ctts, 2, sampleCount[i], sampleExtra[i] + ); outRestore(); } sampleCount[i] = 1; - sampleExtra[i] = sample.info.sampleCompositionTimeOffset; + sampleExtra[i] = correctedOffset; } } From 13697eea6314b6b0c21b04f79a2cfded7416f476 Mon Sep 17 00:00:00 2001 From: Aman Gautam Date: Sun, 22 Mar 2026 22:22:46 +0530 Subject: [PATCH 2/4] Fix checkstyle violations: mark local variables as final --- .../schabi/newpipe/streams/Mp4FromDashWriter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java index cd2a4c58233..c91f2878785 100644 --- a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java +++ b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java @@ -162,12 +162,12 @@ public void build(final SharpStream output) throws IOException { final int[] defaultMediaTime = new int[readers.length]; final int[] defaultSampleDuration = new int[readers.length]; final int[] sampleCount = new int[readers.length]; - long[] firstPts = new long[readers.length]; - boolean[] firstPtsSet = new boolean[readers.length]; + final long[] firstPts = new long[readers.length]; + final boolean[] firstPtsSet = new boolean[readers.length]; + final long[] basePts = new long[readers.length]; + final boolean[] basePtsSet = new boolean[readers.length]; boolean minPtsComputed = false; long minPts = 0; - long[] basePts = new long[readers.length]; - boolean[] basePtsSet = new boolean[readers.length]; final TablesInfo[] tablesInfo = new TablesInfo[tracks.length]; for (int i = 0; i < tablesInfo.length; i++) { @@ -350,7 +350,7 @@ public void build(final SharpStream output) throws IOException { } // Normalize composition timestamps to align audio and video timelines - long pts = sample.info.sampleCompositionTimeOffset; + final long pts = sample.info.sampleCompositionTimeOffset; if (!firstPtsSet[i]) { firstPts[i] = pts; firstPtsSet[i] = true; @@ -385,7 +385,7 @@ public void build(final SharpStream output) throws IOException { basePtsSet[i] = true; } - int correctedOffset = (int) (pts - basePts[i]); + final int correctedOffset = (int) (pts - basePts[i]); if (tablesInfo[i].ctts > 0) { if (correctedOffset == sampleExtra[i]) { sampleCount[i]++; From 47f0ed86377f887c57b7198ac838f6e16ac92e9d Mon Sep 17 00:00:00 2001 From: Aman Gautam Date: Sun, 22 Mar 2026 22:25:20 +0530 Subject: [PATCH 3/4] Fix checkstyle: make minPts variables final --- .../newpipe/streams/Mp4FromDashWriter.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java index c91f2878785..0388c2d7a57 100644 --- a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java +++ b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java @@ -166,8 +166,8 @@ public void build(final SharpStream output) throws IOException { final boolean[] firstPtsSet = new boolean[readers.length]; final long[] basePts = new long[readers.length]; final boolean[] basePtsSet = new boolean[readers.length]; - boolean minPtsComputed = false; - long minPts = 0; + final boolean[] minPtsComputedArr = new boolean[]{false}; + final long[] minPtsArr = new long[]{0}; final TablesInfo[] tablesInfo = new TablesInfo[tracks.length]; for (int i = 0; i < tablesInfo.length; i++) { @@ -356,7 +356,7 @@ public void build(final SharpStream output) throws IOException { firstPtsSet[i] = true; } - if (!minPtsComputed) { + if (!minPtsComputedArr[0]) { boolean allSet = true; for (int k = 0; k < readers.length; k++) { if (!firstPtsSet[k]) { @@ -366,19 +366,19 @@ public void build(final SharpStream output) throws IOException { } if (allSet) { - minPts = firstPts[0]; + minPtsArr[0] = firstPts[0]; for (int k = 1; k < readers.length; k++) { - minPts = Math.min(minPts, firstPts[k]); + minPtsArr[0] = Math.min(minPtsArr[0], firstPts[k]); } - minPtsComputed = true; + minPtsComputedArr[0] = true; } } sampleIndex[i]++; if (!basePtsSet[i]) { - if (minPtsComputed) { - basePts[i] = minPts; + if (minPtsComputedArr[0]) { + basePts[i] = minPtsArr[0]; } else { basePts[i] = firstPts[i]; } From 4c7c2292dd72cf435f4b065e00f8b7a7d0362ff5 Mon Sep 17 00:00:00 2001 From: Aman Gautam Date: Sun, 22 Mar 2026 22:32:22 +0530 Subject: [PATCH 4/4] Fix checkstyle: make allSet computation compliant with final rule --- .../schabi/newpipe/streams/Mp4FromDashWriter.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java index 0388c2d7a57..d9c750b51ca 100644 --- a/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java +++ b/app/src/main/java/org/schabi/newpipe/streams/Mp4FromDashWriter.java @@ -357,12 +357,16 @@ public void build(final SharpStream output) throws IOException { } if (!minPtsComputedArr[0]) { - boolean allSet = true; - for (int k = 0; k < readers.length; k++) { - if (!firstPtsSet[k]) { - allSet = false; - break; + final boolean allSet; + { + boolean temp = true; + for (int k = 0; k < readers.length; k++) { + if (!firstPtsSet[k]) { + temp = false; + break; + } } + allSet = temp; } if (allSet) {