HTML5视频的跨平台提示点事件

时间:2014-08-08 20:20:54

标签: iphone ipad video html5-video flowplayer

编辑为广告清晰度

我希望创建一个HTML5视频播放,以特定的定时提示点触发事件。例如,我希望在视频播放过程中每隔一秒触发一次事件,检查文本框的内容(即包含second2文本框;包含second2文本框)。 “棘手”部分是我需要它在所有主要平台/浏览器上工作,包括IPhones和IPads。

IPhones特别好像是一个问题,无论播放器,设置,黑客我尝试过 - 当视频开始播放时,浏览器转到后台,视频以全屏容器(Quicktime?)播放。当视频停止播放并且浏览器返回控制时,我看到cuepoint事件被触发,但如果视频播放期间文本框无法访问则没有用!

我对FlowPlayer非常熟悉,并且已经完成了大量工作,以确保它适用于大多数相关平台的播放;它的API的cuepoint功能似乎正是我们需要的但是它有一个特定的警告/限制:

  

请注意,提示点受HTML5视频API的设备限制。在不支持内联视频的设备上   因为他们将播放委托给系统组件(例如QuickTime   在iPhone上)在现实世界中,提示点的效果几乎没有   设置

有没有人在iPhone / iPad上使用Flowplayer cuepoints或替代技术?显然,如果我可以维护一个代码库,那么最好有多个特定于平台的版本。

2 个答案:

答案 0 :(得分:1)

这是一个简单的视频元素控制器,它跟踪视频元素触发的timeupdate事件,以触发指定时间码的回调函数。

它允许您为同一时间码附加多个回调。

timeupdate事件在不同的设备上以不同的速率触发,因此有一个限制,即提示点只能附加在整数值,所以在5秒而不是5.5,你可以删除它但是然后存在风险不会触发提示点

/**
 * Function which allows you to register cuepoints to trigger callbacks
 * at specific timecodes
 * @param {HTMLElement} video_el The video element you want to track
 */
var VideoController = function(video_el){
    /**
     * The video element this controller is for
     * @type {HTMLElement}
     */
    this.element = video_el; // 

    /**
     * Object containing all the cuepoints
     * @type {Object}
     */
    this.cuepoints = {};

    /**
     * The last processed_timecode so we dont fire events more than once
     * @type {Number}
     */
    this.processed_timecode = undefined;

    /**
     * Allows you to trigger a callback at a specific timecode
     * @param {Number}   timecode The timecode you want to trigger your callback
     * @param {Function} callback Your callback function
     */
    this.addCuepoint = function(timecode, callback){
        // 
        timecode = Math.floor(timecode);

        //
        if(this.cuepoints[timecode] === undefined){
            this.cuepoints[timecode] = [];
        }

        this.cuepoints[timecode].push(callback);

        return this;
    }

    /**
     * Internal method to track the videos current timecode and to trigger
     * the cuepoints when neccesary
     * @param  {[type]} e A timeupdate event from the video
     */
    this.timeupdate = function(e){

        var timecode = Math.floor(e.target.currentTime);

        // check to see if there is a callback registered for this timecode
        if(this.cuepoints.hasOwnProperty(timecode) && this.cuepoints[timecode] !== undefined && this.processed_timecode !== timecode){

            //if there is it loops through the array of callbacks and triggers them
            for(var i = 0,l=this.cuepoints[timecode].length;i<l;i++){
                this.cuepoints[timecode][i]();  
            }

        }

        //updates the processed_timecode so we do not fire these callbacks again
        this.processed_timecode = timecode;

    }.bind(this);

    // add addEventListener to the video element to track the video timecode
    this.element.addEventListener('timeupdate', this.timeupdate);

    return this;
}

var video = document.getElementById('myVideoElement');
var video_controller = new VideoController(video);


video_controller.addCuepoint(2,function(){
    console.log('do something at 2 seconds');
});
video_controller.addCuepoint(2,function(){
    console.log('do something else at 2 seconds');
});

答案 1 :(得分:1)

我已经调整@Irfan上面的答案来使用requestAnimationFrame而不是依赖于timeupdate事件。 这将允许在半秒等时更精细地触发事件,只需根据需要调整.tofixed(1)。 这对于iPhone网络视频限制不太有帮助,但对于其他用例,它应该对需要精确触发或基于视频时间的事件的其他人有所帮助。

// Request Animation Frame Shim 
// Source: https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            function( callback ){
                window.setTimeout(callback, 1000 / 60);
            };
})();


var VideoController = function(video_el){
    this.element = video_el; 
    this.cuepoints = {};
    this.processed_timecode = undefined;
    var self = this;
    this.addCuepoint = function(timecode, callback){
        var timecode = timecode.toFixed(1);
        if(this.cuepoints[timecode] === undefined){
            this.cuepoints[timecode] = [];
        }
        this.cuepoints[timecode].push(callback);
        return this;
    }
    this.rafUpdate = function(timestamp){
        var timecode = video_el.currentTime.toFixed(1);
        if(!video_el.duration){
            requestAnimFrame(self.rafUpdate);
        }else if( timecode < video_el.duration ){
            requestAnimFrame(self.rafUpdate);
        }
        if( self.cuepoints.hasOwnProperty(timecode) && self.cuepoints[timecode] !== undefined && self.processed_timecode !== timecode ){
            for(var i = 0,l=self.cuepoints[timecode].length;i<l;i++){
                self.cuepoints[timecode][i]();  
            }
        }
        self.processed_timecode = timecode;
    }
    requestAnimFrame( this.rafUpdate ); // keeps better time than video.timeupdate
    return this;
}


var video = document.getElementById('myvideo');
globalVars['video'] = video; 
var video_controller = new VideoController(globalVars['video']);
video_controller.addCuepoint(10.2,function(){
    endframe.play();
});