/** @file This file the information about the video player. */
/** Global reference to the video player
* @global
*/
var oVP;
/**
* Creates a video player pointing to files specified by the url
* @constructor
*/
function JSVideo() {
var fname_folder = main_media.GetFileInfo().GetImagePath()+"/";
fname_folder = fname_folder;
// *******************************************
// Private variables:
// *******************************************
// Struct with video data:
var oVideoData = null;
// HTML elements with video data:
var aFrameImages = [];
// Display width/height for video:
var imageWidth;
var imageHeight;
// Current displayed video frame:
var iFrameCtr = 0;
// Last "time" for frame rate calculation:
var iLastTime = -1;
// Indicates whether the video has started playing:
var bPlaying = false;
// Indicates if the video is paused:
var bPaused = false;
// Indicates whether it was the user who paused the video
var uPaused = false;
// Indicates if the scroll button is clicked:
var scroll_button_clicked = false;
// *******************************************
// Public methods:
// *******************************************
// Starting point of video player. Load a video file from URL.
this.getnumFrames = function (){
if (oVideoData == null) return 0;
else return oVideoData.frames;
}
this.getcurrentFrame = function (){
return iFrameCtr;
}
/** This function checks that the loaded frames are correct, stores them in the video structure
* It prepares the polygon for scaling.
* @param {int} frame - the position corresponding to the first frame in the set
* @param {bool} first_time - boolean indicating whether it was the first frame load of the video
* @param {json} response - json with the set of jpg frames being loaded
*/
this.loadFile = function(frame, first_time, isbackground, response) {
if (first_time || frame == iFrameCtr) $('#oLoading').css('display',"block");
var fncLoad = function() {
try {
console.timeEnd('Load video');
oVideoData = eval("(" + response + ")");
if (first_time){
oVP.imageWidth = oVideoData.width;
oVP.imageHeight = oVideoData.height;
oVP.CreateVideoCanvas();
}
if (first_time || frame >= iFrameCtr) $('#oLoading').css('display',"none");
oVP.GenerateFrames();
if (first_time) ovP.GoToFrame(frame);
ovP.seekChunkToDownload(frame);
if (first_time || frame == iFrameCtr ) oVP.Play();
}
catch(e) {
console.log("Error parsing video data ", e);
}
}
var fncError = function() {
console.log("Error loading video file");
}
if (response) fncLoad();
else fncError();
}
/** This function creates the html elements (display, scroll bar and buttons) for the video player */
// Create video canvas elements.
this.CreateVideoCanvas = function() {
// Create canvas:
var oCanvas = '<svg id="canvas" width="' + this.imageWidth + '" height="' + this.imageHeight + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;left:8px;top:8px;z-index:-5;"></svg><div id="oCanvas" style="background-color:black;width:' + this.imageWidth + 'px;height:' + this.imageHeight + 'px;position:relative;z-index:-5;" />';
$('#videoplayer').append(oCanvas);
// Create "loading" message:
var oLoading = '<div id="oLoading" style="width:100%;height:30px;position:absolute;bottom:0px;padding-top:10px;color:white;text-align:center;display:none;font-family:verdana;font-size:12px;z-index:4" >Loading video file...</div>';
$('#oCanvas').append(oLoading);
// Create scroll bar:
var oScroll = '<div id="oScroll" style="width:'+this.imageWidth+'px;"></div>'
var oLoad = '<div id="oLoadBar" style="width:'+this.imageWidth+'px; z-index:0"></div>'
$('#videoplayer').append(oScroll);
$('#oScroll').slider({
range : "min",
min : 1,
max : this.imageWidth,
value : 1,
slide : function (event, ui) {
pos = ui.value/ovP.imageWidth;
iFrameCtr = Math.max(Math.floor(pos*(oVideoData.frames-1)),1);
ovP.DisplayFrame(iFrameCtr);
}
});
// Create loaded bar
$('#oScroll').append(oLoad);
$('#oLoadBar').slider({
range : "min",
min : 1,
max : this.imageWidth,
value : 1,
});
$("#oScroll .ui-slider-range").css("background", "red");
$("#oLoadBar .ui-slider-range").css("background", "gray");
$("#oLoadBar .ui-slider-handle").css("display", "none");
$('#oLoadBar.ui-slider, #oLoadBar ui-slider-handler').off();
//$('#oScroll.ui-slider, #oScroll ui-slider-handler').off();
// Create controls:
var oControls = '<div id="oControls" style="width:' + this.imageWidth + 'px;height:30px;bottom:0px;text-align:center;padding-top:10px;z-index:10;" />';
$('#videoplayer').append(oControls);
// Step beginning button:
var oBtnStepBeginning = '<img id="stepbeginningbutton" src="./annotationTools/video/icons/video_beginning.png" style="border-width:px;padding:10px;" onclick="oVP.StepBeginning();" title="Go to beginning" />';
$('#oControls').append(oBtnStepBeginning);
// Step backward button:
var oBtnStepBackward = '<img id="stepbackwardbutton" src="./annotationTools/video/icons/video_stepback.png" style="border-width:px;padding:10px;" onclick="oVP.StepBackward();" title="Step backward" />';
$('#oControls').append(oBtnStepBackward);
// Pause button:
var oBtnPause = '<img id="playpausebutton" src="./annotationTools/video/icons/video_pause.png" style="border-width:px;padding:10px;" onclick="oVP.Pause(true);" title="Pause" />';
$('#oControls').append(oBtnPause);
// Step forward button:
var oBtnStepForward = '<img id="stepforwardbutton" src="./annotationTools/video/icons/video_stepforward.png" style="border-width:px;padding:10px;" onclick="oVP.StepForward();" title="Step forward" />';
$('#oControls').append(oBtnStepForward);
// Step end button:
var oBtnStepEnd = '<img id="stependbutton" src="./annotationTools/video/icons/video_end.png" style="border-width:px;padding:10px;" onclick="oVP.StepEnd();" title="Go to end" />';
$('#oControls').append(oBtnStepEnd);
var frameNumber = '<div>Frame number: <p style="display: inline-block" id="framenum">0</p></div>';
$('#oControls').append(frameNumber);
var goToFrameForm = '<form action="">Go to frame:<input type="text" id="frameinput" placeholder="Frame Number"></input><input type="button" onclick="oVP.GoToFrameButtonClicked()" value="Submit"></input></form>';
$('#oControls').append(goToFrameForm);
};
this.poly_id = Array();
this.X = Array();
this.Y = Array();
this.display_polygon = Array();
/** This function is called when the user clicks the Go to frame button. It displays the frame indicated by the text field */
this.GoToFrameButtonClicked = function(){
var framevalue = Math.max(Math.min(this.getnumFrames()-1,$('#frameinput').val()),0);
this.GoToFrame(parseInt(framevalue));
}
/** This function generates the html <img> elements that contain the loaded frames */
this.GenerateFrames = function() {
var shift = oVideoData.firstframe;
for(var i = 0; i < oVideoData.data.video.length; i++) {
var oImage = '<img src="' + oVideoData.data.video[i] + '" id="im" style="display:block;position:absolute;padding:0;border-width:0;width:' + this.imageWidth + 'px;height:' + this.imageHeight + 'px;z-index:-3;" />';
aFrameImages[i+shift] = oImage;
}
}
/** This function displays the frame at position i, as well as the annotations corresponding to such frame.
* If such frame is not available, it pauses the player, loads a chunk of frames starting from i and replays.
* @param {int} i - the index of the frame to be displayed
*/
this.DisplayFrame = function(i) {
// Show frame:
$('#framenum').html(i);
if (aFrameImages[i] == null){
this.Pause();
ovP.loadChunk(i, 2, false, false);
//return;
}
if($('#im').length) {
$('#im').replaceWith(aFrameImages[i]);
}
else {
$('#oCanvas').append(aFrameImages[i]);
}
$('#myCanvas_bg').empty();
var attr = 'fill="none" stroke="' + HashObjectColor(name) + '" stroke-width="4"';
var scale = 1;
// Plot polygons:
var xml = LM_xml
var N = $(xml).children("annotation").children("object").length;
for(var it = 0; it < N; it++) {
var obj = $(xml).children("annotation").children("object").eq(it);
// Get object name:
// Get points:
var anno_id = obj.children("id").text();
var X = Array();
var Y = Array();
var framestamps = (obj.children("polygon").children("t").text()).split(',')
for(var ti=0; ti<framestamps.length; ti++) { framestamps[ti] = parseInt(framestamps[ti], 10); }
var objectind = framestamps.indexOf(i);
if (objectind >= 0){
var pointsx = (obj.children("polygon").children("x").text()).split(';')[objectind]
X = pointsx.split(',')
for(var ti=0; ti<X.length; ti++) { X[ti] = parseInt(X[ti], 10); }
var pointsy = (obj.children("polygon").children("y").text()).split(';')[objectind]
Y = pointsy.split(',')
for(var ti=0; ti<Y.length; ti++) { Y[ti] = parseInt(Y[ti], 10); }
var obj_name = "foo";
if (obj.children("name")) obj_name = obj.children("name").text();
if (select_anno == null || (select_anno && select_anno.anno_id != anno_id)){
polid = DrawPolygon('myCanvas_bg',X,Y,obj_name,attr,scale);
$('#'+polid).attr('onmousedown','StartEditVideoEvent("'+polid+'",' + it + ',evt); return false;');
//$('#'+polid).attr('onmousemove','main_handler.CanvasMouseMove(evt,'+ it +'); return false;');
$('#'+polid).attr('oncontextmenu','return false');
$('#'+polid).css('cursor','pointer');
}
else {
$('#'+select_anno.polygon_id).parent().remove();
$('#'+select_anno.polygon_id).remove();
adjust_event.x = X;
adjust_event.y = Y;
adjust_event.polygon_id = adjust_event.DrawPolygon(adjust_event.dom_attach,X,Y,obj_name,scale);
select_anno.polygon_id = adjust_event.polygon_id;
adjust_event.RemoveControlPoints();
adjust_event.RemoveCenterOfMass();
adjust_event.ShowControlPoints();
adjust_event.ShowCenterOfMass();
}
}
}
}
/** This function sets the player to frame 'frame'.
* @param {int} frame - the index of the frame of interest
*/
this.GoToFrame = function(frame){
iFrameCtr = frame;
this.DisplayFrame(iFrameCtr);
this.UpdateScrollbar(iFrameCtr/oVideoData.frames);
}
this.ShowFirstFrame = function() {
// $('#oCanvas').append(aFrameImages[0]);
this.DisplayFrame(0);
this.UpdateScrollbar(0);
}
/** This function updates the position of the scroll bar.
* @param {float} pos - float from 0 to 1 indicating the position of the scroll bar
*/
this.UpdateScrollbar = function(pos) {
$('#oScroll').slider('value', pos*this.imageWidth);
//$('#scrollbutton').css('left',pos*this.imageWidth);
//$('#oProgress').css('width',pos*this.imageWidth);
}
/** This function updates the position of the load bar.
* @param {float} pos - float from 0 to 1 indicating the position of the load bar
*/
this.UpdateLoadbar = function(pos){
//$('#oLoadBar').css('width',pos*this.imageWidth);
$('#oLoadBar').slider('value', pos*this.imageWidth);
}
/** This function sets the player to play. It can be called when a chunk of needed frames is loaded or when the user hits the play button.
* @param {bool} buttonClicked - boolean indicating whether the user clicked the play button or the video was played because the chunks got loaded
*/
this.Play = function(buttonClicked) {
//if (active_canvas != REST_CANVAS) return;
if (buttonClicked) uPaused = false;
else if (uPaused == true) return;
if (aFrameImages[iFrameCtr] == null) return;
if (bPlaying) {
if (bPaused) bPaused = false;
// Replace with pause button:
$('#playpausebutton').attr('src','annotationTools/video/icons/video_pause.png');
$('#playpausebutton').attr('title','Pause');
$('#playpausebutton').attr('onclick','oVP.Pause(true);');
if(iFrameCtr == (oVideoData.frames-1)) iFrameCtr = 0;
return;
}
bPlaying = true;
this.NextFrame();
}
/** Displays the next frame in a video file according to the video rate.
*/
this.NextFrame = function() {
if (!bPlaying) return;
var iFrameRate = Math.round(1000 / oVideoData.rate);
var iNow = new Date().getTime();
var iLag = 0;
if (!bPaused) {
iFrameCtr++;
if (iLastTime > -1) {
var iDeltaTime = iNow - iLastTime;
iLag = iDeltaTime - iFrameRate;
while (iLag > iFrameRate) {
iFrameCtr++;
iLag -= iFrameRate;
}
}
if (iLag < 0) iLag = 0;
if (iFrameCtr >= oVideoData.frames) {
iFrameCtr = oVideoData.frames-1;
this.Pause();
}
this.DisplayFrame(iFrameCtr);
this.UpdateScrollbar(iFrameCtr/oVideoData.frames);
}
iLastTime = iNow;
setTimeout(function() {
oVP.NextFrame();
}, iFrameRate - iLag);
}
// Pause playback:
this.Pause = function(buttonClicked) {
if (buttonClicked) uPaused = true;
bPaused = true;
// Replace with play button:
$('#playpausebutton').attr('src','./annotationTools/video/icons/video_play.png');
$('#playpausebutton').attr('title','Play');
$('#playpausebutton').attr('onclick','oVP.Play(true);');
}
/** This function forces to go to the next frame, regardless of frame rate.
*/
this.StepForward = function() {
if(!bPaused) this.Pause();
else {
iFrameCtr++;
if (iFrameCtr >= oVideoData.frames) {
iFrameCtr = oVideoData.frames-1;
}
// Render next frame:
this.DisplayFrame(iFrameCtr);
this.UpdateScrollbar(iFrameCtr/oVideoData.frames);
}
}
/** This function goes to the previous frame.
*/
this.StepBackward = function() {
if(!bPaused) this.Pause();
else {
iFrameCtr--;
if (iFrameCtr <= 0) {
iFrameCtr = 1;
}
// Render next frame:s
this.DisplayFrame(iFrameCtr);
this.UpdateScrollbar(iFrameCtr/oVideoData.frames);
}
}
/** This function goes to the start of the video.
*/
this.StepBeginning = function() {
this.Pause();
iFrameCtr = 1;
// Render next frame:
this.DisplayFrame(iFrameCtr);
this.UpdateScrollbar(iFrameCtr/oVideoData.frames);
}
/** This function goes to the end of the video.
*/
this.StepEnd = function() {
this.Pause();
iFrameCtr = oVideoData.frames-1;
// Render next frame:
this.DisplayFrame(iFrameCtr);
this.UpdateScrollbar(iFrameCtr/oVideoData.frames);
}
/** This function looks for future frames that haven't been loaded yet and loads them into the player.
* @param {int} frame - the frame index from which to start seeking
*/
this.seekChunkToDownload = function (frame){
while (aFrameImages[frame] != null) frame++;
if (frame < oVideoData.frames) this.loadChunk(frame, 1, false, true);
}
/** This function loads a set of frames to the player.
* @param {int} frame - the first frame to load
* @param {int} duration - the duration of the chunk to be loaded
* @param {bool} first_time - boolean indicating whether the function is called for the first time
*/
this.loadChunk = function(frame, duration, first_time, isbackground){
ovP = this;
$.ajax({
async: true,
type: "POST",
url: "./annotationTools/php/encode.php",
data: {width: "640", height: "480", rate:"15", input: fname_folder,frame: frame.toString(), duration: duration},
success: function(response){
last_frame = Math.min(frame + duration*15, ovP.getnumFrames());
ovP.loadFile(frame, first_time, isbackground, response)
if (ovP.getnumFrames() != 0 && ovP.getcurrentFrame() <= last_frame) ovP.UpdateLoadbar(last_frame/ovP.getnumFrames());
}
});
}
}