Skip to content

Instantly share code, notes, and snippets.

@xuan9
Last active September 1, 2016 13:01
Show Gist options
  • Select an option

  • Save xuan9/9196fc96b0c4c19004859f36c8c74bd7 to your computer and use it in GitHub Desktop.

Select an option

Save xuan9/9196fc96b0c4c19004859f36c8c74bd7 to your computer and use it in GitHub Desktop.
auto layout html5 videos for webrtc call or meeting
var layoutVideosTimer, hideVideoMenuTimer;
function showVideoMenuForAWhile() {
console.debug("showVideoMenuForAWhile");
clearTimeout(hideVideoMenuTimer);
showVideosMenu();
hideVideoMenuTimer = setTimeout(hideVideosMenu, 30000);
}
function showVideosMenu() {
$(".video-call-actions").css("visibility", "visible");
}
function hideVideosMenu() {
$(".video-call-actions").css("visibility", "hidden");
}
// $(".all-videos").on("loadedmetadata", "video", function () {
// console.debug("loadedmetadata");
// relayoutVideos();
// })
function relayoutVideos(delay) {
if(!delay) delay = 550;
clearTimeout(layoutVideosTimer);
layoutVideosTimer = setTimeout(layoutVideos, delay);
}
function getVideoRatio(video) {
return video.videoHeight ? video.videoWidth / video.videoHeight : 4 / 3;
}
function layoutVideos() {
var SAMLL_VIDEO_SIZE_PERCENT = 20;
var screenWidth = $(".all-videos").width();
var screenHeight = $(".all-videos").height();
var screenRatio = screenWidth / screenHeight;
// console.debug("screenRatio: " + screenRatio + ", getVideoRatio: " + getVideoRatio($("video")));
var largeVideos = $('.large-videos > video');
var largeVideosCount = largeVideos.size();
var maxLargeVideoRatio = getMaxRatio(largeVideos);
// console.debug("maxLargeVideoRatio: " + maxLargeVideoRatio);
var smallVideos = $('.small-videos > video');
var smallVideosCount = smallVideos.size();
if (largeVideosCount == 0 && smallVideosCount == 0) return;
$(".small-videos").css({ "flex-grow": 1,"justify-content":"", "align-items":"","position": "","width":"","height":"","right":"","bottom":""});
$(".large-videos").css({ "flex-grow": 4, "justify-content": "","align-items":""});
if (screenRatio < maxLargeVideoRatio) {
$(".all-videos").css("flex-direction", "column");
} else {
$(".all-videos").css("flex-direction", "row");
}
if (smallVideosCount == 0) {
$('.small-videos').css("display", "none");
} else {
$('.small-videos').css("display", "flex");
}
if (largeVideosCount == 0) {
$('.large-videos').css("display", "none");
} else {
$('.large-videos').css("display", "flex");
}
if (smallVideosCount > 0 && largeVideosCount == 1) {
//if set large vidoes flex = 1, now calc small flex:
screenRatio - maxLargeVideoRatio
var sflex;
if(screenRatio<maxLargeVideoRatio){
sflex = (1/screenRatio - 1/maxLargeVideoRatio)*maxLargeVideoRatio
}else{
sflex =(screenRatio - maxLargeVideoRatio)/ maxLargeVideoRatio;
}
if (sflex > 1) sflex = 1 / sflex;
if (sflex < 0.1 || (sflex * screenWidth < 200 && sflex < 0.25)) {
$(".small-videos").css({"justify-content": "flex-end","align-items":"flex-end","position": "absolute","width":(screenWidth/5)+"px","height":screenHeight+"px","right":"0px","bottom":"0px"});
$(".large-videos").css({"justify-content": "flex-start","align-items":"flex-start"});
}
$(".small-videos").css("flex-grow", parseInt(sflex * 10000));
$(".large-videos").css("flex-grow", 10000);
console.info("sflex: "+sflex);
}
if (largeVideosCount > 0) {
layoutGrid(largeVideos.parent());
}
if (smallVideosCount > 0) {
layoutGrid(smallVideos.parent());
}
function getMaxRatio(videos) {
return Math.max(...$.map(videos, getVideoRatio));;
}
function layoutGrid(container) {
var count = $("video", container).size();
var videoRatio = getMaxRatio($('video', container));
var containerWidth = container.width(), containerHeight = container.height();
var cells = getGrid(videoRatio, containerWidth / containerHeight, count);
console.info("layout: " + cells[0] + " X " + cells[1]);
var actualRows = cells[1] == 1 ? count : cells[0];
var actualCols = cells[0] == 1 ? count : cells[1];
var width = parseInt(containerWidth / actualCols);
var height = parseInt(width / videoRatio);
if (height * cells[0] > containerHeight) {
height = parseInt(containerHeight / actualRows);
width = parseInt(height * videoRatio);
}
// console.debug("video size: " + (width / containerWidth * 100) + "% x " + (height / containerHeight * 100) + "%");
// console.debug("video size: " + width + "px x " + height + "px");
$('video', container).css({
"width": width + "px",
"height": height + "px"
});
}
function getGrid(ratio, containerRatio, count) {
var rate = containerRatio / ratio;
var isWider = rate >= 1;
if (rate < 1) {
rate = 1 / rate;
}
var widerFactor = Math.round(rate);
for (var rows = 1; rows <= count; rows++) {
var cols = widerFactor * (rows - 1);
while (rows * cols < count && cols < (rate * (rows + 1) - 1)) {
cols++;
}
if (rows * cols >= count) {
return isWider ? [rows, cols] : [cols, rows];
}
}
}
}
$(window).resize(relayoutVideos);
<div style="height:100%;width:100%; display:flex;flex:1 " class='all-videos' onmousemove="showVideoMenuForAWhile()">
<div style="flex:4;
align-content: center;
align-items: center;
justify-content: center;
justify-items: center;
display: flex;flex-wrap:wrap;background-color:white;flex-direction:row;margin:5px" class='large-videos'>
<video autoplay onloadedmetadata='relayoutVideos()'></video>
</div>
<div style="flex:1;display:flex;flex-direction:row;flex-wrap:wrap; justify-content: center; align-content: center;
align-items: center;
justify-content: center;
justify-items: center; margin:5px" class='small-videos'>
<video autoplay onloadedmetadata='relayoutVideos()'></video>
</div>
<div class="video-call-actions" style="visibility:hidden">
</div>
</div>
<script>
navigator.webkitGetUserMedia({
video: true,
audio: false
},
function(stream) {
var vs = $("video");
vs.each(i=>{
$(vs[i]).attr('src', URL.createObjectURL(stream));
});
},
function(error) {
console.log("Video capture error: ", error.code);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment