Using the Media Capabilities API

The Media Capabilities API enables real time feedback about media playback to better enable adaptative streaming. It provides information about the audio and video decoding and encoding abilities of the device, exposing information such as whether a media configuration is supported and whether playback should be smooth and power efficient. In the future, it will provide access to display property information.

The MediaCapabilities interface

The MediaCapabilities is published through the navigator.mediaCapabilities and WorkerNavigator.mediaCapabilities object.

If the object exists, the media capabilities interface is available. You can test for the presence of mediaCapabilities object like so:

if ("mediaCapabilities" in navigator) {
  // mediaCapabilities is available
} else {
  // mediaCapabilities IS NOT available
}

Taking video as an example, to obtain information about video decoding abilities, you create a video decoding configuration which you pass as a parameter to  MediaCapabilities.decodingInfo() method. This returns a promise that fulfills with information about the media capabilities as to whether the video can be decoded, and whether decoding will be smooth and power efficient. You can also test audio decoding as well as video and audio encoding.

Creating a video decoding configuration

The MediaCapabilities.decodingInfo() method takes as a parameter a media decoding configuration. There are very specific ways to go about creating the configuration defined by the MediaDecodingConfiguration dictionary.

In our example, we are testing the decoding capabilities of a video configuration. The configuration requires the type of media being tested — e.g. a plain file or MediaSource — and a VideoConfiguration including values for the contentType, width, height, bitrate, and framerate:

  • The contentType muse be a valid video MIME type.
  • The width and height are the proportions of the video.
  • The bitrate is the number of bits used to encode 1s of video.
  • The framerate is the number of frames per one second of video.
const videoConfiguration = {
    type: 'file', 
    video: {
        contentType: "video/webm;codecs=vp8", 
        width: 800,     
        height: 600,    
        bitrate: 10000, 
        framerate: 15  
     }
};

Had we been querying the decodability of an audio file, we would create an audio configuration including the number of channels and sample rate, and excluding the dimensions and framerate:

const audioConfiguration = {
    type: 'file',
    audio: {
        contentType: "audio/ogg", 
        channels: 2,
        bitrate: 132700,
        samplerate: 5200
     }
};

Had we been testing encoding capabilities, we would have created a MediaEncodingConfiguration, which requires the type of media being tested — either record (for recording media, i.e. a MediaRecorder object) or transmission (for media transmitted over electronic means like RTCPeerConnection) — plus either an audio or video configuration as described above.

Querying the browser about decoding abilities

Now that we've created a video decoding configuration we can pass it as a paramater of the MediaCapabilities.decodingInfo() method to determine if a video matching this configuration would be decodable and if the playback would be smooth and power efficient.

var promise = navigator.mediaCapabilities.decodingInfo(videoConfiguration);

The decodingInfo() and encodingInfo() methods both return promises. Once the promises state is fulfilled, you can access the MediaCapabilitiesInfo interface's supported, smooth, and powerEfficient properties.

Handling the response

Instead of the assigning the promise to a variable, we can post the values returned by the promise to console:

navigator.mediaCapabilities.decodingInfo(videoConfiguration).then(result => {
    console.log('This configuration is ' + 
        (result.supported ? '' : 'not ') + 'supported, ' +
        (result.smooth ? '' : 'not ') + 'smooth, and ' +
        (result.powerEfficient ? '' : 'not ') + 'power efficient.')
});

The response provided is defined by the  MediaCapabilitiesInfo interface.

Handling errors

In our video decoding example, a TypeError would be raised if the media configuration passed to the decodingInfo()method was invalid. The error can be due to the type not being one of the two possible values, the contentType not being a valid codec MIMME type, or invalid or omitted definitions required in the VideoConfiguration.

navigator.mediaCapabilities.decodingInfo(videoConfiguration).then(
      console.log('It worked')
    ).catch(error => 
       console.log('It failed: ' + error)
    );

Media Capabilities live example

CSS

li { margin : 1em; }

HTML

<form>
<p>Select your video configuration and find out if this browser supports the codec, 
and whether decoding will be smooth and power efficient:</p>
  <ul>
  <li>
    <label for="codec">Select a codec</label>
    <select id="codec">
      <option>video/webm; codecs=vp8</option>
      <option>video/webm; codecs=vp9</option>
      <option>video/mp4; codecs=avc1</option>
      <option>video/ogg; codecs=theora</option>
      <option>invalid</option>
    </select>
  </li>
  <li>
    <label for="size">Select a size</label>
    <select id="size">
      <option>7680x4320</option>
      <option>3840x2160</option>
      <option>2560x1440</option>
      <option>1920x1080</option>
      <option>1280x720</option>
      <option selected>800x600</option>
      <option>640x480</option>
      <option>320x240</option>
      <option value=" x ">none</option>
    </select>
  </li>
  <li>
    <label for="framerate">Select a framerate</label>
    <select id="framerate">
      <option>60</option>
      <option>50</option>
      <option>30</option>
      <option>24</option>
      <option selected>15</option>
    </select>
  </li>
    <li>
    <label for="bitrate">Select a bitrate</label>
    <select id="bitrate">
      <option>4000</option>
      <option>2500</option>
      <option>800</option>
    </select>
  </li>
  </ul>
  <p><input type="button" value="Test this Video Configuration" id="tryit"></p>
</form> 

<ul id="results"></ul>

JavaScript

let mc = {
  videoConfiguration : new Object(),
  
  tryit: function () {
   mc.createConfiguration();
   mc.testit();
  },
    
  createConfiguration: function () {
    var size = document.getElementById('size').value.split('x');
    mc.videoConfiguration = {
      type: 'file',
      video: {
        contentType: document.getElementById('codec').value,
        width: size[0],
        height: size[1],
        bitrate: document.getElementById('bitrate').value,
        framerate: document.getElementById('framerate').value,
      }
    }
  },

  testit: function () {
    let content = '';
    navigator.mediaCapabilities.decodingInfo(mc.videoConfiguration).then(result => { 
      var li = document.createElement('li'),
        mcv = mc.videoConfiguration.video;
      content = 'A ' + mcv.width + 'x' + mcv.height + ', ' + mcv.contentType + ' at ' + mcv.framerate  + 'fps and ' +  mcv.bitrate + ' bps video ' +
        (result.supported ? ' IS ' : 'IS NOT ') + ' supported, ' +
        (result.smooth ? ' IS ' : ' is NOT ') + ' smooth, and' +
        (result.powerEfficient ? ' IS ' : ' IS NOT ') + 'power efficient.';
      var ul = document.getElementById("results")
      li.innerHTML = content;
      ul.appendChild(li);
    }).catch((error) => {
        var li = document.createElement('li'),
            ul = document.getElementById("results");
        li.innerText = 'Codec ' + mc.videoConfiguration.video.contentType + ' threw an error: ' + error;
        ul.appendChild(li);
    });
  }
}

document.getElementById('tryit').addEventListener('click', mc.tryit);

Live Result

Browser compatibility

Update compatibility data on GitHub
DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidEdge MobileFirefox for AndroidOpera for AndroidiOS SafariSamsung Internet
Basic support
Non-standard
Chrome Full support 66Edge ? Firefox Full support 63IE ? Opera Full support 55Safari ? WebView Android Full support 66Chrome Android Full support 66Edge Mobile ? Firefox Android ? Opera Android Full support 55Safari iOS ? Samsung Internet Android ?
encodingInfo
Non-standard
Chrome Full support 67
Disabled
Full support 67
Disabled
Disabled From version 67: this feature is behind the chrome://flags/#enable-experimental-web-platform-features preference (needs to be set to enabled). To change preferences in Chrome, visit chrome://flags.
Edge ? Firefox Full support 63IE ? Opera ? Safari ? WebView Android Full support 67
Disabled
Full support 67
Disabled
Disabled From version 67: this feature is behind the chrome://flags/#enable-experimental-web-platform-features preference (needs to be set to enabled).
Chrome Android Full support 67
Disabled
Full support 67
Disabled
Disabled From version 67: this feature is behind the chrome://flags/#enable-experimental-web-platform-features preference (needs to be set to enabled). To change preferences in Chrome, visit chrome://flags.
Edge Mobile ? Firefox Android ? Opera Android ? Safari iOS ? Samsung Internet Android ?
decodingInfo
Non-standard
Chrome Full support 66Edge ? Firefox Full support 63IE ? Opera Full support 55Safari ? WebView Android Full support 66Chrome Android Full support 66Edge Mobile ? Firefox Android ? Opera Android Full support 55Safari iOS ? Samsung Internet Android ?

Legend

Full support  
Full support
Compatibility unknown  
Compatibility unknown
Non-standard. Expect poor cross-browser support.
Non-standard. Expect poor cross-browser support.
User must explicitly enable this feature.
User must explicitly enable this feature.

See also

Document Tags and Contributors

Contributors to this page: ExE-Boss, welenofsky, chrisdavidmills, jwhitlock, estelle
Last updated by: ExE-Boss,