mirror of
https://github.com/TheGreyDiamond/open360viewer.git
synced 2025-12-17 02:10:45 +01:00
Basic video playing works; still a few bugs to fix left
This commit is contained in:
26
index.js
26
index.js
@@ -35,6 +35,30 @@ const template = [
|
|||||||
{
|
{
|
||||||
role: "help",
|
role: "help",
|
||||||
submenu: [
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "Switch to image mode",
|
||||||
|
click: async () => {
|
||||||
|
win.loadURL(
|
||||||
|
url.format({
|
||||||
|
pathname: path.join(__dirname, "dist/ui_templates/index.html"),
|
||||||
|
protocol: "file:",
|
||||||
|
slashes: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Switch to video mode",
|
||||||
|
click: async () => {
|
||||||
|
win.loadURL(
|
||||||
|
url.format({
|
||||||
|
pathname: path.join(__dirname, "dist/ui_templates/videoPlayer.html"),
|
||||||
|
protocol: "file:",
|
||||||
|
slashes: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
{ role: "toggleDevTools" },
|
{ role: "toggleDevTools" },
|
||||||
{
|
{
|
||||||
label: "About",
|
label: "About",
|
||||||
@@ -77,7 +101,7 @@ function createWindow() {
|
|||||||
|
|
||||||
win.loadURL(
|
win.loadURL(
|
||||||
url.format({
|
url.format({
|
||||||
pathname: path.join(__dirname, "dist/ui_templates/index.html"),
|
pathname: path.join(__dirname, "dist/ui_templates/videoPlayer.html"),
|
||||||
protocol: "file:",
|
protocol: "file:",
|
||||||
slashes: true,
|
slashes: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"start": "electron .",
|
"start": "electron .",
|
||||||
"startDev": "npm run buildCss && npm run minify && 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",
|
"buildCss": "npx tailwindcss -i ./src/main.css -o ./dist/output.css",
|
||||||
"buildCssWatch": "npx tailwindcss -i ./src/main.css -o ./dist/output.css --watch",
|
"buildCssWatch": "npx tailwindcss -i ./src/main.css -o ./dist/output.css --watch",
|
||||||
"package": "electron-forge package",
|
"package": "electron-forge package",
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>360 Viewer</title>
|
<title>360 Viewer</title>
|
||||||
<script src="../../node_modules/marzipano/dist/marzipano.js">
|
<script src="../../node_modules/marzipano/dist/marzipano.js"></script>
|
||||||
</script>
|
<script src="../../node_modules/marzipano/demos/video/VideoAsset.js"></script>
|
||||||
|
|
||||||
<link href="../output.css" rel="stylesheet">
|
<link href="../output.css" rel="stylesheet">
|
||||||
<link href="../../node_modules/@fortawesome/fontawesome-free/css/all.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>
|
<script src="../../node_modules/@themesberg/flowbite/dist/flowbite.bundle.js"></script>
|
||||||
|
|||||||
132
src/ui_templates/videoPlayer.html
Normal file
132
src/ui_templates/videoPlayer.html
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>360 Viewer - Video mode</title>
|
||||||
|
<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="pano"></div>
|
||||||
|
<center>
|
||||||
|
<h1 id="state" style="display: none;"></h1>
|
||||||
|
<div id="fakeDropzone"
|
||||||
|
class="border-4 rounded-lg border-dashed border-gray-700 dark:border-white dark:text-white w-96 mt-12">
|
||||||
|
<i class="far fa-folder-open text-2xl mt-6"></i><br>
|
||||||
|
<a class="text-lg">Drag & Drop a file here</a><br>
|
||||||
|
<des class="text-gray-700">or</des><br>
|
||||||
|
<button onclick="ipcRenderer.sendSync('synchronous-message', 'openFile');" type="button"
|
||||||
|
class="z-40 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Browse
|
||||||
|
Files</button>
|
||||||
|
</div>
|
||||||
|
<div id="loadingBig" style="display: none;">
|
||||||
|
<svg class="animate-spin h-5 w-5 h-24 text-white" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||||
|
viewBox="0 0 24 24" id="loadingSpinner">
|
||||||
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
|
<path class="opacity-75" fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="video-controls" id="video-controls">
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
document.getElementById("pano").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;
|
||||||
|
loadVideoFromSource(superFile)
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('dragover', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('dragenter', (event) => {
|
||||||
|
console.log('File is in the Drop Space');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('dragleave', (event) => {
|
||||||
|
console.log('File has left the Drop Space');
|
||||||
|
});
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// multiResVideo.setResolutionIndex(1, "\\\\nasspi\\homes\\Datein\\360\\SAM_100_0023.mp4");
|
||||||
|
const { ipcRenderer } = require("electron");
|
||||||
|
ipcRenderer.on("FileData", function (event, data) {
|
||||||
|
console.log(data);
|
||||||
|
if (data.canceled == false) {
|
||||||
|
document.getElementById("fakeDropzone").style.display = "none";
|
||||||
|
document.getElementById("loadingBig").style.display = "none";
|
||||||
|
loadVideoFromSource(data.filePaths[0])
|
||||||
|
// multiResVideo.setResolutionIndex(1, );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</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)
|
||||||
|
};
|
||||||
147
src/videoPlayer.css
Normal file
147
src/videoPlayer.css
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#pano {
|
||||||
|
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: .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