I have researched and experimented my brains out on this one. I have built a working application that uses the HTML5 canvas to play videos and interact with users through a web page (a game, sort of). Works like a charm, but I want to add captions to the video to make it more accessible. I don't even seem to be able to get the WebVTT file to load and I've reached the stage of voodoo programming by trying examples from the web and am making no progress. I have tried to distill the application down to its bare minimum here in hopes someone can provide some insight into what I'm doing wrong.
The video plays when I click on the canvas, the "...waiting for cuechange event..." message stays up while it plays, and then it goes to the "video complete ... reload to try again" message when done (kept it simple by requiring a page reload to try the test again), so the basic mechanics seem to be working. It never gets into the "load" function for the text track (never displays "... loaded text track ..."), and the updateSubtitle() function is never invoked. If I insert a trackElement.readyStatus() call, it always returns 0 (unsurprisingly). As a further note, if I add a testStatus.innerHTML = "...loaded metadata..."; statement in the "loadedmetadata" listener, it does get there.
var canvasContext, videoElement, intervalHandle, testStatus, trackElement;
function processFrame() {
canvasContext.drawImage(videoElement, 193, 50, 256, 194);
}
function videoEnded() {
clearInterval(intervalHandle);
testStatus.innerHTML = "video complete ... reload to try again";
}
var count = 0;
function updateSubtitle(event) {
count = count + 1;
testStatus.innerHTML = "count" + count;
}
function clickHandler(event) {
testStatus.innerHTML = "...waiting for cuechange event...";
videoElement.setAttribute("src", "start.ogg");
videoElement.load();
intervalHandle = setInterval(processFrame, 25);
videoElement.play();
}
function init() {
var canvasElement, textTrack;
canvasElement = document.createElement("canvas");
videoElement = document.createElement("video");
videoElement.addEventListener("loadedmetadata", function() {
trackElement = document.createElement("track");
trackElement.kind = "captions";
trackElement.label = "English";
trackElement.srclang = "en";
trackElement.src = "start_en.vtt";
trackElement.addEventListener("load", function() {
testStatus.innerHTML = "... loaded text track ...";
trackElement.mode = "showing";
});
videoElement.appendChild(trackElement);
trackElement.addEventListener("cuechange", updateSubtitle, false);
});
var mainDiv = document.getElementById("arghMainDiv");
canvasElement.setAttribute("id", "mediaScreen");
canvasElement.width = 640;
canvasElement.height = 480;
var firstChild;
if(mainDiv.hasChildNodes()) {
firstChild = mainDiv.firstChild;
mainDiv.insertBefore(canvasElement, firstChild);
} else {
firstChild = mainDiv.appendChild(canvasElement);
}
testStatus = document.createElement("p");
testStatus.setAttribute("id", "testStatus");
mainDiv.insertBefore(testStatus, firstChild);
testStatus.innerHTML = "click on canvas to test";
canvasContext = canvasElement.getContext('2d');
canvasElement.addEventListener("click", clickHandler);
videoElement.addEventListener("ended", videoEnded);
}
#fatalError {
color: red;
}
#arghMainDiv {
text-align: center;
}
#mediaScreen {
border: 5px solid #303030;
margin-left: auto;
margin-right: auto;
display: block;
cursor: default;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Problems With TextTrack Object</title>
<link rel="stylesheet" type="text/css" href="subargh.css">
<script src="subargh.js"></script>
</head>
<body onload="init()">
<div id="arghMainDiv">
</div>
</body>
</html>
If you want the video and WebVTT files I'm using (just a few seconds long), they are here and here (respectively). I should also mention that if I play the video using VLC, that it recognizes and plays the .vtt file as subtitles properly on the video (so it appears to be well-formed). I am running my tests on Firefox 57.0.4 (64-bit) on a Windows 7 system if that makes any difference (but I am under the impression that Firefox is mostly fixed where Timed Text Tracks are concerned now).
Related
I would like to create a javascript html5 script that allows to have
poster and play a youtube video with its transcript.
and in this script I'd like a button that captures the images from the video as soon as I press the button.
And that the transcript is written in the browser and as the video progresses.
the goal is that at the end of the video I'll have a full article of the video.
Example:
1) I put a youtube link in the script
2) I see in the html5 page the video
3) I press play on the video
4) the transcription how to write in the html page ok
5) at any time I can make a pose of the video to take a screenshot of the image.
the result must be the following.
I'm taking a screenshot so one frame of the video to start with.
I've got the text underneath.
screenshot image
transcribed text
screenshot image
transcribed text
screenshot image
transcribed text
screenshot image
transcribed text
until the end of the video
the screenshot captures it's me who makes them by pressing the button to capture the screenshot.
I managed to make a page that takes the screenshot with a button from a local mp4 video.
but what I can't do, and that's where I need your help:
1) is to play a youtube video in an html5 page with always the screen shot button
2) write in real time the transcription in a html5 page until the end of the video.
thank you for your help.
<script>
var videoId = 'video';
var scaleFactor = 0.5;
var snapshots = [] ;
/**
* Captures a image frame from the provided video element.
*
* #param {Video} video HTML5 video element from where the image frame will be captured.
* #param {Number} scaleFactor Factor to scale the canvas element that will be return. This is an optional parameter.
*
* #return {Canvas}
*/
function capture(video, scaleFactor) {
if (scaleFactor == null) {
scaleFactor = 1;
}
var w = video.videoWidth * scaleFactor;
var h = video.videoHeight * scaleFactor;
var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, w, h);
innerHTML = "<br>";
return canvas ;
}
/**
* Invokes the <code>capture</code> function and attaches the canvas element to the DOM.
*/
function shoot() {
var video = document.getElementById(videoId);
var output = document.getElementById('output');
var canvas = capture(video, scaleFactor);
canvas.onclick = function() {
window.open(this.toDataURL(image/jpg));
};
snapshots.unshift(canvas);
output.innerHTML = '';
for (var i = 0; i < 10; i++) {
output.appendChild(snapshots[i]) ;
}
}
(function() {
var captureit = document.getElementById('cit');
captureit.click();
})();
</script>
<style>
.wrap {
border: solid 1px #ccc;
padding: 10px;
text-align: center;
}
#output {
display: inline-block;
top: 4px;
position: relative;
border: dotted 1px #ccc;
padding: 2px;
}
.button {
border: solid 2px #ccc;
}
</style>
<html>
<body>
<div class="wrap">
<video id="video" width="600" controls="true">
<source src = "http://127.0.0.1/divi.mp4" type = "video/mp4"></source>
<!-- FireFox 3.5 -->
<source src = "http://127.0.0.1/divi.mp4" type = "video/mp4"></source>
<!-- WebKit -->
Your browser does not support HTML5 video tag. Please download FireFox 3.5 or higher.
</video>
<br/>
<button id="cit" onclick="shoot()" class="button">Capture</button>
<br/>
<div id="output">
</div>
here are two scripts the first one has a button that captures the images of an MP4 video
and the second one that stupidly extracts all the images from a video automatically...
what I'm missing is:
1) put the link of any youtube video that is displayed in the html5 page
2) when I click on play I get the transcript which is written below the video automatically.
3) I want to do a pose to make a screen capture
4) continue transcription
5) image capture of the video etc...
text
image
text
image
until the end of the video
the goal of getting my full article.
I have a lot of tutorials on youtube and I would like to have them in documentation on my website.
create a complete article for each video
the best thing is to have a motion capture of the automatic image.
that is to say:
1) I click on the video
2) the script takes a first capture of the video
3) the transcription is written below the image captured in the html5 page
4) as soon as the image changes the script detects it and takes the print screen by itself without any button.
and so on until the end of the video without my intervention.
it creates a complete article on its own
just by putting my youtube link!!
It'll be the best of the best...
thank you for your support I'm sure that among you there are people who have websites and would like to have a script that can do articles alone...
3) as soon as
everybody!
i have an idea, but I don't know how to implement it.
how to make sure that when you press ctrl + shift + i also on the f12 key changed a certain part of the html code?
for example: SRC="video.MP4 "on SRC=" error.MP4
Thanks!
update -9.24.18
you need to make it so that the user was difficult to copy the link from scr="video.mp4"
-Aison
Here's one way you could do this:
<video id="someVideo" src="somfile.mp4" />
<script>
function KeyPress(e)
{
var evtobj = window.event ? event : e;
// 73 = i
if (evtobj.keyCode == 73 && evtobj.ctrlKey && evtobj.shiftKey)
{
document.getElementById('someVideo').src = "error.mp4";
}
}
// On keypress, activate our function
document.onkeydown = KeyPress;
</script>
However, as I mentioned in the comments this will in no way prevent users from downloading your mp4 file.
Users can still:
Right click, inspect element
Hit f12
Have the 'inspect element' open before visiting your website
Save your webpage
Save just the video from your webpage
Disable JS / override your JS.
Access your webpage without the use of a webbrowser (GET/save your webpage)
There are other ways as well, that's just off the top of my head.
Edit following comments:
You could instead use an html5 <canvas>.
This will hide the source. However, it will cause the video to no longer work if the user has JS disabled.
Example (you'll have to either add your own play button, or change the script to start the video automatically):
<!-- You can hide this element anywhere in your hmtl. It will not be visbile (via CSS) -->
<!-- note: I used `muted="muted"` because otherwise you will get an error when starting the video without a user action -->
<video id="someVideo" muted="muted" controls>
<source src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4" type="video/mp4">
</video>
<!-- canvas will display the video -->
<canvas id="myCanvas"></canvas>
<script>
document.addEventListener('DOMContentLoaded', function()
{
var hiddenVideo = document.getElementById('someVideo');
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var cw = Math.floor(canvas.clientWidth);
var ch = Math.floor(canvas.clientHeight);
canvas.width = cw;
canvas.height = ch;
hiddenVideo.addEventListener('play', function(){
draw(this,context,cw,ch);
},false);
hiddenVideo.onloadstart = function(){
this.play();
};
},false);
function draw(v,c,w,h)
{
if(v.paused || v.ended)
return false;
c.drawImage(v,0,0,w,h);
setTimeout(draw,20,v,c,w,h);
}
</script>
<style>
#someVideo
{
display: none;
width: 200px;
height: 200px;
}
#myCanvas
{
width: 200px;
height: 200px;
}
</style>
Since you're giving the mp4 file to the user, you cannot prevent the user from having the mp4 file.
I am trying to debug a case where all sprites that have the hand cursor turned on do not actually display them properly.
When you hover, the cursor does not change
When you click down, the hand cursor still fires.
Down events still fire but I think over/out events are not firing
There are no errors/warnings for the game in the console.
Same thing happens in a few browsers
Since this project is a derivative of another project where the cursor works, I'm trying to slowly step back my code but not really having luck so far with that. So trying to drum up ideas on how to figure this out.
Edit
Since this happened again, on another project I thought I would post up code. I boiled this down to a very simple game and it still happens. This is with Phaser 2.4.8 and Pixi v2.2.9.
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style>
body {
margin: 0;
padding: 0;
background: #000;
}
canvas {
margin: 0 auto;
}
</style>
<script src="./assets/js/phaser.min.js"></script>
<script>
var game = new Phaser.Game(2280, 1440, Phaser.CANVAS, '', {
preload: function() {
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.load.spritesheet('help', 'assets/img/help-button.png', 130, 130);
},
create: function() {
var help = game.add.sprite(0, 0, 'help', 0);
help.inputEnabled = true;
help.input.useHandCursor = true;
}
});
function resizeGame() {
this.scale.refresh();
}
window.onresize = resizeGame.bind(game);
</script>
</head>
<body>
<div id="game"></div>
<audio id="audio" controls style="display:none">
Your browser does not support the audio element.
</audio>
</body>
</html>
I have a chunk of code that causes a graph that monitors a graph to update periodically and is displayed with a raspberry pi, but the problem I'm having is because of the Pi's limited memory, Chromium dies because it run out of memory. I think this is because when the image updates, it saves the older images somewhere. I've tried using JS to delete the image and create a new one with an updated image, but it didn't work. I'm not too familiar with Javascript so I wasn't sure if I was making a rookie mistake or something. Here is the code:
<script type= "text/javascript">
var graph = "http://www.example.com";
function preload()
{
try
{
var buffer = new Image();
buffer.src = graph;
buffer.onload = function()
{
while (1)
{
setTimeout(preload, 1000);
document.getElementById('graph').src = buffer.src;
}
}
}
catch(err)
{
txt = "Error\n" + err.message;
alert(txt);
}
}
preload()
</script>
And the HTML for the image is:
<img src= "http://www.example.com" id=graph width=1015
height=275 frameborder="0" onload="preload()" style="display: block;
margin-left: auto; margin-right: auto;" align="bottom"/>
Here is a vastly simplified script for you - your loop made no sense at all and there is no Ajax in your code
var graph = "https://zabbix.tulsahpc.org/signage/sign.png",tId;
window.onload=function() {
tId=setInterval(function() {
document.getElementById('graph').src = graph+new Date().getTime();// avoid cache
},10000);// reload every 10 secs
}
I have been trying to set up a javascript game loop and I have two issues I am running into. I find that in chrome when I lose focus of the browser window and then click back the animation I have running does this weird "catch up" thing where it quickly runs through the frames it should of been rendering in the background. I also have noticed that the animation is blury when moving at the current speed I have it at yet other people have been able to get their canvas drawings to move quickly and still look crisp. I know their seems to be a lot out about this but I cant make sense of what my issue really is. I thought this was a recommended way to create a game loop.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Frame Test</title>
<link href="/css/bootstrap.css" media="all" rel="stylesheet" type="text/css" />
<script language="javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"
type="text/javascript">
</script>
<script language="javascript" src="js/jquery.hotkeys.js" type="text/javascript"></script>
<script language="javascript" src="js/key_status.js" type="text/javascript"></script>
<script language="javascript" src="js/util.js" type="text/javascript"></script>
<script language="javascript" src="js/sprite.js" type="text/javascript"></script>
</head>
<body>
<button id="button1">
Toggle Loop</button>
<h1 id="frameCount">
Game Loop Test</h1>
<canvas id="gameCanvas" width="800" height="500">
<p>Your browser doesn't support canvas.</p>
</canvas>
<script type='text/javascript'>
// demo code used for playing around with javascript-canvas animations
var frameCount = 0;
var drawingCanvas = document.getElementById('gameCanvas');
// Check the element is in the DOM and the browser supports canvas
if (drawingCanvas.getContext) {
var context = drawingCanvas.getContext('2d');
var x = 100;
var y = 100;
var right = true;
context.strokeStyle = "#000000";
context.fillStyle = "Green";
context.beginPath();
context.arc(x, y, 50, 0, Math.PI * 2, true);
context.closePath();
context.stroke();
context.fill();
}
function Timer(settings) {
this.settings = settings;
this.timer = null;
this.on = false; //Bool that represents if the timer is running or stoped
this.fps = settings.fps || 30; //Target frames per second value
this.interval = Math.floor(1000 / 30);
this.timeInit = null; //Initial time taken when start is called
return this;
}
Timer.prototype =
{
run: function () {
var $this = this;
this.settings.run();
this.timeInit += this.interval;
this.timer = setTimeout(
function () { $this.run() },
this.timeInit - (new Date).getTime()
);
},
start: function () {
if (this.timer == null) {
this.timeInit = (new Date).getTime();
this.run();
this.on = true;
}
},
stop: function () {
clearTimeout(this.timer);
this.timer = null;
this.on = false;
},
toggle: function () {
if (this.on) { this.stop(); }
else { this.start(); }
}
}
var timer = new Timer({
fps: 30,
run: function () {
//---------------------------------------------run game code here------------------------------------------------------
//Currently Chorme is playing a catch up game with the frames to be drawn when the user leaves the browser window and then returns
//A simple canvas animation is drawn here to try and figure out how to solve this issue. (Most likely related to the timer implimentation)
//Once figured out probably the only code in this loop should be something like
//updateGameLogic();
//updateGameCanvas();
frameCount++;
if (drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
//Canvas commands go here
context.clearRect((x - 52), 48, (x + 52), 104);
// Create the yellow face
context.strokeStyle = "#000000";
context.fillStyle = "Green";
context.beginPath();
if (right) {
x = x + 6;
if (x > 500)
right = false;
} else {
x = x - 6;
if (x < 100)
right = true;
}
context.arc(x, 100, 50, 0, Math.PI * 2, true);
context.closePath();
context.stroke();
context.fill();
}
document.getElementById("frameCount").innerHTML = frameCount;
//---------------------------------------------end of game loop--------------------------------------------------------
}
});
document.getElementById("button1").onclick = function () { timer.toggle(); };
frameCount++;
document.getElementById("frameCount").innerHTML = frameCount;
</script>
</body>
</html>
-------------Update ---------------------
I have used requestanimation frame and that has solved the frame rate problam but I still get weird ghosting/bluring when the animation is running. any idea how I should be drawing this thing?
Okay, so part of your problem is that when you switch tabs, Chrome throttles down its performance.
Basically, when you leave, Chrome slows all of the calculations on the page to 1 or 2 fps (battery-saver, and more performance for the current tab).
Using setTimeout in the way that you have is basically scheduling all of these calls, which sit and wait for the user to come back (or at most are only running at 1fps).
When the user comes back, you've got hundreds of these stacked calls, waiting to be handled, and because they've all been scheduled earlier, they've all passed their "wait" time, so they're all going to execute as fast as possible (fast-forward), until the stack is emptied to where you have to start waiting 32ms for the next call.
A solution to this is to stop the timer when someone leaves -- pause the game.
On some browsers which support canvas games in meaningful ways, there is also support for a PageVisibility API. You should look into it.
For other browsers, it'll be less simple, but you can tie to a blur event on the window for example.
Just be sure that when you restart, you also clear your interval for your updates.
Ultimately, I'd suggest moving over to `requestAnimationFrame, because it will intelligently handle frame rate, and also handle the throttling you see, due to the stacked calls, but your timer looks like a decent substitute for browsers which don't yet have it.
As for blurriness, that needs more insight.
Reasons off the top of my head, if you're talking about images, are either that your canvas' width/height are being set in CSS, somewhere, or your sprites aren't being used at a 1:1 scale from the image they're pulled from.
It can also come down to sub-pixel positioning of your images, or rotation.
Hope that helps a little.
...actually, after looking at your code again, try removing "width" and "height" from your canvas in HTML, and instead, change canvas.width = 800; canvas.height = 500; in JS, and see if that helps any.