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 dropped frames caused by AVC min/max PTS not matching first/last PTS #2876

Merged
merged 6 commits into from Jul 13, 2020

Conversation

robwalch
Copy link
Collaborator

@robwalch robwalch commented Jul 9, 2020

This PR will...

  1. Fix segment duration calculation when first and last PTS do not match min and max (fixes HLS.js dropping frames after discontinuities #2873)
  2. Fix rounding errors in initPTS calculation:
    Actual 😞 90000 * 16.4 === 1475999.9999999998
    Expected 90000 * 16.4 === 1476000
  3. Limit how frequently the position of video frames are adjusted based on estimated next DTS, maintaining composition time when possible
    1. Clamp DTS to 0 after timecode hole/overlap check and Safari frame duration calculation (prevents incorrect nextDTS delta adjustment from being applied)
    2. Adjust timecode hole tolerance to account for 59.94 and 29.97 frame rate variance (prevents adjustment from being applied with 0-2 dts sample duration variance)
  4. When backtracking because of dropped video frames, reset the demuxer so that we don't use next DTS based on dropped frames
  5. Do not drop audio frames based on overlap when samples are not from the same level or a discontinuity. The estimated next PTS is often wrong and causes gaps by dropping audio that should be appended

Why is this Pull Request needed?

Incorrect segment duration calculation causes frame drops at discontinuities, and other playlist alignment and buffer errors. Also prevent some of the sample timecode hacks from doing more harm than good.

Resolves issues:

#2873

Checklist

  • changes have been done against master branch, and PR does not conflict
  • new unit / functional tests have been added (whenever applicable)

// compute first DTS and last DTS, normalize them against reference value
let sample = inputSamples[0];
firstDTS = Math.max(sample.dts, 0);
firstPTS = Math.max(sample.pts, 0);
Copy link
Collaborator Author

@robwalch robwalch Jul 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clamping to zero can cause timecode to be modified in the following block (delta = firstDTS - nextAvcDts...if (delta)) which can then prevent compositionTimeOffset from being calculated properly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the stream should come in DTS order.

I forget the exact look of them, but I know the whole thing with audio priming can lead to negative PTS times to get audio to not have any pops at the start of streams, something that popped into my head as something to raise here, where previously those would have been clamped to start at 0, thinking if there is any behaviour later that might change?

Copy link
Collaborator Author

@robwalch robwalch Jul 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem I see if that ptsNormalize is subtracting initPTS from these timecodes. So any stream with CTS > 0 on the first frame will produce negative DTS values that get clamped here. Do we want to set those DTS values to 0 and as a result change the CTS 0 on those frames?

The change below is that const delta = firstDTS - nextAvcDts will report a delta where it might not have. Moving the DTS then causes this "fix" to kick in, which then also moves PTS of the first frame, which then causes the duration of the segment to be modified, which then changes the entire timeline.

We want to stop doing that because it results in bugs like #2873 which this fixes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

audio priming is a concern as it can produce gaps at the start of streams. But that's happening regardless of these changes. I'll look at more streams on the JW platform as we've had problems with audio priming shifting PTS in some levels with different encoding profiles than others (where some mezzanine levels have different mp4 edts than others).

@robwalch robwalch added this to Top priorities in Release Planning and Backlog via automation Jul 9, 2020
@robwalch robwalch moved this from Top priorities to v0.14.1 in Release Planning and Backlog Jul 9, 2020
@robwalch robwalch added this to the 0.14.1 milestone Jul 9, 2020
src/remux/mp4-remuxer.js Outdated Show resolved Hide resolved
src/remux/mp4-remuxer.js Outdated Show resolved Hide resolved
logger.log(`Video: PTS/DTS adjusted: ${toMsFromMpegTsClock(firstPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
minPTS -= delta;
if (foundHole) {
logger.warn(`AVC: ${toMsFromMpegTsClock(delta, true)} ms hole between fragments detected,filling it`);
Copy link
Collaborator

@itsjamie itsjamie Jul 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping the current PTS / DTS in these log message would be nice for peopel trying to fix bad content.

Copy link
Collaborator Author

@robwalch robwalch Jul 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed these from logs to warnings because I believe most of the time these adjustments are being made in error. These hacks are certainly needed in some cases, but should not be for well formed streams.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@itsjamie that information is available in the following log message

logger.log(`Video: PTS/DTS adjusted: ${toMsFromMpegTsClock(minPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);

itsjamie
itsjamie previously approved these changes Jul 13, 2020
// 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) / (inputSamples.length - 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);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will keep initial DTS appearing as it was before, and apply the same change to initial frame CTS as before. The difference is now we avoid modifying both initial PTS and mp4SampleDuration in the code above.

logger.log(`AVC: ${toMsFromMpegTsClock(delta, true)} ms hole between fragments detected,filling it`);
} else if (delta < -1) {
logger.log(`AVC: ${toMsFromMpegTsClock(-delta, true)} ms overlapping between fragments detected`);
const foundHole = delta > 2;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check prevents us from adjusting timecode in our first BBB test stream with a 59.94 and 29.97 frame rates.

@robwalch robwalch merged commit 45d5a92 into master Jul 13, 2020
@robwalch robwalch deleted the bugfix/fix-dropped-frames branch July 13, 2020 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

HLS.js dropping frames after discontinuities
2 participants