video-dev / hls.js

HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.
https://hlsjs.video-dev.org/demo
Other
14.79k stars 2.57k forks source link

support playlists with drift between actual PTS and HLS time tracking #24

Closed mangui closed 9 years ago

mangui commented 9 years ago

from https://github.com/dailymotion/hls.js/issues/22#issuecomment-146040643:

https://s3.amazonaws.com/tablo-theoplayer-testing/playlist.m3u8

the start position of each fragment (as inferred by the playlist via EXTINF) starts to drift away from the start position in the PTS data. This appears to get progressively worse over time.

For example:

Segment EXTINF range PTS range Difference
#53 426 to 436 426.459377778 to 436.369277778 0.459
#368 3576 to 3586 3579.609366667 to 3589.519277778 3.609
#586 5756 to 5766 5761.789366667 to 5771.699266667 5.789

This gradual drift means that whenever one seeks, the player can't find an appropriate segment, as the data doesn't match up.

flashls logic should be imported in hls.js to cope with fragment drift: in flashls, fragment duration are recomputed after fragment parsing, and the whole level (fragment start offset and duration) is re-adjusted to take into account any potential drift: https://github.com/mangui/flashls/blob/dev/src/org/mangui/hls/model/Level.as#L274-L368

also, when switching to a level on which PTS is unknown, a PTS analysis is first performed to find the right fragment : https://github.com/mangui/flashls/blob/dev/src/org/mangui/hls/loader/FragmentLoader.as#L682-L775

matb33 commented 9 years ago

Below is a hack temporary solution until @mangui has time to implement the above. I emphasize that this is a hack solution -- it works but you need to wait until the looping error event is fired before it recovers, so it's generally slow. It doesn't hurt to keep once the proper drift solution is implemented, as it offers a fallback recovery in case the looping crops up for other potential reasons:

var hls = new Hls();
var video = document.getElementById('your-video-id');

hls.attachVideo(video);

//...

hls.on(Hls.Events.ERROR, function (event, data) {
  if (!data.fatal && data.details === Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR) {
    seekToNearestBuffered();
  }
});

function seekToNearestBuffered() {
  var pos = video.currentTime,
    closest = null,
    smallestDiff = null,
    start, diff;

  console.log("[hlsjs] attempt to seek to nearest buffered area, currentTime:", pos);

  for (var i = 0; i < video.buffered.length; i++) {
    start = video.buffered.start(i);
    diff = Math.abs(pos - start);
    if (smallestDiff === null || diff < smallestDiff) {
      closest = start;
      smallestDiff = diff;
    }
  }

  if (closest !== null) {
    console.log("[hlsjs] seeking to closest buffered area start:", closest);
    video.currentTime = closest;
  }
}
mangui commented 9 years ago

@matb33 your playlist should work, you can check on drift_refactor branch @shacharz it should also fix the playback of https://livestream.peer5.com/video/soccer/index.m3u8

mangui commented 9 years ago

closing as implemented

matb33 commented 8 years ago

So far this drift fix has been working great. We're running it through a beta period with several users and will let you know if we encounter issues.