27

I have a video element:

var video = window.content.document.createElement("video");
video.width = width;
video.height = height; 
video.style.backgroundColor = "black";
window.content.document.body.appendChild(video);

And I'm retrieving it's source via getUserMedia() on Firefox:

window.navigator.getMedia = ( window.navigator.getUserMedia || window.navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia || window.navigator.msGetUserMedia);

window.navigator.getMedia( //constraints, sucessCallback, errorCallback
    {video: true, audio: false},
    function(stream) {
        if (window.navigator.mozGetUserMedia) 
            video.mozSrcObject = stream;
        else 
        {
            var vendorURL = window.URL || window.webkitURL;
            video.src = vendorURL.createObjectURL(stream);
        }
        video.play();
    },
    function(err) {
        console.log("Error: " + err);
    }
);

The problem is I need to know the "active area" of video, and it's returning me 0:

video.onloadedmetadata = function(){

    console.log(this.width + "x" +this.height); 
    console.log(this.videoWidth + "x" +this.videoHeight);
}

So, how can I retrieve the REAL values?: enter image description here

gal007
  • 6,911
  • 8
  • 47
  • 70
  • 1
    When I am running your code using FF, this.width and this.height return the actual dimensions of the video element. Just to test I set video.width and video.height equal to 400 and the first console line returned 400x400. – Sam Oct 10 '13 at 17:19

4 Answers4

28

There are two issues here:

  1. video.videoWidth and video.videoHeight properties weren't getting set as soon as the loadedmetadata event fired. This was a bug in FireFox, which is now fixed (thanks to @Martin Ekblom for pointing out the bug).
  2. The video itself doesn't take up the whole area of the video element, which none of the answers seem to have addressed. Instead, it scales to fit inside the element.

I don't think there's a direct way to get the dimensions of the active area, but after struggling with this myself, I wrote up a solution to calculate it from the values we do know:

function videoDimensions(video) {
  // Ratio of the video's intrisic dimensions
  var videoRatio = video.videoWidth / video.videoHeight;
  // The width and height of the video element
  var width = video.offsetWidth, height = video.offsetHeight;
  // The ratio of the element's width to its height
  var elementRatio = width/height;
  // If the video element is short and wide
  if(elementRatio > videoRatio) width = height * videoRatio;
  // It must be tall and thin, or exactly equal to the original ratio
  else height = width / videoRatio;
  return {
    width: width,
    height: height
  };
}

Essentially, we take the aspect ratio of the video element, the aspect ratio of the video, and the dimensions of video element, and use those to determine the area the video is occupying.

This assumes the video's fitting method hasn't been modified via CSS (not sure if that's even possible at this time, but the spec allows for it). For more details on that and a few other things, see the blog post I wrote ("Finding the true dimensions of an HTML5 video’s active area"), inspired by this question and its lack of complete answers.

It's interesting to note that while the spec specifically mentions the possible edges around a video (letterboxing and pillarboxing), I wasn't able to find any other mentions of it, apart from your question.

Nateowami
  • 1,005
  • 16
  • 23
  • I don't see this being fixed in FireFox Developers edition 51.0a2. After loadedmetadata event fires the videoWidth/videoHeight is being reported for me at 640 x 480, which in my case is wrong. – smatthews1999 Nov 07 '16 at 13:50
  • @smatthews1999 Is the video loaded from a file with a ` – Nateowami Nov 12 '16 at 15:44
  • 2
    @Natewami getUserMedia. I was able to use the clientWidth and clientHeight of the video element. – smatthews1999 Nov 12 '16 at 22:46
  • @Nateowami Your website is dead. For everyone else, you can read his blog post here instead: https://nathanielpaulus.wordpress.com/2016/09/04/finding-the-true-dimensions-of-an-html5-videos-active-area/ – Yay295 Jul 27 '18 at 15:09
  • @Yay295 Yeah, sorry about that. Thanks for posting the link. I need to get it fixed. It went down when I inadvertantly deleted the server. – Nateowami Jul 27 '18 at 20:23
  • Thanks for the video.offset.. didn't known those values – Baptiste Gavalda Jan 03 '19 at 12:50
  • When I first opened video.videoHeight or video.videoWidth in my browser's watch expressions, I was getting either 0 or undefined. I recommend adding the following statement: `setInterval(function(){ console.log( videoDimensions(video) ); }, 3000);` To my surprise I ended up getting the actual dimensions of the video stream. – wgwz Mar 30 '20 at 19:45
  • @wgwz Did you listen for the loadedmetadata event to be fired before accessing the dimensions? – Nateowami Mar 30 '20 at 23:32
  • @Nateowami I did not but will keep that in mind as I proceed. You might want to consider updating: https://stackoverflow.com/a/19425152/4028706 (Which I up-voted already because I recognized it's probably what I'm actually looking for). – wgwz Mar 31 '20 at 16:21
11

You should add a loadeddata event listener to the video, and try to read the size then, which is when enough information about the stream has been decoded and the dimensions can be accurately determined.

Still, it sometimes takes a bit in some cases to get the dimensions ready, so you might want to try several times (with delay) until it works.

That might be why it is not working for you but it's working for Sam.

Here's how I check the video size, with several attempts if required, in my gumhelper library: https://github.com/sole/gumhelper/blob/master/gumhelper.js#L38

Notice how we try several times and if it doesn't work we "give up" and default to 640x480.

sole
  • 2,057
  • 2
  • 17
  • 18
  • I was having the same problem then changed to `loadeddata` from `loadedmetadata` and it worked. Thanks! – dariru Jul 11 '17 at 00:05
2

"loadeddata" should only fire once. It's better to use "timeupdate" to repeatedly check if the video width and height have been set, in particular with getUserMedia where you don't really pause the video, but go straight into playback.

Silvia
  • 543
  • 5
  • 5
1

Actually this seems to be a bug in FF: https://bugzilla.mozilla.org/show_bug.cgi?id=926753