<html>
<script src="VideoFrame.js"></script>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<div class="frame" >
<video height="100%" id="video">
<source src="./916.MP4"></source>
</video>
<canvas id="mycanvas" width="500" height="300" style="border: 1px solid blue;">
</canvas>
</div>
<div class="frame2">
<span id="currentFrame">0</span>
</div>
<div id="controls">
<button id="play-pause">Play</button>
</div>
<style>
.frame{
position:absolute;
height: 300;
width: 700;
z-index:10;
left:200;
border:1px solid red
}
#mycanvas{
position:absolute;
height: 300;
width: 500;
z-index:10;
left:0;
}
.frame2{
z-index: 20;
position:absolute;
height: 300;
width: 300;
left:200;
font-size: 80;
color: red;
}
</style>
<script>
var currentFrame = $('#currentFrame');
var canvas=$('#mycanvas')
var video = VideoFrame({
id : 'video',
frameRate: 15, //帧率
callback : function(frame) {
currentFrame.html(frame);
var c= document.getElementById("mycanvas");
var a=c.getContext("2d");
a.strokeStyle = "red";
// 5
// if(frame==135){
// let div = document.getElementById("play-pause");
// div.click();
// }
if(frame==20||frame==25||frame==222||frame==159||frame==226){
console.log(c,7788999);
a.strokeRect(15, 15, 20, 20);
}else{
a.clearRect(0, 0, c.width, c.height); //清空这个范围的画布
}
}
});
$('#play-pause').click(function(){
if(video.video.paused){
video.video.play();
video.listen('frame');
$(this).html('Pause');
}else{
video.video.pause();
video.stopListen();
$(this).html('Play');
}
});
</script>
</html>
js文件
/**
* @class
* @classdesc Main VideoFrame Implementation.
* @param {Object} options - Configuration object for initialization. 用于初始化的配置对象
*/
var VideoFrame = function(options) {
if (this === window) { return new VideoFrame(options); }
this.obj = options || {};
this.frameRate = this.obj.frameRate || 24;
this.video = document.getElementById(this.obj.id) || document.getElementsByTagName('video')[0];
};
/**
* FrameRates - Industry standard frame rates 行业标准帧率
*
* @namespace
* @type {Object}
* @property {Number} film - 24
* @property {Number} NTSC - 29.97
* @property {Number} NTSC_Film - 23.98
* @property {Number} NTSC_HD - 59.94
* @property {Number} PAL - 25
* @property {Number} PAL_HD - 50
* @property {Number} web - 30
* @property {Number} high - 60
*/
var FrameRates = {
film: 24,
NTSC : 29.97,
NTSC_Film: 23.98,
NTSC_HD : 59.94,
PAL: 25,
PAL_HD: 50,
web: 30,
high: 60
};
VideoFrame.prototype = {
/**
* Returns the current frame number
*
* @return {Number} - Frame number in video
*/
get : function() {
return Math.floor(this.video.currentTime.toFixed(5) * this.frameRate);
},
/**
* Event listener for handling callback execution at double the current frame rate interval
*
* @param {String} format - Accepted formats are: SMPTE, time, frame
* @param {Number} tick - Number to set the interval by.
* @return {Number} Returns a value at a set interval
*/
listen : function(format, tick) {
var _video = this;
if (!format) { console.log('VideoFrame: Error - The listen method requires the format parameter.'); return; }
this.interval = setInterval(function() {
if (_video.video.paused || _video.video.ended) { return; }
var frame = ((format === 'SMPTE') ? _video.toSMPTE() : ((format === 'time') ? _video.toTime() : _video.get()));
if (_video.obj.callback) { _video.obj.callback(frame, format); }
return frame;
}, (tick ? tick : 1000 / _video.frameRate / 2));
},
/** Clears the current interval */
stopListen : function() {
var _video = this;
clearInterval(_video.interval);
},
fps : FrameRates
};
/**
* Returns the current time code in the video in HH:MM:SS format
* - used internally for conversion to SMPTE format.
*
* @param {Number} frames - The current time in the video
* @return {String} Returns the time code in the video
*/
VideoFrame.prototype.toTime = function(frames) {
var time = (typeof frames !== 'number' ? this.video.currentTime : frames), frameRate = this.frameRate;
var dt = (new Date()), format = 'hh:mm:ss' + (typeof frames === 'number' ? ':ff' : '');
dt.setHours(0); dt.setMinutes(0); dt.setSeconds(0); dt.setMilliseconds(time * 1000);
function wrap(n) { return ((n < 10) ? '0' + n : n); }
return format.replace(/hh|mm|ss|ff/g, function(format) {
switch (format) {
case "hh": return wrap(dt.getHours() < 13 ? dt.getHours() : (dt.getHours() - 12));
case "mm": return wrap(dt.getMinutes());
case "ss": return wrap(dt.getSeconds());
case "ff": return wrap(Math.floor(((time % 1) * frameRate)));
}
});
};
/**
* Returns the current SMPTE Time code in the video.
* - Can be used as a conversion utility.
*
* @param {Number} frame - OPTIONAL: Frame number for conversion to it's equivalent SMPTE Time code.
* @return {String} Returns a SMPTE Time code in HH:MM:SS:FF format
*/
VideoFrame.prototype.toSMPTE = function(frame) {
if (!frame) { return this.toTime(this.video.currentTime); }
var frameNumber = Number(frame);
var fps = this.frameRate;
function wrap(n) { return ((n < 10) ? '0' + n : n); }
var _hour = ((fps * 60) * 60), _minute = (fps * 60);
var _hours = (frameNumber / _hour).toFixed(0);
var _minutes = (Number((frameNumber / _minute).toString().split('.')[0]) % 60);
var _seconds = (Number((frameNumber / fps).toString().split('.')[0]) % 60);
var SMPTE = (wrap(_hours) + ':' + wrap(_minutes) + ':' + wrap(_seconds) + ':' + wrap(frameNumber % fps));
return SMPTE;
};
/**
* Converts a SMPTE Time code to Seconds
*
* @param {String} SMPTE - a SMPTE time code in HH:MM:SS:FF format
* @return {Number} Returns the Second count of a SMPTE Time code
*/
VideoFrame.prototype.toSeconds = function(SMPTE) {
if (!SMPTE) { return Math.floor(this.video.currentTime); }
var time = SMPTE.split(':');
return (((Number(time[0]) * 60) * 60) + (Number(time[1]) * 60) + Number(time[2]));
};
/**
* Converts a SMPTE Time code, or standard time code to Milliseconds
*
* @param {String} SMPTE OPTIONAL: a SMPTE time code in HH:MM:SS:FF format,
* or standard time code in HH:MM:SS format.
* @return {Number} Returns the Millisecond count of a SMPTE Time code
*/
VideoFrame.prototype.toMilliseconds = function(SMPTE) {
var frames = (!SMPTE) ? Number(this.toSMPTE().split(':')[3]) : Number(SMPTE.split(':')[3]);
var milliseconds = (1000 / this.frameRate) * (isNaN(frames) ? 0 : frames);
return Math.floor(((this.toSeconds(SMPTE) * 1000) + milliseconds));
};
/**
* Converts a SMPTE Time code to it's equivalent frame number
*
* @param {String} SMPTE - OPTIONAL: a SMPTE time code in HH:MM:SS:FF format
* @return {Number} Returns the long running video frame number
*/
VideoFrame.prototype.toFrames = function(SMPTE) {
var time = (!SMPTE) ? this.toSMPTE().split(':') : SMPTE.split(':');
var frameRate = this.frameRate;
var hh = (((Number(time[0]) * 60) * 60) * frameRate);
var mm = ((Number(time[1]) * 60) * frameRate);
var ss = (Number(time[2]) * frameRate);
var ff = Number(time[3]);
return Math.floor((hh + mm + ss + ff));
};
/**
* Private - seek method used internally for the seeking functionality.
*
* @param {String} direction - Accepted Values are: forward, backward
* @param {Number} frames - Number of frames to seek by.
*/
VideoFrame.prototype.__seek = function(direction, frames) {
if (!this.video.paused) { this.video.pause(); }
var frame = Number(this.get());
/** To seek forward in the video, we must add 0.00001 to the video runtime for proper interactivity */
this.video.currentTime = ((((direction === 'backward' ? (frame - frames) : (frame + frames))) / this.frameRate) + 0.00001);
};
/**
* Seeks forward [X] amount of frames in the video.
*
* @param {Number} frames - Number of frames to seek by.
* @param {Function} callback - Callback function to execute once seeking is complete.
*/
VideoFrame.prototype.seekForward = function(frames, callback) {
if (!frames) { frames = 1; }
this.__seek('forward', Number(frames));
return (callback ? callback() : true);
};
/**
* Seeks backward [X] amount of frames in the video.
*
* @param {Number} frames - Number of frames to seek by.
* @param {Function} callback - Callback function to execute once seeking is complete.
*/
VideoFrame.prototype.seekBackward = function(frames, callback) {
if (!frames) { frames = 1; }
this.__seek('backward', Number(frames));
return (callback ? callback() : true);
};
/**
* For seeking to a certain SMPTE time code, standard time code, frame, second, or millisecond in the video.
* - Was previously deemed not feasible. Veni, vidi, vici.
*
* @param {Object} option - Configuration Object for seeking allowed keys are SMPTE, time, frame, seconds, and milliseconds
* example: { SMPTE: '00:01:12:22' }, { time: '00:01:12' }, { frame: 1750 }, { seconds: 72 }, { milliseconds: 72916 }
*/
VideoFrame.prototype.seekTo = function(config) {
var obj = config || {}, seekTime, SMPTE;
/** Only allow one option to be passed */
var option = Object.keys(obj)[0];
if (option == 'SMPTE' || option == 'time') {
SMPTE = obj[option];
seekTime = ((this.toMilliseconds(SMPTE) / 1000) + 0.001);
this.video.currentTime = seekTime;
return;
}
switch(option) {
case 'frame':
SMPTE = this.toSMPTE(obj[option]);
seekTime = ((this.toMilliseconds(SMPTE) / 1000) + 0.001);
break;
case 'seconds':
seekTime = Number(obj[option]);
break;
case 'milliseconds':
seekTime = ((Number(obj[option]) / 1000) + 0.001);
break;
}
if (!isNaN(seekTime)) {
this.video.currentTime = seekTime;
}
};
版权声明:本文为weixin_43994675原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。