Pretty WebUI
This commit is contained in:
parent
e778410dd5
commit
2dcf3f1fe4
6 changed files with 839 additions and 0 deletions
409
web-ui/BMD-Camera-Control.js
Normal file
409
web-ui/BMD-Camera-Control.js
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
class BMDCamera {
|
||||
// Pretty name and network hostname (strings)
|
||||
name;
|
||||
hostname;
|
||||
APIAddress;
|
||||
|
||||
// Camera index, used for muticam support
|
||||
index;
|
||||
|
||||
// == TODO: Having trouble with the codec and video formats on the SC 6K Pro ==
|
||||
// Codec and Video Formats (JSON objects)
|
||||
codecFormat;
|
||||
videoFormat;
|
||||
|
||||
// Supported Codecs/Videos (arrays)
|
||||
supportedCodecFormats;
|
||||
supportedVideoFormats;
|
||||
// ============================================================================
|
||||
|
||||
// Current Transport Mode (string)
|
||||
transportMode;
|
||||
|
||||
// Whether the transport is playing or not (boolean)
|
||||
isPlaying;
|
||||
|
||||
// Playback state (JSON object)
|
||||
playbackState;
|
||||
|
||||
// Record state (JSON object)
|
||||
recordState;
|
||||
|
||||
// Timecode (JSON Object)
|
||||
timecode;
|
||||
// (pack the source into here also)
|
||||
|
||||
// Presets (JSON object)
|
||||
presets;
|
||||
activePreset;
|
||||
|
||||
// Iris (floats)
|
||||
apertureStop;
|
||||
apertureNormalised;
|
||||
|
||||
// Zoom (floats)
|
||||
zoomMM;
|
||||
zoomNormalised;
|
||||
|
||||
// Focus (float)
|
||||
focusNormalised;
|
||||
|
||||
// ISO (int)
|
||||
ISO;
|
||||
|
||||
// Gain (int)
|
||||
gain;
|
||||
|
||||
// White Balance (ints)
|
||||
WhiteBalance;
|
||||
WhiteBalanceTint;
|
||||
|
||||
// ND Filter (int, string)
|
||||
NDStop;
|
||||
NDMode;
|
||||
|
||||
// Shutter (JSON object)
|
||||
shutter;
|
||||
// has to be an object because it either returns with shutterSpeed or shutterAngle
|
||||
|
||||
// AE Mode (JSON Object)
|
||||
AutoExposureMode;
|
||||
|
||||
// Basic Color Correction (JSON objects w/ RGBL)
|
||||
CClift;
|
||||
CCgamma;
|
||||
CCgain;
|
||||
CCoffset;
|
||||
|
||||
// Other Color Correction (JSON objects w/ 2 numbers)
|
||||
CCcontrast;
|
||||
CCcolor;
|
||||
CClumacontribution;
|
||||
|
||||
// ============= CONSTRUCTOR ================
|
||||
constructor(hostname, index) {
|
||||
this.hostname = hostname;
|
||||
this.index = index;
|
||||
this.APIAddress = "http://"+hostname+"/control/api/v1";
|
||||
this.name = this.hostname.replace(".local","").replaceAll("-"," ");
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
// Important refreshing function
|
||||
refresh() {
|
||||
this.getAllInfo();
|
||||
sleep(500).then(() =>
|
||||
this.updateUIAll()
|
||||
);
|
||||
}
|
||||
|
||||
// Wrapper for API call, returns the JSON object from the camera
|
||||
async pullData(endpoint) {
|
||||
return await sendRequest("GET",this.APIAddress+endpoint,"");
|
||||
}
|
||||
|
||||
// Wrapper for API call, returns whatever the camera sent back in response
|
||||
async pushData(endpoint, data) {
|
||||
return await sendRequest("PUT",this.APIAddress+endpoint,data);
|
||||
}
|
||||
|
||||
// ======= UI Updaters ==========
|
||||
updateUIAll() {
|
||||
this.updateUIname();
|
||||
this.updateUIhostname();
|
||||
this.updateUICodecFormat();
|
||||
this.updateUIVideoFormat();
|
||||
this.updateUISupportedCodecFormats();
|
||||
this.updateUISupportedVideoFormats();
|
||||
this.updateUITransportMode();
|
||||
this.updateUIisPlaying();
|
||||
this.updateUIPlaybackState();
|
||||
this.updateUIRecordState();
|
||||
this.updateUITimecode();
|
||||
this.updateUIPresets();
|
||||
this.updateUIActivePreset();
|
||||
this.updateUIAperture();
|
||||
this.updateUIZoom();
|
||||
this.updateUIFocus();
|
||||
this.updateUIISO();
|
||||
this.updateUIgain();
|
||||
this.updateUIWhiteBalance();
|
||||
this.updateUINDStop();
|
||||
this.updateUIshutter();
|
||||
this.updateUIAutoExposureMode();
|
||||
this.updateUIColorCorrection();
|
||||
}
|
||||
|
||||
updateUIname() {
|
||||
document.getElementsByClassName("cameraName")[this.index].innerHTML = this.name;
|
||||
}
|
||||
|
||||
updateUIhostname() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUICodecFormat() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUIVideoFormat() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUISupportedCodecFormats() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUISupportedVideoFormats() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUITransportMode() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUIisPlaying() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUIPlaybackState() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUIRecordState() {
|
||||
if (this.recordState.recording) {
|
||||
document.getElementsByClassName("cameraControlsContainer")[this.index].classList.add("liveCam");
|
||||
} else {
|
||||
document.getElementsByClassName("cameraControlsContainer")[this.index].classList.remove("liveCam");
|
||||
}
|
||||
}
|
||||
|
||||
updateUITimecode() {
|
||||
var tcString = parseInt(this.timecode.timecode.toString(16),10).toString().match(/.{1,2}/g).join(':');
|
||||
|
||||
document.getElementsByClassName("timecodeLabel")[this.index].innerHTML = tcString;
|
||||
}
|
||||
|
||||
updateUIPresets() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUIActivePreset() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUIAperture() {
|
||||
document.getElementsByClassName("irisRange")[this.index].value = this.apertureNormalised;
|
||||
document.getElementsByClassName("apertureStopsLabel")[this.index].innerHTML = this.apertureStop.toFixed(1);
|
||||
}
|
||||
|
||||
updateUIZoom() {
|
||||
document.getElementsByClassName("zoomRange")[this.index].value = this.zoomNormalised;
|
||||
document.getElementsByClassName("zoomMMLabel")[this.index].innerHTML = this.zoomMM;
|
||||
}
|
||||
|
||||
updateUIFocus() {
|
||||
document.getElementsByClassName("focusRange")[this.index].value = this.focusNormalised;
|
||||
}
|
||||
|
||||
updateUIISO() {
|
||||
// TBD
|
||||
}
|
||||
|
||||
updateUIgain() {
|
||||
var gainString = "";
|
||||
|
||||
if (this.gain >= 0) {
|
||||
gainString = "+"+this.gain+"db"
|
||||
} else {
|
||||
gainString = this.gain+"db"
|
||||
}
|
||||
|
||||
document.getElementsByClassName("gainSpan")[this.index].innerHTML = gainString;
|
||||
}
|
||||
|
||||
updateUIWhiteBalance() {
|
||||
document.getElementsByClassName("whiteBalanceSpan")[this.index].innerHTML = this.WhiteBalance+"K";
|
||||
}
|
||||
|
||||
updateUINDStop() {
|
||||
document.getElementsByClassName("ndFilterSpan")[this.index].innerHTML = this.NDStop;
|
||||
}
|
||||
|
||||
updateUIshutter() {
|
||||
var shutterString = ""
|
||||
|
||||
if ('shutterSpeed' in this.shutter) {
|
||||
shutterString = "1/"+this.shutter.shutterSpeed
|
||||
} else {
|
||||
var shangleString = this.shutter.shutterAngle.toString();
|
||||
shutterString = shangleString.slice(0,3)+(shangleString.slice(3,4) == '0' ? '' : "."+shangleString.slice(3,4))+"°"
|
||||
}
|
||||
|
||||
document.getElementsByClassName("shutterSpan")[this.index].innerHTML = shutterString;
|
||||
}
|
||||
|
||||
updateUIAutoExposureMode() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
updateUIColorCorrection() {
|
||||
//TBD
|
||||
}
|
||||
|
||||
// =============== GETTERS ==================
|
||||
|
||||
// name, hostname, APIaddress, index handled by constructor
|
||||
|
||||
getCodecFormat() {
|
||||
this.pullData("/system/codecFormat").then((value) => {this.codecFormat = value});
|
||||
}
|
||||
|
||||
getVideoFormat() {
|
||||
this.pullData("/system/videoFormat").then((value) => {this.videoFormat = value});
|
||||
}
|
||||
|
||||
getSupportedCodecFormats() {
|
||||
this.pullData("/system/supportedCodecFormats").then((value) => {this.supportedCodecFormats = value});
|
||||
}
|
||||
|
||||
getSupportedVideoFormats() {
|
||||
this.pullData("/system/supportedVideoFormats").then((value) => {this.supportedVideoFormats = value});
|
||||
}
|
||||
|
||||
getTransportMode() {
|
||||
this.pullData("/transports/0").then((value) => {this.transportMode = value});
|
||||
}
|
||||
|
||||
getIsPlaying() {
|
||||
this.pullData("/transports/0/play").then((value) => {this.isPlaying = value});
|
||||
}
|
||||
|
||||
getPlaybackState() {
|
||||
this.pullData("/transports/0/playback").then((value) => {this.playbackState = value});
|
||||
}
|
||||
|
||||
getRecordState() {
|
||||
this.pullData("/transports/0/record").then((value) => {this.recordState = value});
|
||||
}
|
||||
|
||||
getTimecode() {
|
||||
this.pullData("/transports/0/timecode").then((value) => {this.timecode = value});
|
||||
this.pullData("/transports/0/timecode/source").then((value) => {this.timecode.source = value.source});
|
||||
}
|
||||
|
||||
getPresets() {
|
||||
this.pullData("/presets").then((value) => {this.presets = value.presets});
|
||||
}
|
||||
|
||||
getActivePreset() {
|
||||
this.pullData("/presets/active").then((value) => {this.activePreset = value});
|
||||
}
|
||||
|
||||
getAperture() {
|
||||
this.pullData("/lens/iris").then((value) => {this.apertureStop = value.apertureStop; this.apertureNormalised = value.normalised});
|
||||
}
|
||||
|
||||
getZoom() {
|
||||
this.pullData("/lens/zoom").then((value) => {this.zoomMM = value.focalLength; this.zoomNormalised = value.normalised});
|
||||
}
|
||||
|
||||
getFocus() {
|
||||
this.pullData("/lens/focus").then((value) => {this.focusNormalised = value.normalised});
|
||||
}
|
||||
|
||||
getISO() {
|
||||
this.pullData("/video/iso").then((value) => {this.ISO = value.iso});
|
||||
}
|
||||
|
||||
getGain() {
|
||||
this.pullData("/video/gain").then((value) => {this.gain = value.gain});
|
||||
}
|
||||
|
||||
getWhiteBalance() {
|
||||
this.pullData("/video/whiteBalance").then((value) => {this.WhiteBalance = value.whiteBalance});
|
||||
this.pullData("/video/whiteBalanceTint").then((value) => {this.WhiteBalanceTint = value.whiteBalanceTint});
|
||||
}
|
||||
|
||||
getND() {
|
||||
this.pullData("/video/ndFilter").then((value) => {this.NDStop = value.stop});
|
||||
this.pullData("/video/ndFilter/displayMode").then((value) => {this.NDMode = value.displayMode});
|
||||
}
|
||||
|
||||
getShutter() {
|
||||
this.pullData("/video/shutter").then((value) => {this.shutter = value});
|
||||
}
|
||||
|
||||
getAutoExposureMode() {
|
||||
this.pullData("/video/autoExposure").then((value) => {this.AutoExposureMode = value});
|
||||
}
|
||||
|
||||
getColorCorrection() {
|
||||
this.pullData("/colorCorrection/lift").then((value) => {this.CClift = value});
|
||||
this.pullData("/colorCorrection/gamma").then((value) => {this.CCgamma = value});
|
||||
this.pullData("/colorCorrection/gain").then((value) => {this.CCgain = value});
|
||||
this.pullData("/colorCorrection/offset").then((value) => {this.CCoffset = value});
|
||||
this.pullData("/colorCorrection/contrast").then((value) => {this.CCcontrast = value});
|
||||
this.pullData("/colorCorrection/color").then((value) => {this.CCcolor = value});
|
||||
this.pullData("/colorCorrection/lumaContribution").then((value) => {this.CClumacontribution = value});
|
||||
}
|
||||
|
||||
getAllInfo() {
|
||||
this.getCodecFormat();
|
||||
this.getVideoFormat();
|
||||
this.getSupportedCodecFormats();
|
||||
this.getSupportedVideoFormats();
|
||||
this.getTransportMode();
|
||||
this.getIsPlaying();
|
||||
this.getPlaybackState();
|
||||
this.getRecordState();
|
||||
this.getTimecode();
|
||||
this.getPresets();
|
||||
this.getActivePreset();
|
||||
this.getAperture();
|
||||
this.getZoom();
|
||||
this.getFocus();
|
||||
this.getISO();
|
||||
this.getGain();
|
||||
this.getWhiteBalance();
|
||||
this.getND();
|
||||
this.getShutter();
|
||||
this.getAutoExposureMode();
|
||||
this.getColorCorrection();
|
||||
}
|
||||
|
||||
// =============== Other Commands =======================
|
||||
doAutoFocus() {
|
||||
this.pushData("/lens/focus/doAutoFocus")
|
||||
}
|
||||
|
||||
/* Timer Stuff */
|
||||
everySecond() {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper Functions */
|
||||
async function sendRequest(method, url, data) {
|
||||
const xhttp = new XMLHttpRequest();
|
||||
var responseObject;
|
||||
|
||||
// TODO: Add error code handling
|
||||
xhttp.onload = function() {
|
||||
if (this.responseText) {
|
||||
responseObject = JSON.parse(this.responseText);
|
||||
} else {
|
||||
responseObject = {"status": this.statusText};
|
||||
}
|
||||
}
|
||||
|
||||
xhttp.open(method, url, false);
|
||||
xhttp.send(JSON.stringify(data));
|
||||
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
102
web-ui/index.html
Normal file
102
web-ui/index.html
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Page title and metadata -->
|
||||
<title>Blackmagic Camera Control WebUI</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="description" content="JS-based web interface for controlling Blackmagic Design cameras via the official REST API">
|
||||
<meta name="author" content="Dylan Speiser">
|
||||
|
||||
<!-- Linking the stylesheet -->
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body onload="bodyOnLoad()">
|
||||
<!-- JavaScript Linking -->
|
||||
<script src="BMD-Camera-Control.js"></script>
|
||||
<script src="web-ui.js"></script>
|
||||
|
||||
<!------ Page Content ------>
|
||||
|
||||
<!-- Header Div -->
|
||||
<div class="flexContainerH" id="headerContainer">
|
||||
<h1>Blackmagic Camera Control WebUI</h1>
|
||||
</div>
|
||||
|
||||
<!-- Camera Select Bar -->
|
||||
<div class="flexContainerH" id="cameraSelectContainer">
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Camera Controls Box -->
|
||||
<div class="flexContainerH" id="allCamerasContainer">
|
||||
<div class="flexContainerV cameraControlsContainer">
|
||||
<div class="flexContainerH cameraControlHeadContainer">
|
||||
<h2 class="cameraName">CAM1</h2>
|
||||
</div>
|
||||
|
||||
<div class="flexContainerH cameraControlColorCorrectionContainer">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flexContainerH cameraControlExposureContainer">
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel">FILTER</span>
|
||||
<!-- Add control arrows -->
|
||||
<span class="ndFilterSpan">0</span>
|
||||
</div>
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel">GAIN</span>
|
||||
<!-- Add control arrows -->
|
||||
<span class="gainSpan">+0db</span>
|
||||
</div>
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel">SHUTTER</span>
|
||||
<!-- Add control arrows -->
|
||||
<span class="shutterSpan">1/50</span>
|
||||
</div>
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel">BALANCE</span>
|
||||
<!-- Add control arrows -->
|
||||
<span class="whiteBalanceSpan">5600K</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flexContainerH cameraControlLensContainer">
|
||||
<div class="lensSliderContainer">
|
||||
<span>FOCUS</span>
|
||||
<input type="range" orient="vertical" max="1" min="0" step="0.001" class="focusRange">
|
||||
<button onclick="cameras[ci].doAutoFocus()">AF</button>
|
||||
</div>
|
||||
<div class="lensSliderContainer">
|
||||
<span>IRIS</span>
|
||||
<input type="range" orient="vertical" max="1" min="0" step="0.001" class="irisRange">
|
||||
<span class="apertureStopsLabel">X.X</span>
|
||||
</div>
|
||||
<div class="lensSliderContainer">
|
||||
<span>ZOOM</span>
|
||||
<input type="range" orient="vertical" max="1" min="0" step="0.001" class="zoomRange">
|
||||
<span class="zoomMMLabel">XXmm</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flexContainerV cameraControlsContainerExpanded">
|
||||
<div class="flexContainerH cameraControlExpandedHeadContainer">
|
||||
<h2 class="timecodeLabel">TIMECODE</h2>
|
||||
</div>
|
||||
<div class="connectionContainer">
|
||||
<span>Hostname: </span>
|
||||
<input type="text" value="Studio-Camera-6K-Pro.local" class="hostnameInput" onkeydown="textInputTrigger(this)">
|
||||
<button onclick='cameras[ci] = new BMDCamera(document.getElementsByClassName("hostnameInput")[ci].value,ci);'>Connect</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Footer Div -->
|
||||
<div class="flexContainerH" id="footerContainer">
|
||||
<button onclick="cameras.forEach((element) => {element.refresh()});">Refresh</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
web-ui/resources/NotoSansDisplay-VariableFont_wdth,wght.ttf
Normal file
BIN
web-ui/resources/NotoSansDisplay-VariableFont_wdth,wght.ttf
Normal file
Binary file not shown.
BIN
web-ui/resources/NotoSansDisplay-VariableFont_wdth,wght.woff
Normal file
BIN
web-ui/resources/NotoSansDisplay-VariableFont_wdth,wght.woff
Normal file
Binary file not shown.
218
web-ui/style.css
Normal file
218
web-ui/style.css
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/* Load NotoSansDisplay Font from resources */
|
||||
@font-face {
|
||||
font-family: 'NotoSansDisplay';
|
||||
src: url('resources/NotoSansDisplay-VariableFont_wdth\,wght.woff') format('woff'), /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||
url('resources/NotoSansDisplay-VariableFont_wdth\,wght.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5, Opera 10+, Safari 3—5 */
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'NotoSansDisplay', sans-serif;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
background: #181818;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Page Body Flexboxes */
|
||||
.flexContainerH {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flexContainerV {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
/* Horizontal Container Styles */
|
||||
#headerContainer {
|
||||
background: #181818;
|
||||
background: linear-gradient(0deg, #181818 0%, #303030 100%);
|
||||
border-bottom: 1px solid black;
|
||||
width: 100%;
|
||||
height: 7.77vh;
|
||||
flex-wrap: wrap;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
#headerContainer h1 {
|
||||
font-weight: 100;
|
||||
color: white;
|
||||
margin-left: 1.3vw;
|
||||
}
|
||||
|
||||
#cameraSelectContainer {
|
||||
background: #222222;
|
||||
border: 1px solid black;
|
||||
width: 100%;
|
||||
height: 3.53vh;
|
||||
}
|
||||
|
||||
#allCamerasContainer {
|
||||
width: 100%;
|
||||
height: 83.1vh;
|
||||
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
|
||||
scrollbar-color: #202020 #151515;
|
||||
}
|
||||
|
||||
#footerContainer {
|
||||
background: #181818;
|
||||
background: linear-gradient(0deg, #181818 0%, #303030 100%);
|
||||
border: 1px solid black;
|
||||
width: 100%;
|
||||
height: 5vh;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* Camera Controls Container */
|
||||
.cameraControlsContainer {
|
||||
width: 15vw;
|
||||
height: 100%;
|
||||
background: #282828;
|
||||
flex-direction: column;
|
||||
border: 1px solid black;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cameraControlsContainer.selectedCam {
|
||||
background: #323232;
|
||||
}
|
||||
|
||||
.liveCam .cameraControlHeadContainer {
|
||||
background: rgb(184,3,16);
|
||||
background: linear-gradient(90deg, rgba(184,3,16,1) 0%, rgba(255,0,19,1) 15%, rgba(255,0,19,1) 85%, rgba(184,3,16,1) 100%);
|
||||
}
|
||||
|
||||
.cameraControlHeadContainer {
|
||||
width: 100%;
|
||||
height: 5vh;
|
||||
border-bottom: 2px solid black;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cameraName {
|
||||
font-weight: 100;
|
||||
color: white;
|
||||
margin-inline-start: 0.6em;
|
||||
margin-inline-end: 0.6em;
|
||||
}
|
||||
|
||||
/* Color Correction Section */
|
||||
.cameraControlColorCorrectionContainer {
|
||||
width: 100%;
|
||||
height: 33vh;
|
||||
}
|
||||
|
||||
/* Exposure Section */
|
||||
.cameraControlExposureContainer {
|
||||
width: 100%;
|
||||
height: 4.4vh;
|
||||
background-color: #171717;
|
||||
border-top: 1px solid #2d2d2d;
|
||||
border-bottom: 1px solid #2d2d2d;
|
||||
display: inline-flex;
|
||||
justify-content: space-evenly;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.selectedCam .cameraControlExposureContainer {
|
||||
border-top: 1px solid #3a3a3a;
|
||||
border-bottom: 1px solid #3a3a3a;
|
||||
}
|
||||
|
||||
.ccExposureSettingContainer {
|
||||
display: flex;
|
||||
color: white;
|
||||
font-size: 0.86em;
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 0.5vh;
|
||||
padding-top: 0.25vh;
|
||||
}
|
||||
|
||||
.exposureControlLabel {
|
||||
color: #6e6e6e;
|
||||
font-size: 0.666em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Lens Stuff */
|
||||
.cameraControlLensContainer {
|
||||
width: 100%;
|
||||
height: 41.9vh;
|
||||
border-bottom: 1px solid black;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.lensSliderContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.lensSliderContainer span {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.lensSliderContainer button {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
input[type=range][orient=vertical] {
|
||||
-webkit-appearance: slider-vertical;
|
||||
width: 2vw;
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
/* Right side (expanded) */
|
||||
.cameraControlsContainerExpanded {
|
||||
width: 84.75vw;
|
||||
height: 100%;
|
||||
background: #282828;
|
||||
flex-direction: column;
|
||||
border: 1px solid black;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cameraControlExpandedHeadContainer {
|
||||
width: 100%;
|
||||
height: 5vh;
|
||||
border-bottom: 2px solid black;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.timecodeLabel {
|
||||
font-weight: 100;
|
||||
color: white;
|
||||
margin-inline-start: 0.6em;
|
||||
margin-inline-end: 0.6em;
|
||||
}
|
||||
|
||||
/* Connection Settings */
|
||||
.connectionContainer {
|
||||
margin: 1.5vw;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
border-radius: 0.5vh;
|
||||
background: rgb(30, 30, 30);
|
||||
color: white;
|
||||
height: 2em;
|
||||
width: 10vw;
|
||||
border: 1px solid rgb(20, 20, 20);
|
||||
margin-left: 1vw;
|
||||
text-align: center;
|
||||
font-family: 'NotoSansDisplay', sans-serif;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=text]:focus {
|
||||
border: 1px solid rgb(150, 58, 0);
|
||||
}
|
||||
110
web-ui/web-ui.js
Normal file
110
web-ui/web-ui.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* Global variables */
|
||||
var cameras = [];
|
||||
var ci = 0;
|
||||
|
||||
function bodyOnLoad() {
|
||||
//let intervalID = setInterval(timerCallFunction, 1000);
|
||||
|
||||
let newCamHostname = document.getElementsByClassName("hostnameInput")[ci].value;
|
||||
|
||||
if (newCamHostname) {
|
||||
cameras[ci] = new BMDCamera(newCamHostname,ci);
|
||||
}
|
||||
}
|
||||
|
||||
// function timerCallFunction() {
|
||||
// cameras.forEach((camera) => camera.everySecond());
|
||||
// }
|
||||
|
||||
function textInputTrigger(element) {
|
||||
if (event.key === 'Enter') {
|
||||
cameras[ci] = new BMDCamera(element.value, ci);
|
||||
}
|
||||
}
|
||||
|
||||
function makeFakeCamera() {
|
||||
cam = new BMDCamera("Studio-Camera-6K-Pro.local",0)
|
||||
return Object.assign(cam,{
|
||||
"name": "Studio Camera 6K Pro",
|
||||
"hostname": "Studio-Camera-6K-Pro.local",
|
||||
"APIAddress": "http://Studio-Camera-6K-Pro.local/control/api/v1",
|
||||
"index": 0,
|
||||
"transportMode": {
|
||||
"mode": "InputPreview"
|
||||
},
|
||||
"isPlaying": false,
|
||||
"playbackState": {
|
||||
"loop": false,
|
||||
"position": 0,
|
||||
"singleClip": false,
|
||||
"speed": 0,
|
||||
"type": "Play"
|
||||
},
|
||||
"recordState": {
|
||||
"recording": false
|
||||
},
|
||||
"timecode": {
|
||||
"clip": 0,
|
||||
"timecode": 289550880,
|
||||
"source": "Clip"
|
||||
},
|
||||
"presets": {
|
||||
"presets": []
|
||||
},
|
||||
"activePreset": "default",
|
||||
"apertureStop": 4.400000095367432,
|
||||
"apertureNormalised": 0.021739130839705467,
|
||||
"zoomMM": 18,
|
||||
"zoomNormalised": 0,
|
||||
"focusNormalised": 0.5,
|
||||
"ISO": 400,
|
||||
"gain": 0,
|
||||
"NDStop": 0,
|
||||
"NDMode": "Fraction",
|
||||
"shutter": {
|
||||
"continuousShutterAutoExposure": false,
|
||||
"shutterSpeed": 50
|
||||
},
|
||||
"AutoExposureMode": {
|
||||
"mode": "Off",
|
||||
"type": ""
|
||||
},
|
||||
"CClift": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"luma": 0,
|
||||
"red": 0
|
||||
},
|
||||
"CCgamma": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"luma": 0,
|
||||
"red": 0
|
||||
},
|
||||
"CCgain": {
|
||||
"blue": 1,
|
||||
"green": 1,
|
||||
"luma": 1,
|
||||
"red": 1
|
||||
},
|
||||
"CCoffset": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"luma": 0,
|
||||
"red": 0
|
||||
},
|
||||
"CCcontrast": {
|
||||
"adjust": 1,
|
||||
"pivot": 0.5
|
||||
},
|
||||
"CCcolor": {
|
||||
"hue": 0,
|
||||
"saturation": 1
|
||||
},
|
||||
"CClumacontribution": {
|
||||
"lumaContribution": 1
|
||||
},
|
||||
"WhiteBalance": 5600,
|
||||
"WhiteBalanceTint": 0
|
||||
})
|
||||
}
|
||||
Loading…
Reference in a new issue