Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

<video> and onloadedmetadata-event

I'd like to use the dimensions of a HTML5 video element in JavaScript. The video-tag itself does not have any dimensions set, so I expect it to scale to the size of the video (which it does). My markup looks like this:

<video id="viddy" autoplay>
<source src="myvideo.mp4" type='video/mp4; codecs="avc1.42E01E"' />
</video>

When I just use jQuery to get the element's height() and/or width() I will get a default value of 300 as it will not wait for the video to load. So what I found out on the web (here and here) is that I should be waiting for the onloadedmetadata-event. So I am trying to do the following in my JS:

var video = document.getElementById('viddy');
video.onloadedmetadata = function(e){
var dimensions = [video.videoWidth, video.videoHeight];
alert(dimensions);
} 

Yet, the event will never fire (although the video will load and play) and I'll never get my dimensions. Same happens with a jQuery-bind('load', and every other way I could think of. Any idea? Thanks.

like image 432
m90 Avatar asked Jan 24 '12 08:01

m90


2 Answers

Put your code into a function at the end of your HTML head (e.g. called init) and bind it to the DOMContentLoaded event:

function init() {
    var video = document.getElementById('viddy');
    video.onloadedmetadata = function(e){
        var dimensions = [video.videoWidth, video.videoHeight];
        alert(dimensions);
    }
}

document.addEventListener("DOMContentLoaded", init, false);
<video id="viddy" autoplay>
    <source src="http://media.w3.org/2010/05/sintel/trailer.webm" type='video/webm' />
</video>

For Chrome

You should change adding the listener to:

video.addEventListener('loadedmetadata', function(e){

function init() {
    var video = document.getElementById('viddy');
    video.addEventListener('loadedmetadata', function(e){
        var dimensions = [video.videoWidth, video.videoHeight];
        alert(dimensions);
    });
}

document.addEventListener("DOMContentLoaded", init, false);
<video id="viddy" autoplay>
    <source src="http://media.w3.org/2010/05/sintel/trailer.webm" type='video/webm' />
</video>

With jQuery

$(document).ready(function() {
    $('#viddy').on('loadedmetadata', function() {
        var dimensions = [this.videoWidth, this.videoHeight];
        alert(dimensions);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<video id="viddy" autoplay>
    <source src="http://media.w3.org/2010/05/sintel/trailer.webm" type='video/webm' />
</video>
like image 50
scessor Avatar answered Nov 10 '22 00:11

scessor


TL;DR Adding loadedmetadata listener after DOMContentLoaded will not guarantee the listener will be added before loadedmetadata event is fired, however, adding the event listener to an element created before the video element with src (e.g. document) and in capture phase or adding the event listener to the video element inline as an attribute will.

The dimensions of the video file will be loaded with the video file metadata. So you will need to wait loadedmetadata event to be fired then you will be able to get dimensions from videoWidth and videoHeight properties of the html video element, where they will be set and ready, these you got all correct.

Note for DOMContentLoaded: Adding the event listener after the dom content loaded event will only guarantee the exsitence of the html element in first place to be able to add an event listener on. That is the correct method of doing that thing and here it is not the issue. On the contrary, it is the cause that the issue in question has been run into: The element's existence, with a src attribute to load data, before the event listener added is kind of sort of the reason event listener is prone to miss the event it should catch and handle.

By the time you add this event listener to the video element, the event might have already happened, propagated and ended, since you add the event handler after the video element created with its src attribute. It will start loading video hence video metadata. If it is slow enough to do that your code will get a chance to be added to the video element before loadedmetadata event ended after video metadata has been loaded.

  1. You need to register the event handler before the video element starts loading its video file. Here it is by with src attribute, so you need to add the handler before or same time you add the src attribute.

    You can add an inlined event attribute on the video element itself: <video src="some-video-url" onloadedmetadata="somehandler">. Here not sure if the handler should be defined inline too or just referencing work too.

  2. You can add the event listener before the video element is created with a src attribute. That means you need to add it to another ancestor html element that is created before the video element is created wth a src attribute. Also that event does not bubble but captures. So, you have to add it for capture phase of the event and to a ancestor element, e.g. document.

document.addEventListener("loadedmetadata", function(e){
    // if necesssary one can add custom logic here for example to check if the event target is the element we are listening the event for with event.target
    var video = e.target;
    var dimensions = [video.videoWidth, video.videoHeight];
    alert(dimensions);
}, true);
<video id="viddy" autoplay>
    <source src="http://media.w3.org/2010/05/sintel/trailer.webm" type='video/webm' />
</video>
like image 26
sçuçu Avatar answered Nov 10 '22 01:11

sçuçu