Reputation: 2095
As it takes time for the video player to load the mp4 video, does HTML5 support playing a "loading" logo when loading the video ?
Since my asp.net apps is a mobile page, it needs the user to click on the video to play the video (android, iphone not support autoplay). So, I cannot make a "loading" logo as poster, otherwise, the user will be confused about it. I want to display a loading logo when user click play button on iPad.
thanks
Joe
Upvotes: 26
Views: 72871
Reputation: 671
For those who need or prefer to do it with js only without using css: The reason why we are forced to use css background instead of just setting a GIF as the video poster is because Safari will not play the GIF and will show only the first frame of the GIF animation. Yet we want to be able to offer the best UX on every platform by not showing the user a static frame.
The workaround:
Example with a 3 frame animation,
let base64StringForVideoPosterFrame1;
let base64StringForVideoPosterFrame2;
let base64StringForVideoPosterFrame3;
getFile1(); // Start the fetch chain
function getFile1() {
fetch("/images/video_poster_frames/video_poster_frame_1.png").then(response => response.blob()).then(blob => {
const reader = new FileReader();
reader.onload = () => { base64StringForVideoPosterFrame1 = reader.result.split(',')[1]; };
reader.readAsDataURL(blob);
}).catch(error => { console.error('Problem with fetch:', error); }).finally(() => { getFile2(); });
}
function getFile2() {
fetch("/images/video_poster_frames/video_poster_frame_2.png").then(response => response.blob()).then(blob => {
const reader = new FileReader();
reader.onload = () => { base64StringForVideoPosterFrame2 = reader.result.split(',')[1]; };
reader.readAsDataURL(blob);
}).catch(error => { console.error('Problem with fetch:', error); }).finally(() => { getFile3(); });
}
function getFile3() {
fetch("/images/video_poster_frames/video_poster_frame_3.png").then(response => response.blob()).then(blob => {
const reader = new FileReader();
reader.onload = () => { base64StringForVideoPosterFrame3 = reader.result.split(',')[1]; };
reader.readAsDataURL(blob);
}).catch(error => { console.error('Problem with fetch:', error); }).finally(() => { setPosters(); });
}
let posters = [];
function setPosters() {
posters = [
'data:image/png;base64,'+base64StringForVideoPosterFrame1,
'data:image/png;base64,'+base64StringForVideoPosterFrame2,
'data:image/png;base64,'+base64StringForVideoPosterFrame3
];
}
Let's say there are 2 videos in your HTML,
// Note that you can extend this to cover every single video element by using getElementsByTagName("video")
const v1 = document.getElementById('video1');
const v2 = document.getElementById('video2');
// -
let currentPosterIndex = 0;
function changePoster() {
v1.poster = posters[currentPosterIndex];
v2.poster = posters[currentPosterIndex];
currentPosterIndex = (currentPosterIndex + 1) % posters.length; // Loop back to the beginning every time we reach the end
}
// Change poster every 333 milliseconds
setInterval(changePoster, 333);
In your HTML
<video src="myVideo.fileExtension" onplaying="hideControls(this)" onwaiting="showControls(this)" preload="auto" poster="">No video support?</video>
<script type="text/javascript">
//We hide the video control buttons and the playhead when the video is playing (and is enjoyed by the viewer)
function hideControls(event){ event.controls=false; }
//If the video has to pause and wait for data download from the server we let controls be seen whenever the user hovers or taps on the video. This also makes the built-in loading animation of the browser appear e.g. the rotating circular shape and we give it a little delay (like 1 sec) because we don't want the controls to blink and the delayed show-up actually looks nicer.
function showControls(event){ setTimeout(()=>{ event.controls=true; },1000); }
</script>
To make it even better you could use ontimeupdate
instead of onplaying
which would fire continuously.
Adjust delay times to suit your needs.
Note: If necessary check whether you need playsinline to handle video autoplay
correctly in Safari.
Upvotes: 1
Reputation: 101
Also a simple solution to add a preloader image while loading the video: HTML:
<video class="bg_vid" autoplay loop poster="images/FFFFFF-0.png">
the poster is a transparent image 1px.
CSS:
video {
background-image: url(images/preload_30x30.gif);
background-repeat: no-repeat;
background-size: 30px 30px;
background-position: center;
}
Upvotes: 10
Reputation: 73
My solution was to add the following inside of the window.fbAsyncInit = function():
var finished_rendering = function() {
var el = document.querySelector('div#loading_msg');
el.style.display="none";
}
FB.Event.subscribe('xfbml.render', finished_rendering);
Found: https://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe/v2.12
Upvotes: 0
Reputation: 14630
It took me a way too long to actually figure out how to do this, but I'm going to share it here because I FINALLY found a way! Which is ridiculous when you think about it, because loading is something that all videos have to do. You'd think they would have taken this into account when creating the html5 video standard.
My original theory that I thought should have worked (but wouldn't) was this
Simple, right? The problem was that I couldn't get the background image to show when the source elements were set, or the video.src attribute was set. The final stroke of genius/luck was to find out (through experimentation) that the background-image will not disappear if the poster is set to something. I'm using a fake poster image, but I imagine it would work as well with a transparent 1x1 image (but why worry about having another image). So this makes this probably a kind of hack, but it works and I don't have to add extra markup to my code, which means it will work across all my projects using html5 video.
HTML
<video controls="" poster="data:image/gif,AAAA">
<source src="yourvid.mp4"
</video>
CSS (loading class applied to video with JS)
video.loading {
background: black url(/images/loader.gif) center center no-repeat;
}
JS
$('#video_id').on('loadstart', function (event) {
$(this).addClass('loading');
});
$('#video_id').on('canplay', function (event) {
$(this).removeClass('loading');
$(this).attr('poster', '');
});
This works perfectly for me but only tested in chrome and safari on mac. Let me know if anyone finds bugs and or improvements!
Upvotes: 32
Reputation: 18870
You could probably do it with JavaScript by creating an image overlay with an animated "loading" gif which you only display when the video is loading and is not ready to play.
You'd have to write JavaScript to link up with the Media API for detecting when the video is ready to play and so forth though (so you could hide the image again), but it should be possible.
Upvotes: 1
Reputation: 3686
Use the tag id poster
<video controls="controls" poster="/IMG_LOCATION/IMAGENAME">
More info can be found http://www.w3schools.com/html5/att_video_poster.asp
Upvotes: 2