Search code examples
htmlvideohtml5-video

HTML5 frame-by-frame viewing / frame-seeking?


I'm looking for a way to view HTML5 <video>, frame-by-frame.

The scenario: Having a video, with an additional button that skips to the next frame when pressed.

What do you think is the best method to do this?

  1. Play the video normally, Listen to timeUpdate event, which on FireFox is called for every frame, and then just pause the video. However, the other browsers don't behave like Firefox.
  2. Change the currentTime element manually to +1/24 of a second, where "24" is the frame rate. I have no idea how to aquire the FPS, however.
  3. Any other helpful way you can think of.

EDIT

I have found this very useful HTML5 test page, which tracks all browsers' ability to achieve accurate frame-seeking.


Solution

  • It seems that most browsers allow the second approach, although you would need to know the frame rate. Opera, however, is the exception, and requires an approach similar to your first one (the result is not perfect). Here's a demo page I came up with that uses a 29.97 frames/s video (U.S. television standard). Note that it has not been extensively tested, so it might not work in IE 9, Firefox 4, or future versions of any browser.

    HTML:

    <p id="time"></p>
    <video id="v0" controls tabindex="0" autobuffer preload>
        <source type="video/webm; codecs=&quot;vp8, vorbis&quot;" src="http://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"></source>
        <source type="video/ogg; codecs=&quot;theora, vorbis&quot;" src="http://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.ogv"></source>
        <source type="video/mp4; codecs=&quot;avc1.42E01E, mp4a.40.2&quot;" src="http://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.mp4"></source>
        <p>Sorry, your browser does not support the &lt;video&gt; element.</p>
    </video>
    

    JavaScript (run on page load and uses jQuery 1.4.4 for the sake of brevity):

    var vid = $('#v0')[0];
    
    vid.onplay = vid.onclick = function() {
        vid.onplay = vid.onclick = null;
        
        setTimeout(function() {
            vid.pause();
            setInterval(function() {
                if($.browser.opera) {
                    var oldHandler = vid.onplay;
                    vid.onplay = function() {
                        vid.pause();
                        vid.onplay = oldHandler;
                    };
                    vid.play();
                } else {
                    vid.currentTime += (1 / 29.97);
                }
            }, 2000);
        }, 12000);
        
        setInterval(function() {
            $('#time').html((vid.currentTime * 29.97).toPrecision(5));
        }, 100);
    };