HTML 5 Video: Playing multiple "clips" with javascript - javascript

I'm having a problem with HTML Video and JavaScript so have written some simple code to demonstrate. There is one video which contains three "clips" all five seconds long (obviously, real-world, they are a lot longer). One at 25 - 30 seconds, one at 55 - 60 seconds and the last at 85 - 90 seconds. I want the user to be able to click the relevant button for each five second clip.
There are two issues:
The Chrome currenttimer() bug which doesn't seem to let you change the start time of an external video (The video will be stored on an Azure Blob). There appear to be a number of posts on this but no fix.
When you play the first clip and then try and play the second clip, because the start time of clip 2 is after the end time for clip 1, it doesn't play because the AddEventListener is still in effect. Is there a way to drop the original EventListener or replace it with the new end time?
Here is the code being used:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div style="width: 700px; height: 400px; margin: auto; text-align: center;">
<video id="video1" width="620" controls>
<source type="video/mp4" src="external video link here" />
Your browser does not support HTML5 video.
</video>
<input type="button" value="Play Clip 1 (25 - 30 seconds" onclick="javascript: showvid(25);" /><br />
<input type="button" value="Play Clip 2 (55 - 60 seconds" onclick="javascript: showvid(55);" /><br />
<input type="button" value="Play Clip 3 (85 - 90 seconds" onclick="javascript: showvid(85);" /><br />
</div>
<script type="text/javascript">
function showvid(timer) {
var myVideo = document.getElementById("video1");
myVideo.currentTime = timer;
myVideo.play();
myVideo.addEventListener("timeupdate", function () {
if (this.currentTime >= (timer + 5)) {
this.pause();
}
});
}
</script>
</body>
</html>
UPDATE 1
I've changed the event listener check to pause the video only if the currenttime is within a second of the end time. SO if the next clip is more than a second away, they listener won't stop the clip before it starts.
Still looking into the Chrome issue.

I don't know what Chrome bug you are talking about, but for cleaner code, you might be interested in the #t=start[,end] Media Fragment, which will allow you to set a time range directly as the source of your <video>:
onclick =e=> {
const data = e.target.dataset;
if(!data.start) return;
vid.src = vid.src.split('#')[0] +
'#t=' + data.start + ',' + data.end;
// url.vid#t=start,end
vid.play();
}
<button data-start="5" data-end="10">play [5,10]</button>
<button data-start="35" data-end="40">play [35,40]</button>
<button data-start="00:01:25" data-end="00:01:30">play [00:01:25,00:01:30]</button>
<video id="vid" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" muted></video>
Now if you really wish to go the way you were going, then you'll have change your code a bit.
Never add a new event listener from an user-generated event.
Add it once, and only trigger semaphores / update variables from user events.
So we first add the timeupdate event on our <video>, then if no user generated event did happen, we exit early. Otherwise, we check for a variable that is accessible to both our event listeners (here called next_stop) if we should pause or not.
Then, in the buttons event listeners, we update the <video>'scurrentTime, request it to play and update next_stop.
The two event listeners can interact thanks to the shared next_stop variable, but no more conflicts.
let next_stop = Infinity; // a variable shared by both event listeners
// add the event listeners only once
vid.addEventListener('timeupdate', handleTimeupdate, {passive: true});
document.addEventListener('click', handleClick);
function handleTimeupdate(evt) {
// not set? exit early
if(!isFinite(next_stop)) return;
// a single action
if(this.currentTime > next_stop) {
this.pause();
// if you want to disable the range once it's done
// e.g to allow default controls interactions
// next_stop = Infinity;
}
}
function handleClick(evt) {
const times = parseTime(evt.target);
if(!times) return;
// update the video's current time
vid.currentTime = times.start;
// update the shared variable
next_stop = times.end;
// start playing if needed
if(vid.paused) {
vid.play();
}
}
function parseTime(target) {
const data = target.dataset;
if(!data || !data.start) return null;
return {start: +data.start, end: +data.end};
}
<button data-start="5" data-end="10">play [5,10]</button>
<button data-start="35" data-end="40">play [35,40]</button>
<button data-start="85" data-end="90">play [00:01:25,00:01:30]</button>
<video id="vid" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" controls></video>

Related

JavaScript play audio segment

I need to call a script and specify 3 parameters, audio file ID, audio start time, audio end time (optional).
With zero prior JS knowledge, I'm unable to get this script I stitched together to work flawlessly. The main bug now is that if EventListener is active and a segment is still playing and the user clicks on another segment, it should cancel active EventListener and assign a new one if end time is specified.
Any help would be great.
<!DOCTYPE html>
<script>
function audio_play(fileID, sTime, eTime){
var audio = document.getElementById(fileID);
var segmentEnd;
audio.pause();
audio.currentTime = 0;
audio.addEventListener('timeupdate', function (){
if (segmentEnd && (audio.currentTime >= segmentEnd)) {
audio.pause();
segmentEnd = 0;
audio.currentTime = 0;
}
console.log(audio.currentTime);
}, false);
audio.currentTime = sTime;
segmentEnd = eTime;
audio.play();
}
</script>
<body>
<html lang="en">
<audio id="id1" src="1.mp3" controls preload></audio>
<audio id="id2" src="2.mp3" controls preload></audio>
<p>File 1 / Segment (15-20)</p>
<p>File 1 / Segment (60-65)</p>
<p>File 1 / Segment (20 ...)</p>
<br>
<p>File 2 / Segment (15-20)</p>
<p>File 2 / Segment (30-35)</p>
<p>File 2 / Segment (40 ...)</p>
</body>
</html>
I tried to add temporary variable to interrupt EventListener. It didn't work.

Any way to get a currentTime value prior to the seek on HTMLMediaElement?

Let's say our app is using the default video player on Safari.
When a user is playing a video and then attempts to move to a different position of the video using the seek bar, it seems like pause event is fired first, and then we'll get seeking and seeked events fired.
I am wondering if we can get the currentTime value prior to the seek. For instance, assuming that a user jumps from t = 7 to t = 42 using the seek bar, I want to get 7 as the currentTime value somehow.
I expected that we could get this value by accessing currentTime property inside the pause event handler that is invoked right after the seek like the following:
const video = document.querySelector('#myvideo');
video.addEventListener('pause', () => {
// I expected that the `video.currentTime` here has the "previous" position,
// but it already points to the new position
console.log(video.currentTime);
});
but unfortunately the currentValue was already updated to the new value at that point.
Is there any good way to achieve it?
(EDIT)
Caching currentTime manually doesn't help, because apparently a timeupdate event fires before a pause event. More specifically, taking the following code as an example, when a user attempts to jump to another position, cache and currentTime printed within the pause handler seem always identical.
<!DOCTYPE html>
<html>
<body>
<video
id="myvideo"
width="640"
height="360"
controls
src="video.mp4"
></video>
</body>
<script>
const video = document.querySelector("#myvideo");
let cache = 0;
video.addEventListener("timeupdate", () => {
cache = video.currentTime;
});
video.addEventListener("pause", () => {
console.log({ cache, currentTime: video.currentTime });
});
</script>
</html>
I think #Kaiido means this when saying "Cache two values".
Code is untested (but looks better than being kept in comments section)
<script>
const video = document.querySelector("#myvideo");
let cache = 0;
let cache_prev = 0;
video.addEventListener("timeupdate", () => {
cache_prev = cache; //# save last known value
cache = video.currentTime; //# before updating to new currentTime
});
video.addEventListener("pause", () => {
console.log("cache_prev : " + cache_prev );
console.log("cache : " + cache );
console.log("currentTime : " + video.currentTime );
});
</script>

How to select the time of a video in html?

I am creating a website with vue.js where a user can select the time when something pops up in a video. The problem is that I cannot select the time of the video.
For example:
The user wants an image to popup at 5:00 in his video. How can I let the user select the time and let the image display at the right time?
Here is how to do it with raw javascript. Just adopt it to your code.
<!DOCTYPE html>
<html>
<body>
<video width="200" controls>
<source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support HTML video.
</video>
<br>
<big><span id="popup">Here will be popup</span></big>
<br>
<label for="time_to_popup">do popup after (secs): </label>
<input type="text" id="time_to_popup" value="2" name="time_to_popup">
<p>
Video courtesy of
Big Buck Bunny.
</p>
<script>
var intervalID = null;
// get video object
const video = document.querySelector('video');
// if play is started set interval to check play time
// and do popup if playing time bigger than popup trigger time
video.addEventListener('play', (event) => {
intervalID = setInterval(function() {
if (video.currentTime > parseInt(document.getElementById("time_to_popup").value)) {
document.getElementById("popup").textContent = "BOOOOOOM !!!!!";
}
}, 1000);
});
// remove interval and revert popup message to normal text
// if video is paused
video.addEventListener('pause', (event) => {
document.getElementById("popup").textContent = "Here will be popup";
clearInterval(intervalID);
});
</script>
</body>
</html>
In short:
html5 video object has currentTime (video.currentTime) attribute that can be used to get current time. Also you can use paused (video.paused) attribute to check is video playing.

How to make a short beep in javascript that can be called *repeatedly* on a page?

This is like the question at:
Sound effects in JavaScript / HTML5
but I'm just seeking a specific answer to the issue of repeatability.
The above question and other similar ones have helpful answers to use the following javascript:
function beep1()
{ var snd = new Audio("file.wav"); // buffers automatically when created
snd.play();
}
or even more self-contained, you can now include a wav in-line, such as:
function beep2()
{ var snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
snd.play();
}
When I tried these examples, I could only get the sound to play once on my computer. I noticed this was a common complaint in multiple questions, but never saw an answer to it.
The closest thing to an answer was in the referenced question in which #Kornel stated:
To play same sound multiple times, create multiple instances of the Audio object.
You could also set snd.currentTime=0 on the object after it finishes playing.
If this is the key to my puzzle, I don't quite understand it. (I don't know how to destroy / release an audio object.) Can someone show me exactly how to get a button to keep replaying my sound every time it is clicked, either using one of the suggestions of #Kornel or some other way?
Put the sound references outside of the function. Otherwise, each time you call the function, a new sound object is created.
var snd1 = new Audio("file.mp3");
var snd2 = new Audio("data:audio/mpeg;base64,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wZ0G7jqlt/OcDIKX+/1NblSX+VKfQfP8xuJJGk7////rf////+PgXTv///1JThJJQainmySAB6imUyuVbVttUo7T4Csa821OuF88f62+CZHFnGf///mQgYIEO0SMF2NVy9NxYTdlqJ8AuS4zr//SJoTUJ+CaKKTcZvosrUPo8W/MUv0f033E9E/QpN6P///v/////WRR2mwUAYUABjabRu1vrOLKAF0kIdHjnEx/iNWo7jGn1////mApxNTJQQOU1Het/NoUFTMQs6Vja///THaGIl/0fojl8mjd/Jo8W+ZfpNpCajsz7////6kn/////WRRgDz//LD1KSTDjKOciSAKxdLx5S31uYqKIWj/+5JECgAC8V5M6g9rdFyr6Vo9rW6KtHcr5DEJQRkSpLRklSigvVc4QpmyPe9H3zHR1/in9P/8VNCMJOzYUDyVjfwHP0ZgiZt/3/+9EBnDKbegdUrckhgntHaQ9vX/X/9A/////+r/////mJ3/9ItRcoVRogAcmV9N8z0pvES8QQsKoMGXEymPQyWm6E4HQLqgpv/CZJAtYXQSwoF8e6SB56zABEoW+qgZjJAZovGr0Gl5/OjFKL3JwnaX9v7/X8y1f/////////49WAzMzEYYMZLq6CUANIqbDX7lisBIdraAEPwShTRc9WZ2vAqBc4NQ9GrUNaw0Czcrte0g1NEoiU8NFjx4NFh54FSwlOlgaCp0S3hqo8SLOh3/63f7P/KgKJxxhgGSnAFMCnIogwU5JoqBIDAuBIiNLETyFmiImtYiDTSlb8ziIFYSFv/QPC38zyxEOuPeVGHQ77r/1u/+kq49//6g4gjoVQSUMYQUSAP8PwRcZIyh2kCI2OwkZICZmaZxgnsNY8DmSCWX0idhtz3VTJSqErTSB//1X7TTTVVV//uSZB2P8xwRJ4HvYcItQlWBACM4AAABpAAAACAAADSAAAAEVf/+qCE000VVVVU0002//+qqqqummmmr///qqqppppoqqqqppppoqqATkEjIyIxBlBA5KwUEDBBwkFhYWFhUVFfiqhYWFhcVFRUVFv/Ff/xUVFRYWFpMQU1FMy45OS41qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==");
function beep1() {
snd1.play();
}
function beep2() {
snd2.play();
}
beep1();
setInterval(beep2, 300);
We can create audio waveforms with the web audio api.
The following example shows a bip, made of two tones, one is at 233hz for 100ms with a gain of 10DB, the second is at 603Hz with a duration of 200ms, with 3DB of gain.
Both sounds are in a loop of 1500ms, with the help of setInterval.
This is a minimal example, it can't be stopped! (As asked!)
// gain, frequency, duration
let a = new AudioContext()
function k(w,x,y){
console.log("Gain:"+w, "Hz:"+x, "ms:"+y)
v = a.createOscillator()
u = a.createGain()
v.connect(u)
v.frequency.value = x
v.type = "square"
u.connect(a.destination)
u.gain.value = w * 0.01
v.start(a.currentTime)
v.stop(a.currentTime + y *0.001)
}
setInterval(function(){ k(10,233,100); k(3,603,200)}, 1500)
There is ways to create much more complex 8bits songs in few lines, with differents loops of many duration and tones:
let a = new AudioContext()
function k(w,x,y){
console.log("Gain:"+w, "Hz:"+x, "ms:"+y)
let v = a.createOscillator()
let u = a.createGain()
v.connect(u)
v.frequency.value = x
v.type = "square"
u.connect(a.destination)
u.gain.value = w * 0.01
v.start(a.currentTime)
v.stop(a.currentTime + y *0.001)
}
setInterval(function(){ k(10,233,100); k(3,603,200)}, 1000)
setInterval(function(){ k(8,1646,100); k(8,1444,100) }, 500)
setInterval(function(){ k(8,728,100); k(8,728,100) }, 3000)
setInterval(function(){ k(8,728,100); k(8,728,100) }, 3000)
setInterval(function(){ k(8,364,100); k(8,364,100) }, 6000)
setInterval(function(){ k(8,364,100); k(8,157,200) }, 12000)
We can as well set the values in an array, and loop trough it.
With for, for..in, while, do..while, much more complex, but to create patterns, arpeggios, etc.
Someone, one day will enjoy this ;)
What about using the new Audio API. (No Microsoft support!)
var audioContext = AudioContext && new AudioContext();
function beep(amp, freq, ms){//amp:0..100, freq in Hz, ms
if (!audioContext) return;
var osc = audioContext.createOscillator();
var gain = audioContext.createGain();
osc.connect(gain);
osc.value = freq;
gain.connect(audioContext.destination);
gain.gain.value = amp/100;
osc.start(audioContext.currentTime);
osc.stop(audioContext.currentTime+ms/1000);
}
Didn't you try this
Just the HTML5 thing
<audio controls loop>
<source src="horse.ogg" type="audio/ogg">
<source src="horse.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
I needed an "alert" for a web app that will be used predominately on a mobile device. The new autoplay policy https://developers.google.com/web/updates/2017/09/autoplay-policy-changes, was giving me a problem so I did this...
Top of html code to play the "alert" you need a button so the user interacts with the page and authorizes future use of audio.
<p align="center" id="snd_btn"><button id="allow_alert" class="btn btn-danger" onclick="play_sound();"> Allow Alert </button></p>
Add'l html...................
then later in the script section I have ....
<script>
function play_sound(){
snd.play(); // plays the "1-second-of-silence.mp3"
$("#snd_btn").hide(); // this hides the prompt "Allow Alert"
}
snd = new Audio("sound/1-second-of-silence.mp3");
snd2 = new Audio("sound/PHONERNG.WAV");
the as part of an online event (map coordinates update) this is included in the ajax success function ...
success: function(data){
if(data['badge'] > 0){
$("#vt_badge").html(data['badge']);
snd2.play(); //Plays the "alert" sound
}
}
'''''
</script>
Th "allow alert" button is only there on page load so the user interacts with it, and it plays a sound, "1-second-of-silence.mp3". That satisfies the player's requirement for page interaction, now the actual alert, "PHONERNG.WAV" plays automatically as required.
MrFitz
This works better for me.
Just follow the snippet below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Press the Button</h1>
<button onclick="play()">Press Here!</button>
<script>
function play() {
var audio = new Audio(
'https://media.geeksforgeeks.org/wp-content/uploads/20190531135120/beep.mp3');
audio.play();
}
</script>
</body>
</html>

HTML5 Video - How to do a seamless play and/or loop of several videos?

How can I reliably play several videos one after another seamlessly? As there is a small pause or flicker between playing 2 videos.
In my particular example I have 3 videos. I need to play all 3 of them seamlessly one after another, and I also need to loop middle video an arbitrary number of times (say 2 or 3). All of that needs to happen seamlessly and consistently across different browsers.
I've been trying everything under the moon, from starting video playback on video end, to using several video tags and hiding and replacing them, I even tried to implement this in Flash, but alas nothing works, and the same problem happens in current Flash as well.
I've seen this (or similar) question asked many times but I haven't seen a reliable solution yet.
Does anyone know a solution to this?
After trying various things I have finally been able to create what seems to be a working solution. I haven't tested this on older browsers or other OSes, but this works on latest versions of Chrome, IE, Firefox and Opera. (Although some more feedback of whether this works on other systems would be appreciated)
The idea is to have all 3 videos output frames to HTML5 canvas. The original videos are hidden and preloaded in advance to avoid pause between loading.
Here is the code:
var playCounter = 0;
var clipArray = [];
var $video1 = $("#video1");
var $video2 = $("#video2");
var $video3 = $("#video3");
$video1.attr("src", "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4");
$video2.attr("src", "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4");
$video3.attr("src", "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4");
var timerID;
var $canvas = $("#myCanvas");
var ctx = $canvas[0].getContext("2d");
function stopTimer() {
window.clearInterval(timerID);
}
$('#startPlayback').click(function() {
stopTimer();
playCounter = $('#playbackNum').val();
clipArray = [];
// addd element to the end of the array
clipArray.push(1);
for (var i = 0; i < playCounter; i++) {
clipArray.push(2);
}
clipArray.push(3);
$video2[0].load();
$video3[0].load();
$video1[0].play();
});
function drawImage(video) {
//last 2 params are video width and height
ctx.drawImage(video, 0, 0, 640, 360);
}
// copy the 1st video frame to canvas as soon as it is loaded
$video1.one("loadeddata", function() {
drawImage($video1[0]);
});
// copy video frame to canvas every 30 milliseconds
$video1.on("play", function() {
timerID = window.setInterval(function() {
drawImage($video1[0]);
}, 30);
});
$video2.on("play", function() {
timerID = window.setInterval(function() {
drawImage($video2[0]);
}, 30);
});
$video3.on("play", function() {
timerID = window.setInterval(function() {
drawImage($video3[0]);
}, 30);
});
function onVideoEnd() {
//stop copying frames to canvas for the current video element
stopTimer();
// remove 1st element of the array
clipArray.shift();
//IE fix
if (!this.paused) this.pause();
if (clipArray.length > 0) {
if (clipArray[0] === 1) {
$video1[0].play();
}
if (clipArray[0] === 2) {
$video2[0].play();
}
if (clipArray[0] === 3) {
$video3[0].play();
}
} else {
// in case of last video, make sure to load 1st video so that it would start from the 1st frame
$video1[0].load();
}
}
$video1.on("ended", onVideoEnd);
$video2.on("ended", onVideoEnd);
$video3.on("ended", onVideoEnd);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div id="border">
<video id="video1" width="640" height="360" hidden>
<source type="video/mp4">
Your browser does not support playing this Video
</video>
<video id="video2" width="640" height="360" hidden>
<source type="video/mp4">
Your browser does not support playing this Video
</video>
<video id="video3" width="640" height="360" hidden>
<source type="video/mp4">
Your browser does not support playing this Video
</video>
<div>
<canvas id="myCanvas" width="640" height="360"> </canvas>
</div>
<div role="controls">
<div>
<label>
Times the middle video will repeat itself:
</label>
</div>
<div>
<input id="playbackNum" value="1" />
</div>
<p>
<button id="startPlayback">Start</button>
</p>
</div>
</div>
Please note, the code is not very pretty and would benefit from some cleanup and optimization, but at least this should show the way to work around the problem and implement a seamless playback of several videos in HTML5.
Also make sure to include jQuery source file in html file location for the code to work.
I have used VideoJS for some time and it allows seamless video playing.
http://videojs.com
You will be required jQuery for this. There are many other jQuery video players.

Categories

Resources