%PDF- %PDF-
| Direktori : /proc/self/root/data/old/usr/share/gpac/gui/ |
| Current File : //proc/self/root/data/old/usr/share/gpac/gui/webvtt-renderer.js |
/* JavaScript Renderer for WebVTT tracks
Generates GPAC Scene Graph (SVG, BIFS) to display WebVTT cues */
alert("WebVTT Rendered Loaded");
var DEBUG = false;
var rect = document.documentElement.getRectPresentationTrait("viewBox");
var width = rect.width;
var height = rect.height;
var xOffset = 5;
var yOffset = 5;
var fontSize = 20;
var textColor = "white";
var fontFamily = "SANS";
var lineIncrement = fontSize;
var nbCues = 0;
var cueArea = document.createElement("g");
document.documentElement.appendChild(cueArea);
function reportMessage(msg) {
if (DEBUG) {
alert(msg);
}
}
function createTextArea(settingsObj) {
var t = document.createElement("textArea");
t.setAttribute("x", xOffset+settingsObj.xPosition);
t.setAttribute("y", yOffset);
var w, h;
if (settingsObj.fromTop) {
t.setAttribute("display-align", "before");
h=height-2*yOffset;
} else {
t.setAttribute("display-align", "after");
h = height-2*yOffset-settingsObj.linePosition;
}
w = settingsObj.size-2*xOffset;
t.setAttribute("height", h);
t.setAttribute("width", w);
reportMessage("Creating textArea size " + w + " x " + h);
t.setAttribute("fill", textColor);
t.setAttribute("font-size", fontSize);
t.setAttribute("font-family", fontFamily);
t.setAttribute("text-align", settingsObj.align);
t.setAttribute("line-increment", lineIncrement);
cueArea.appendChild(t);
reportMessage("textArea created: "+t);
return t;
}
function printObj(o) {
for (var p in o) {
if (o.hasOwnProperty(p)) {
alert(""+p+": "+o[p]);
}
}
}
function addSpan(parent, cuePart) {
reportMessage("adding tspan to "+parent+" with cuePart: "+ cuePart);
var i;
var span = document.createElement('tspan');
//alert('adding span for '+parent+': '+cuePart+' token:'+cuePart.token);
if (cuePart.token === undefined) {
span.textContent = cuePart;
} else {
if (cuePart.token === 'i') {
span.setAttribute("font-style", "italic");
} else if (cuePart.token === 'u') {
span.setAttribute("text-decoration", "underline");
} else if (cuePart.token === 'b') {
span.setAttribute("font-weight", "bold");
}
for (i in cuePart.children) {
addSpan(span, cuePart.children[i]);
}
}
parent.appendChild(span);
reportMessage("tspan created "+span);
return span;
}
function parseCueSettings(cueSettings){
reportMessage("Parsing cue settings: "+cueSettings);
var obj = {};
var settingsArray = cueSettings.split(/\s/g);
//.filter(function(set) { return set && !!set.length; });
// Convert the Array into an object
var compositeCueSettings = {};
for (var settingsIndex in settingsArray) {
var nvArray = settingsArray[settingsIndex].split(":");
compositeCueSettings[nvArray[0]] = nvArray[1];
}
// Compute real values
if (compositeCueSettings.line !== undefined) {
if (compositeCueSettings.line.match(/\%/)) {
obj.linePosition = parseFloat(compositeCueSettings.line.replace(/\%/ig,""));
if (isNaN(obj.linePosition)) {
obj.linePosition = nbCues*lineIncrement;
} else {
obj.linePosition *= height/100;
}
} else {
obj.linePosition = parseFloat(compositeCueSettings.line)*lineIncrement;
if (isNaN(obj.linePosition)) {
obj.linePosition = nbCues*lineIncrement;
} else {
if (obj.linePosition > 0) {
obj.fromTop = true;
} else {
obj.fromTop = false;
obj.linePosition = -obj.linePosition;
}
}
}
} else {
obj.linePosition = nbCues*lineIncrement;
}
reportMessage("linePosition: "+obj.linePosition);
if (compositeCueSettings.position !== undefined) {
obj.xPosition = parseFloat(compositeCueSettings.position.replace(/\%/ig,""));
if (isNaN(obj.xPosition)) {
obj.xPosition = 50;
} else {
obj.xPosition *= width/100;
}
} else {
obj.xPosition = 50;
}
reportMessage("xPosition: "+obj.xPosition);
if (compositeCueSettings.size !== undefined) {
obj.size = parseFloat(compositeCueSettings.size.replace(/\%/ig,""));
if (isNaN(obj.size)) {
obj.size = 100;
}
} else {
obj.size = 100;
}
obj.size *= width/100;
reportMessage("size: "+obj.size);
if (compositeCueSettings.align !== undefined) {
if (compositeCueSettings.align === "middle") {
obj.align = "center";
} else if (compositeCueSettings.align === "left") {
obj.align = "start";
} else if (compositeCueSettings.align === "right") {
obj.align = "end";
} else if (compositeCueSettings.align === "start") {
obj.align = "start";
} else if (compositeCueSettings.align === "end") {
obj.align = "end";
} else {
obj.align = "center";
}
} else {
obj.align = "center";
}
reportMessage("align: "+obj.align);
reportMessage("cue settings parsed: "+obj);
return obj;
}
function removeCues() {
cueArea.textContent = '';
nbCues = 0;
}
function addCue(id, start, end, settings, payload) {
reportMessage("adding cue: "+id+","+start+","+end+","+settings+","+payload);
var lines = payload.split('\n');
var settingObj = parseCueSettings(settings);
var tA = createTextArea(settingObj);
for (var lineIndex in lines) {
var parsedCue = parseCue(lines[lineIndex]);
for (var cuePartIndex in parsedCue) {
addSpan(tA, parsedCue[cuePartIndex]);
}
tA.appendChild(document.createElement('tbreak'));
}
nbCues++;
reportMessage("cue added: "+tA);
}
/* Code adapted from https://raw.github.com/cgiffard/Captionator/master/js/captionator.js */
var SRTChunkTimestampParser = /(\d{2})?:?(\d{2}):(\d{2})[\.\,](\d+)/;
function parseCue(cueText) {
reportMessage("Parsing cue text: "+cueText);
var cueStructure = new Array,
cueSplit = [],
splitIndex,
currentToken,
currentContext,
stack = [],
stackIndex = 0,
chunkTimestamp,
timeData,
lastCueTime;
cueSplit = cueText.split(/(<\/?[^>]+>)/ig);
currentContext = cueStructure;
for (splitIndex in cueSplit) {
if (cueSplit.hasOwnProperty(splitIndex)) {
currentToken = cueSplit[splitIndex];
if (currentToken.substr(0,1) === "<") {
if (currentToken.substr(1,1) === "/") {
// Closing tag
var TagName = currentToken.substr(2).split(/[\s>]+/g)[0];
if (stack.length > 0) {
// Scan backwards through the stack to determine whether we've got an open tag somewhere to close.
var stackScanDepth = 0;
for (stackIndex = stack.length-1; stackIndex >= 0; stackIndex --) {
var parentContext = stack[stackIndex][stack[stackIndex].length-1];
stackScanDepth = stackIndex;
if (parentContext.token === TagName) { break; }
}
currentContext = stack[stackScanDepth];
stack = stack.slice(0,stackScanDepth);
} else {
// Tag mismatch!
alert("Tag mismatch when parsing WebVTT cue: "+cueText);
}
} else {
// Opening Tag
// Check whether the tag is valid according to the WebVTT specification
// If not, don't allow it (unless the sanitiseCueHTML option is explicitly set to false)
if (( currentToken.substr(1).match(SRTChunkTimestampParser) ||
currentToken.match(/^<v\s+[^>]+>/i) ||
currentToken.match(/^<c[a-z0-9\-\_\.]+>/) ||
currentToken.match(/^<(b|i|u|ruby|rt)>/)) ) {
var tmpObject = {
"token": currentToken.replace(/[<\/>]+/ig,"").split(/[\s\.]+/)[0],
"rawToken": currentToken,
"children": []
};
if (tmpObject.token === "v") {
tmpObject.voice = currentToken.match(/^<v\s*([^>]+)>/i)[1];
} else if (tmpObject.token === "c") {
tmpObject.classes = currentToken
.replace(/[<\/>\s]+/ig,"")
.split(/[\.]+/ig)
.slice(1)
.filter(hasRealTextContent);
} else if (!!(chunkTimestamp = tmpObject.rawToken.match(SRTChunkTimestampParser))) {
cueStructure.isTimeDependent = true;
timeData = chunkTimestamp.slice(1);
tmpObject.timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours
parseInt((timeData[1]||0) * 60,10) + // Minutes
parseInt((timeData[2]||0),10) + // Seconds
parseFloat("0." + (timeData[3]||0)); // MS
}
currentContext.push(tmpObject);
stack.push(currentContext);
currentContext = tmpObject.children;
}
}
} else {
// Text string
currentToken = currentToken
.replace(/</g,"<")
.replace(/>/g,">")
.replace(/\&/g,"&");
currentToken = currentToken.replace(/\n+/g,"<br />");
currentContext.push(currentToken);
}
}
}
reportMessage("cue text parsed: "+cueStructure);
return cueStructure;
}