Search code examples
javascriptffmpeghtml5-videomp4media-source

Is there a way to play fragmented mp4 at random chunk?


Say there is a video rendered into fragmented mp4 consisting of a number of chunks/fragments. The question is: after the init was loaded to MediaSource buffer, is there a way to play a random fragment?

A small research of the thing's specifications gave little understanding of the problem. Fragments seem to have a kind of an order IDs hardcoded in them. It's a fairly reasonable idea to include it in a file in case of unreliable connection and asynchronous fetching while streaming content, but is there a way to parse a chunk and change its ID using JavaScript?

The code below is just playing 2 minute video split into 12 fragments based on user's time and is supposed to be able to start at any chunk (not only the first) and then to repeat.

let mediaSource = new MediaSource
document.getElementById('video').src = URL.createObjectURL(mediaSource)

mediaSource.addEventListener('sourceopen', () => {
    let buffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"')
    let loadToBuffer = url => {
        let xhr = new XMLHttpRequest
        xhr.responseType = 'arraybuffer'
        xhr.open('GET', url, true)
        xhr.addEventListener('loadend', () => buffer.appendBuffer(new Uint8Array(xhr.response)))
        xhr.send()
    }
    loadToBuffer('video/init.mp4')
    setInterval(() => loadToBuffer('video/video' + (Math.floor(new Date().getTime() / 1000 / 10) % 12) + '.m4s'), 10 * 1000)
})

Solution

  • When you load fragments in a sourceBuffer, those fragments include presentation time stamps (PTS), which put them in the correct playback order in the buffer.

    You can either modify the fragments themselves, for which you have to parse the atoms and change the PTS (and possibly other) values, or change the video element currentTime property, so you can play the video at that was correctly buffered.

    You can inspect the buffered property on the video element object to check the range of time that has been loaded.