AntonAL
AntonAL

Reputation: 17430

HTML5 video error handling

I need to tell, whether video cannot be played ("x" sign is shown in browser).

This code does't works. "onerror" event will never be fired under Firefox

var v = document.getElementsByTagName("video")[0];
    if ( v != undefined )
        v.onerror = function(e) {
            if ( v.networkState == v.NETWORK_NO_SOURCE )
            {
                // handle error
            }
        }

What's wrong here ?

Upvotes: 32

Views: 82946

Answers (6)

Aleš Kotnik
Aleš Kotnik

Reputation: 2724

To catch error event, you should use video.addEventListener():

var video = document.createElement('video');
var onError = function() { // your handler};
video.addEventListener('error', onError, true);
...
// remove listener eventually
video.removeEventListener('error', onError, true);

Note that the 3rd parameter of addEventListener (on capture) should be set to true. Error event is typically fired from descendants of video element ( tags).

Anyway, relying on video tag to fire an error event is not the best strategy to detect if video has played. This event is not fired on some android and iOS devices.

The most reliable method, I can think of, is to listen to timeupdate and ended events. If video was playing, you'll get at least 3 timeupdate events. In the case of error, ended will be triggered more reliably than error.

Upvotes: 6

Pug example

video(src= encodeURI(item.urlVideo), type='video/mp4'  onerror="myFunction('param',this)")
script(src='/javascripts/onerror.js')

function myFunction(param, me) { 
    console.log(me);
    me.poster = './images/placeholder.jpg'; }

Upvotes: -2

Benny Code
Benny Code

Reputation: 54995

It's good to know that Chrome and Firefox have different onerror callbacks. The error must therefore be mapped. Mozilla uses error.originalTarget.

Here is a sample on how to do it with pure JavaScript:

const file = 'https://samples.ffmpeg.org/MPEG-4/MPEGSolution_jurassic.mp4';

window.fetch(file, {mode: 'no-cors'})
.then((response) => response.blob())
.then((blob) => {
  const url = window.URL.createObjectURL(blob);
  const video = document.createElement('video');      

  video.addEventListener('error', (event) => {
    let error = event;

    // Chrome v60
    if (event.path && event.path[0]) {
      error = event.path[0].error;
    }

    // Firefox v55
    if (event.originalTarget) {
      error = error.originalTarget.error;
    }

    // Here comes the error message
    alert(`Video error: ${error.message}`);

    window.URL.revokeObjectURL(url);
  }, true);

  video.src = url;
  document.body.appendChild(video);
});

The above example maps an incoming error event into a MediaError which can be used to display an error playback message.

Upvotes: 9

therealklanni
therealklanni

Reputation: 652

"onerror" is not a valid event type for <video>

Use "error" instead.

document.getElementsByTagName('video')[0].addEventListener('error', function(event) { ... }, true);

For a complete list of events for <video> go here: https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox

Upvotes: 29

Kenny Ki
Kenny Ki

Reputation: 3430

From Firefox 4 onwards, the 'error' event is dispatched on the <source> element.

And you should add an error handler on the only/last source:

HTML

<video id="vid" controls>
  <source src="dynamicsearch.mp4" type="video/mp4"></source>
  <source src="otherdynamicsearch.avi" type="video/avi"></source>
</video>

JS

var v = document.querySelector('video#vid');
var sources = v.querySelectorAll('source');

if (sources.length !== 0) {
    var lastSource = sources[sources.length-1];

    lastSource.addEventListener('error', function() {
        alert('uh oh');
    });
}

JQuery

$('video source').last().on('error', function() {
    alert('uh oh');
});

AngularJS

You can create an error handling directive (or just use ng-error):

<video id="vid" controls>
  <source src="dynamicsearch.mp4" type="video/mp4"></source>
  <source src="otherdynamicsearch.avi" type="video/avi" ng-error="handleError()"></source>
</video>

Where the error handling directive's link function should do (copied from ng-error):

element.on('error', function(event) {
    scope.$apply(function() {
        fn(scope, {$event:event});
    });
});

Upvotes: 27

ccallendar
ccallendar

Reputation: 988

Try adding the event listener to the tag instead - I think the onerror attribute ("error" event) works on the source tag now, not the video tag.

Upvotes: 2

Related Questions