Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve camera removal and error handling #299

Merged
merged 7 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/animator.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h3 id="loading-window-message"></h3>
<div id="preview-area">
<!-- No source message -->
<div id="preview-area-message" class="visible-capture preview-area-item">
<h2>Select a camera source to begin!</h2>
<h2></h2>
</div>
<!-- Onion skinning frame -->
<img id="onion-skinning-frame" class="visible-capture">
Expand Down Expand Up @@ -230,7 +230,7 @@ <h2 class="sidebar-header">
<li id="current-frame-rate">
<span></span> FPS
</li>
<li id="current-resolution">No camera selected</li>
<li id="current-resolution"></li>
<li class="no-pipe" id="current-mode">
<span></span> mode</li>
</ul>
Expand Down
2 changes: 2 additions & 0 deletions src/css/animator.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
body[data-has-frames="false"] #btn-export-video,
body[data-has-frames="false"] #btn-conform-take {
background-color: var(--ba-light-mid);
box-shadow: none;
color: var(--ba-dark-active);
cursor: not-allowed;
}
Expand Down Expand Up @@ -79,6 +80,7 @@ body[data-has-frames="false"] #btn-conform-take:focus {
align-items: center;
display: flex;
justify-content: center;
z-index: 1;
}

#preview,
Expand Down
12 changes: 9 additions & 3 deletions src/css/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ input[type="number"], input[type="text"], select {
padding: 0.25rem;
}
input[type="number"]:focus, input[type="text"]:focus, select:focus {
box-shadow: none;
border: 0.0625rem solid var(--ba-lightyellow);
border-radius: 0.25rem;
box-shadow: 0 0 0.0625rem 0.0625rem var(--ba-lightyellow);
outline: none;
}

Expand All @@ -66,6 +66,13 @@ label {
margin-bottom: 0.25rem;
}

/* Display danger outline around element */
.input-border-danger {
border: 0.0625rem solid var(--ba-lightred);
border-radius: 0.25rem;
box-shadow: 0 0 0.0625rem 0.0625rem var(--ba-lightred);
}

.btn {
appearance: none;
background-color: var(--ba-light);
Expand All @@ -85,7 +92,7 @@ label {
background-color: var(--ba-light-active);
}
.btn:focus {
box-shadow: none;
box-shadow: 0 0 0.0625rem 0.0625rem var(--ba-lightyellow);
border: 0.0625rem solid var(--ba-lightyellow);
border-radius: 0.25rem;
outline: none;
Expand Down Expand Up @@ -288,7 +295,6 @@ aside li { margin: 0.25rem 0; }
.sidebar-item {
border-bottom: 0.0625rem solid var(--ba-border);
margin: 0 1rem;
overflow: auto;
}

.sidebar-header {
Expand Down
50 changes: 34 additions & 16 deletions src/js/animator/core/Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {};
let curStream = null;

// Get the DOM selectors needed
const previewAreaMessage = document.querySelector("#preview-area-message");
let qResoluSelect = document.querySelector("#camera-resolution-select"),
qCameraSelect = document.querySelector("#camera-source-select"),
videoCapture = document.createElement("video");
Expand Down Expand Up @@ -72,6 +73,30 @@ module.exports = {};

/** Static methods */

Camera.setBlankCamera = function () {
// Stop the previous camera from streaming
if (curStream) {
let curTrack = curStream.getVideoTracks()[0];
curTrack.stop();
}

Camera.successCam = {};
// Switch to "no camera selected"
qCameraSelect.value = "#";
// Reset resolution select
qResoluSelect.innerHTML = "";

// Set preview area message
previewAreaMessage.classList.add("visible-capture");
previewAreaMessage.innerHTML = `<h2>Select a camera source to begin!</h2>`;

// Set select element styling
qCameraSelect.classList.add("input-border-danger");

// Update status bar
StatusBar.setResolution("No camera selected");
};

/**
* Displays the stream from a video onto another video element.
* @param {HTMLVideoElement} feed - the source element.
Expand Down Expand Up @@ -161,6 +186,7 @@ module.exports = {};
Camera.display(feed, document.querySelector("#preview"));
} catch (err) {
Notification.error(`${curCam.name} could not be loaded!`);
Camera.setBlankCamera();
} finally {
Loader.hide();
}
Expand All @@ -184,16 +210,11 @@ module.exports = {};
* @param {Array} sources - @todo.
*/
function _findVideoSources(sources) {
// If no camera has been selected yet add "no camera selected option"
if (qCameraSelect.length == 0) {
const option = window.document.createElement("option");
option.text = "No camera selected";
option.setAttribute("disabled", true);
option.setAttribute("style", "display: none;");
option.setAttribute("value", "#");
qCameraSelect.appendChild(option);
qCameraSelect.value = "#";
}
// Add blank camera option
const option = window.document.createElement("option");
option.text = "No camera selected";
option.value = "#";
qCameraSelect.appendChild(option);

// Remove all camera select options except "No camera selected"
var num = qCameraSelect.options.length;
Expand All @@ -208,6 +229,7 @@ module.exports = {};

// Filter out all non-video streams
sources = sources.filter(source => source.kind === "videoinput");

// Add any new devices that have been connected and check for the currently connected camera
sources.forEach(function(source, i) {
// Get the proper camera name
Expand All @@ -234,18 +256,14 @@ module.exports = {};
// Check if device is the current camera
if (source.deviceId === Camera.successCam.id) {
isCurCamStillConnected = true;
qCameraSelect.value = Camera.successCam.id;
}
});

// Switch to "no camera selected" if current success camera is no longer connected
if (Object.keys(Camera.successCam).length > 0 && !isCurCamStillConnected) {
Notification.info(`${Camera.successCam.name} has been removed`);
Camera.successCam = {};

// Switch to "no camera selected"
qCameraSelect.value = "#";
// Reset resolution select
qResoluSelect.innerHTML = "";
Camera.setBlankCamera();
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/js/animator/core/ExportVideo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
const path = require("path");

const ConfirmDialog = require("../ui/ConfirmDialog");
const Camera = require("./Camera");
const Notification = require("../../common/Notification");

const DEFAULT_FILE_NAME = "output.mp4";
Expand Down Expand Up @@ -72,6 +73,9 @@
// Load in default FFmpeg arguments
customArgumentsInput.value = ExportVideo.generateFfmpegArguments(outputPath, exportFrameDir, frameRate, presetValue);

// Set blank camera
Camera.setBlankCamera();

// Event listeners

// Activate choose export video file path dialog on button click
Expand Down
3 changes: 3 additions & 0 deletions src/js/animator/core/PreviewOverlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@

// Add to container
previewArea.appendChild(this.element);

// Hide element if not streaming
this.element.classList.toggle("hidden", !global.projectInst.streaming);
}

/**
Expand Down
22 changes: 18 additions & 4 deletions src/js/animator/projects/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,31 @@
* The event listeners for a project
*/
setListeners() {
var self = this;
let self = this;

self.playback = new Playback(self);

// Initialises the preview window
preview.addEventListener("play", function () {
PlaybackCanvas.setDimensions(preview.videoWidth.toString(), preview.videoHeight.toString())
self.streaming = true;

// Reload preview overlays
PreviewOverlay.drawAll();

// Enable onion skin
self.currentTake.onionSkin.setVisibility(true);
});

// Detect preview ending
preview.addEventListener("suspend", function () {
self.streaming = false;

// Reload preview overlays
PreviewOverlay.drawAll();

// Disable onion skin
self.currentTake.onionSkin.setVisibility(false);
});

// Capture a frame
Expand Down Expand Up @@ -117,12 +132,11 @@
*/
takeFrame() {
var self = this;
// Stop playback
this.playback.videoStop();
this.setCurrentMode("capture");

// Take a picture
if (self.streaming) {
self.setCurrentMode("capture");

self.currentTake.captureFrame()
.then(function () {
// Scroll to the end of the framereel
Expand Down
25 changes: 18 additions & 7 deletions src/js/animator/ui/CaptureOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const { ipcRenderer } = require("electron");

const Camera = require("../core/Camera");
const Notification = require("../../common/Notification");

const cameraSelect = document.querySelector("#camera-source-select");
const resolutionSelect = document.querySelector("#camera-resolution-select");
Expand All @@ -11,19 +12,29 @@

class CaptureOptions {
static setListeners() {
// Set the blank camera on load
Camera.setBlankCamera();

// Get the resolutions for a camera upon changing it
cameraSelect.addEventListener("change", function() {
var curCam = Camera.getSelectedCamera();
curCam.showResolutions();
cameraSelect.addEventListener("change", function (e) {
if (e.target.value === "#") {
Notification.info(`${Camera.successCam.name} has been disconnected`);
Camera.setBlankCamera();
} else {
let curCam = Camera.getSelectedCamera();
curCam.showResolutions();

// Hide the select camera message
previewAreaMessage.classList.remove("visible-capture");
// Hide the select camera message
previewAreaMessage.classList.remove("visible-capture");
// Set select element styling
cameraSelect.classList.remove("input-border-danger");
}
});

// Reload the camera on changing resolution
resolutionSelect.addEventListener("change", function() {
var curCam = Camera.getSelectedCamera();
var feed = curCam.updateResolution(Camera.getSelectedResolution());
let curCam = Camera.getSelectedCamera();
let feed = curCam.updateResolution(Camera.getSelectedResolution());
Camera.display(feed, preview);
});

Expand Down
8 changes: 8 additions & 0 deletions src/js/animator/ui/OnionSkin.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@
onionSkinWindow.removeAttribute("src");
}

/**
* Hide/show the onion skin window
* @param {Boolean} status Set to true to show the window
*/
setVisibility(status = true) {
onionSkinWindow.classList.toggle("hidden", !status);
}

/**
* Sets opacity of the onion skin window when the slider is moved.
* @param {Object} e - Event object from addEventListener.
Expand Down