I have a full background HTML5 video autoplaying on the website. Some iOS mobile devices with Safari seem to be having an issue loading the video up, although a majority of times, it's working fine. It erroneously shows the following:
My code is as follows:
const videoDisplay = () => {
let isMobile = {
iOS: function() {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
},
Android: function() {
return navigator.userAgent.match(/Android/i);
},
BlackBerry: function() {
return navigator.userAgent.match(/BlackBerry/i);
},
Opera: function() {
return navigator.userAgent.match(/Opera Mini/i);
},
Windows: function() {
return navigator.userAgent.match(/IEMobile/i) || navigator.userAgent.match(/WPDesktop/i);
},
any: function() {
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
}
};
if(isMobile.any()) {
return (
<div className="fullscreen-video-wrap">
<video playsInline loop autoPlay muted poster="./media/landingpg_bg.jpg">
<source src={require("./media/video.mp4")} type="video/mp4" />
<source src={require("./media/video.webm")} type="video/webm" />
<source src={require("./media/video.ogv")} type="video/ogg" />
<img src={require("./media/landingpg_bg.jpg")} alt=""/>
Your browser does not support the video tag. I suggest you upgrade your browser.
</video>
</div>
)
} else {
return (
<div className="fullscreen-video-wrap">
<video playsInline loop autoPlay muted poster="./media/landingpg_bg.jpg">
<source src={require("./media/video.mp4")} type="video/mp4" />
<source src={require("./media/video.webm")} type="video/webm" />
<source src={require("./media/video.ogv")} type="video/ogg" />
<img src={require("./media/landingpg_bg.jpg")} alt=""/>
Your browser does not support the video tag. I suggest you upgrade your browser.
</video>
</div>
)
}
}
return (
<div className="v-header">
{videoDisplay()}
<Modal isOpen={modal} setModal={setModal} setFinishModal={setFinishModal} />
<FinishModal isOpen={finishModal} setFinishModal={setFinishModal}/>
<div className="menu">
<animated.img
className={`logo ${(modal || finishModal) && "invisible"}`}
src={require("./media/Renterii_logo_w.png")}
alt="renterii logo"
style={props}
/>
<animated.div
className={`notify ${(modal || finishModal) && "invisible"}`}
onClick={onClickHandler}
style={props2}
>
RENT ITEMS
</animated.div>
<animated.div
className={`social-media ${(modal || finishModal) && "invisible"}`}
style={props3}
>
</animated.div>
</div>
</div>
)
Computer browsers seem to be having no issues with the background video. So far it's been working fine with Firefox, Chrome, and Samsung browsers on mobile devices as well.
I had the same issue with the ios mobile devices and solved it.
As mentioned here : Creating Video for Safari on iPhone: "HTTP servers hosting media files for iOS must support byte-range requests, which iOS uses to perform random access in media playback. (Byte-range support is also known as content-range or partial-range support.) Most, but not all, HTTP 1.1 servers already support byte-range requests."
So you must check whether your server uses byte-range caching or else reconfigure it (I did it with nginx).
PS: Another secondary reason for ios video incompatibility could be the incompatible codecs of each video. The following compression standards are supported:
-H.264 Baseline Profile Level 3.0 video, up to 640 x 480 at 30 fps. Note that B frames are not supported in the Baseline profile.
-MPEG-4 Part 2 video (Simple Profile)
-AAC-LC audio, up to 48 kHz
Related
I want to make the video autoplay without any user gesture in reactjs. I know as per recent google and apple web video policy we cannot autoplay a video having audio without user gesture.But i have seen few websites which still autoplays the video across modern web browsers also.
I came across many questions related to this issue on stackoverflow but none helped me.
Here is what i have tried.
Try 1.
<video id="miniVideo" preLoad="yes" autoPlay="autoplay" loop width="100%" height="auto" playsInline>
<source src="/mini/video/cooper.mp4" type="video/mp4" />
<source src="/mini/video/cooper.webm" type="video/webm" />
</video>
Try 2.
<iframe playsInline id="miniVideo" src="/mini/video/cooper.mp4" width="100%"
height="400px"
allow="autoplay; fullscreen"></iframe>
Try 3.
Script:
componentDidMount(){
var videoTimer = document.getElementById("miniVideo");
videoTimer.play();
}
HTML:
<video id="miniVideo" width="100%" height="100%">
<source src="/video/cooper.mp4" type="video/mp4" />
<p>This browser does not support the video element.</p>
</video>
Your help will be well appreciated.Thanks
I am not sure about Safari but Chrome has changed the autoplay policy. Look here:https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
In order to autoplay, add muted attributed to video tag.
For example:
import React, { Component } from 'react';
class Player extends Component {
constructor(props) {
super(props);
this.state = {
isVideoMuted: true
};
}
handleMuteState = () => {
this.setState(prevState => ({
isVideoMuted: !prevState.isVideoMuted
}));
}
render() {
return (
<div>
<video muted={this.state.isVideoMuted} src="./video.mp4" />
<button onClick={this.handleMuteState}>{this.state.isVideoMuted ? 'Unmute' : 'Mute'}</button >
</div>
);
}
}
export default Player;
I have a react application where i am using html5 video tag to show a cover video. It works on ipad, android and all the major browsers but on iphone it just shows a glimpse of a play button which if clicked shows a full page video.
class FrontPage extends React.Component{
constructor(props) {
super(props);
this.authorize = [''];
}
render() {
return (
<div>
<video controls="true" style={BGstyle} preload="yes" autoPlay muted loop width="100%" height="auto">
<source src="/images/film.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
<Ladder/>
<SignUp/>
</div>
);
}
}
var BGstyle = {
position: "absolute",
zIndex:999,
right:0,
bottom:0,
minWidth:'100%',
width: 'auto',
backgroundSize:"cover"
}
export default FrontPage;
you can see it on www.viogto.dk
For iOS 10+
Try the playsinline attribute.
But in camel case for react :
<video playsInline>
Source - New video Policies for iOS
In iOS 8 and iOS 9
Short answer: use iphone-inline-video, it enables inline playback and syncs the audio.
Source - https://stackoverflow.com/a/36348909/3337722
I have problems to get a video to play on my Android mobile in the latest version of Chrome. In other browsers like the Puffin browser the video is playing. For test purposes I tried all common formats:
mp4
<br />
<video autoplay="autoplay" loop="loop" onended="this.play()"><source src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4" type="video/mp4" /></video>
<br />
webm
<br />
<video autoplay="autoplay" loop="loop" onended="this.play()"><source src="http://clips.vorwaerts-gmbh.de/VfE.webm" type="video/webm" /></video>
<br />
ogg
<br />
<video autoplay="autoplay" loop="loop" onended="this.play()"><source src="http://clips.vorwaerts-gmbh.de/VfE.ogv" type="video/ogg" /></video>
https://codepen.io/anon/pen/ozpVNP
According to Mozilla the first video, that is H.264 + AAC in MP4 should play. I also take this article in account and tried to play the videos by JavaScript additionally as well as tried to remove the type attribute on the first video tag without success.
How can I get it work in Chrome on Mobile?
<video autoplay loop autobuffer muted playsinline>
<source src="video/video-hat.mp4" type="video/mp4">
</video>
The problem is that Google want that users initiate by themselves any media, so If you debug your device chrome browser, you will get the warning "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture."
So that means you need to attach the video initialization, for example, with a click event
There doesn't appear to be any great info on this, so thought I'd post my findings.
I've been debugging html5 video playback on Chrome desktop and mobile on an Android 5.0.1 Samsung S4 with Chrome 61 and the embedded browser, and Safari 9 & 11, using an automatic javascript play/pause written in AngularJS (below). The video is embedded in a carousel so is sometimes visible, sometimes not. In summary:
I would recommend having both webm(vp8/vorbis) and mp4(h264/aac) formats. These are the most supported formats and have equivalent quality for the same bitrate. ffmpeg can encode both.
It seems Chrome mobile prefers webm if it can get it, so put that first.
If a browser plays a file when you direct it to the file url, this does not mean it will play it when embedded in a video tag, though it will tell you if the format & codecs are supported if it does play. Chrome mobile seems very picky about having a video source whose resolution is too high.
Safari (and probably iOS) will not play a video unless served by a server supporting byte-ranges. Apache, nginx and Amazon S3 for example do support them, but many smaller web servers (like WSGI servers) do not.
The order of the videos matters more than the source media attribute. Always have low resolution versions of a video first. The example below uses 1920x1080 and 1280x720. It seems if the mobile browser encounters a video that is "too high-res", it just stops processing the other sources and prefers the poster.
having a controls attribute and manual play vs playing through javascript doesn't appear to make any difference.
the muted attribute stops android from putting a little speaker icon in the status bar when playing but off-screen, even when the video doesn't have audio. As a side-note, I'd also really think about your audience if you intend to autoplay video with sound. Personally I think it's a bad idea.
the preload attribute doesn't seem to make much difference. The browser will tend to automatically preload the selected video metadata anyway.
having a source type attribute does not stop the video from playing. If anything it helps the browser choose which source to pick for the best
the JS video.oncanplay event is the best way to see if the video tag has been successful. If you don't get that, the video won't play, but the browser won't tell you why.
HTML:
<video class="img-responsive-upscale ng-scope"
video-auto-ctrl loop muted preload poster="0022.png">
<source src="vid_small.webm" media="(max-width: 1280px)" type="video/webm">
<source src="vid_small.mp4" media="(max-width: 1280px)" type="video/mp4">
<source src="vid.webm" media="(max-width: 1920px)" type="video/webm">
<source src="vid.mp4" type="video/mp4">
<img src="0022.png" alt="something"
title="Your browser does not support the <video> tag">
</video>
Javascript:
<script type="text/javascript">
angular.module('myproducts.videoplay', []).directive('videoAutoCtrl',
function() {
return {
require: '^uibCarousel',
link: function(scope, element, attrs) {
var video = element[0];
var canplay = false;
var rs = ["HAVE_NOTHING", "HAVE_METADATA", "HAVE_CURRENT_DATA", "HAVE_FUTURE_DATA", "HAVE_ENOUGH_DATA"];
var ns = ["NETWORK_EMPTY", "NETWORK_IDLE", "NETWORK_LOADING", "NETWORK_NO_SOURCE"];
function vinfo() {
console.log("currentSrc = " + video.currentSrc);
console.log("readyState = " + rs[video.readyState]);
console.log("networkState = " + ns[video.networkState]);
bufinfo();
}
function bufinfo() {
// tr is a TimeRanges object
tr = video.buffered
if (tr.length > 0) {
var ranges = ""
for (i = 0; i < tr.length; i++) {
s = tr.start(i);
e = tr.end(i);
ranges += s + '-' + e;
if (i + 1 < tr.length) {
ranges += ', '
}
}
console.log("buffered time ranges: " + ranges);
}
}
video.onerror = function () {
console.log(video.error);
}
video.oncanplay = function () {
canplay = true;
if (!playing) {
console.log("canplay!");
vinfo();
}
}
var playing = false;
function playfulfilled(v) {
console.log("visible so playing " + video.currentSrc.split('/').pop());
playing = true;
}
function playrejected(v) {
console.log("play failed", v);
}
function setstate(visible) {
if (canplay) {
if (visible) {
p = video.play();
if (p !== undefined) {
p.then(playfulfilled, playrejected);
}
} else if (playing) {
video.pause();
console.log("invisible so paused");
playing = false;
}
} else {
console.log("!canplay, visible:", visible);
vinfo();
}
}
// Because $watch calls $parse on the 1st arg, the property doesn't need to exist on first load
scope.$parent.$watch('active', setstate);
}
};
});
</script>
I had an issue where the video worked on my desktop chrome, and desktop-mobile view, but not my iphone. Turns out i needed to add the "playsinline" property to the video tag. :]
The issue fixed for me after switching off "Data saving" mode in chrome.
I spend all my afternoon to fix an autoplay problem on iOS and discovered you just to disable the "ECO MODE" or it won't play automatically.
<video width="352" height="198" controls>
<source src="video.m3u8" type="application/x-mpegURL">
</video>
This code works fine with all browsers on my android device but doesn't works on Firefox / Chrome / Safari on my computer.
I need to play the video on all devices. What can I do?
HLS is not supported on most browsers natively. But can be played via libraries such as hls.js.
this should easily work
<script src="https://cdn.jsdelivr.net/npm/hls.js#latest"></script>
<video id="video"></video>
<script>
if(Hls.isSupported()) {
var video = document.getElementById('video');
var hls = new Hls();
hls.loadSource('https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
video.play();
});
}
</script>
In the HTML5 spec, it suggests you put fallback material in the <video> tag for older browsers that do not support it.
<video width="400" controls>
<source src="mov_bbb.mp4" type="video/mp4">
<source src="mov_bbb.ogg" type="video/ogg">
Your browser does not support HTML5 video.
</video>
However, I cannot find anything for fallbacks when all source types are unsupported. For instance, my Chromium browser cannot play video/mp4, but it can play video/ogg. So I would expect this to render the fallback text.
<video width="400" controls>
<source src="mov_bbb.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
Instead, I just get a video player with nothing in it because it can't load the mp4 file.
Is there a way to have a fallback in HTML 5 video when there is no usable video source? I am aware that the fallback I was attempting is only for old browsers, but I still need a fallback for no available source.
Actually, when you try to load unsupported media types in <source> element, an error event will fire.
You could then listen to these events, and if none of the sources is recognized, trigger the fallback :
var sources = document.querySelectorAll('source');
var source_errors = 0;
for (var i = 0; i < sources.length; i++) {
sources[i].addEventListener('error', function(e) {
if (++source_errors >= sources.length)
fallBack();
});
}
function fallBack() {
document.body.removeChild(document.querySelector('video'));
document.body.appendChild(document.createTextNode('No video with supported media and MIME type found'));
}
<video controls>
<source src="foo.bar" type="video/foo" />
<source src="bar.foo" type="video/bar" />
</video>
It's mentioned in the specs a way to fallback.
"listen to the error event on the last source element and trigger fallback behavior"
<div>
<video width="400" controls>
<source src="mov_bbb.mp4" type="video/mp4">
<source src="mov_bbb.ogg" type="video/ogg"
onerror="parentNode.parentElement.innerText = 'Your browser does not support the video codec' ">
</video>
</div>
There's no HTML behaviour for this, so we'll have to add our own behaviour with JavaScript.
(function() {
"use strict";
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function setVideoFallback(lazyArea) {
var lowData = false;
if ("connection" in navigator) {
lowData = navigator.connection.saveData === true ||
navigator.connection.effectiveType === "slow-2g" ||
navigator.connection.effectiveType === "2g";
}
//DocumentFragments don't support getElementsByTagName
//oldIE doesn't support querySelectorAll
var lazyVideos = lazyArea.querySelectorAll ?
lazyArea.querySelectorAll("video") :
lazyArea.getElementsByTagName("video");
for (var i = lazyVideos.length; i--;) {
var lazyVideo = lazyVideos[i];
var cantPlay = true;
if (lazyVideo.canPlayType) {
//Loop through the various source elements, and check if
//the browser thinks it can play them
//This works better if we specify the codec along with
//the MIME type
var sources = lazyVideo.getElementsByTagName("source");
for (var i2 = sources.length; i2--;) {
if (lazyVideo.canPlayType(sources[i2].type)) {
cantPlay = false;
break;
}
}
}
//If on a low-data connection, remove the autoplay attribute
//(it's only polite)
if (lowData) {
lazyVideo.removeAttribute("autoplay");
lazyVideo.setAttribute("controls", "");
}
//If you can't play any of the available formats, skip straight to fallback content
if (cantPlay) {
//Extract the fallback and replace the video with it
var children = lazyVideo.childNodes;
for (var i3 = children.length; i3--;) {
var childNode = children[i3];
if (childNode.tagName !== "TRACK" && childNode.tagName !== "SOURCE") {
insertAfter(childNode, lazyVideo);
}
}
lazyVideo.parentNode.removeChild(lazyVideo);
}
}
}
/**
* Retrieve the elements from the 'lazy load' noscript tags and prepare them for display
*/
function setUp() {
//Get all the noscript tags on the page
var lazyLoadAreas = document.getElementsByTagName("noscript");
var supportsTemplates = typeof HTMLTemplateElement === "function";
for (var i = lazyLoadAreas.length; i--;) {
var noScriptTag = lazyLoadAreas[i];
//only process the ones marked for lazy loading
if (!noScriptTag.hasAttribute("data-lazy-load")) continue;
// The contents of a noscript tag are treated as text to JavaScript
var lazyAreaHtml = noScriptTag.textContent || noScriptTag.innerHTML;
// So we stick them in the innerHTML of a new div tag to 'load' them
var lazyArea;
if (supportsTemplates) {
//(if possible, templates are better as they won't start any network calls)
var lazyTemplate = document.createElement("template");
lazyTemplate.innerHTML = lazyAreaHtml;
lazyArea = lazyTemplate.content;
} else {
lazyArea = document.createElement("div");
lazyArea.innerHTML = lazyAreaHtml;
}
setVideoFallback(lazyArea);
noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
}
}
//If the page has loaded already, run setup - if it hasn't, run as soon as it has.
if (document.readyState !== "loading") {
setUp();
} else {
document.addEventListener("DOMContentLoaded", setUp);
}
})();
<main>
<figure>
<!--[if !IE]><!-->
<noscript data-lazy-load>
<video height="338" width="600" autoplay loop muted>
<!--<source src="./Sample.mp4" type="video/mp4; codecs=avc1.42E01E,mp4a.40.2">-->
<source src="http://dl3.webmfiles.org/big-buck-bunny_trailer.webm" type="video/webm; codecs=vp8,vorbis">
<source src="https://upload.wikimedia.org/wikipedia/commons/0/07/Backgammon_example.ogv" type="video/ogg; codecs=theora,vorbis">
<!--<![endif]-->
<img src="https://media2.giphy.com/media/BfbUe877N4xsUhpcPc/giphy.gif?cid=790b76115cadcffa59306b73776453f3" height="360" width="480"/>
<!--[if !IE]><!-->
</video>
</noscript>
<!--<![endif]-->
<figcaption>
A bunny emerging from his den and stretching.
<!--[if !IE]><!-->
<noscript aria-hidden="true"><p>
Note: Without JavaScript, the above animation might not play. In that case, the animation can be directly accessed
here.
</p></noscript>
<!--<![endif]-->
</figcaption>
</figure>
</main>
Using the canPlayType function, we ask the browser if it thinks it can play any of the source types. If it doesn't, we pull out the fallback content.
We encase the video in noscript tags so that it won't start loading until we've run the script (unless scripting is disabled, which is the desired behaviour).
We also use IE conditional tags, because oldIE can't read the contents of noscript tags with script.
(Tested with Edge, Firefox, Chrome, and every compatibility mode IE has. The Webm shows in all browers bar IE, which shows the GIF in every compatibility mode.)
#Jaw.sh There's two fallback options that are commonly in use.
Fallback to Flash version of the video.
Fallback to a direct download of the video.
Today's browsers (Opera I'm not sure and not really concerned), are all capable of playing MP4 H.264. So you shouldn't worry too much about incompatibilities, unless most of your viewers live in China.