how to play a video backwards with js?

Viewed 86
<video id="vid" controls>
   <source src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/twitter_cat.mp4"  type="video/mp4">
</video>
<script>
    window.onload=()=>{
        const vid= document.getElementById("vid");
        vid.currentTime=4;
        vid.playbackRate=-0.5;
        vid.play();
    }
    
</script>

I tried that but it didn't work, is there a way to play backward videos?

3 Answers

This is complicated, but most video formats and compression types are meant to be played forward, like this:

  1. Raw footage is uploaded
  2. A few Key frames are selected, that most of the video is based off of.
  3. The compression software keeps track of the changes between the last frame and the current frame. It could be something like "This region changed from black to grey" or "this blob of blue pixels moved up"
  4. The non-Key frames are discarded and only the changes are kept

As you can see, this would cause a massive problem when trying to play backward, because the changes that make up a frame are based on a frame that is based of changes of a frame that is based off changes....of a Key frame. Playing forward isn't an issue, because you don't have to go back to the last Key frame and keep track of the changes, you already have the last frame right in front of you. Although there are brute force ways of doing it backward (see here), these are normally slow and memory heavy. The best answer for you question is unfortunately, you can't.

Many video formats are Streaming Media formats that are designed to be played forward.

Playing it backwards would require decoding the whole stream, storing each raw frame on the disk to avoid clobbering memory, then rendering the frames backwards.

TMLVideoElement.prototype.playBackwards = function() {
this.pause();

    var video = this;

    var fps = 25;
    var intervalRewind = setInterval(function() {
        if(video.currentTime == 0){
            clearInterval(intervalRewind);
            video.pause();
        } else {
            video.currentTime += -(1/fps);
        }
    }, 1000 / fps);
};

My ugly go at it, simply look out for seeked event after triggering it in initial canplay event, seeking backwards from that point by a few frames.

(function() {
  var playbackSpeed = .05
  var video = document.getElementById('vid')

  video.addEventListener('canplay', function() {
    if (!this.started) {
      this.started = true
      this.play()
      this.currentTime = this.duration - .01
    }
  })

  video.addEventListener('seeked', function() {
    this.currentTime = this.currentTime <= 0.01 ? 
      this.duration - .01 : this.currentTime - playbackSpeed
  })
}())
<video id="vid" controls>
  <source
    src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/twitter_cat.mp4"
    type="video/mp4"
  />
</video>

Related