Browse Source

Fixed mini video sizing in Firefox by implementing object-fit shim.

Updated Modernizr to latest version with object-fit detection.
pull/31/head
Simon Eisenmann 12 years ago
parent
commit
2146bc03b7
  1. 5
      src/styles/components/_audiovideo.scss
  2. 779
      static/js/libs/modernizr.js
  3. 303
      static/js/services/videolayout.js

5
src/styles/components/_audiovideo.scss

@ -45,7 +45,7 @@
} }
} }
.mainScreenshare #audiovideo { .mainScreenshare #audiovideo {
@include breakpt($breakpoint-video-medium, max-width, only screen) { @include breakpt($breakpoint-video-medium, max-width, only screen) {
display: none; display: none;
} }
@ -97,6 +97,9 @@
transform: scale(-1, 1); transform: scale(-1, 1);
z-index: 2; z-index: 2;
} }
video {
object-fit: contain;
}
} }
.audiovideo { .audiovideo {

779
static/js/libs/modernizr.js

File diff suppressed because it is too large Load Diff

303
static/js/services/videolayout.js

@ -18,17 +18,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
define(["jquery", "underscore"], function($, _) { define(["jquery", "underscore", "modernizr"], function($, _, Modernizr) {
var dynamicCSSContainer = "audiovideo-dynamic"; var dynamicCSSContainer = "audiovideo-dynamic";
var renderers = {}; var renderers = {};
var getRemoteVideoSize = function(videos, peers) { var getRemoteVideoSize = function(videos, peers) {
var size = { var size = {
width: 1920, width: 1920,
height: 1080 height: 1080
} }
if (videos.length) { if (videos.length) {
if (videos.length === 1) { if (videos.length === 1) {
var remoteVideo = peers[videos[0]].element.find("video").get(0); var remoteVideo = peers[videos[0]].element.find("video").get(0);
size.width = remoteVideo.videoWidth; size.width = remoteVideo.videoWidth;
@ -37,34 +37,36 @@ define(["jquery", "underscore"], function($, _) {
} }
} }
return size; return size;
} }
// videoLayout var objectFitSupport = Modernizr["object-fit"] && true;
return ["$window", function($window) {
// Video layout with all videos rendered the same size. // videoLayout
var OnePeople = function(container, scope, controller) { return ["$window", function($window) {
};
OnePeople.prototype.name = "onepeople"; // Video layout with all videos rendered the same size.
var OnePeople = function(container, scope, controller) {
};
OnePeople.prototype.render = function(container, size, scope, videos, peers) { OnePeople.prototype.name = "onepeople";
if (this.closed) { OnePeople.prototype.render = function(container, size, scope, videos, peers) {
return;
} if (this.closed) {
return;
}
var videoWidth; var videoWidth;
var videoHeight; var videoHeight;
if (videos.length) { if (videos.length) {
var remoteSize = getRemoteVideoSize(videos, peers); var remoteSize = getRemoteVideoSize(videos, peers);
videoWidth = remoteSize.width; videoWidth = remoteSize.width;
videoHeight = remoteSize.height; videoHeight = remoteSize.height;
} }
if (!videoWidth) { if (!videoWidth) {
// XXX(longsleep): Improve this condition - its crap to compare style opacity (tm)! // XXX(longsleep): Improve this condition - its crap to compare style opacity (tm)!
if (scope.localVideo.style.opacity === '1') { if (scope.localVideo.style.opacity === '1') {
videoWidth = scope.localVideo.videoWidth; videoWidth = scope.localVideo.videoWidth;
videoHeight = scope.localVideo.videoHeight; videoHeight = scope.localVideo.videoHeight;
@ -92,6 +94,17 @@ define(["jquery", "underscore"], function($, _) {
//console.log("resize", container, videos.length, aspectRatio, innerHeight, innerWidth); //console.log("resize", container, videos.length, aspectRatio, innerHeight, innerWidth);
var extraCSS = {}; var extraCSS = {};
if (!objectFitSupport) {
// Make mini video fit into available space on browsers with no object-fit support.
// http://caniuse.com/object-fit
var aspectRatioLocal = scope.localVideo.videoWidth/scope.localVideo.videoHeight;
extraCSS = {
".renderer-onepeople .miniVideo": {
width: ($(scope.mini).height()*aspectRatioLocal)+"px"
}
};
}
if (videos.length === 1) { if (videos.length === 1) {
var newVideoWidth = innerWidth < aspectRatio * innerHeight ? innerWidth : aspectRatio * innerHeight; var newVideoWidth = innerWidth < aspectRatio * innerHeight ? innerWidth : aspectRatio * innerHeight;
var newVideoHeight = innerHeight < innerWidth / aspectRatio ? innerHeight : innerWidth / aspectRatio; var newVideoHeight = innerHeight < innerWidth / aspectRatio ? innerHeight : innerWidth / aspectRatio;
@ -124,100 +137,100 @@ define(["jquery", "underscore"], function($, _) {
*/ */
container.style.width = newContainerWidth + "px"; container.style.width = newContainerWidth + "px";
container.style.left = ((innerWidth - newContainerWidth) / 2) + 'px'; container.style.left = ((innerWidth - newContainerWidth) / 2) + 'px';
extraCSS = { extraCSS = $.extend(extraCSS, {
".renderer-onepeople .remoteVideos": { ".renderer-onepeople .remoteVideos": {
">div": { ">div": {
width: singleVideoWidth+"px", width: singleVideoWidth+"px",
height: singleVideoHeight+"px" height: singleVideoHeight+"px"
} }
} }
}; });
} }
$.injectCSS(extraCSS, { $.injectCSS(extraCSS, {
truncateFirst: true, truncateFirst: true,
containerName: dynamicCSSContainer containerName: dynamicCSSContainer
}); });
}; };
OnePeople.prototype.close = function(container, scope, controller) {
this.closed = true;
}; OnePeople.prototype.close = function(container, scope, controller) {
this.closed = true;
// Smally inherits from OnePeople };
var Smally = function(container, scope, controller) {
// Call super.
OnePeople.call(this, container, scope, controller);
}
Smally.prototype = Object.create(OnePeople.prototype);
Smally.prototype.constructor = Smally;
Smally.prototype.name = "smally";
// A view with one selectable large video. The others are small.
var ConferenceKiosk = function(container, scope, controller) {
this.remoteVideos = $(container).find(".remoteVideos"); // Smally inherits from OnePeople
this.bigVideo = $("<div>").addClass("bigVideo").get(0); var Smally = function(container, scope, controller) {
this.remoteVideos.before(this.bigVideo); // Call super.
OnePeople.call(this, container, scope, controller);
this.big = null; }
this.remoteVideos.on("click", ".remoteVideo", _.bind(function(event) { Smally.prototype = Object.create(OnePeople.prototype);
if ($(event.currentTarget).hasClass("remoteVideo")) { Smally.prototype.constructor = Smally;
event.stopPropagation(); Smally.prototype.name = "smally";
this.makeBig($(event.currentTarget));
} // A view with one selectable large video. The others are small.
}, this)); var ConferenceKiosk = function(container, scope, controller) {
this.remoteVideos = $(container).find(".remoteVideos");
this.bigVideo = $("<div>").addClass("bigVideo").get(0);
this.remoteVideos.before(this.bigVideo);
this.big = null;
this.remoteVideos.on("click", ".remoteVideo", _.bind(function(event) {
if ($(event.currentTarget).hasClass("remoteVideo")) {
event.stopPropagation();
this.makeBig($(event.currentTarget));
}
}, this));
}; };
ConferenceKiosk.prototype.name = "conferencekiosk"; ConferenceKiosk.prototype.name = "conferencekiosk";
ConferenceKiosk.prototype.makeBig = function(remoteVideo) { ConferenceKiosk.prototype.makeBig = function(remoteVideo) {
if (this.big === remoteVideo) { if (this.big === remoteVideo) {
return; return;
} }
if (this.big) { if (this.big) {
// Add old video back. // Add old video back.
this.big.insertAfter(remoteVideo); this.big.insertAfter(remoteVideo);
this.big.find("video").get(0).play(); this.big.find("video").get(0).play();
} }
this.big = remoteVideo; this.big = remoteVideo;
remoteVideo.appendTo(this.bigVideo); remoteVideo.appendTo(this.bigVideo);
remoteVideo.find("video").get(0).play(); remoteVideo.find("video").get(0).play();
}; };
ConferenceKiosk.prototype.render = function(container, size, scope, videos, peers) { ConferenceKiosk.prototype.render = function(container, size, scope, videos, peers) {
var big = this.big; var big = this.big;
if (big) { if (big) {
var currentbigpeerid = this.big.data("peerid"); var currentbigpeerid = this.big.data("peerid");
if (!peers[currentbigpeerid]) { if (!peers[currentbigpeerid]) {
console.log("Current big peer is no longer there", currentbigpeerid); console.log("Current big peer is no longer there", currentbigpeerid);
this.big = big = null; this.big = big = null;
} }
} }
if (!big) { if (!big) {
if (videos.length) { if (videos.length) {
this.makeBig(peers[videos[0]].element); this.makeBig(peers[videos[0]].element);
this.bigVideo.style.opacity = 1; this.bigVideo.style.opacity = 1;
} }
} }
var remoteSize = getRemoteVideoSize(videos, peers); var remoteSize = getRemoteVideoSize(videos, peers);
var aspectRatio = remoteSize.width/remoteSize.height; var aspectRatio = remoteSize.width/remoteSize.height;
var innerHeight = size.height - 110; var innerHeight = size.height - 110;
var innerWidth = size.width; var innerWidth = size.width;
var extraCSS = {}; var extraCSS = {};
var bigVideoWidth = innerWidth < aspectRatio * innerHeight ? innerWidth : aspectRatio * innerHeight; var bigVideoWidth = innerWidth < aspectRatio * innerHeight ? innerWidth : aspectRatio * innerHeight;
var bigVideoHeight = innerHeight < innerWidth / aspectRatio ? innerHeight : innerWidth / aspectRatio; var bigVideoHeight = innerHeight < innerWidth / aspectRatio ? innerHeight : innerWidth / aspectRatio;
this.bigVideo.style.width = bigVideoWidth + 'px'; this.bigVideo.style.width = bigVideoWidth + 'px';
@ -225,7 +238,7 @@ define(["jquery", "underscore"], function($, _) {
// Make space for own video on the right if width goes low. // Make space for own video on the right if width goes low.
if (((size.width - (videos.length-1) * 192) / 2) < 192) { if (((size.width - (videos.length-1) * 192) / 2) < 192) {
extraCSS = { extraCSS = {
".renderer-conferencekiosk .remoteVideos": { ".renderer-conferencekiosk .remoteVideos": {
"margin-right": "192px", "margin-right": "192px",
"overflow-x": "auto", "overflow-x": "auto",
@ -239,65 +252,65 @@ define(["jquery", "underscore"], function($, _) {
containerName: dynamicCSSContainer containerName: dynamicCSSContainer
}); });
}; };
ConferenceKiosk.prototype.close = function(container, scope, controller) { ConferenceKiosk.prototype.close = function(container, scope, controller) {
this.closed = true; this.closed = true;
if (this.big) { if (this.big) {
this.remoteVideos.append(this.big); this.remoteVideos.append(this.big);
this.big.find("video").get(0).play(); this.big.find("video").get(0).play();
} }
this.big = null; this.big = null;
this.bigVideo.remove() this.bigVideo.remove()
this.bigVideo = null; this.bigVideo = null;
this.remoteVideos = null; this.remoteVideos = null;
}; };
// Register renderers. // Register renderers.
renderers[OnePeople.prototype.name] = OnePeople; renderers[OnePeople.prototype.name] = OnePeople;
renderers[Smally.prototype.name] = Smally; renderers[Smally.prototype.name] = Smally;
renderers[ConferenceKiosk.prototype.name] = ConferenceKiosk; renderers[ConferenceKiosk.prototype.name] = ConferenceKiosk;
// Public api. // Public api.
var current = null; var current = null;
return { return {
update: function(name, size, scope, controller) { update: function(name, size, scope, controller) {
var videos = _.keys(controller.peers); var videos = _.keys(controller.peers);
var peers = controller.peers; var peers = controller.peers;
var container = scope.container; var container = scope.container;
var layoutparent = scope.layoutparent; var layoutparent = scope.layoutparent;
if (!current) { if (!current) {
current = new renderers[name](container, scope, controller) current = new renderers[name](container, scope, controller)
console.log("Created new video layout renderer", name, current); console.log("Created new video layout renderer", name, current);
$(layoutparent).addClass("renderer-"+name); $(layoutparent).addClass("renderer-"+name);
return true; return true;
} else { } else {
if (current.name !== name) { if (current.name !== name) {
current.close(container, scope, controller); current.close(container, scope, controller);
$(container).removeAttr("style"); $(container).removeAttr("style");
$(layoutparent).removeClass("renderer-"+current.name); $(layoutparent).removeClass("renderer-"+current.name);
current = new renderers[name](container, scope, controller) current = new renderers[name](container, scope, controller)
$(layoutparent).addClass("renderer-"+name); $(layoutparent).addClass("renderer-"+name);
console.log("Switched to new video layout renderer", name, current); console.log("Switched to new video layout renderer", name, current);
return true; return true;
} }
} }
return current.render(container, size, scope, videos, peers); return current.render(container, size, scope, videos, peers);
}, },
register: function(name, impl) { register: function(name, impl) {
renderers[name] = impl; renderers[name] = impl;
}, },
layouts: function() { layouts: function() {
return _.keys(renderers); return _.keys(renderers);
} }
} }
}]; }];
}); });
Loading…
Cancel
Save