Google Chrome does not autoplay HTML5 video on mobile - html

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.

Related

How to autoplay two HTML5 videos together after loading?

I'm trying to have two HTML5 videos autoplay at the exact same time. In other words, can I prevent these videos from playing until they have both loaded?
I don't want one to begin playing with the second is still loading. I hope this makes sense.
You can use the 'onloadeddata' function to check both have loaded, and then start both at the same time. I think you are at the mercy of the browser and JavaScript engine implementation for exactly how accurate the synching will be, but from quick testing this seems pretty synched so long as you are not worried about millisecond synch.
See below for an example.
var vid1 = document.getElementById("MyVid1");
var vid2 = document.getElementById("MyVid2");
var vid1Ready = false
var vid2Ready = false
vid1.onloadeddata = function() {
if (vid2Ready == true) {
vid1.play()
vid2.play()
} else {
vid1Ready = true
}
};
vid2.onloadeddata = function() {
if (vid1Ready == true) {
vid1.play()
vid2.play()
} else {
vid2Ready = true
}
};
<video id="MyVid1" width="320" height="176" controls preload="auto">
<source src="http://ftp.nluug.nl/pub/graphics/blender/demo/movies/ToS/tears_of_steel_720p.mov" type="video/mp4">
Your browser does not support this video format
</video>
<video id="MyVid2" width="320" height="176" controls preload="auto">
<source src="http://peach.themazzone.com/durian/movies/sintel-1024-surround.mp4" type="video/mp4">
Your browser does not support this video format
</video>

mobile browsers having issues loading up a html5 background video

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

How to play an audio file in the background after clicking a link? (no embed)

Currently I am using following code to play some audio after a link is clicked:
Pronunciation of a word
For now if the user clicks on the link, a new page with an audio playing panel is loaded. After playing the audio, the user has to click GO BACK button of the browser to get back to the original content.
Is it possible to play the audio without being directed to a new page? When the user clicks on the link, the audio just plays in the background?
(Don't want to use embed because it's just a 1 second audio for a word's pronunciation as a minor explanation of an uncommon word).
Actually the href attribute is redirecting you to the new page, you can use e.prevenDefault() in the link click event handler to stop this redirection and create a dynamic audio element with this href as source and play it.
This is what you need:
function playItHere(e, link) {
var audio = document.createElement("audio");
var src = document.createElement("source");
src.src = link.href;
audio.appendChild(src);
audio.play();
e.preventDefault();
}
Pronunciation of a word
In html5, you can actually use the <audio> tag to get that done!
<audio src="/music/myaudio.ogg" autoplay> Sorry, your browser does not support the <audio> element. </audio>
SOURCE: Wired
If you use a tag be careful with href .
Code snippet fixed .
First you will need to make convert ogg to the mp3 and than use it for multi source .
Small browser detector (chrome/opera/safari - mp3 and mozilla - ogg . )
E("PLAYER").addEventListener("error", function(e) {
console.log("error: " + e.target.error)
});
function PLAYER_BACKGROUND(what) {
var SOURCE_PATH = E(what).getAttribute("whattoplay")
if (isChrome == true)
{
SOURCE_PATH = SOURCE_PATH.replace(".ogg" , ".mp3")
}
else {
SOURCE_PATH = SOURCE_PATH.replace( ".mp3" , ".ogg" )
}
E("PLAYER").src = SOURCE_PATH
E("PLAYER").play()
}
<script>
var E = function(id){return document.getElementById(id)};
var isChrome = /Chrome/.test(navigator.userAgent) || /Safari/.test(navigator.userAgent);
</script>
<a id="audio_1" onclick="PLAYER_BACKGROUND(this.id)" whattoplay="https://maximumroulette.com/framework/res/audio/laser7.ogg" href="javascript:void(0)">Pronunciation of a word</a>
<audio style="display:none" id="PLAYER" autoplay controls>
<source src="#" type="audio/ogg">
<source src="#" type="audio/mpeg">
Sorry, your browser does not support the element.
</audio>

HTML5 video fallback when all types unsupported

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.

loop html5 video using ended event broken

I am searching for the holy grail of a simple looping html5 video, I am currently using the following code which doesn't seem work
<video width="650" height="650" class="outer_shadow" autoplay="" ended="this.play()" loop>
<source src="/videos?video_id=ag1kZXZ-anQtd2luZG93cg4LEghUaW1lRGF0YRgNDA">
</video>
Can anyone could hilight why this code doesn't work/suggest their best work arround?
Surely you just need to set the loop attribute (see fiddle tested in Chrome):
<video id="myVideo" width="650" height="650" class="outer_shadow" autoplay loop>
<source src="http://content.bitsontherun.com/videos/nPripu9l-60830.mp4">
</video>​
If firefox still doesn't like the loop attribute, try the following fix:
document.getElementById('myVideo').addEventListener('ended', function(){
this.currentTime = 0;
}, false);
Update:
Perhaps not as simple as you had hoped but, as a work around for the problem, it might be worth trying one of the many HTML5 video libraries such as video.js. If the problem persists you could, as a worst case, force the library to use Flash where supported (ie. desktop) and fall-back to HTML5 where it's not (as explained here).
Here is the fiddle with working example of HTML5 video player that loops several videos. Just add your URLs to src array...
<script src="http://code.jquery.com/jquery-1.9.0.min.js"></script>
<video id="video" width="500" height="400" controls autoplay></video>
<script>
var src = [
"http://content.adfox.ru/131007/adfox/205544/865991_11.mp4",
"http://all.rutube.ru/130627/gpmdigital/217059/805529_11.mp4"
];
var curSrc = 0;
$(function() {
$('#video').attr("src", src[curSrc % src.length]);
curSrc++;
var video = $('#video').get(0);
$('#video')
.on('loadedmetadata', function() {
video.currentTime=0.01;
video.play();
})
.on('ended', function() {
console.log('ended');
video.src = src[curSrc % src.length];
video.load();
curSrc++;
});
});
</script>