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
Conversation
// 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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
src/remux/mp4-remuxer.js
Outdated
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`); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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`);
…etection is not based on what was previously appeneded
d090481
to
05ce6a7
Compare
// 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); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
This PR will...
Actual 😞
90000 * 16.4 === 1475999.9999999998
Expected
90000 * 16.4 === 1476000
nextDTS delta
adjustment from being applied)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