mirror of
https://github.com/TheGreyDiamond/open360viewer.git
synced 2025-07-17 20:33:48 +02:00
Merge pull request #1 from TheGreyDiamond/video-support
Adds equirectangular video support
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
# open360viewer
|
||||
open360viewer is an opensource 360° image viewer. It is based on electron and marzipano. It currently supports opening equirectangular 360° images.
|
||||
open360viewer is an opensource 360° media viewer. It is based on electron and marzipano. It currently supports opening equirectangular 360° images and videos.
|
||||
|
||||
## Getting started
|
||||
Currently the viewer can only be used if you have nodeJs installed. Complete packaging is planned.
|
||||
@ -10,8 +10,8 @@ Currently the viewer can only be used if you have nodeJs installed. Complete pac
|
||||
If you are developing you might want to use `npm run startDev` as it also builds all assets at each launch.
|
||||
## Features
|
||||
- viewing equirectangular 360° images
|
||||
### WiP
|
||||
- viewing equirectangular 360° videos
|
||||
### WiP
|
||||
### Planned features
|
||||
- being able to flip through all images in a folder
|
||||
- show meta data
|
||||
|
18
index.js
18
index.js
@ -8,7 +8,7 @@ const {
|
||||
} = require("electron");
|
||||
const url = require("url");
|
||||
const path = require("path");
|
||||
|
||||
const FileType = require("file-type");
|
||||
let win;
|
||||
const isMac = process.platform === "darwin";
|
||||
|
||||
@ -24,8 +24,14 @@ const template = [
|
||||
dialog
|
||||
.showOpenDialog({ properties: ["openFile", "multiSelections"] })
|
||||
.then(function (data) {
|
||||
console.log(data);
|
||||
win.webContents.send("FileData", data);
|
||||
if (data.canceled == false) {
|
||||
FileType.fromFile(data.filePaths[0]).then((type) => {
|
||||
data.type = type["mime"].split("/")[0];
|
||||
win.webContents.send("FileData", data);
|
||||
});
|
||||
}
|
||||
// console.log(await FileType.fromFile(data));
|
||||
// win.webContents.send("FileData", data);
|
||||
});
|
||||
},
|
||||
},
|
||||
@ -96,8 +102,10 @@ app.on("ready", function () {
|
||||
dialog
|
||||
.showOpenDialog({ properties: ["openFile", "multiSelections"] })
|
||||
.then(function (data) {
|
||||
console.log(data);
|
||||
win.webContents.send("FileData", data);
|
||||
FileType.fromFile(data.filePaths[0]).then((type) => {
|
||||
data.type = type["mime"].split("/")[0];
|
||||
win.webContents.send("FileData", data);
|
||||
});
|
||||
});
|
||||
} else if (arg == "resize") {
|
||||
// A really ugly hack to force the window to update, so the canvas shows up
|
||||
|
@ -12,7 +12,7 @@
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "electron .",
|
||||
"startDev": "npm run buildCss && npm run minify && electron .",
|
||||
"minify": "minify src/main.js > dist/main.js && minify src/ui_templates/index.html > dist/ui_templates/index.html && minify src/ui_templates/about.html > dist/ui_templates/about.html",
|
||||
"minify": "minify src/main.js > dist/main.js && minify src/ui_templates/index.html > dist/ui_templates/index.html && minify src/videoPlayer.css > dist/videoPlayer.css && minify src/videoPlayHandler.js > dist/videoPlayHandler.js && minify src/ui_templates/videoPlayer.html > dist/ui_templates/videoPlayer.html && minify src/ui_templates/about.html > dist/ui_templates/about.html",
|
||||
"buildCss": "npx tailwindcss -i ./src/main.css -o ./dist/output.css",
|
||||
"buildCssWatch": "npx tailwindcss -i ./src/main.css -o ./dist/output.css --watch",
|
||||
"package": "electron-forge package",
|
||||
@ -51,16 +51,17 @@
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"@themesberg/flowbite": "^1.2.0",
|
||||
"electron": "^16.0.5",
|
||||
"file-type": "^16.5.3",
|
||||
"marzipano": "^0.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"minify": "^8.0.3",
|
||||
"tailwindcss": "^3.0.8",
|
||||
"@electron-forge/cli": "^6.0.0-beta.61",
|
||||
"@electron-forge/maker-deb": "^6.0.0-beta.61",
|
||||
"@electron-forge/maker-rpm": "^6.0.0-beta.61",
|
||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.61",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.61",
|
||||
"electron": "^16.0.5"
|
||||
"electron": "^16.0.5",
|
||||
"minify": "^8.0.3",
|
||||
"tailwindcss": "^3.0.8"
|
||||
}
|
||||
}
|
||||
|
31
src/main.js
31
src/main.js
@ -8,7 +8,11 @@ ipcRenderer.on("FileData", function (event, data) {
|
||||
document.getElementById("loadingBig").style.display = "block";
|
||||
document.getElementById("state").innerHTML =
|
||||
"Loading file. If this stays empty try another file.";
|
||||
loadImageFromSource(data.filePaths[0]);
|
||||
if (data.type == "image") {
|
||||
loadImageFromSource(data.filePaths[0]);
|
||||
} else if (data.type == "video") {
|
||||
loadVideoFromSource(data.filePaths[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -16,7 +20,7 @@ function openFile() {
|
||||
ipcRenderer.sendSync("synchronous-message", "openFile");
|
||||
}
|
||||
|
||||
var viewer = new Marzipano.Viewer(document.getElementById("pano"));
|
||||
var viewer = new Marzipano.Viewer(document.getElementById("pano2"));
|
||||
function newPano(path) {
|
||||
var sourceIm = Marzipano.ImageUrlSource.fromString(path);
|
||||
// Create scene.
|
||||
@ -28,9 +32,10 @@ function newPano(path) {
|
||||
});
|
||||
scene.switchTo();
|
||||
setTimeout(function () {
|
||||
scene.switchTo()
|
||||
}, 20);
|
||||
ipcRenderer.sendSync("synchronous-message", "resize");
|
||||
scene.switchTo();
|
||||
}, 20);
|
||||
ipcRenderer.sendSync("synchronous-message", "resize");
|
||||
document.getElementById("video-controls").style.display = "none";
|
||||
}
|
||||
|
||||
var geometry = new Marzipano.EquirectGeometry([{ width: 4000 }]);
|
||||
@ -41,3 +46,19 @@ var limiter = Marzipano.RectilinearView.limit.traditional(
|
||||
(120 * Math.PI) / 180
|
||||
);
|
||||
var view = new Marzipano.RectilinearView({ yaw: Math.PI }, limiter);
|
||||
|
||||
function loadVideoFromSource(path) {
|
||||
setTimeout(function () {
|
||||
multiResVideo.setResolutionIndex(1, path, loadingDone);
|
||||
}, 20);
|
||||
}
|
||||
|
||||
function loadingDone(state) {
|
||||
if (!state) {
|
||||
document.getElementById("loadingBig").style.display = "none";
|
||||
ipcRenderer.sendSync("synchronous-message", "resize");
|
||||
document.getElementById("pano").style.display = "block";
|
||||
document.getElementById("pano2").style.display = "none";
|
||||
document.getElementById("video-controls").style.display = "block";
|
||||
}
|
||||
}
|
||||
|
@ -2,26 +2,39 @@
|
||||
<html class="dark">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>360 Viewer</title>
|
||||
<script src="../../node_modules/marzipano/dist/marzipano.js">
|
||||
</script>
|
||||
<meta name="viewport"
|
||||
content="target-densitydpi=device-dpi, width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui" />
|
||||
<link rel="stylesheet" href="../../dist/videoPlayer.css">
|
||||
<link href="../output.css" rel="stylesheet">
|
||||
<link href="../../node_modules/@fortawesome/fontawesome-free/css/all.css" rel="stylesheet">
|
||||
<script src="../../node_modules/@themesberg/flowbite/dist/flowbite.bundle.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="dark:bg-gray-800">
|
||||
<div id="alert-1" class="flex p-4 mb-4 bg-red-100 rounded-lg dark:bg-red-200" role="alert" style="display: none;">
|
||||
<svg class="flex-shrink-0 w-5 h-5 text-red-700 dark:text-red-800" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path></svg>
|
||||
<svg class="flex-shrink-0 w-5 h-5 text-red-700 dark:text-red-800" fill="currentColor" viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<div class="ml-3 text-sm font-medium text-red-700 dark:text-red-800">
|
||||
The provided image was invalid and could not be loaded.
|
||||
The provided image was invalid and could not be loaded.
|
||||
</div>
|
||||
<button type="button" class="ml-auto -mx-1.5 -my-1.5 bg-red-100 text-red-500 rounded-lg focus:ring-2 focus:ring-red-400 p-1.5 hover:bg-red-200 inline-flex h-8 w-8 dark:bg-red-200 dark:text-red-600 dark:hover:bg-red-300" data-collapse-toggle="alert-1" aria-label="Close" onclick="document.getElementById('alert-1').style.display = 'none'">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||
<button type="button"
|
||||
class="ml-auto -mx-1.5 -my-1.5 bg-red-100 text-red-500 rounded-lg focus:ring-2 focus:ring-red-400 p-1.5 hover:bg-red-200 inline-flex h-8 w-8 dark:bg-red-200 dark:text-red-600 dark:hover:bg-red-300"
|
||||
data-collapse-toggle="alert-1" aria-label="Close"
|
||||
onclick="document.getElementById('alert-1').style.display = 'none'">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<center>
|
||||
<h1 id="state" style="display: none;"></h1>
|
||||
@ -48,19 +61,65 @@
|
||||
<div id="pano">
|
||||
|
||||
</div>
|
||||
<div id="pano2">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="video-controls" id="video-controls" style="display: none;">
|
||||
<div class="control-btn play" id="play-pause">
|
||||
<i class="fas fa-play play-icon"></i>
|
||||
<i class="fas fa-pause pause-icon"></i>
|
||||
</div>
|
||||
<div class="control-btn sound" id="mute">
|
||||
<i class="fas fa-volume-up sound-on"></i>
|
||||
<i class="fas fa-volume-mute sound-off"></i>
|
||||
</div>
|
||||
<div class="time">
|
||||
<h5 class="initial-time" id="current-time-indicator"></h5>
|
||||
<div class="progress-wrapper" id="progress-background">
|
||||
<div class="progress-bar">
|
||||
<span class="progress-fill" id="progress-fill"></span>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="end-time" id="duration-indicator"></h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script src="../../node_modules/marzipano/dist/marzipano.js"></script>
|
||||
|
||||
<script src="../../node_modules/marzipano/demos/video-multi-res/VideoAsset.js"></script>
|
||||
<script src="../../node_modules/marzipano/demos/video-multi-res/EventEmitter.js"></script>
|
||||
<script src="../../node_modules/marzipano/demos/video-multi-res/EventEmitterProxy.js"></script>
|
||||
<script src="../../node_modules/marzipano/demos/video-multi-res/NullVideoElementWrapper.js"></script>
|
||||
<script src="../../node_modules/marzipano/demos/video-multi-res/loadVideoInSync.js"></script>
|
||||
<script src="../../dist/videoPlayHandler.js"></script>
|
||||
<script src="../../node_modules/marzipano/demos/video-multi-res/interface.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
const FileType = require("file-type");
|
||||
document.getElementById("pano").style.display = "none";
|
||||
document.getElementById("pano2").style.display = "none";
|
||||
|
||||
document.addEventListener('drop', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
document.getElementById("fakeDropzone").style.display = "none";
|
||||
document.getElementById("loadingBig").style.display = "block";
|
||||
document.getElementById("state").innerHTML = "Loading file. If this stays empty try another file."
|
||||
|
||||
const superFile = event.dataTransfer.files[0].path;
|
||||
loadImageFromSource(superFile)
|
||||
FileType.fromFile(superFile).then((type) => {
|
||||
type = type["mime"].split("/")[0];
|
||||
if (type == "image") {
|
||||
loadImageFromSource(superFile)
|
||||
} else if (type == "video") {
|
||||
loadVideoFromSource(superFile)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
document.addEventListener('dragover', (e) => {
|
||||
@ -80,18 +139,18 @@
|
||||
testImage(path,
|
||||
function (e, suc) {
|
||||
if (suc == "success") {
|
||||
document.getElementById("pano").style.display = "block";
|
||||
setTimeout(function() {
|
||||
document.getElementById("pano2").style.display = "block";
|
||||
setTimeout(function () {
|
||||
newPano(path)
|
||||
}, 50);
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
document.getElementById("state").innerHTML = "Load failed."
|
||||
document.getElementById('alert-1').style.display = 'block';
|
||||
document.getElementById("fakeDropzone").style.display = "block";
|
||||
document.getElementById("loadingBig").style.display = "none";
|
||||
document.getElementById("pano").style.display = "none";
|
||||
document.getElementById("pano2").style.display = "none";
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -125,36 +184,5 @@
|
||||
|
||||
</script>
|
||||
<script src="../main.js"></script>
|
||||
<style>
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
-webkit-touch-callout: none;
|
||||
-ms-content-zooming: none;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#pano {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
</html>
|
80
src/videoPlayHandler.js
Normal file
80
src/videoPlayHandler.js
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
// Create viewer.
|
||||
var viewer = new Marzipano.Viewer(document.querySelector('#pano'));
|
||||
|
||||
// Create layer.
|
||||
var asset = new VideoAsset();
|
||||
var source = new Marzipano.SingleAssetSource(asset);
|
||||
var geometry = new Marzipano.EquirectGeometry([ { width: 1 } ]);
|
||||
|
||||
var limiter = Marzipano.RectilinearView.limit.traditional(2560, 100*Math.PI/180);
|
||||
var view = new Marzipano.RectilinearView(null, limiter);
|
||||
|
||||
var scene = viewer.createScene({ source: source, geometry: geometry, view: view, pinFirstLevel: false });
|
||||
|
||||
scene.switchTo({ transitionDuration: 0 });
|
||||
|
||||
var emitter = new EventEmitter();
|
||||
var videoEmitter = new EventEmitterProxy();
|
||||
|
||||
|
||||
|
||||
function setResolutionIndex(index, vidScr, cb) {
|
||||
cb = cb || function() {};
|
||||
|
||||
var videoSrc = vidScr;
|
||||
|
||||
var previousVideo = asset.video() && asset.video().videoElement();
|
||||
|
||||
loadVideoInSync(videoSrc, previousVideo, function(err, element) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousVideo) {
|
||||
previousVideo.pause();
|
||||
previousVideo.volume = 0;
|
||||
previousVideo.removeAttribute('src');
|
||||
}
|
||||
|
||||
var VideoElementWrapper = NullVideoElementWrapper;
|
||||
var wrappedVideo = new VideoElementWrapper(element);
|
||||
asset.setVideo(wrappedVideo);
|
||||
|
||||
videoEmitter.setObject(element);
|
||||
|
||||
emitter.emit('change');
|
||||
emitter.emit('resolutionChange');
|
||||
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
var multiResVideo = {
|
||||
layer: function() {
|
||||
return scene.layer();
|
||||
},
|
||||
element: function() {
|
||||
return asset.video() && asset.video().videoElement();
|
||||
},
|
||||
resolutions: function() {
|
||||
return resolutions;
|
||||
},
|
||||
resolutionIndex: function() {
|
||||
return currentState.resolutionIndex;
|
||||
},
|
||||
resolution: function() {
|
||||
return currentState.resolutionIndex != null ?
|
||||
resolutions[currentState.resolutionIndex] :
|
||||
null;
|
||||
},
|
||||
setResolutionIndex: setResolutionIndex,
|
||||
resolutionChanging: function() {
|
||||
return currentState.resolutionChanging;
|
||||
},
|
||||
addEventListener: emitter.addEventListener.bind(emitter),
|
||||
|
||||
// events from proxy to videoElement
|
||||
addEventListenerVideo: videoEmitter.addEventListener.bind(videoEmitter)
|
||||
};
|
192
src/videoPlayer.css
Normal file
192
src/videoPlayer.css
Normal file
@ -0,0 +1,192 @@
|
||||
#pano {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#pano2 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
/* General layout */
|
||||
|
||||
.video-controls {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.control-btn,
|
||||
.time {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
box-size: border-box;
|
||||
}
|
||||
|
||||
.video-controls {
|
||||
height: 40px;
|
||||
}
|
||||
.play,
|
||||
.sound,
|
||||
.options {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.play {
|
||||
left: 0;
|
||||
}
|
||||
.sound {
|
||||
left: 40px;
|
||||
}
|
||||
.options {
|
||||
right: 0;
|
||||
}
|
||||
.resolution {
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.time {
|
||||
position: absolute;
|
||||
left: 80px;
|
||||
right: 140px;
|
||||
}
|
||||
|
||||
/* Control button style (play, mute, options, resolution) */
|
||||
|
||||
.control-btn {
|
||||
background-color: rgb(103, 115, 131);
|
||||
background-color: rgba(103, 115, 131, 0.8);
|
||||
cursor: pointer;
|
||||
transition: 0.3s all ease-in-out;
|
||||
}
|
||||
|
||||
.control-btn:hover {
|
||||
background-color: rgb(78, 88, 104);
|
||||
background-color: rgba(78, 88, 104, 0.8);
|
||||
}
|
||||
|
||||
/* Play, mute, options */
|
||||
|
||||
.play img,
|
||||
.sound img,
|
||||
.options img {
|
||||
height: 66%;
|
||||
width: 66%;
|
||||
margin-top: 17%;
|
||||
margin-left: 17%;
|
||||
}
|
||||
|
||||
/* Progress bar */
|
||||
|
||||
.initial-time,
|
||||
.progress-wrapper,
|
||||
.end-time {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.initial-time,
|
||||
.end-time {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.initial-time {
|
||||
left: 14px;
|
||||
}
|
||||
|
||||
.end-time {
|
||||
right: 14px;
|
||||
}
|
||||
|
||||
.progress-wrapper {
|
||||
left: 78px;
|
||||
right: 78px;
|
||||
}
|
||||
|
||||
.initial-time,
|
||||
.end-time {
|
||||
text-align: center;
|
||||
top: 12px;
|
||||
}
|
||||
|
||||
.progress-wrapper {
|
||||
padding: 15px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 10px;
|
||||
background-color: rgb(103, 115, 131);
|
||||
background-color: rgba(103, 115, 131, 0.8);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.progress-wrapper .progress-fill {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background-color: #eee;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.initial-time,
|
||||
.end-time {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.time {
|
||||
background-color: rgb(58, 68, 84);
|
||||
background-color: rgba(58, 68, 84, 0.8);
|
||||
}
|
||||
|
||||
/* Show state */
|
||||
|
||||
.play-icon {
|
||||
display: block;
|
||||
font-size: x-large;
|
||||
padding: 8px;
|
||||
}
|
||||
.pause-icon {
|
||||
display: none;
|
||||
font-size: x-large;
|
||||
padding: 8px;
|
||||
}
|
||||
.video-playing .play-icon {
|
||||
display: none;
|
||||
}
|
||||
.video-playing .pause-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sound-on {
|
||||
display: block;
|
||||
font-size: x-large;
|
||||
padding: 8px;
|
||||
}
|
||||
.sound-off {
|
||||
display: none;
|
||||
font-size: x-large;
|
||||
padding: 8px;
|
||||
}
|
||||
.video-muted .sound-on {
|
||||
display: none;
|
||||
}
|
||||
.video-muted .sound-off {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.resolution-changing-indicator,
|
||||
.resolution-modal-changing-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.video-resolution-changing .resolution-changing-indicator,
|
||||
.video-resolution-changing .resolution-modal-changing-indicator {
|
||||
display: block;
|
||||
}
|
Reference in New Issue
Block a user