20

So I'm serving H.264 .mp4 video on my website. I'm using open source HTML5 video player http://mediaelementjs.com/. Some visitors are viewing from Safari for iPhone. The iPhone 4 supports video playback only up to 720p, so if I make my videos smaller than that, they work on the 4 and the 4S. But the 4S supports video up to 1080p. So how would I serve a larger video to the 4S and a smaller video to the 4? I tried this:

<video width="640" height="400" id="player" controls="controls" preload="auto">
    <source src="https://s3.amazonaws.com/my-big-1080p-video.mp4" type="video/mp4">
    <source src="https://s3.amazonaws.com/my-small-720p-video.mp4" type="video/mp4">
</video>

But it didn't work. The iPhone 4 isn't smart enough to try the second source. How can I make my website serve the correct video to the different devices?

Moshe
  • 57,511
  • 78
  • 272
  • 425
Binyamin Bauman
  • 1,041
  • 10
  • 11
  • 4
    Two thoughts on this, although hardly an answer: 1) Try checking and parsing the user-agent string. It might contain useful information. 2) Consider use using the lower res video on both iPhone models. Remember your users' data usage plans. This website contains some information about what you're trying to do: http://davidwalsh.name/detect-iphone – Moshe Jun 07 '12 at 12:29
  • You can try using the media query. – Alexandre Khoury Jun 07 '12 at 12:30
  • @Mageek Media queries won't work, because iPhone 4 and 4s both have retina display. – jasssonpet Jun 07 '12 at 12:58
  • 1
    @Moshe I ended up doing your suggestion #2, serving the lower-res video to all devices – Binyamin Bauman Jun 07 '12 at 15:40
  • 1
    I think the only option is to have an user choice to opt-in for 1080p quality, like Youtube does. HTMLVideo Javascript element accepts different kind of format detections, but I am not sure if iOS safari supports playback support detection by resolution. – Mikko Ohtamaa Jun 11 '12 at 11:38

11 Answers11

9

Play 720p video on iPhone 4 — 1080p video on iPhone 4S

Try this on an iPhone 4 and a 4S (jsfiddle)

<video src="http://file.brow.sr/1080p.mp4" onerror="this.src='http://file.brow.sr/720p.mp4';" controls loop width="320" height="180">
</video>

Explanation

Load the 1080p video, then use Javascript's onError to fall back to 720p.

Safari will sniff the header of the 1080p file to determine if it's playable, and if it's too big to decode it will throw an error. We then catch that error to provide the 720p video.

By using this kind of feature detection, the fallback will not only work on one device (iPhone 4) but probably on a lot of different capable browsers.

Why multiple <source>'s won't work

When using multiple <source> tags with the same MIME types, the browser will load the first source that has a compatible MIME type and discard the others, even if that video is not playable. That's because source elements are expected to provide alternative video codecs (eg. ogg, webm, mp4), not alternative frame sizes / file sizes.

Duvrai
  • 3,398
  • 3
  • 20
  • 21
2

Here is how to go about it:

1) Retrieve the device model by using wurfl

<script type='text/javascript' src=“//wurfl.io/wurfl.js"></script>

You can either use HTTP or HTTPS (both are are supported) If you plan to use the device information provided by the script to make rendering decisions, then you might want to include the script in the element. Otherwise, you can load it asynchronously. Now you have access to the WURFL object within JavaScript.

Sample response looks something like:

{ complete_device_name:"Apple iPhone 5", form_factor:"Smartphone", is_mobile:true }

off course you can(and should)

console.log(WURFL);

to find out the rest of the properties you can use.

2) Now that you know which exactly which device model your users are on, you can switch the video players configs.

How about something like?

<video width="IPHONE5_VIDEO_WIDTH"
       height="IPHONE5_VIDEO_HEIGHT"
       id="player" controls="controls"
       preload="auto">
       <source src="IPHONE5_VIDEO_URL" type="video/mp4">
</video>

super clean and readable right? Hope that helps.

Eddy Ferreira
  • 770
  • 8
  • 14
1

I have a php script that does this. I got it here - http://detectmobilebrowsers.com/ - and yes, there is a javascript, JQuery, etc. versions. It's worked quite well for us and it has the benefit of seeming to stay fairly updated. The only issue we've run into was an iPad that had been deliberate set not to identify itself as a mobile device.

RecentCoin
  • 316
  • 3
  • 5
1

Your solution don't work because of the reason mentioned by dear @Duvrai. I've searched to attain a right way to meet your purpose and it seemed we have no choice unless using some javascript code (here without considering server side programming) to make a decision which source should be delivered. The bellow snippet detects the browser Type and its Version:

navigator.sayswho= (function(){
    var ua= navigator.userAgent, tem, 
    M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
    if(/trident/i.test(M[1])){
        tem=  /\brv[ :]+(\d+)/g.exec(ua) || [];
        alert('IE '+(tem[1] || ''));
    }
    if(M[1]=== 'Chrome'){
        tem= ua.match(/\bOPR\/(\d+)/)
        if(tem!= null) alert('Opera '+tem[1]);
    }
    M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
    if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
    alert( M.join(' '));
})();

Now you can write some lines of code in javascript and decide to change video sources based on browser Type and Version.

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
  • 1
    The version will not tell you the difference between iPhone 4 and 4S because both can have iOS 5-7. – Duvrai Jan 20 '15 at 09:31
  • @Duvrai Here we have faced with rendering engine related to browser ability that may differ by the OS version. haven't we? – Amirhossein Mehrvarzi Jan 20 '15 at 10:40
  • 1
    The question was not about OS version, but hardware model (iPhone 4/4S) Also, did you read the other answers? @WebOrCode and others already gave almost the same answer. – Duvrai Jan 20 '15 at 20:26
  • @Duvrai I can't understand one thing! what happens if a user upgrade his browser to latest one? He can't play high resolution streams? In other words, Is the hardware point of decision to play types of resolutions? – Amirhossein Mehrvarzi Jan 21 '15 at 10:03
  • Yes. Max resolution depends on hardware capabilities. So iOS version doesn't matter. – Duvrai Jan 22 '15 at 20:18
0

Try this link The library should be able to detect user-agent and you can serve appropriate files accordingly.

swiftBoy
  • 35,607
  • 26
  • 136
  • 135
HobieCat
  • 119
  • 1
  • 11
  • iOS device cannot be detected by user agent detection, because different devices have the same Safari browser – Mikko Ohtamaa Jun 11 '12 at 11:37
  • Mikko, have a look here before stating sentences: http://blog.mobileesp.com/?page_id=53. I personally use this lib for a couple of apps and, oh my god guess what... it's telling the difference between an ipod, an iphone and an ipad – HobieCat Jun 11 '12 at 14:11
  • It still cannot make different between iPhone 4S (full HD) and iPhone 4 (no HD playback) - both report the same user agent AFAIK – Mikko Ohtamaa Jun 11 '12 at 19:38
0

I cannot offer sample code since I am not an Apple geek, but I can tell you based off of my experience trying to make sites compatible between XHTML and HTML5 that it is better to check for browser capability than browser version.

The reason for this is that there are too many browser versions to justify the upkeep, and also the user agent string can be modified. I recommend that you write a script that checks for HTML5 video capabilities with a simple if statement, and then render either one video or the other depending upon the results.

Asciiom
  • 9,867
  • 7
  • 38
  • 57
0

A mobile device detection database like WURFL (Wireless Universal Resource File - http://wurfl.sourceforge.net/) or DeviceAtlas may be overkill if video is the only capability you're checking for. But it is a quick way to get robust capabilities detection for a vastly larger range of devices than you would be able to feasibly compile checks for, and would come in handy if your site ever needs to verify other capabilities besides video support.

trevdor
  • 81
  • 3
0

MEJS player does not handle errors correctly, I'd to add more support to be able to detect what actually happened. On iPhone it even sometimes throws an error event but there is no actual error and you can play the video correctly.

Open mediaelement-and-player.js and look for

        // error handling
        media.addEventListener('error',function() {
            loading.hide();
            controls.find('.mejs-time-buffering').hide();
            error.show();
            error.find('mejs-overlay-error').html("Error loading this resource");
        }, false);

Then use this code:

        // error handling
        media.addEventListener('error',function() {
            var
                videoError = error.closest('.mejs-inner').find('video,audio')[0].error,
                msg = 'Error loading this resource.';

            if (!videoError) { //webkit sometimes throws error event but video has no actual error and can play the video correctly - ignore the event
                console.log('MEJS event: error throws but no error found - ignored');
                return;
            }

            //hide elements visible while loading and playing - cannot play after error
            loading.hide();
            controls.addClass('hidden'); //controls are automatically displayed when mouse hover is detected - must hide it permanently using class with !important
            error.closest('.mejs-inner').find('.mejs-overlay-play').hide(); //also hide overlay with play button
            error.show();

            //get relevant error message
            switch(videoError.code) { //see http://www.w3.org/TR/html5/embedded-content-0.html#error-codes
                case videoError.MEDIA_ERR_ABORTED: //loading stopped (by user, e.g. by pressing ESC or Back)
                    msg = 'Video loading aborted';
                    break;
                case videoError.MEDIA_ERR_DECODE: //invalid format (actually presumed format is OK, but the data does not correspond with the defined format - probably corrupted file of data transfer)
                    msg = 'Video file is broken';
                    break;
                case videoError.MEDIA_ERR_NETWORK: //network problem (was able to connect to the provided URL but could not get the video data)
                    msg = 'Network connection lost';
                    break;
                case videoError.MEDIA_ERR_SRC_NOT_SUPPORTED: //invalid source URL (url provided does not lead to a supported video file)
                    msg = 'Video not supported';
                    break;
            }

            //display error
            console.log('Video error: ' + msg + ', code: ' + videoError.code);
            error.find('.mejs-overlay-error').html(msg);
        }, false);

If you need to you can add your own handling that will switch to 720p in case of unsupported video.

And in mediaelementplayer.css add this (not sure if actually required or just improvement for my theme):

/* Display errors */
.mejs-overlay-error {
    color: white;
    background: black;
    text-align: center;
    font-size: 1.2EM;
}
.mejs-controls.hidden {
    display: none !important;
}
/* End: Display errors */

This is for version 2.13.1, not sure if newer version is better.

Update: newest version 2.16.3 contains exactly same useless error handler.

Radek Pech
  • 3,032
  • 1
  • 24
  • 29
-1

This will detect the iOS version. Maybe it can be useful:

if (navigator.userAgent.indexOf('5_0') != -1) {
    alert('IOS 5');
} else {
    alert('Other');
}

Edit: I have have ajusted and tested the script.

-1

Put this in your tags:

<meta name="viewport" content="initial-scale=1.0">
<meta name="viewport" content="width=320.1">    
<script>
if (window.screen.height==568) { // iPhone 5
                    document.querySelector("meta[name=viewport]").content="width=320.1";
                  // your code here
                }
</script>
-1

I use this code:

    // iPhone 3
    if (window.screen.height==480 && window.screen.width==320 && window.devicePixelRatio==1)
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:300px;width:500px;"></div>');
    } 
    // iPhone 4, this is Retina
    else if (window.screen.height==480 && window.screen.width==320 && window.devicePixelRatio==2) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:300px;width:500px;"></div>');
    } 
    // iPhone 5
    else if (window.screen.height==568 && window.screen.width==320 && window.devicePixelRatio==2) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:400px;width:600px;"></div>');
    } 
    // iPad
    else if (window.screen.height==1024 && window.screen.width==768 && window.devicePixelRatio==1) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:425px;width:680px;"></div>');
    } 
    // iPad Retina
    else if (window.screen.height==1024 && window.screen.width==768 && window.devicePixelRatio==2) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:425px;width:680px;"></div>');
    } 
    // all other, this was before for all 
    else  
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:400px;width:600px;"></div>');
    }
WebOrCode
  • 6,852
  • 9
  • 43
  • 70
  • This does not differentiate between iPhone 4 and 4S, which was the actual question. – Duvrai Jan 15 '15 at 22:40
  • 1
    You are correct, my code is using screen resolution for iOS device detection. iPhone 4 and 4S have same screen resolute, so this concept is not applicable. Actually I am using this code just for screen resolution, not device detection, somebody will find it use full. – WebOrCode Jan 16 '15 at 11:31