I can implement a poster at the beginning of a video using poster="beginning.jpg", but how to put a different image at the end of video? example image is like ending.jpg
<video controls width="100%" poster="beginning.jpg" >
<source src="video.mp4" />
</video>
here is jsfiddle
First add an Id to the video.
var video = document.getElementById('video');
var posterURL = 'end.jpg';
// Preload the end poster when the video starts to play
video.addEventListener('play', function() {
var image = new Image();
image.src = posterURL;
});
// Set and display the end poster
video.addEventListener('ended', function() {
video.poster = posterURL;
video.load();
});
Use ended, play events, .load()
<video width="100%" controls poster="/image/src/">
<source src="/video/src/" type="video/mp4" />
</video>
<script>
var video = document.querySelector("video");
video.onplay = function() {
this.setAttribute("poster", "") // remove `poster` image
video.onended = function(e) {
this.setAttribute("poster", "/new/image/src") // set new `poster` image
// call `.load()`
this.load();
}
</script>
jsfiddle https://jsfiddle.net/ey4tfp30/4/
Related
I am adding multiple HTML5 videos onto a webpage.
The code I am replicating is from this recommended accessible approach. http://jspro.brothercake.com/audio-descriptions/ The video plays fine, and audio captions work, but when I add a new video to the same page the second video does not play the audio captions at all. Does anyone have suggestions on how I can fix this issue?
<video id="video" preload="auto" controls="controls"
width="640" height="360" poster="./media/HorribleHistories.jpg">
<source src="./media/HorribleHistories.mp4" type="video/mp4" />
<source src="./media/HorribleHistories.webm" type="video/webm" />
</video>
<audio id="audio" preload="auto">
<source src="./media/HorribleHistories.mp3" type="audio/mp3" />
<source src="./media/HorribleHistories.ogg" type="audio/ogg" />
</audio>
<script type="text/javascript">
(function()
{
//get references to the video and audio elements
var video = document.getElementById('video');
var audio = document.getElementById('audio');
//if media controllers are supported,
//create a controller instance for the video and audio
if(typeof(window.MediaController) === 'function')
{
var controller = new MediaController();
audio.controller = controller;
video.controller = controller;
}
//else create a null controller reference for comparison
else
{
controller = null;
}
//reduce the video volume slightly to emphasise the audio
audio.volume = 1;
video.volume = 0.8;
//when the video plays
video.addEventListener('play', function()
{
//if we have audio but no controller
//and the audio is paused, play that too
if(!controller && audio.paused)
{
audio.play();
}
}, false);
//when the video pauses
video.addEventListener('pause', function()
{
//if we have audio but no controller
//and the audio isn't paused, pause that too
if(!controller && !audio.paused)
{
audio.pause();
}
}, false);
//when the video ends
video.addEventListener('ended', function()
{
//if we have a controller, pause that
if(controller)
{
controller.pause();
}
//otherwise pause the video and audio separately
else
{
video.pause();
audio.pause();
}
}, false);
//when the video time is updated
video.addEventListener('timeupdate', function()
{
//if we have audio but no controller,
//and the audio has sufficiently loaded
if(!controller && audio.readyState >= 4)
{
//if the audio and video times are different,
//update the audio time to keep it in sync
if(Math.ceil(audio.currentTime) != Math.ceil(video.currentTime))
{
audio.currentTime = video.currentTime;
}
}
}, false);
})();
</script>
So your problem is to do with how you are grabbing the elements in the first place.
var video = document.getElementById('video');
var audio = document.getElementById('audio');
What you are doing is grabbing a single item on the page with the ID of "video" (same for "audio").
IDs have to be unique, so what you want to do is use classes instead.
<video class="video" preload="auto" controls="controls"
width="640" height="360" poster="./media/HorribleHistories.jpg">
See I changed the ID to a class.
Now any element with the class "video" can be used in our code.
However we do need to modify our code a bit as now we have multiple items to bind to.
please note the below is to give you an idea of how you loop items etc. You would need to rewrite your code to move each of the steps into functions etc. as your original code is not designed to work with multiple items
(function()
{
//get references to every single video and audio element
var videos = document.querySelectorAll('.video');
var audios = document.querySelectorAll('.audio');
// loop through all videos adding logic etc.
for(x = 0; x < videos.length; x++){
// grab a single video from our list to make our code neater
var video = videos[x];
if(typeof(window.MediaController) === 'function')
{
var controller = new MediaController();
video.controller = controller;
} else {
controller = null;
}
video.volume = 0.8;
//...etc.
}
})();
Quick Tip:
I would wrap your <video> and <audio> elements that are related in a <div> with a class (e.g. class="video-audio-wrapper").
This way you can change your CSS selector to something like:
var videoContainers = document.querySelectorAll('.video-audio-wrapper');
Then loop through them instead and check if they have a video and / or audio element
for(x = 0; x < videoContainers.length; x++){
var thisVideoContainer = videoContainers[x];
//query this container only - we can use `querySelector` as there should only be one video per container and that returns a single item / the first item it finds.
var video = thisVideoContainer.querySelector('video');
var audio = thisVideoContainer.querySelector('audio');
//now we can check if an element exists
if(video.length == 1){
//apply video logic
}
if(audio.length == 1){
//apply audio logic
}
// alternatively we can check both exist if we have to have both
if(video.length != 1 || audio.length != 1){
// we either have one or both missing.
// apply any logic for when a video / audio element is missing
//using "return" we can exit the function early, meaning all code after this point is not run.
return false;
}
///The beauty of this approach is you could then just use your original code!
}
Doing it this way you could recycle most of your code.
Thank you for your suggestions in changing the ID's into classes and adding the video wrapper <div> to the video container. That all makes sense in grouping each video on 1 page. I updated the the following code, but the audio captions won't play at all. The video plays and pauses fine, and the volume works. I am also not getting any syntax errors in the browser console. Here's what I got for my HTML and JS. I appreciate your help/feedback.
<div class="video-container-wrapper">
<div class="video-container">
<video class="video" preload="auto" controls="controls" width="640" height="360" poster="img/red-zone-thumb.png">
<source src="https://player.vimeo.com/external/395077086.hd.mp4?s=1514637c1ac308a950fafc00ad46c0a113c6e8be&profile_id=175" type="video/mp4">
<track kind="captions" label="English captions" src="captions/redzone-script.vtt" srclang="en" default="">
</video>
<audio class="audio" preload="auto">
<source src="captions/redzone-message.mp3" type="audio/mp3">
</audio>
</div>
</div>
Javascript:
var videoContainers = document.querySelectorAll('.video-container-wrapper');
for (x = 0; x < videoContainers.length; x++) {
var thisVideoContainer = videoContainers[x];
//query this container only - we can use `querySelector` as there should only be one video per container and that returns a single item / the first item it finds.
var video = thisVideoContainer.querySelector('video');
var audio = thisVideoContainer.querySelector('audio');
//now we can check if an element exists
if (video.length == 1) {
//apply video logic
//reduce the video volume slightly to emphasise the audio
video.volume = 0.8;
//when the video ends
video.addEventListener('ended', function () {
video.pause();
}, false);
}
if (audio.length == 1) {
//apply audio logic
audio.volume = 1;
//when the video plays
video.addEventListener('play', function () {
if (audio.paused) {
audio.play();
}
}, false);
// when the video ends
video.addEventListener('ended', function () {
audio.pause();
}, false);
//when the video time is updated
video.addEventListener('timeupdate', function () {
if (audio.readyState >= 4) {
//if the audio and video times are different,
//update the audio time to keep it in sync
if (Math.ceil(audio.currentTime) != Math.ceil(video.currentTime)) {
audio.currentTime = video.currentTime;
}
}
}, false);
}
}
I want to get the duration of video by javascript and this code doesn't work
<video id="myVideo">
<source src="">
</video>
<script>
var vid = document.getElementById("myVideo");
alert(vid.duration);
</script>
You need to wait for the file's metadata to load:
var vid = document.getElementById("myVideo");
vid.addEventListener('loadedmetadata', function() {
console.log(vid.duration);
});
I'm trying to make a random video player in html/js.
It is supposed to play a different video on pageload and as soon as one video is over, it should play another one.
HTML
<video width="320" height="240" autoplay>
<source src="abcdefg.com/example1.mp4" type="video/mp4">
<source src="abcdefg.com/example2.mp4" type="video/mp4">
</video>
JS
<script>
var videos = [
[{type:'mp4', 'src':'abcdefg.com/example1.mp4'}],
[{type:'mp4', 'src':'abcdefg.com/example2.mp4'}],
];
$(function() {
var number = Math.floor(Math.random()*videos.length);
$(this).find('source').each(function(index){
videoSrc = videos[number][index].src;
$(this).attr('src', videoSrc);
$('video').load();
$('video').play();
});
});
</script>
However, my current code plays the same video every page reload and as soon as it's over, nothing happens.
How do I need to optimize my code so it automatically plays a different video on every pageload + when the previous video is over?
Try this,I have added an event listener to video end property and called the newvideo() function ,so that every time the video finishes a new random video is loaded from array.I could'nt find more video urls ,you can test and let me know if it works for you.
$(document).ready(function(){
var videos = [
[{type:'mp4', 'src':'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4'}],
[{type:'mp4', 'src':'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4'}],
[{type:'mp4', 'src':'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4'}]
];
// selecting random item from array,you can make your own
var randomitem = videos[Math.floor(Math.random()*videos.length)];
// This function adds a new video source (dynamic) in the video html tag
function videoadd(element, src, type) {
var source = document.createElement('source');
source.src = src;
source.type = type;
element.appendChild(source);
}
// this function fires the video for particular video tag
function newvideo(src)
{
var vid = document.getElementById("myVideo");
videoadd(vid,src ,'video/ogg');
vid.autoplay = true;
vid.load();
//vid.play();
}
// function call
newvideo(randomitem[0].src)
// Added an event listener so that everytime the video finishes ,a new video is loaded from array
document.getElementById('myVideo').addEventListener('ended',handler,false);
function handler(e)
{
newvideo(randomitem[0].src)
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<video width="320" height="240" autoplay id="myVideo">
</video>
I need to display a video to canvas from video using the Createjs Ticker to navigate to the video timeline. I use the currentFrame/FPS to get readable time for my video tag. In Safari it's working fine but in chrome, video is lagging and my canvas is not updated. Ticker is set to 25 FPS.
Here is my HTML :
<video id="video" autoplay controls preload="auto" muted width="1280" height="720">
<source src="video.mp4" type="video/mp4" >
</video>
Here is my JS :
var video;
var first = true;
var first_2 = true
document.addEventListener('DOMContentLoaded',initVideo,false);
function initVideo() {
video = document.getElementById("video");
video.addEventListener('canplaythrough', function() {
if(first){
first = false;
init(); // Create Ticker
}
},false);
video.addEventListener('play', function() {
if(first_2){
first_2 = false;
video.pause();
}
});
}
function copyVideoToCanvas() {
video.currentTime = currentFrame/25;
exportRoot.videoBase.removeAllChildren();
var btmp = new createjs.Bitmap(video);
exportRoot.videoBase.addChild(btmp);
}
I modify the Animate cc code :
this.frame_0 = function() {
root = this;
root.addEventListener("tick", tick);
function tick(evt){
copyVideoToCanvas(time(root.currentFrame));
}
function time(t) {
return t/25;
}
}
Any ideas ?
Currently I'm designing a Web application (game) on Tizen where I want to:
Display an image
Play an audio clip(around 15-17 seconds long)
Do nothing for 5 seconds
Play another audio clip(about 2-3 seconds)
Hide the image
These steps are to be performed in a loop (N times) in order. However, when I run my App on the emulator, it plays all the sounds to be played on step 2 together at the same time while the image is never visible.
Following is my Javascript function:
function performTask(image, audioName) { //sending id for image and audio, e.g.: performTask("img1", "aud1")
// Show the image
img = document.getElementById(image);
if (img && img.style) {
img.style.height = screen.height;
img.style.width = screen.width;
img.style.visibility = "visible";
} else {
console.log("exercise(): error in setting image");
}
// play the audio
try {
myAudio = document.getElementById(audioName);
myAudio.play();
myAudio.onended = function() {
timeOut();
};
} catch (error) {
console.error("exercise(): " + error.message);
}
// after 30 seconds, ring the bell!!
try {
console.log("playing bell");
document.getElementById("bell").play();
} catch (error) {
console.error("bell: " + error.message);
}
//hide image
img.style.visibility = "hidden";
}
The timeOut() function:
var timer = 5000;
function timeOut() {
if (timer > 0) {
setTimeout(timeOut(), timer--);
}
}
The structure of the HTML page where this is called:
...
<body onload="someFunc()"> <!-- this calls performTask() in a for-loop-->
<p>
<img src='images/image1.png' alt="pose1n12" id="img1" />
.... 10 more such images
</p>
<p>
<audio id="bell">
<source src='audio/bell.mp3' type="audio/mpeg" />
</audio>
<audio id="aud1">
<source src='audio/aud1.mp3' type="audio/mpeg" />
</audio>
.... 10 more such clips
</p>
EDIT: Adding the definition for someFunc()
function someFunc() {
var a;
image = ''; // select image at particular count
audioName = ''; // select respective audio
for (a = 1; a <= 12; a++) { // the asana tracker loop
switch (a) { // assigns image & audio
case 1:
image = "img1n12";
audioName = "1N12";
break;
...... continues till case 12
}
}
performTask(image, audioName);
}
Please help.
By my understanding there is an "ended" event fired when a sound has finished playing.
http://forestmist.org/blog/html5-audio-loops/
You could use this to make stage 2 trigger stage 3 and have stage 4 trigger stage 5.
when playing the first audio, you should do every other step on the call back onended, and if you need to wait again some other time, you need to pass the call back to the setTimeout, the following code is a bit simplified :
// on Global scope
var audioName = "something";
var img = document.getElementById("image_id");
showImage ();
playAudio(audioName, function () {
playBell ();
hideImage ();
});
Now the functions definition would be like this :
function showImage () {
if (img && img.style) {
img.style.height = screen.height;
img.style.width = screen.width;
img.style.visibility = "visible";
} else {
console.log("exercise(): error in setting image");
}
}
function playAudio (audioName, callback) {
try {
myAudio = document.getElementById(audioName);
myAudio.play();
myAudio.onended = function() {
setTimeout(callback, 5000); // after 5 seconds
};
} catch (error) {
console.error("exercise(): " + error.message);
}
}
function playBell () {
try {
console.log("playing bell");
document.getElementById("bell").play();
} catch (error) {
console.error("bell: " + error.message);
}
}
function hideImage() {
img.style.visibility = "hidden";
}
Here I have two examples of addEventListener('ended'). This event listener should work fine for what you are asking.
First Method: Calls another function ChangeSrc() and uses the same player.
Method one will get the player by id, tell the player to play and add the event listener. This will listen of the ended event then call ChangeSrc(). When ChangeSrc is called the eventlistener is removed and the player src is changed to the next track and then told to play.
HTML:
<b>Method One</b><button onclick="MethodOne()">Start</button><br>
<img id="DemoImg" src="sample1.png"/><br/>
<audio id="DemoAud" controls>
<source src='sample1.mp3' type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
Javascript
function MethodOne(){
var a=document.getElementById("DemoImg");
var b=document.getElementById("DemoAud");
b.play();
b.addEventListener('ended',ChangeSrc,false);
}
function ChangeSrc(){
var a=document.getElementById("DemoImg");
var b=document.getElementById("DemoAud");
b.removeEventListener("ended",ChangeSrc);
a.src="sample2.png";
b.src="sample2.mp3";
b.play();
}
Second Method: Uses one function and two players (Like your source code does)
This method is very much like the first method but had the function in the eventlistener, this will tell the other player to play as this function will only run when the first audio clip has ended. This will also display the container for the image/player.
HTML
<b>Method Two</b><button onclick="MethodTwo()">Start</button><br>
<div id="Demo2" class="DemoBlock">
<img id="DemoImg2" src="sample1.png"/><br/>
<audio id="DemoAud2" controls>
<source src='sample1.mp3' type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
</div><div id="Demo3" class="DemoBlock">
<img id="DemoImg3" src="sample2.png"/><br/>
<audio id="DemoAud3" controls>
<source src='sample2.mp3' type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
</div>
Javascript:
function MethodTwo(){
var a=document.getElementById("DemoAud2");
var b=document.getElementById("DemoAud3");
a.play();
a.addEventListener('ended',function(){
document.getElementById("Demo3").style.display="inline-block";
b.play();
},false);
}
This Exmaple is just to show you two different methods of the using the eventlistener, the rest is down to you to integrate this into your existing source code.
Demo Source Code
function MethodOne(){
var a=document.getElementById("DemoImg");
var b=document.getElementById("DemoAud");
b.play();
b.addEventListener('ended',ChangeSrc,false);
}
function ChangeSrc(){
var a=document.getElementById("DemoImg");
var b=document.getElementById("DemoAud");
b.removeEventListener("ended",ChangeSrc);
a.src="http://coded4u.com/28831485/sample2.png";
b.src="http://coded4u.com/28831485/sample2.mp3";
b.play();
}
function MethodTwo(){
var a=document.getElementById("DemoAud2");
var b=document.getElementById("DemoAud3");
a.play();
a.addEventListener('ended',function(){
document.getElementById("Demo3").style.display="inline-block";
b.play();
},false);
}
.DemoBlock{display:inline-block;}
#Demo3{display:none;}
<b>Method One</b><button onclick="MethodOne()">Start</button><br>
<img id="DemoImg" src="http://coded4u.com/28831485/sample1.png"/><br/>
<audio id="DemoAud" controls>
<source src='http://coded4u.com/28831485/sample1.mp3' type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
<hr/>
<b>Method Two</b><button onclick="MethodTwo()">Start</button><br>
<div id="Demo2" class="DemoBlock">
<img id="DemoImg2" src="http://coded4u.com/28831485/sample1.png"/><br/>
<audio id="DemoAud2" controls>
<source src='http://coded4u.com/28831485/sample1.mp3' type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
</div><div id="Demo3" class="DemoBlock">
<img id="DemoImg3" src="http://coded4u.com/28831485/sample2.png"/><br/>
<audio id="DemoAud3" controls>
<source src='http://coded4u.com/28831485/sample2.mp3' type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
</div>
I hope this helps. Happy coding!