Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix gaps introduced in video buffer by remuxer work-around #2894

Merged
merged 1 commit into from Jul 16, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 14 additions & 13 deletions src/remux/mp4-remuxer.js
Expand Up @@ -52,9 +52,12 @@ class MP4Remuxer {
// if first audio DTS is not aligned with first video DTS then we need to take that into account
// when providing timeOffset to remuxAudio / remuxVideo. if we don't do that, there might be a permanent / small
// drift between audio and video streams
let audiovideoDeltaDts = (audioTrack.samples[0].pts - videoTrack.samples[0].pts) / videoTrack.inputTimeScale;
audioTimeOffset += Math.max(0, audiovideoDeltaDts);
videoTimeOffset += Math.max(0, -audiovideoDeltaDts);
// Use pts at timeOffset 0 so that VOD streams begin at 0
const tsDelta = timeOffset > 0 ? audioTrack.samples[0].dts - videoTrack.samples[0].dts
: audioTrack.samples[0].pts - videoTrack.samples[0].pts;
const audiovideoTimestampDelta = tsDelta / videoTrack.inputTimeScale;
audioTimeOffset += Math.max(0, audiovideoTimestampDelta);
videoTimeOffset += Math.max(0, -audiovideoTimestampDelta);
}
// Purposefully remuxing audio before video, so that remuxVideo can use nextAudioPts, which is
// calculated in remuxAudio.
Expand Down Expand Up @@ -258,11 +261,16 @@ class MP4Remuxer {
firstDTS = inputSamples[0].dts;
lastDTS = inputSamples[nbSamples - 1].dts;

// on Safari let's signal the same sample duration for all samples
// sample duration (as expected by trun MP4 boxes), should be the delta between sample DTS
// set this constant duration as being the avg delta between consecutive DTS.
const averageSampleDuration = Math.round((lastDTS - firstDTS) / (nbSamples - 1));

// check timestamp continuity across consecutive fragments (this is to remove inter-fragment gap/hole)
const delta = firstDTS - nextAvcDts;
// if fragment are contiguous, detect hole/overlapping between fragments
if (contiguous) {
const foundHole = delta > 2;
const foundHole = delta > averageSampleDuration;
const foundOverlap = delta < -1;
if (foundHole || foundOverlap) {
if (foundHole) {
Expand All @@ -274,17 +282,10 @@ class MP4Remuxer {
minPTS -= delta;
inputSamples[0].dts = firstDTS;
inputSamples[0].pts = minPTS;
logger.log(`Video: PTS/DTS adjusted: ${toMsFromMpegTsClock(minPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
logger.log(`Video: First PTS/DTS adjusted: ${toMsFromMpegTsClock(minPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
}
}

// on Safari let's signal the same sample duration for all samples
// sample duration (as expected by trun MP4 boxes), should be the delta between sample DTS
// set this constant duration as being the avg delta between consecutive DTS.
if (isSafari) {
mp4SampleDuration = Math.round((lastDTS - firstDTS) / (nbSamples - 1));
}

// Clamp first DTS to 0 so that we're still aligning on initPTS,
// and not passing negative values to MP4.traf. This will change initial frame compositionTimeOffset!
firstDTS = Math.max(firstDTS, 0);
Expand All @@ -304,7 +305,7 @@ class MP4Remuxer {
// normalize PTS/DTS
if (isSafari) {
// sample DTS is computed using a constant decoding offset (mp4SampleDuration) between samples
sample.dts = firstDTS + i * mp4SampleDuration;
sample.dts = firstDTS + i * averageSampleDuration;
} else {
// ensure sample monotonic DTS
sample.dts = Math.max(sample.dts, firstDTS);
Expand Down