I have a HTML5 video element in my page and what I'd like to happen is when it reaches the 3 second mark, it needs to pause for 2 seconds and then continue playback.
The video length is about 8 seconds.
<video id="video" playsinline autoplay muted loop>
<source src="video.mp4" type="video/mp4"/>
<source src="video.webm" type="video/webm"/>
</video>
This does it
const video = document.getElementById('myVideo');
function playVid() {
video.play();
window.setTimeout(pauseVid, 3000);
}
function play() {
video.play();
}
function pauseVid() {
video.pause();
window.setTimeout(play, 5000);
}
setTimeout() .currentTime & timeupdate
Go to the link above to understand why setTimeout() ain't so great.
.currentTime Property
This property is used by <audio> and <video> tags to get/set playback time in seconds. In the following demo it is used to get the time:
var t = this.currentTime;
timeupdate Event
This event fires 4 times a second while an <audio> or <video> tag is playing. In the demo both a <video> and <audio> tag are registered to to the timeupdate event:
video.addEventListener("timeupdate", tick);
timer.addEventListener("timeupdate", tock);
Setup
[controls] Attribute
Added so the time can be reviewed as the demo runs, it's optional and recommended that it not be used in production.
<audio> Tag
An <audio> tag has been added as a timer, The attributes [muted] and [autoplay] are required:
<audio id='timer' src='https://od.lk/s/NzlfOTEwMzM5OV8/righteous.mp3' muted controls autoplay></audio>
Both tags will start playing and are listening to the timeupdate event and will call a function at a predetermined time:
function tick(e) {
var t = this.currentTime;
if (t >= 3) {
this.pause();
video.removeEventListener("timeupdate", tick);
}
}
function tock(e) {
var t = this.currentTime;
if (t >= 5) {
video.play();
timer.removeEventListener("timeupdate", tock);
}
}
Basically when the <video> and <audio> tags are triggered every 250ms, they are calling those functions:
<video> calls function tick()
if the playback time is 3 or more seconds it pauses.
to avoid constant triggering every 250ms, the eventListener is removed.
<audio> calls function tock()
if the playback time is 5 or more seconds it will play the <video>.
for the same reason as the <video>, the eventListener is removed.
Demo
var video = document.getElementById('video');
var timer = document.getElementById('timer');
video.addEventListener("timeupdate", tick);
timer.addEventListener("timeupdate", tock);
function tick(e) {
var t = this.currentTime;
if (t >= 3) {
this.pause();
video.removeEventListener("timeupdate", tick);
}
}
function tock(e) {
var t = this.currentTime;
if (t >= 5) {
video.play();
timer.removeEventListener("timeupdate", tock);
}
}
<video id="video" playsinline muted loop controls autoplay width='300'>
<source src="https://html5demos.com/assets/dizzy.mp4" type="video/mp4"/>
</video>
<audio id='timer' src='https://od.lk/s/NzlfOTEwMzM5OV8/righteous.mp3' muted controls autoplay></audio>
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 m trying to make my video play only the first 30 secs of the video and return to the starting time going as loop irrespective of video length.
Here's my code so far.
HTML
<video width="100%" height="192px" id="player" controls loop >
<source src="images/videos/<?= $v_video; ?>" type="video/mp4">
<source src="images/videos/<?= $v_video; ?>" type="video/ogg">
</video>
JS
<script>
var playTimeout;
$("#player").on("play", function(e) {
playTimeout = setTimeout(function() {
$("player").pause();
$("player").setCurrentTime(0); // Restarts video
}, 30000); // 30 seconds in ms
});
$("#player").on("pause", function(e) {
clearTimeout(playTimeout);
});
</script>
However, it stills keeps on playing after 30sec.
Any help is appreciated.
$("player").pause();
$("player").setCurrentTime(0); // Restarts video
needs to be
$("#player").get(0).pause();
$("#player").get(0).currentTime = 0; // Restarts video
Also, I would use the timeupdate event so that the video doesn't reset while it is still loading (in your example, with a slow connection, if they spend 10 seconds buffering before playback, it would reset after only 20 seconds of playing).
See example (set to 3 seconds instead of 30 for easier demo):
var playTimeout;
$("#player").on("timeupdate", function(e) {
playTimeout = setTimeout(function() {
$("#player").get(0).pause();
$("#player").get(0).currentTime = 0; // Restarts video
}, 3000); // 3 seconds in ms
});
$("#player").on("pause", function(e) {
clearTimeout(playTimeout);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<video id="player" controls="true" height="200" width="300">
<source type="video/ogg" src="http://media.w3.org/2010/05/bunny/movie.ogv">
<source type="video/mp4" src="http://media.w3.org/2010/05/bunny/movie.mp4">
</video>
I have a video in my html. I would like the video to pause at 5 seconds after playing so I used addEventListener. I also have 2 buttons that call either restart() or jump().
When I play my video, an EventListener is called on my video. It pauses at 5 seconds, but I can't get it to play after 5 seconds (I've tried removing the listener but then the video no longer pauses). When I call jump(), it'll take me to 10 seconds but continue to pause when I try to play it. When I call reset(), the video will play up to 5 seconds again, which makes sense since I have a Listener on it. How do I get it to play after 10 seconds for when I call jump()? At first I thought I would have to remove my Listener but I believe I'll need that still because I would like the video to pause at 15 seconds. Or maybe I need to call removeEventListener somewhere else?
js
var video = document.getElementById("myvid");
video.addEventListener("timeupdate", function(){
if(this.currentTime >= 5) {
this.pause();
}
});
function restart(){
video.currentTime = 0;
}
function jump(){
video.currentTime = 10;
if (video.currentTime >=15){
video.pause
}
}
html
<video id="myvid" width="320" height="240" controls>
<source src="video.mp4" type="video/mp4">
</video>
<button onclick="restart()">restart</button>
<button onclick="jump()">jump</button>
You must keep the pause time in a variable. Then you can use it in the jump function:
var video = document.getElementById( 'myvid' ),
pausedtime = 0;
video.addEventListener( 'timeupdate', function() {
if ( this.currentTime >= pausedtime + 5 ) {
this.pause();
pausedtime = this.currentTime
}
});
function restart(){
video.currentTime = 0;
pausedtime = 0;
video.play()
}
function jump(){
pausedtime += 5;
video.currentTime = pausedtime;
video.play()
}
<video id="myvid" width="320" height="240" controls>
<source src="http://iandevlin.com/html5/media-player/parrots.mp4.mp4" type="video/mp4">
<source src="http://iandevlin.com/html5/media-player/parrots.webm" type="video/webm">
</video>
<br>
<button type="button" onclick="restart()">Restart</button>
<button type="button" onclick="jump()">Jump</button>
I want to be able to reload the video into the HTML5 video without having to reset the currentTime when it is loaded. The way I am currently doing it is the following:
<button onclick="getCurTime()" type="button">Get current time position</button>
<button onclick="setCurTime()" type="button">Set time position to 5 seconds</button><br>
<div style="width:800px; height:445px;">
<video id="myVideo" width="100%" height="100%" controls="controls">
<source src="http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4" type="video/mp4">
</video>
<script>
var vid = document.getElementById("myVideo");
function setCurTime() {
vid.currentTime=100;
}
$(document).ready(function ()
{
$('#myVideo').videocontrols(
{
preview:
{
sprites: ['big_bunny_108p_preview.jpg'],
step: 10,
width: 200
},
theme:
{
progressbar: 'blue',
range: 'pink',
volume: 'pink'
}
});
vid.play();
});
setInterval(function(){
if(vid.currentTime > vid.duration-1)
{
myVideo.src = "http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4";
myVideo.load();
myVideo.play();
vid.currentTime = vid.duration-60*5
}
}, 1);
</script>
</div>
How would I go about doing this? Is there even a way to just update the data in the video player without having to reload the video? I want to be able to do this so if someone makes a modification to the video, it will just update the data in the video player so the user doesn't have to reload the whole video again.
per discussion in comment thread above, I'm still not 100% sure why you're reloading the same video so I may be missing some context, but the following code will let you change the video source but preserve the current time. It does assume jQuery for the event handler (though you can easily use the regular javascript event handler on the same event to do the same thing)
<video id="v" width="320" height="240" controls="controls" mute>
<source src="Video.mp4" />
</video>
<button onclick="reload()">Reload</button>
<script>
function reload() {
vid=document.getElementById("v")
// record the current time for the video that is playing
curTime = vid.currentTime
// set the source for the replacement video...
vid.src = "http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4";
// ... and load it
vid.load();
// add event handler for "canplay" to set the time, and then start the video
$("#v").on("canplay",function() {
vid.currentTime = curTime
vid.play();
// remove the event to stop it triggering multiple times
$("#v").off("canplay")
})
}
</script>
Can I make a countdown to the end of the HTML5 video?
<video id="video" width="400" height="225" preload="auto">
<source src="video.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
</video>
<div id="countdown">Video ends after <span>XX</span> seconds.</div>
I understand that a have to wait for the video load, and then if the video is loaded, need to know the length and run video and coundown.
Listen to the timeupdate event fired by the video object and update the time remaining.
Something like this should work:
var video = document.getElementById('video');
video.addEventListener('timeupdate', updateCountdown);
function updateCountdown() {
var timeSpan = document.querySelector('#countdown span');
timeSpan.innerText = video.duration - video.currentTime;
}
This should do the trick for you
countdown = video.duration - video.currentTime
See here for more details