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?:
There are two issues here:
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).
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.
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.
"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.
Actually this seems to be a bug in FF:
https://bugzilla.mozilla.org/show_bug.cgi?id=926753
Related
I've tried several answers found here.
This code works in Firefox and outputs the right size, but not in Chrome or IE.
Mainly I am trying to get just the width.
Example
I have the output the width under the video using 3 examples.
https://jsfiddle.net/a8a1o8k2/
JavaScript
https://stackoverflow.com/a/4129189/6806643
var vid1 = document.getElementById("video");
vid1.videoHeight; // returns the intrinsic height of the video
vid1.videoWidth; // returns the intrinsic width of the video
returns 0
https://stackoverflow.com/a/9333276/6806643
var vid2 = document.getElementById("video");
vid2.addEventListener( "loadedmetadata", function (e) {
var width = this.videoWidth,
height = this.videoHeight;
}, false );
returns 0
https://stackoverflow.com/a/16461041/6806643
var vid3 = document.getElementById("video");
var videotag_width = vid3.offsetWidth;
var videotag_height = vid3.offsetHeight;
sometimes returns the correct value
sometimes returns 300 (default player size if no video source)
Edit: improved solution after I have actually read the crossbrowser issue.
The solution below should work on both Chrome and Firefox. The issue is that Firefox treats readyState differently than Chrome.
var vid2 = document.getElementById("video");
vid2.addEventListener("loadedmetadata", getmetadata);
if (vid2.readyState >= 2) {
getmetadata(vid2);
}
function getmetadata(){
document.getElementById('output2').innerHTML = "Test 2: " + vid2.videoWidth;
}
Updated JSFiddle
If you are trying to define the size of your video with java script im not sure what you are actually trying to do, althought it seems to me like you just want it to be customizable like this example.
If we presume the video was embedded the code below might do the trick
// Find all YouTube videos
var $allVideos = $("iframe[src^='//www.youtube.com']"),
// The element that is fluid width
$fluidEl = $("body");
// Figure out and save aspect ratio for each video
$allVideos.each(function() {
$(this)
.data('aspectRatio', this.height / this.width)
// and remove the hard coded width/height
.removeAttr('height')
.removeAttr('width');
});
// When the window is resized
$(window).resize(function() {
var newWidth = $fluidEl.width();
// Resize all videos according to their own aspect ratio
$allVideos.each(function() {
var $el = $(this);
$el
.width(newWidth)
.height(newWidth * $el.data('aspectRatio'));
});
// Kick off one resize to fix all videos on page load
}).resize();
You can also refer to this page how it actually works and there is also an CSS and HTML example of dynamic video rescaling as well:
https://css-tricks.com/NetMag/FluidWidthVideo/Article-FluidWidthVideo.php
I am using a html5 video on my website. I want it to play only when in view and pause otherwise.
I am also using javascript to have a play/pause button on it.
I was able to use both the features on one site easily and the video was the first element on the site. However this time it is the second div
I feel like there is a conflict because of the same element being targetted or something going wrong that I just can't seem to understand
In this case the video autoplays when I open the site, and when I scroll to the actual video, it stops(pauses)! Can anyone see what I am doing wrong ?
<script>
var videos = document.getElementsByTagName("video"), fraction = 0.8;
function checkScroll() {
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction) {
video.play();
} else {
video.pause();
}
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
</script>
I have attached a fiddle
http://jsfiddle.net/5wZLL/12/
other plugins that I have used on this site :
Stellar.Js
FlexSlider
SmoothScroll
The code you've posted here is mostly fine and should work more or less correctly, but here are a few things to look out for:
Remove the autoplay attribute completely from your video element. Setting it to "0" does not turn it off. Any value at all for autoplay will make it true.
You'll probably want to call checkScroll one time at page load to cover the initial window state, in case the video is in view initially. Otherwise, it won't start until you scroll at least one time.
The math here assumes that your video is positioned statically, with no parent elements that have CSS position as fixed, relative, or absolute. If you need to do that, you may need to modify the position calculation slightly. But this is not a problem in the jsfiddle you posted.
Based on the value of fraction, the video will only play if 80% of it is visible. If the browser window is smaller than 80% of the area of the video element, it will never play no matter where you scroll. You may want to adjust the value compared to visible to account for that, or you can leave it as is. Up to you.
Make sure the video is actually being loaded. If the file is not found or if the network is too slow, the play state may be set but you may not see it playing. You might want to have some other visual indicator of the play state, using the play and pause events and the paused property.
Finally, if you're going to have a separate pause/play button, you'll want to use that to set some external variable that disables the scrolling logic so they don't conflict.
Based on your description, I suspect that you want to pay close attention to 1. and 3., as they will likely solve your problem.
Update:
It looks like your problem is 3. When you have parent elements that are not positioned statically, offsetTop and offsetLeft are not sufficient to get the position of your video element within the page. You need to loop through all the ancestor elements that can affect the position, like this:
parent = video;
while (parent && parent !== document.body) {
x += parent.offsetLeft;
y += parent.offsetTop;
parent = parent.offsetParent;
}
Here's a working example:
http://jsbin.com/qekat/1/edit
I am resizing my videojs player on window.resize
The black "video container", if you will, gets resized, but the actual video, stays the same size. It will now shrink inside its container (resized), or overlap its container (resized to smaller).
A page reload rebuilds the player and it plays within its new bounds.
How do I tell it to re-initialize on the new size, without a page reload.
What makes this extra interesting, is that it seems to work when running on my localhost, development web-server. Running it on on-line hosting, renders above issues.
function redrawVideoPlayer() {
var newHeight
var newWidth
newWidth = $(window).width() * 0.33;
newHeight = newWidth * 0.75;
$('#ytvidplayer').css('height', newHeight);
$('#ytvidplayer').css('width', newWidth);
//set related video div height eual to video height
$('#related_vids_scroller').css('height', newHeight);
var myVideo = videojs('ytvidplayer');
myVideo.width(newWidth).height(newHeight);
myVideo.load();
myVideo.play();
}
I think this is a cool way to maintain your video's aspect ratio even after resizing events. Let's break it down:
You'll need a resize function that takes in the known aspect ratio of your video (in my code it is the 'dimensionsize' parameter passed into a resizeVideoJS() function as a string like so: '1920x760'. The other parameters are the initialized videoJS video object 'video' and the browser window object 'win'.) I'm passing in parameters because my code is broken into two modules, one module that handles action and helper functions - like resizeVideo or togglePoster, etc. - and the other is a widget that initializes and binds events to the video object. The resizeVideoJS() function is defined in the actions module and called in the widget.
So here is the code:
function resizeVideoJS( video, win, dimensionSize ) {
var width,
aspectRatio;
video.pause();
aspectRatio = _calculateAspectratio( dimensionSize );
width = video.width() <= 0 ? win.innerWidth : video.width();
video.height( width * aspectRatio );
}
function _calculateAspectratio( videoDimensionsStr ) {
var parts;
parts = videoDimensionsStr.split( 'x' );
return parts[ 1 ] / parts[ 0 ];
}
Next, I simply create a _resizeCallbackHelper() function in my widget that checks against resize events and fires off whenever they occur (although I also use Lodash's throttle function with it because resize events can fire off rapidly).
function _resizeCallbackHelper( ) {
if ( config[ screensize ].dimensions && win.innerWidth !== screen.windowWidth ) {
videoPoster ? dom.hide( videoPoster ) : false;
screen = videoAction.setScreenSizeInfoVariables( win );
_setVideoDimensions();
videoAction.resizeVideoJS( video, win, dimensionSize );
config[ screensize ].poster ? _setVideoPoster() : false;
}
}
A little explanation about the above _resizeCallbackHelper() function:
config[screensize] is a configuration object I create from data-settings="" inside the video tag in my html. This has all the settings of the video, like video.muted() or even video.dimensions. I made this as an object of nested objects, so that it looks like { Desktop: { dimensions: '1920x760', muted: true }, Mobile : { dimensions: '760x320', muted: false } }. But you can do it however you want. I just like this because it allows for custom settings across different devices. I define my dimensions and screensize using the below _setVideoDimensions() function where screen is an object with booleans telling which screen type the video is loading in. As you can see config[screensize] becomes either config['MOBILE'] or config['TABLET'] or config['DESKTOP'] in order to load those settings:
function _setVideoDimensions() {
screensize = screen.isHandheld ? ( screen.isMobile || screen.isLargeMobileDevice ? 'MOBILE' : 'TABLET' ) : 'DESKTOP';
dimensionSize = config[ screensize ].dimensions || desktop.dimensions;
}
The 'win.innerWidth !== screen.windowWidth' in the resize helper function is a check against resize events that fire in tablets when scrolling, even though the screen does not actually resize. This is a good thing to understand and know happens when scrolling in most tablets. Then I fire off some events that need to happen on resize, including the resizeVideoJS() function from the videoAction module - and notice I make sure to set the new video dimensions first with _setVideoDimensions().
Finally, I make sure to call the resize helper function on the resize event like so:
resizeCallback = throttle( _resizeCallbackHelper, 2000 );
$.on( 'window', 'resize', resizeCallback );
I hope this helps anyone coming across this problem.
The YouTube API docs define the minimum size of an embedded player t to be 200px by 200px (link).
To allow room for critical player functionality, players must be at least 200px by 200px.
My testing has lead me to the conclusion that this is true. If I try to play a video in a player which is smaller than the minimum size, I get an error message which says "Video player is too small." and the video will not play.
However, smaller players are possible. SwitchCam, for example, uses them on pages like this one.
I've tried reducing the player size by setting it's height and width attributes, by using it's style attribute and by wrapping it in a containing element which has it's height and width set. None of these options appear to work.
What else can I try to reduce the size of the player?
EDIT
It appears that some videos will play in really small players but others will not. If you're going to test a potential solution, please use this video ID: -rMTExNTx2s
It's appears there is a restriction on some video which don't allow embeding video on size inferior to 200*200 (px). This restriction is not applied for all video (maybe older than last update youtube API, i don't know).
After some tests, this restriction is applied when youtube player readystate changed to status: PlayerState.PLAYING (evt.data === 1)
So as a basic workaround, you could change size of iframe 'on the fly' after the satus has been updated, see demo&code below:
DEMO
var player,
myWidth = "114px",
myHeight = "65px";
function onYouTubePlayerAPIReady() {
player = new YT.Player('testVideo', {
height: myWidth,
width: myHeight,
videoId: '-rMTExNTx2s',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
},
playerVars: {
controls:0,
showinfo:0
}
});
}
function onPlayerStateChange(evt) {
if (evt.data == -1) {
evt.target.a.width = "200px";
evt.target.a.height = "200px";
}
else if (evt.data == 1) {
evt.target.a.className = "";
evt.target.a.width = myWidth;
evt.target.a.height = myHeight;
done = true;
}
}
As you can ssee in this DEMO, i set an hidden class with css .hidden{opacity:0}. This is used to hide player before the video is loaded. Using display:none; doesn't work, its surely an other API restriction.
Still in this DEMO, you have to wait until the video has started to play to see the player appears.
You have now to find the best workaround which could fit your needs, using e.g a thumbnail image and moving from negative offset player to wished location when readystate has changed, hope you got the idea.
Not the most elegant solution, but have you thought about actually scaling down a larger player with the CSS3 transform: scale() property? Beware it's not supported in IE < 9.
The main reason not to do this, though, is that you'll be reducing the size of the UI controls which in turn reduces usability.
I wrote a simple javascript code to load an image and alert its width and height, but I found its width and height will different between desktop and iPad.
For example, I load an image that size is 8000*1845, browser shows image width is 8000 and height is 1845. Therefore, on iPad, browser show image width is 2000 and height is 462.
The other image is 2600 * 2400, browser shows image width is 2000 and height is 2400, but it shows image width is 1300 and height is 1200.
I don't know whether I misunderstanding something or not. Will iOS downsize the image?
Anybody knows? Please tell me what happen?
var img8000 = new Image();
img8000.src = '8000_1845.jpg';
img8000.onload = function () {
alert(img8000.width + ' ' + img8000.height);
}
var img2600 = new Image();
img2600.src = '2600_2400.jpg';
img2600.onload = function () {
alert(img2600.width + ' ' + img2600.height);
}
When you get the image's height or width using this.width or when using jQuery's $(this).width() you are actually getting its current dimensions. If the image is scaled up or down, then the values you get will not match the actual source image's dimensions.
I made an example you can play with. It is pre-written to use onclick, but if you remove those onclick attributes and uncomment the jQuery code, you'll find it alerts the same values.
You should attempt to avoid image scaling by placing the image somewhere on the page where the CSS does not affect its size (as a test, try making a blank page containing just the image), and remove any custom height/width attributes if they exist.
Otherwise, if the scaling is done natively by the iPad Safari browser, there is little you can do.