Pausing HTML Embedded Video - javascript

I'm using this kind of cross-broswer embedding:
<video width="549" height="309" controls poster="video/stills/index_demo_videoScreen.jpg" style="margin-top:20px;">
<source src="video/2014-reel-web.mp4" type="video/mp4">
<source src="video/2014-reel-web.ogg" type="video/ogg">
<embed width="549" height="309" allowfullscreen="true" allowscriptaccess="always" type="application/x-shockwave-flash" src="video/2014-reel-web.swf">
</video>
It's not the "video for everyone" solution, but it is a lot simpler. Whatever it doesn't work on, I don't particularly care.
What I need to know is how can I stop the video from playing when the user navigates away from it (as it will still be on the page, just not visible)?
I have this:
$("video").each(function(index) {
$(this)[0].pause();
});
But that doesn't work if the video has had to fall back to the swf object. Is it even possible to target it and get it to stop playing?
One thing I tried was using jQuery to replace the HTML content of the video tag with nothing (on the theory that I could rebuild the contents, thus resetting things) but even that just silently does nothing.

UPDATE: I got it to work with pure JavaScript (DEMO) but as you said this solution does not apply to older browsers that don't support <video>.
For new browsers add onblur="vpause()" to video element then this:
var test = document.getElementById('video');
test.addEventListener("play", vfocus, false)
test.focus();
function vfocus(){
test.focus();
}
function vpause() {
test.pause();
}
For old browsers:
http://mediaelementjs.com/

Related

Javascript autoplay video (mp4) on Opera browser?

I have made a website which we use on a TV to welcome guests/customers to our business. There's a SQL database which we write their names to be presented on the screen, and there is also a video which is playing in a different frame on the same website.
This all works very well on desktop PC Chrome. But we use the built in browser in the TV (which is a business model used for stuff like this). The browser is Opera and it supports HTML5.
Problem is that after a while, can be 2 hours, can be a day, it will stop playing the video, and just show a black frame.
This is the code:
<source src="video/video1.mp4" type='video/mp4'/>
</video>
<script type='text/javascript'>
video_count =1;
videoPlayer = document.getElementById("video");
function run(){
video_count++;
if (video_count == 3) video_count = 1;
var nextVideo = "video/video"+video_count+".mp4";
videoPlayer.src = nextVideo;
videoPlayer.play();
videoPlayer.loop();
};
</script>
This will play the files named video1.mp4 and video2.mp4... etc. Right now there is only one file in this folder called video1.mp4, and it will autoplay and it will loop. But it will fail to autoplay after a while and just show a black frame.
Any ideas?
Thanks!
I'd recommend looking into video events with javascript in this case if you're starting to see bugs.
For example (from Detect when an HTML5 video finishes post) you could start playing your next video like this:
<script type='text/javascript'>
document.getElementById('myVideo').addEventListener('ended',myHandler,false);
function myHandler(e) {
// What you want to do after the event
}
</script>
You could simply move on to the next video, or seek back to 0 on its timeline and play it again. The other option if you're wanting to loop 1 video, you'd be better using the loop option in your <video> tag:
<video loop>
<source src="video/video1.mp4" type="video/mp4">
</video>

HTML5 Video to play after AJAX page load

I am struggling to get an HTML5 video to play when arriving at the page via an AJAX request.
If you refresh the page, or land directly on the page, it works fine. But when navigating to the page via AJAX it does not play.
The code is:
<video id="video" autoplay="autoplay" loop="loop" muted="muted" poster="http://localhost/wp-content/themes/studioindigo/videos/contactbackground.jpg">
<source src="http://localhost/wp-content/themes/studioindigo/videos/contactbackground.mp4" type="video/mp4">
<source src="http://localhost/wp-content/themes/studioindigo/videos/contactbackground.webmhd.webm" type="video/webm">
<img src="http://localhost/wp-content/themes/studioindigo/videos/contactbackground.jpg" alt="your browser does not support html5 video">
</video>
I have tried firing the following code on success of AJAX page load:
video = document.getElementById('video');
video.load();
video.addEventListener('loadeddata', function() {
video.play();
}, false);
And also simply:
video = document.getElementById('video');
video.play();
I have also tried using plugins such as video.js, but to no avail.
I can't help but think I am missing something really simple. Surely if the video is on the page and has autoplay set, then it should just play regardless of whether you arrive at the page via AJAX or directly?
The AJAX request for the page only updates the #main element (which the video is inside) and the does history.pushState - could that be anything to do with it? It doesn't seem likely...
For anyone struggling with the same issue, I found that after the ajax call the video had the property 'paused: true' even thought autoplay was set and I was calling video.play() on 'loadeddata'.
The solution was to trigger video.play() when pause is detected. I also found that it worked smoother not having the 'autoplay' attribute on the video and became jerky after multiple initialisations.
DOM:
<video id="video" loop muted>
<source src="video.mp4" type="video/mp4">
<source src="video.webm" type="video/webm">
</video>
JS:
video = jQuery('#video').get()[0];
video.addEventListener('loadeddata', function() {
video.play();
});
video.addEventListener('pause', function() {
video.play();
});
Also, for anyone wondering why I might want this ability, it is for a video playing on the background of a webpage, hence no need for user to play/pause it.
you can call video.play() before your ajax calling.
like
html
<video id="video">...</video>
JS
function play() {
$("#video")[0].play(); // call play here !!!
$.ajax(
"your url",
{your data},
function() {
$("#video")[0].play(); // usually we call play() here, but it will be pause beccause it can not be play if not in click or touch event sync
....
}
);
}
Your video tag has no ID. What if you had two <video> tags? You want:
<video id="blah"...
and then:
video = document.getElementById('blah');
Potentially it's a syntax error, because you seem to have some PHP leaking into the HTML in the form of '; ?> at the end of the poster and src attributes.
It seems like these answers do not work anymore. I tried the accepted one, and it didn't work.
It looks like Chrome can't find the video object and it stands as undefined.
You can do something else. Quite simple. You use the Global Event Handlers .ajaxSuccess as a marker for that the request has been handled and the video can now play.
In that way you are sure that the video object exist. And for Chrome you do a little if statement.
video = jQuery('#video').get()[0];
jQuery( document ).ajaxSuccess(function( event, xhr, settings ) {
if( video ) {
video.play();
} else {
// Chrome can't find the video object and throws a 'undefined'
// Therefore you have to activate the video manually
jQuery("#videoID")[0].play();
}
});

Play full HTML5 video and then loop a section of it

I'm trying to play an 8.6 second video once completely, and then loop a small section of the video infinitely, to keep the illusion of a never-ending video. So far I've looked into the media fragments URI, and the ended event of the video. Setting the currentTime attribute in the ended event listener works, but it makes the video "blink".
At present, I'm using a timeupdate event listener to change the time when the video is approaching the end [shown below]
elem.addEventListener('timeupdate', function () {
if (elem.currentTime >= 8.5) {
elem.currentTime = 5;
elem.play();
}
}, false);
JSFiddle here
This works as well, but the video pauses visibly before restarting at 5 seconds. Is there a smoother way of playing the video once and then looping a segment of it?
Your code is fine, the problem is with your MP4 file! Try using a much smaller video like this one ( http://www.w3schools.com/tags/movie.mp4 ) to confirm the issue is not with your code.
So how can you achieve the same result but with large videos files?
You will need two video files:
video1 is the main video
video2 is the looping video
Remember: HTML5 video has no problem playing and looping large video files so we will use this method to play the videos.
In the example below we will play the first video and when it finishes we will execute a function to hide video1 and then show/play video2. (Video 2 is already set to loop)
Don't forget to load JQuery in your head otherwise this will not work.
<video id="video1" width="1080" height="568" poster="movie.png" autoplay onended="run()">
<source src="movie.webm" type="video/webm">
<source src="movie.ogg" type="video/ogg">
<source src="movie.mp4" type="video/mp4">
<object data="movie.mp4" width="1080" height="568">
<embed width="1080" height="568" src="movie.swf">
</object>
Optional test to be displayed if the browser doesn't support the video tag (HTML 5)
</video>
<video id="video2" width="1080" height="568" poster="loop.png" loop>
<source src="loop.webm" type="video/webm">
<source src="loop.ogg" type="video/ogg">
<source src="loop.mp4" type="video/mp4">
<object data="loop.mp4" width="1080" height="568">
<embed width="1080" height="568" src="loop.swf">
</object>
Optional test to be displayed if the browser doesn't support the video tag (HTML 5)
</video>
<script>
$( "#video2" ).hide();
function run(){
$( "#video1" ).hide();
$( "#video2" ).show();
document.getElementById("video2").play();
};
</script>
Try the following, to 'rewind' it as soon as it ends:
vidElem.addEventListener("ended", function () {
vidElem.currentTime = 2.5;
vidElem.play();
}, false);
Updated fiddle: http://jsfiddle.net/Lt4n7/1/
I just had to deal with the same problem and noticed the same issues with flickering. Here was my solution:
Get 2 videos (or sets of videos) - one for the non-looped section, the other for the looped section
Create 2 video elements
set the looping element to 'display:none'
Then just capture the ended event and swap display status (example uses jquery but you could use 'style.display="none/block"' just as easily:
VideoPlayer1 = document.getElementById('video1');
VideoPlayer2 = document.getElementById('video2');
VideoPlayer1.addEventListener('ended', videoLooper, false);
function videoLooper()
{
VideoPlayer2.play();
$(VideoPlayer2).show();
$(VideoPlayer1).hide();
}
You can't solve this issue in javascript. That delay you see depends on the video compression and the hardware.
To start playing at a time that is not 0, the video decoder has to go back and find a key frame and then build the current frame by reading everything between the last key frame and your chosen time.
I'm not an expert in video compression, but maybe there is a way to pick these key frames and place them exactly where you need them. I don't think it will be easy and smooth, though.
If you're looking for an easier solution, use #Random's, but it uses two <video> tags to work around this limit.
var iterations = 1;
var flag = false;
document.getElementById('iteration').innerText = iterations;
var myVideo = document.getElementById('video-background');
myVideo.addEventListener('ended', function() {
alert('end');
if (iterations < 2) {
this.currentTime = 0;
this.play();
iterations++;
document.getElementById('iteration').innerText = iterations;
} else {
flag = true;
this.play();
}
}, false);
myVideo.addEventListener('timeupdate', function() {
if (flag == true) {
console.log(this.currentTime);
if (this.currentTime > 5.5) {
console.log(this.currentTime);
this.pause();
}
}
}, false);
<div>Iteration: <span id="iteration"></span></div>
<video id="video-background" autoplay="" muted="" controls>
<source src="https://res.cloudinary.com/video/upload/ac_none,q_60/bgvid.mp4" type="video/mp4">
</video>
<div>Iteration: <span id="iteration"></span></div>
// Please note that loop attribute should not be there in video element in order for the 'ended' event to work in ie and firefox

Dynamically using the first frame as poster in HTML5 video?

I'm wondering if there's any straightforward way to achieve this effect, without needing backend code to extract a frame, save it as a jpg and database it somewhere.
An effect whereby the first frame of the video just shows up as the poster when the video loads would be so helpful (it would only work if the browser can play back the video obviously, which might be a little different from how poster traditionally works, but that is not a concern.
Did you try the following?
just append time in seconds #t={seconds} to source URL:
<video controls width="360">
<source src="https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_1MB.mp4#t=0.1" type="video/mp4" />
</video>
I have chosen a fraction of second (0.1) to keep number of frames small, because I have the suspect that if you put 1 second, it would "preload" the first 1 second of video (i.e. 24 frames or more ....). Just in case ...
Works fine on Chrome and Firefox on desktop :)
Works not on Android mobile, though :(
I did not test on iOS, iPhone, IE yet ??
Edit May 2021:
I realized that many modern browsers now show automatically a poster of first frame.
Seems like they heard us :-)
To make it simple you can just add preload="metadata" to your video tag and the second of the first frame #t=0.5 to your video source:
<video width="400" controls="controls" preload="metadata">
<source src="https://www.w3schools.com/html/mov_bbb.mp4#t=0.5" type="video/mp4">
</video>
Best of luck!
There is a Popcorn.js plugin called Popcorn.capture which will allow you to create posters from any frame of your HTML5 video.
There is a limitation that is imposed by the browser that prohibits reading pixel data of resources requested across domains (using the canvas API to record the current value of a frame). The source video must be hosted on the same domain as the script and html page that is requesting it for this approach to work.
The code to create poster using this plugin is quite simple:
// This block of code must be run _after_ the DOM is ready
// This will capture the frame at the 10th second and create a poster
var video = Popcorn( "#video-id" );
// Once the video has loaded into memory, we can capture the poster
video.listen( "canplayall", function() {
this.currentTime( 10 ).capture();
});
I recently did this for a recent project that works on desktop and mobile. The trick was getting it to work on iPhone.
Setting preload=metadata works on desktop and android devices but not iPhone.
For iPhones I had to set it to autoplay so the poster image automatically appears on initial load. iPhones will prevent the video from auto playing, but the poster image appears as the result.
I had to do a check for iPhone using Pavan's answer found here. Detect iPhone Browser. Then use the proper video tag with or without autoplay depending on the device.
var agent = navigator.userAgent;
var isIphone = ((agent.indexOf('iPhone') != -1) || (agent.indexOf('iPod') != -1)) ;
$videoTag = "";
if(isIphone()) {
$videoTag = '<video controls autoplay preload="metadata">';
} else {
$videoTag = '<video controls preload="metadata">';
}
You can set preload='auto' on the video element to load the first frame of the video automatically.
Solution for #2, #3 etc. frames. We need attach disposable handler .one() for resetting default frame.
<video width="300" height="150" id='my-video'>
<source src="testvideo.mp4#t=2" type="video/mp4" />
</video>
$(function () {
let videoJs = videojs('my-video');
videoJs.one('play', function () {
this.currentTime(0);
});
});
I found a great way to dynamically add poster to a video!
To show the desired frame from video (in my case it's the frame at 1.75 seconds) - add preload="metadata" to the video element and #t=1.75 to the end of source URL.
Add eventListener to the video element that will listen for play event only once.
Once the event is emitted reset the video time.
<video width="100%" controls="controls" preload="metadata" id="myVid">
<source src="path/to/your/video#t=1.75" type="video/mp4">
</video>
<script>
var el = document.getElementById('myVid');
el.addEventListener('play', () => {
el.currentTime = 0;
}, { once: true });
</script>

changing source on html5 video tag

I'm trying to build a video player that works everywhere. so far I'd be going with:
<video>
<source src="video.mp4"></source>
<source src="video.ogv"></source>
<object data="flowplayer.swf" type="application/x-shockwave-flash">
<param name="movie" value="flowplayer.swf" />
<param name="flashvars" value='config={"clip":"video.mp4"}' />
</object>
</video>
(as seen on several sites, for example video for everybody)
so far, so good.
But now I also want some kind of playlist/menu along with the video player, from which I can select other videos. Those should be opened within my player right away. So I will have to "dynamically change the source of the video" (as seen on dev.opera.com/articles/everything-you-need-to-know-html5-video-audio/ - section "Let's look at another movie") with Javascript. Let's forget about the Flash player (and thus IE) part for the time being, I will try to deal with that later.
So my JS to change the <source> tags should be something like:
<script>
function loadAnotherVideo() {
var video = document.getElementsByTagName('video')[0];
var sources = video.getElementsByTagName('source');
sources[0].src = 'video2.mp4';
sources[1].src = 'video2.ogv';
video.load();
}
</script>
The problem is, this doesn't work in all browsers. Namely, in Firefox there is a nice page where you can observe the problem I'm having: http://www.w3.org/2010/05/video/mediaevents.html
As soon as I trigger the load() method (in Firefox, mind you), the video player dies.
Now I have found out that when I don't use multiple <source> tags, but instead just one src attribute within the <video> tag, the whole thing does work in Firefox.
So my plan is to just use that src attribute and determine the appropriate file using the canPlayType() function.
Am I doing it wrong somehow or complicating things?
I hated all these answers because they were too short or relied on other frameworks.
Here is "one" vanilla JS way of doing this, working in Chrome, please test in other browsers:
var video = document.getElementById('video');
var source = document.createElement('source');
source.setAttribute('src', 'http://techslides.com/demos/sample-videos/small.mp4');
source.setAttribute('type', 'video/mp4');
video.appendChild(source);
video.play();
console.log({
src: source.getAttribute('src'),
type: source.getAttribute('type'),
});
setTimeout(function() {
video.pause();
source.setAttribute('src', 'http://techslides.com/demos/sample-videos/small.webm');
source.setAttribute('type', 'video/webm');
video.load();
video.play();
console.log({
src: source.getAttribute('src'),
type: source.getAttribute('type'),
});
}, 3000);
<video id="video" width="320" height="240"></video>
External Link
Modernizr worked like a charm for me.
What I did is that I didn't use <source>. Somehow this screwed things up, since the video only worked the first time load() was called. Instead I used the source attribute inside the video tag -> <video src="blabla.webm" /> and used Modernizr to determine what format the browser supported.
<script>
var v = new Array();
v[0] = [
"videos/video1.webmvp8.webm",
"videos/video1.theora.ogv",
"videos/video1.mp4video.mp4"
];
v[1] = [
"videos/video2.webmvp8.webm",
"videos/video2.theora.ogv",
"videos/video2.mp4video.mp4"
];
v[2] = [
"videos/video3.webmvp8.webm",
"videos/video3.theora.ogv",
"videos/video3.mp4video.mp4"
];
function changeVid(n){
var video = document.getElementById('video');
if(Modernizr.video && Modernizr.video.webm) {
video.setAttribute("src", v[n][0]);
} else if(Modernizr.video && Modernizr.video.ogg) {
video.setAttribute("src", v[n][1]);
} else if(Modernizr.video && Modernizr.video.h264) {
video.setAttribute("src", v[n][2]);
}
video.load();
}
</script>
Hopefully this will help you :)
If you don't want to use Modernizr , you can always use CanPlayType().
Your original plan sounds fine to me. You'll probably find more browser quirks dealing with dynamically managing the <source> elements, as indicated here by the W3 spec note:
Dynamically modifying a source element and its attribute when the element is already inserted in a video or audio element will have no effect. To change what is playing, just use the src attribute on the media element directly, possibly making use of the canPlayType() method to pick from amongst available resources. Generally, manipulating source elements manually after the document has been parsed is an unncessarily[sic] complicated approach.
http://dev.w3.org/html5/spec/Overview.html#the-source-element
I solved this with this simple method
function changeSource(url) {
var video = document.getElementById('video');
video.src = url;
video.play();
}
Instead of getting the same video player to load new files, why not erase the entire <video> element and recreate it. Most browsers will automatically load it if the src's are correct.
Example (using Prototype):
var vid = new Element('video', { 'autoplay': 'autoplay', 'controls': 'controls' });
var src = new Element('source', { 'src': 'video.ogg', 'type': 'video/ogg' });
vid.update(src);
src.insert({ before: new Element('source', { 'src': 'video.mp4', 'type': 'video/mp4' }) });
$('container_div').update(vid);
According to the spec
Dynamically modifying a source element and its attribute when the
element is already inserted in a video or audio element will have no
effect. To change what is playing, just use the src attribute on the
media element directly, possibly making use of the canPlayType()
method to pick from amongst available resources. Generally,
manipulating source elements manually after the document has been
parsed is an unncessarily complicated approach.
So what you are trying to do is apparently not supposed to work.
Just put a div and update the content...
<script>
function setvideo(src) {
document.getElementById('div_video').innerHTML = '<video autoplay controls id="video_ctrl" style="height: 100px; width: 100px;"><source src="'+src+'" type="video/mp4"></video>';
document.getElementById('video_ctrl').play();
}
</script>
<button onClick="setvideo('video1.mp4');">Video1</button>
<div id="div_video"> </div>
Yaur: Although what you have copied and pasted is good advice, this does not mean that it is impossible to change the source element of an HTML5 video element elegantly, even in IE9 (or IE8 for that matter).(This solution does NOT involve replacing the entire video element, as it is bad coding practice).
A complete solution to changing/switching videos in HTML5 video tags via javascript can be found here and is tested in all HTML5 browser (Firefox, Chrome, Safari, IE9, etc).
If this helps, or if you're having trouble, please let me know.
This is my solution:
<video id="playVideo" width="680" height="400" controls="controls">
<source id="sourceVideo" src="{{video.videoHigh}}" type="video/mp4">
</video>
<br />
<button class="btn btn-warning" id="{{video.videoHigh}}" onclick="changeSource(this)">HD</button>
<button class="btn btn-warning" id="{{video.videoLow}}" onclick="changeSource(this)">Regular</button>
<script type="text/javascript">
var getVideo = document.getElementById("playVideo");
var getSource = document.getElementById("sourceVideo");
function changeSource(vid) {
var geturl = vid.id;
getSource .setAttribute("src", geturl);
getVideo .load()
getVideo .play();
getVideo .volume = 0.5;
}
</script>
I have a similar web app and am not facing that sort of problem at all. What i do is something like this:
var sources = new Array();
sources[0] = /path/to/file.mp4
sources[1] = /path/to/another/file.ogg
etc..
then when i want to change the sources i have a function that does something like this:
this.loadTrack = function(track){
var mediaSource = document.getElementsByTagName('source')[0];
mediaSource.src = sources[track];
var player = document.getElementsByTagName('video')[0];
player.load();
}
I do this so that the user can make their way through a playlist, but you could check for userAgent and then load the appropriate file that way. I tried using multiple source tags like everyone on the internet suggested, but i found it much cleaner, and much more reliable to manipulate the src attribute of a single source tag. The code above was written from memory, so i may have glossed over some of hte details, but the general idea is to dynamically change the src attribute of the source tag using javascript, when appropriate.
Another way you can do in Jquery.
HTML
<video id="videoclip" controls="controls" poster="" title="Video title">
<source id="mp4video" src="video/bigbunny.mp4" type="video/mp4" />
</video>
<div class="list-item">
<ul>
<li class="item" data-video = "video/bigbunny.mp4">Big Bunny.</li>
</ul>
</div>
Jquery
$(".list-item").find(".item").on("click", function() {
let videoData = $(this).data("video");
let videoSource = $("#videoclip").find("#mp4video");
videoSource.attr("src", videoData);
let autoplayVideo = $("#videoclip").get(0);
autoplayVideo.load();
autoplayVideo.play();
});
I come with this to change video source dynamically. "canplay" event sometime doesn't fire in Firefox so i have added "loadedmetadata". Also i pause previous video if there is one...
var loadVideo = function(movieUrl) {
console.log('loadVideo()');
$videoLoading.show();
var isReady = function (event) {
console.log('video.isReady(event)', event.type);
video.removeEventListener('canplay', isReady);
video.removeEventListener('loadedmetadata', isReady);
$videoLoading.hide();
video.currentTime = 0;
video.play();
},
whenPaused = function() {
console.log('video.whenPaused()');
video.removeEventListener('pause', whenPaused);
video.addEventListener('canplay', isReady, false);
video.addEventListener('loadedmetadata', isReady, false); // Sometimes Firefox don't trigger "canplay" event...
video.src = movieUrl; // Change actual source
};
if (video.src && !video.paused) {
video.addEventListener('pause', whenPaused, false);
video.pause();
}
else whenPaused();
};
Using the <source /> tags proved difficult for me in Chrome 14.0.835.202 specifically, although it worked fine for me in FireFox. (This could be my lack of knowledge, but I thought an alternate solution might be useful anyway.) So, I ended up just using a <video /> tag and setting the src attribute right on the video tag itself. The canPlayVideo('<mime type>') function was used to determine whether or not the specific browser could play the input video. The following works in FireFox and Chrome.
Incidently, both FireFox and Chrome are playing the "ogg" format, although Chrome recommends "webm". I put the check for browser support of "ogg" first only because other posts have mentioned that FireFox prefers the ogg source first (i.e. <source src="..." type="video/ogg"/> ). But, I haven't tested (and highly doubt) whether or not it the order in the code makes any difference at all when setting the "src" on the video tag.
HTML
<body onload="setupVideo();">
<video id="media" controls="true" preload="auto" src="">
</video>
</body>
JavaScript
function setupVideo() {
// You will probably get your video name differently
var videoName = "http://video-js.zencoder.com/oceans-clip.mp4";
// Get all of the uri's we support
var indexOfExtension = videoName.lastIndexOf(".");
//window.alert("found index of extension " + indexOfExtension);
var extension = videoName.substr(indexOfExtension, videoName.length - indexOfExtension);
//window.alert("extension is " + extension);
var ogguri = encodeURI(videoName.replace(extension, ".ogv"));
var webmuri = encodeURI(videoName.replace(extension, ".webm"));
var mp4uri = encodeURI(videoName.replace(extension, ".mp4"));
//window.alert(" URI is " + webmuri);
// Get the video element
var v = document.getElementById("media");
window.alert(" media is " + v);
// Test for support
if (v.canPlayType("video/ogg")) {
v.setAttribute("src", ogguri);
//window.alert("can play ogg");
}
else if (v.canPlayType("video/webm")) {
v.setAttribute("src", webmuri);
//window.alert("can play webm");
}
else if (v.canPlayType("video/mp4")) {
v.setAttribute("src", mp4uri);
//window.alert("can play mp4");
}
else {
window.alert("Can't play anything");
}
v.load();
v.play();
}
I have been researching this for quite a while and I am trying to do the same thing, so hopefully this will help someone else. I have been using crossbrowsertesting.com and literally testing this in almost every browser known to man. The solution I've got currently works in Opera, Chrome, Firefox 3.5+, IE8+, iPhone 3GS, iPhone 4, iPhone 4s, iPhone 5, iPhone 5s, iPad 1+, Android 2.3+, Windows Phone 8.
Dynamically Changing Sources
Dynamically changing the video is very difficult, and if you want a Flash fallback you will have to remove the video from the DOM/page and re-add it so that Flash will update because Flash will not recognize dynamic updates to Flash vars. If you're going to use JavaScript to change it dynamically, I would completely remove all <source> elements and just use canPlayType to set the src in JavaScript and break or return after the first supported video type and don't forget to dynamically update the flash var mp4. Also, some browsers won't register that you changed the source unless you call video.load(). I believe the issue with .load() you were experiencing can be fixed by first calling video.pause(). Removing and adding video elements can slow down the browser because it continues buffering the removed video, but there's a workaround.
Cross-browser Support
As far as the actual cross-browser portion, I arrived at Video For Everybody as well. I already tried the MediaelementJS Wordpress plugin, which turned out to cause a lot more issues than it resolved. I suspect the issues were due to the Wordpress plug-in and not the actually library. I'm trying to find something that works without JavaScript, if possible. So far, what I've come up with is this plain HTML:
<video width="300" height="150" controls="controls" poster="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" class="responsive">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg" />
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4" />
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm" />
<source src="http://alex-watson.net/wp-content/uploads/2014/07/big_buck_bunny.iphone.mp4" type="video/mp4" />
<source src="http://alex-watson.net/wp-content/uploads/2014/07/big_buck_bunny.iphone3g.mp4" type="video/mp4" />
<object type="application/x-shockwave-flash" data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" width="561" height="297">
<param name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" />
<param name="allowFullScreen" value="true" />
<param name="wmode" value="transparent" />
<param name="flashVars" value="config={'playlist':['http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg',{'url':'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4','autoPlay':false}]}" />
<img alt="No Video" src="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" width="561" height="297" title="No video playback capabilities, please download the video below" />
</object>
<strong>Download video:</strong> MP4 format | Ogg format | WebM format
</video>
Important notes:
Ended up putting the ogg as the first <source> because Mac OS Firefox quits trying to play the video if it encounters an MP4 as the first <source>.
The correct MIME types are important .ogv files should be video/ogg, not video/ogv
If you have HD video, the best transcoder I've found for HD quality OGG files is Firefogg
The .iphone.mp4 file is for iPhone 4+ which will only play videos that are MPEG-4 with H.264 Baseline 3 Video and AAC audio. The best transcoder I found for that format is Handbrake, using the iPhone & iPod Touch preset will work on iPhone 4+, but to get iPhone 3GS to work you need to use the iPod preset which has much lower resolution which I added as video.iphone3g.mp4.
In the future we will be able to use a media attribute on the <source> elements to target mobile devices with media queries, but right now the older Apple and Android devices don't support it well enough.
Edit:
I'm still using Video For Everybody but now I've transitioned to using FlowPlayer, to control the Flash fallback, which has an awesome JavaScript API that can be used to control it.
Try moving the OGG source to the top. I've noticed Firefox sometimes gets confused and stops the player when the one it wants to play, OGG, isn't first.
Worth a try.
You shouldn't try to change the src attribute of a source element, according to this spec note .
Dynamically modifying a source element and its attribute when the element is
already inserted in a video or audio element will have no effect. To
change what is playing, just use the src attribute on the media
element directly
So lets say you have:
<audio>
<source src='./first-src'/>
</audio>
To modify the src:
<audio src='./second-src'/>
<source src='./first-src'/>
</audio>
if you already have a loaded video and you try to upload a new one over that one make sure to use the videoRef.load() on the second one, otherwise it wont load.
*videoRef should be the ref of the displayed <video></video> tag
Using JavaScript and jQuery:
<script src="js/jquery.js"></script>
...
<video id="vid" width="1280" height="720" src="v/myvideo01.mp4" controls autoplay></video>
...
function chVid(vid) {
$("#vid").attr("src",vid);
}
...
<div onclick="chVid('v/myvideo02.mp4')">See my video #2!</div>
I ended up making the accepted ansower into a function and improving the resume to keep the time. TLDR
/**
* https://stackoverflow.com/a/18454389/4530300
* This inspired a little function to replace a video source and play the video.
* #param video
* #param source
* #param src
* #param type
*/
function swapSource(video, source, src, type) {
let dur = video.duration;
let t = video.currentTime;
// var video = document.getElementById('video');
// var source = document.createElement('source');
video.pause();
source.setAttribute('src', src);
source.setAttribute('type', type);
video.load();
video.currentTime = t;
// video.appendChild(source);
video.play();
console.log("Updated Sorce: ", {
src: source.getAttribute('src'),
type: source.getAttribute('type'),
});
}

Categories

Resources