Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing HTML5 Video on IPad and seeking

Very strange bug I can't seems to figure out.

I am trying to get an HTML5 video to play from a certain position when a user hits play. I am trying to have it seek right when the video starts to play.

On my play event I do this.currentTime = X

On the browser it works fine. But on the IPad, when I play the video, the video doesn't seek to the right position (it starts from zero).

Even more oddly, if I do the this.currentTime = X call in a setTimeout of let's say 1 second, it works on the IPad (sometimes).

like image 355
K2xL Avatar asked Jun 28 '12 20:06

K2xL


2 Answers

On iOS, videos load at play time (see item #2), not at page load time. My guess is that the video is not loaded when you run this.currentTime = X, so it has no effect. This also explains why delaying the operation can sometimes fix the problem: sometimes it has loaded after a second, sometimes not.

I don't have an iOS device to test, but I'd suggest binding a loadeddata listener to the video so that your currentTime manipulation only happens after the video begins loading:

// within the play event handler...
if(!isIOSDevice) {
     this.currentTime = X;
} else {
    function trackTo(evt) {
        evt.target.currentTime = X;
        evt.target.removeEventListener("loadeddata", trackTo)
    });
    this.addEventListener("loadeddata", trackTo);
}

You'll need to set isIOSDevice elsewhere in your code, based on whether the current visit comes from an iOS device.

like image 119
apsillers Avatar answered Nov 14 '22 22:11

apsillers


While this question is quite old the issue remains open. I discovered a solution that works on multiple tested iPads (1+2+3) for iOS 5 and 6 (iOS3+4 not tested):

Basically you first have to wait for the initial playing event, then add a one-time binder for canplaythrough and then for progress - only then can you actually change the the currentTime value. Any tries before that will fail!

The video has to start playing at first, which makes a black layer on top of the video element kinda handy. Unfortunately, sounds within the video canNOT be deactivated via JavaScript --> not a perfect UX

// https://github.com/JoernBerkefeld/iOSvideoSeekOnLoad / MIT License 
// requires jQuery 1.8+
// seekToInitially (float) : video-time in seconds
function loadingSeek(seekToInitially, callback) {
    if("undefined"==typeof callback) {
        callback = function() {};
    }
    var video = $("video"),
        video0 = video[0],
        isiOS = navigator.userAgent.match(/(iPad|iPhone|iPod)/) !== null,
        test;
    if(isiOS) { // get the iOS Version
        test =navigator.userAgent.match("OS ([0-9]{1})_([0-9]{1})");
        // you could add a loading spinner and a black layer onPlay HERE to hide the video as it starts at 0:00 before seeking
        // don't add it before or ppl will not click on the play button, thinking the player still needs to load
    }
    video.one("playing",function() { 
        if(seekToInitially > 0) {
            //log("seekToInitially: "+seekToInitially);
            if(isiOS) {
                // iOS devices fire an error if currentTime is set before the video started playing
                // this will only set the time on the first timeupdate after canplaythrough... everything else fails
                video.one("canplaythrough",function() { 
                    video.one("progress",function() { 
                        video0.currentTime = seekToInitially;
                        video.one("seeked",function() {
                            // hide the loading spinner and the black layer HERE if you added one before

                            // optionally execute a callback function once seeking is done
                            callback();
                        });
                    });
                });
            } else {
                // seek directly after play was executed for all other devices
                video0.currentTime = seekToInitially; 

                // optionally execute a callback function once seeking is done
                callback();
            }
        } else {
            // seek not necessary

            // optionally execute a callback function once seeking is done
            callback();
        }
    });
}

the whole thing can be downloaded from my GitHub repo

like image 45
Jörn Berkefeld Avatar answered Nov 14 '22 23:11

Jörn Berkefeld