简体   繁体   English

在iPad上播放HTML5视频并寻求

[英]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. 我试图让用户点击播放时从某个位置播放HTML5视频。 I am trying to have it seek right when the video starts to play. 我正在尝试让它在视频开始播放时寻找正确的位置。

On my play event I do this.currentTime = X 在播放事件中我执行此操作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). 但是在iPad上,当我播放视频时,视频找不到正确的位置(从零开始)。

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). 更奇怪的是,如果我在setTimeout中(例如说1秒)执行this.currentTime = X调用,则它可以在iPad上运行(有时)。

On iOS, videos load at play time (see item #2), not at page load time. 在iOS上,视频是在播放时加载(请参阅第2项),而不是页面加载时加载。 My guess is that the video is not loaded when you run this.currentTime = X , so it has no effect. 我的猜测是,当您运行this.currentTime = X ,视频未加载,因此没有任何效果。 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: 我没有要测试的iOS设备,但我建议将已loadeddata侦听器绑定到视频,以便您的currentTime操作仅在视频开始加载后发生:

// 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. 您需要根据当前访问是否来自iOS设备,在代码的其他位置设置isIOSDevice

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): 我发现了一种解决方案,可在iOS 5和6(未测试iOS3 + 4)的多个经过测试的iPad(1 + 2 + 3)上运行:

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. 基本上,您首先必须等待初始playing事件,然后为canplaythrough然后为progress添加一次性活页夹-只有这样,您才可以实际更改currentTime值。 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 不幸的是,无法通过JavaScript禁用视频中的声音->并非完美的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 整个事情都可以从我的GitHub存储库中下载

apsillers is right. ps药者是正确的。 Once the video starts playing, the Quicktime player will come up and the video will not be seekable until the first 'progress' event is triggered. 视频开始播放后,Quicktime播放器将启动,并且在触发第一个“进度”事件之前将无法搜索视频。 If you try to seek before then, you'll get an invalid state error. 如果您在此之前尝试搜索,则会收到无效的状态错误。 Here's my code: 这是我的代码:

cueVideo = function (video, pos) {
    try {
        video.currentTime = pos;

    // Mobile Safari's quicktime player will error if this doesn't work.
    } catch(error) {
        if (error.code === 11) { // Invalid State Error

            // once 'progress' happens, the video will be seekable.
            $(video).one('progress', cueVideo.bind(this, video, pos));
        }
    }
}

try to limit your X to 1 decimal 尝试将您的X限制为1个小数

X.toFixed(1);

As you mentioned it works sometimes after a time of 1 second. 正如您提到的,它有时会在1秒钟后起作用。 Have you tried to set the position after the playing event fires? playing后,您是否尝试过设置位置? or maybe even the canplaythrough event 甚至canplaythrough事件

Take a look at the source of this page to see a whole list of events that can be used (in the javascript file) 查看此页面的源代码,以查看可以使用的事件的完整列表(在javascript文件中)

Appreciate the attempts for answers below. 感谢下面的答案。 Unfortunately, had to resort to just checking inside timeupdate if the currenttime was > 0 and < 1, if it was then went to that part of the video and removed the listener to timeupdate. 不幸的是,如果当前时间> 0且<1,则只能检查timeupdate内部的内容,然后再转到视频的该部分并将监听器移至timeupdate。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM