it actually looks good AND works!

This commit is contained in:
DylanSpeiser-BMD 2024-06-12 17:18:19 -07:00
parent 2dcf3f1fe4
commit 3a5d570add
5 changed files with 826 additions and 145 deletions

View file

@ -20,9 +20,6 @@ class BMDCamera {
// Current Transport Mode (string)
transportMode;
// Whether the transport is playing or not (boolean)
isPlaying;
// Playback state (JSON object)
playbackState;
@ -80,6 +77,9 @@ class BMDCamera {
CCcolor;
CClumacontribution;
// Keep track of unimplemented functions on the camera (array of strings)
UnimplementedFunctionality = [];
// ============= CONSTRUCTOR ================
constructor(hostname, index) {
this.hostname = hostname;
@ -117,7 +117,6 @@ class BMDCamera {
this.updateUISupportedCodecFormats();
this.updateUISupportedVideoFormats();
this.updateUITransportMode();
this.updateUIisPlaying();
this.updateUIPlaybackState();
this.updateUIRecordState();
this.updateUITimecode();
@ -133,14 +132,15 @@ class BMDCamera {
this.updateUIshutter();
this.updateUIAutoExposureMode();
this.updateUIColorCorrection();
this.updateUILinks();
}
updateUIname() {
document.getElementsByClassName("cameraName")[this.index].innerHTML = this.name;
document.getElementById("cameraName").innerHTML = this.name;
}
updateUIhostname() {
//TBD
document.getElementById("hostnameInput").value = this.hostname;
}
updateUICodecFormat() {
@ -163,26 +163,25 @@ class BMDCamera {
//TBD
}
updateUIisPlaying() {
//TBD
}
updateUIPlaybackState() {
//TBD
}
updateUIRecordState() {
if (this.recordState.recording) {
document.getElementsByClassName("cameraControlsContainer")[this.index].classList.add("liveCam");
document.getElementById("cameraControlHeadContainer").classList.add("liveCam");
document.getElementById("cameraControlExpandedHeadContainer").classList.add("liveCam");
} else {
document.getElementsByClassName("cameraControlsContainer")[this.index].classList.remove("liveCam");
document.getElementById("cameraControlHeadContainer").classList.remove("liveCam");
document.getElementById("cameraControlExpandedHeadContainer").classList.remove("liveCam");
}
}
updateUITimecode() {
// Redo this to work with no leading 0
var tcString = parseInt(this.timecode.timecode.toString(16),10).toString().match(/.{1,2}/g).join(':');
document.getElementsByClassName("timecodeLabel")[this.index].innerHTML = tcString;
document.getElementById("timecodeLabel").innerHTML = tcString;
}
updateUIPresets() {
@ -194,21 +193,21 @@ class BMDCamera {
}
updateUIAperture() {
document.getElementsByClassName("irisRange")[this.index].value = this.apertureNormalised;
document.getElementsByClassName("apertureStopsLabel")[this.index].innerHTML = this.apertureStop.toFixed(1);
document.getElementById("irisRange").value = this.apertureNormalised;
document.getElementById("apertureStopsLabel").innerHTML = this.apertureStop.toFixed(1);
}
updateUIZoom() {
document.getElementsByClassName("zoomRange")[this.index].value = this.zoomNormalised;
document.getElementsByClassName("zoomMMLabel")[this.index].innerHTML = this.zoomMM;
document.getElementById("zoomRange").value = this.zoomNormalised;
document.getElementById("zoomMMLabel").innerHTML = this.zoomMM;
}
updateUIFocus() {
document.getElementsByClassName("focusRange")[this.index].value = this.focusNormalised;
document.getElementById("focusRange").value = this.focusNormalised;
}
updateUIISO() {
// TBD
document.getElementById("ISOInput").value = this.ISO;
}
updateUIgain() {
@ -220,15 +219,15 @@ class BMDCamera {
gainString = this.gain+"db"
}
document.getElementsByClassName("gainSpan")[this.index].innerHTML = gainString;
document.getElementById("gainSpan").innerHTML = gainString;
}
updateUIWhiteBalance() {
document.getElementsByClassName("whiteBalanceSpan")[this.index].innerHTML = this.WhiteBalance+"K";
document.getElementById("whiteBalanceSpan").innerHTML = this.WhiteBalance+"K";
}
updateUINDStop() {
document.getElementsByClassName("ndFilterSpan")[this.index].innerHTML = this.NDStop;
document.getElementById("ndFilterSpan").innerHTML = this.NDStop;
}
updateUIshutter() {
@ -237,11 +236,15 @@ class BMDCamera {
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))+"°"
var shangleString = (this.shutter.shutterAngle / 100).toFixed(1).toString()
if (shangleString.indexOf(".0") > 0) {
shutterString = parseFloat(shangleString).toFixed(0)+"°";
} else {
shutterString = shangleString+"°";
}
}
document.getElementsByClassName("shutterSpan")[this.index].innerHTML = shutterString;
document.getElementById("shutterSpan").innerHTML = shutterString;
}
updateUIAutoExposureMode() {
@ -249,7 +252,34 @@ class BMDCamera {
}
updateUIColorCorrection() {
//TBD
// Lift
document.getElementsByClassName("CClumaLabel")[0].innerHTML = this.CClift.luma.toFixed(2);
document.getElementsByClassName("CCredLabel")[0].innerHTML = this.CClift.red.toFixed(2);
document.getElementsByClassName("CCgreenLabel")[0].innerHTML = this.CClift.green.toFixed(2);
document.getElementsByClassName("CCblueLabel")[0].innerHTML = this.CClift.blue.toFixed(2);
// Gamma
document.getElementsByClassName("CClumaLabel")[1].innerHTML = this.CCgamma.luma.toFixed(2);
document.getElementsByClassName("CCredLabel")[1].innerHTML = this.CCgamma.red.toFixed(2);
document.getElementsByClassName("CCgreenLabel")[1].innerHTML = this.CCgamma.green.toFixed(2);
document.getElementsByClassName("CCblueLabel")[1].innerHTML = this.CCgamma.blue.toFixed(2);
// Gain
document.getElementsByClassName("CClumaLabel")[2].innerHTML = this.CCgain.luma.toFixed(2);
document.getElementsByClassName("CCredLabel")[2].innerHTML = this.CCgain.red.toFixed(2);
document.getElementsByClassName("CCgreenLabel")[2].innerHTML = this.CCgain.green.toFixed(2);
document.getElementsByClassName("CCblueLabel")[2].innerHTML = this.CCgain.blue.toFixed(2);
// Offset
document.getElementsByClassName("CClumaLabel")[3].innerHTML = this.CCoffset.luma.toFixed(2);
document.getElementsByClassName("CCredLabel")[3].innerHTML = this.CCoffset.red.toFixed(2);
document.getElementsByClassName("CCgreenLabel")[3].innerHTML = this.CCoffset.green.toFixed(2);
document.getElementsByClassName("CCblueLabel")[3].innerHTML = this.CCoffset.blue.toFixed(2);
}
updateUILinks() {
document.getElementById("documentationLink").href = "http://"+this.hostname+"/control/documentation.html";
document.getElementById("mediaManagerLink").href = "http://"+this.hostname;
}
// =============== GETTERS ==================
@ -257,86 +287,82 @@ class BMDCamera {
// name, hostname, APIaddress, index handled by constructor
getCodecFormat() {
this.pullData("/system/codecFormat").then((value) => {this.codecFormat = value});
this.pullData("/system/codecFormat").then((value) => {this.codecFormat = value; this.updateUICodecFormat()});
}
getVideoFormat() {
this.pullData("/system/videoFormat").then((value) => {this.videoFormat = value});
this.pullData("/system/videoFormat").then((value) => {this.videoFormat = value; this.updateUIVideoFormat()});
}
getSupportedCodecFormats() {
this.pullData("/system/supportedCodecFormats").then((value) => {this.supportedCodecFormats = value});
this.pullData("/system/supportedCodecFormats").then((value) => {this.supportedCodecFormats = value; this.updateUISupportedCodecFormats()});
}
getSupportedVideoFormats() {
this.pullData("/system/supportedVideoFormats").then((value) => {this.supportedVideoFormats = value});
this.pullData("/system/supportedVideoFormats").then((value) => {this.supportedVideoFormats = value; this.updateUISupportedVideoFormats()});
}
getTransportMode() {
this.pullData("/transports/0").then((value) => {this.transportMode = value});
}
getIsPlaying() {
this.pullData("/transports/0/play").then((value) => {this.isPlaying = value});
this.pullData("/transports/0").then((value) => {this.transportMode = value; this.updateUITransportMode()});
}
getPlaybackState() {
this.pullData("/transports/0/playback").then((value) => {this.playbackState = value});
this.pullData("/transports/0/playback").then((value) => {this.playbackState = value; this.updateUIPlaybackState()});
}
getRecordState() {
this.pullData("/transports/0/record").then((value) => {this.recordState = value});
this.pullData("/transports/0/record").then((value) => {this.recordState = value; this.updateUIRecordState()});
}
getTimecode() {
this.pullData("/transports/0/timecode").then((value) => {this.timecode = value});
this.pullData("/transports/0/timecode").then((value) => {this.timecode = value; this.updateUITimecode()});
this.pullData("/transports/0/timecode/source").then((value) => {this.timecode.source = value.source});
}
getPresets() {
this.pullData("/presets").then((value) => {this.presets = value.presets});
this.pullData("/presets").then((value) => {this.presets = value.presets; this.updateUIPresets()});
}
getActivePreset() {
this.pullData("/presets/active").then((value) => {this.activePreset = value});
this.pullData("/presets/active").then((value) => {this.activePreset = value; this.updateUIActivePreset()});
}
getAperture() {
this.pullData("/lens/iris").then((value) => {this.apertureStop = value.apertureStop; this.apertureNormalised = value.normalised});
this.pullData("/lens/iris").then((value) => {this.apertureStop = value.apertureStop; this.apertureNormalised = value.normalised; this.updateUIAperture()});
}
getZoom() {
this.pullData("/lens/zoom").then((value) => {this.zoomMM = value.focalLength; this.zoomNormalised = value.normalised});
this.pullData("/lens/zoom").then((value) => {this.zoomMM = value.focalLength; this.zoomNormalised = value.normalised; this.updateUIZoom()});
}
getFocus() {
this.pullData("/lens/focus").then((value) => {this.focusNormalised = value.normalised});
this.pullData("/lens/focus").then((value) => {this.focusNormalised = value.normalised; this.updateUIFocus()});
}
getISO() {
this.pullData("/video/iso").then((value) => {this.ISO = value.iso});
this.pullData("/video/iso").then((value) => {this.ISO = value.iso; this.updateUIISO()});
}
getGain() {
this.pullData("/video/gain").then((value) => {this.gain = value.gain});
this.pullData("/video/gain").then((value) => {this.gain = value.gain; this.updateUIgain()});
}
getWhiteBalance() {
this.pullData("/video/whiteBalance").then((value) => {this.WhiteBalance = value.whiteBalance});
this.pullData("/video/whiteBalanceTint").then((value) => {this.WhiteBalanceTint = value.whiteBalanceTint});
this.pullData("/video/whiteBalanceTint").then((value) => {this.WhiteBalanceTint = value.whiteBalanceTint; this.updateUIWhiteBalance()});
}
getND() {
this.pullData("/video/ndFilter").then((value) => {this.NDStop = value.stop});
this.pullData("/video/ndFilter").then((value) => {this.NDStop = value.stop; this.updateUINDStop()});
this.pullData("/video/ndFilter/displayMode").then((value) => {this.NDMode = value.displayMode});
}
getShutter() {
this.pullData("/video/shutter").then((value) => {this.shutter = value});
this.pullData("/video/shutter").then((value) => {this.shutter = value; this.updateUIshutter()});
}
getAutoExposureMode() {
this.pullData("/video/autoExposure").then((value) => {this.AutoExposureMode = value});
this.pullData("/video/autoExposure").then((value) => {this.AutoExposureMode = value; this.updateUIAutoExposureMode()});
}
getColorCorrection() {
@ -346,7 +372,7 @@ class BMDCamera {
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});
this.pullData("/colorCorrection/lumaContribution").then((value) => {this.CClumacontribution = value; this.updateUIColorCorrection()});
}
getAllInfo() {
@ -355,7 +381,6 @@ class BMDCamera {
this.getSupportedCodecFormats();
this.getSupportedVideoFormats();
this.getTransportMode();
this.getIsPlaying();
this.getPlaybackState();
this.getRecordState();
this.getTimecode();
@ -373,14 +398,130 @@ class BMDCamera {
this.getColorCorrection();
}
// =============== Other Commands =======================
doAutoFocus() {
this.pushData("/lens/focus/doAutoFocus")
// =============== SETTERS ==================
// name, hostname, APIaddress, index should never have to be set
setCodecFormat(newCodecFormatObject) {
this.pushData("/system/codecFormat",newCodecFormatObject).then(() => sleep(1000).then(() => this.getCodecFormat()));
}
/* Timer Stuff */
everySecond() {
this.refresh();
setVideoFormat(newVideoFormatObject) {
this.pushData("/system/videoFormat",newVideoFormatObject).then(() => sleep(1000).then(() => this.getCodecFormat()));
}
setTransportMode(newTransportModeString) {
this.pushData("/transports/0",{"mode": newTransportModeString}).then(() => sleep(1000).then(() => this.getTransportMode()));
}
setPlaybackState(playbackStateObject) {
this.pushData("/transports/0/playback",playbackStateObject).then(() => sleep(1000).then(() => this.getPlaybackState()));
}
sendPresetFile(file) {
sendRequest("POST",this.APIAddress+"/presets",file)
}
setActivePreset(presetString) {
this.pushData("/presets/active",{"preset": presetString}).then(() => sleep(1000).then(() => this.getActivePreset()));
}
setAperture(apertureNormalisedFloat) {
this.pushData("/lens/iris",{"normalised": apertureNormalisedFloat}).then(() => sleep(1000).then(() => this.getAperture()));
}
setZoom(zoomNormalisedFloat) {
this.pushData("/lens/zoom",{"normalised": zoomNormalisedFloat}).then(() => sleep(1000).then(() => this.getZoom()));
}
setFocus(focusNormalisedFloat) {
this.pushData("/lens/focus",{"normalised": focusNormalisedFloat}).then(() => sleep(1000).then(() => this.getFocus()));
}
setISO(ISOint) {
this.pushData("/video/iso",{"iso":ISOint}).then(() => sleep(1000).then(() => this.getISO()));
}
setGain(gainInt) {
this.pushData("/video/gain",{"gain":gainInt}).then(() => sleep(1000).then(() => this.getGain()));
}
setWhiteBalance(whiteBalanceInt, whiteBalanceTintInt) {
this.pushData("/video/whiteBalance",{"whiteBalance": whiteBalanceInt});
this.pushData("/video/whiteBalanceTint",{"whiteBalanceTint": whiteBalanceTintInt}).then(() => sleep(1000).then(() => this.getWhiteBalance()));
}
setND(NDstopInt) {
this.pushData("/video/ndFilter",{"stop": NDstopInt}).then(() => sleep(1000).then(() => this.getND()));
}
setNDDisplayMode(displayModeString) {
this.pushData("/video/ndFilter/displayMode",{"displayMode": displayModeString}).then(() => sleep(1000).then(() => this.getND()));
}
// Accepts JSON obejcts with either shutterSpeed or shutterAngle properties
// Note that shutterAngle is 100x the displayed value
setShutter(shutterObject) {
this.pushData("/video/shutter",shutterObject).then(() => sleep(1000).then(() => this.getShutter()));
}
setAutoExposureMode(AEmodeObject) {
this.pushData("/video/autoExposure",AEmodeObject).then(() => sleep(1000).then(() => this.getAutoExposureMode()));
}
setCCLift(CCliftObject) {
this.pushData("/colorCorrection/lift",CCliftObject).then(() => sleep(1000).then(() => this.getColorCorrection()));
}
setCCGamma(CCgammaObject) {
this.pushData("/colorCorrection/gamma",CCgammaObject).then(() => sleep(1000).then(() => this.getColorCorrection()));
}
setCCGain(CCgainObject) {
this.pushData("/colorCorrection/gain",CCgainObject).then(() => sleep(1000).then(() => this.getColorCorrection()));
}
setCCOffset(CCoffsetObject) {
this.pushData("/colorCorrection/offset",CCoffsetObject).then(() => sleep(1000).then(() => this.getColorCorrection()));
}
setCCContrast(CCcontrastObject) {
this.pushData("/colorCorrection/contrast",CCcontrastObject).then(() => sleep(1000).then(() => this.getColorCorrection()));
}
setCCColor(CCcolorObject) {
this.pushData("/colorCorrection/color",CCcolorObject).then(() => sleep(1000).then(() => this.getColorCorrection()));
}
setCCLumaContribuion(CClumacontributionObject) {
this.pushData("/colorCorrection/lumaContribution",CClumacontributionObject).then(() => sleep(1000).then(() => this.getColorCorrection()));
}
// =============== Other Commands =======================
doAutoFocus() {
this.pushData("/lens/focus/doAutoFocus").then(() => sleep(1500).then(() => this.getFocus()));
}
play() {
this.pushData("/transports/0/play").then(() => sleep(1000).then(() => this.getPlaybackState()));
}
record() {
this.pushData("/transports/0/record",{"recording": true}).then(() => {
sleep(2000).then(() => this.getRecordState());
});
}
stopTransport() {
this.pushData("/transports/0/stop").then(() => {
sleep(2000).then(() => this.getPlaybackState());
});
}
stopRecord() {
this.pushData("/transports/0/record",{"recording": false}).then(() => {
sleep(2000).then(() => this.getRecordState());
});
}
}
@ -398,8 +539,27 @@ async function sendRequest(method, url, data) {
}
}
xhttp.open(method, url, false);
xhttp.send(JSON.stringify(data));
// Don't keep making API calls for unimplemented features
if (cameras[ci]) {
// First check if the camera exists.
if (cameras[ci].UnimplementedFunctionality.indexOf(url) < 0) {
// If everything is honky dory
xhttp.open(method, url, false);
xhttp.send(JSON.stringify(data));
} else {
// If everything is not honky dory
// do nothing
}
if ((!responseObject) || (Object.hasOwn(responseObject,'error') && responseObject.error == "Not implemented for this device")) {
cameras[ci].UnimplementedFunctionality.push(url);
}
} else {
xhttp.open(method, url, false);
xhttp.send(JSON.stringify(data));
}
return responseObject;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View file

@ -24,71 +24,268 @@
<!-- Camera Select Bar -->
<div class="flexContainerH" id="cameraSelectContainer">
<span class="cameraSwitchLabel selectedCam"><a href="#" onclick="switchCamera(0)">CAM1</a></span>
<span class="camSelectSeparator">|</span>
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(1)">CAM2</a></span>
<span class="camSelectSeparator">|</span>
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(2)">CAM3</a></span>
<span class="camSelectSeparator">|</span>
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(3)">CAM4</a></span>
<span class="camSelectSeparator">|</span>
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(4)">CAM5</a></span>
<span class="camSelectSeparator">|</span>
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(5)">CAM6</a></span>
<span class="camSelectSeparator">|</span>
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(6)">CAM7</a></span>
<span class="camSelectSeparator">|</span>
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(7)">CAM8</a></span>
</div>
<!-- Camera Controls Box -->
<div class="flexContainerH" id="allCamerasContainer">
<div class="flexContainerV cameraControlsContainer">
<div class="flexContainerH cameraControlHeadContainer">
<h2 class="cameraName">CAM1</h2>
<div class="flexContainerV" id="cameraControlsContainer">
<div class="flexContainerH" id="cameraControlHeadContainer">
<h2 id="cameraNumberLabel">CAM1</h2>
</div>
<div class="flexContainerH cameraControlColorCorrectionContainer">
<div class="flexContainerH" id="cameraControlColorCorrectionContainer">
<!-- <div class="flexContainerH" id="cameraControlLGGTabs">
<a href="#" class="ccTabLabel selectedTab" onclick="setCCMode(0)">Lift</a>
<a href="#" class="ccTabLabel" onclick="setCCMode(1)">Gamma</a>
<a href="#" class="ccTabLabel" onclick="setCCMode(2)">Gain</a>
</div> -->
<span style="margin-top: 0.5em;">Lift</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button id="CCResetButton" class="circleButton" onclick="resetCC(0)" title="Reset Lift">&#10227</button>
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel">0.00</span>
</div>
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(0)" title="Set Lift">&#10138</button>
</div>
<span>Gamma</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button id="CCResetButton" class="circleButton" onclick="resetCC(1)" title="Reset Gamma">&#10227</button>
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel">0.00</span>
</div>
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(1)" title="Set Gamma">&#10138</button>
</div>
<span>Gain</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button id="CCResetButton" class="circleButton" onclick="resetCC(2)" title="Reset Gain">&#10227</button>
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel">0.00</span>
</div>
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(2)" title="Set Gain">&#10138</button>
</div>
<span>Offset</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button id="CCResetButton" class="circleButton" onclick="resetCC(3)" title="Reset Offset">&#10227</button>
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel">0.00</span>
</div>
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(3)" title="Set Offset">&#10138</button>
</div>
</div>
<div class="flexContainerH cameraControlExposureContainer">
<div class="flexContainerH" id="cameraControlExposureContainer">
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">FILTER</span>
<!-- Add control arrows -->
<span class="ndFilterSpan">0</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseND()" id="NDL">&#9664</a>
<span id="ndFilterSpan">0</span>
<a class="expAdjArr" href="#" onclick="increaseND()" id="NDR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">GAIN</span>
<!-- Add control arrows -->
<span class="gainSpan">+0db</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseGain()" id="GAL">&#9664</a>
<span id="gainSpan">+0db</span>
<a class="expAdjArr" href="#" onclick="increaseGain()" id="GAR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">SHUTTER</span>
<!-- Add control arrows -->
<span class="shutterSpan">1/50</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseShutter()" id="SHL">&#9664</a>
<span id="shutterSpan">1/50</span>
<a class="expAdjArr" href="#" onclick="increaseShutter()" id="SHR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">BALANCE</span>
<!-- Add control arrows -->
<span class="whiteBalanceSpan">5600K</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalance()" id="WBL">&#9664</a>
<span id="whiteBalanceSpan">5600K</span>
<a class="expAdjArr" href="#" onclick="increaseWhiteBalance()" id="WBR">&#9654</a>
</div>
</div>
</div>
<div class="flexContainerH cameraControlLensContainer">
<div class="flexContainerH" id="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>
<input type="range" orient="vertical" max="1" min="0" step="0.001" id="focusRange" onmouseup="cameras[ci].setFocus(parseFloat(this.value))">
<button id="AFButton" class="circleButton" 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>
<input type="range" orient="vertical" max="1" min="0" step="0.001" id="irisRange" onmouseup="cameras[ci].setAperture(parseFloat(this.value))">
<span id="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>
<input type="range" orient="vertical" max="1" min="0" step="0.001" id="zoomRange" onmouseup="cameras[ci].setZoom(parseFloat(this.value))">
<span id="zoomMMLabel">XXmm</span>
</div>
</div>
</div>
<div class="flexContainerV cameraControlsContainerExpanded">
<div class="flexContainerH cameraControlExpandedHeadContainer">
<h2 class="timecodeLabel">TIMECODE</h2>
<div class="flexContainerV" id="cameraControlsContainerExpanded">
<div class="flexContainerH" id="cameraControlExpandedHeadContainer">
<h2 id="cameraName">CAMERA NAME</h2>
<div id="transportControls">
<!-- These will be sticky buttons for loop, single clip, record -->
<button class="circleButton" onclick="" title="Loop">&#8635</button>
<button class="circleButton" onclick="" title="Single Clip">S</button>
<button class="circleButton" onclick="" title="Back">&#9204</button>
<button class="circleButton" onclick="" title="Forward">&#9205</button>
<button class="circleButton" onclick="cameras[ci].record()" title="Record">&#9210</button>
<button class="circleButton" onclick="cameras[ci].play()" title="Play">&#9654</button>
<button class="circleButton" onclick="cameras[ci].stopTransport(); cameras[ci].stopRecord();" title="Stop">&#9209</button>
</div>
<h2 id="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 class="flexContainerV" id="cameraControlExpandedBodyContainer">
<div class="tableControl">
<h3>Connection</h3>
<table>
<tr>
<td>Hostname</td>
<td>
<input type="text" value="Studio-Camera-6K-Pro.local" id="hostnameInput" onkeydown="textInputTrigger(this)">
<button onclick='cameras[ci] = new BMDCamera(document.getElementById("hostnameInput").value,ci);'>Connect</button>
</td>
</tr>
<tr>
<td>Send API Call</td>
<td>
<input type="radio" id="requestTypeGET" value="GET" name="manualRequestType" checked>
<label for="requestTypeGET">GET</label>
<input type="radio" id="requestTypePUT" value="PUT" name="manualRequestType">
<label for="requestTypePUT">PUT</label>
<input type="text" id="manualRequestEndpointLabel" placeholder="request endpoint">
<input type="text" id="manualRequestBodyLabel" placeholder="request body">
<button onclick="manualAPICall()">Send API Request</button>
</td>
</tr>
</table>
</div>
<div class="tableControl">
<h3>Presets</h3>
<table>
<tr>
<td>Preset Select</td>
<td>
<select id="presetsDropDown" onchange="console.log('Preset selected: '+this.value)">
<option value="default">Default</option>
<option value="other">other</option>
</select>
</td>
</tr>
<tr>
<td style="color: #727272;">Upload a preset file</td>
<td><input type="file" id="presetFileInput"></td>
</tr>
</table>
</div>
<div class="tableControl">
<h3>Exposure</h3>
<table>
<tr>
<td>ISO</td>
<td><input type="number" id="ISOInput" step="100" oninput="cameras[ci].setISO(parseInt(this.value))"></td>
</tr>
<tr>
<td>AE Mode</td>
<td>
<select id="AEmodeDropDown">
<option value="Off">Off</option>
<option value="Continuous">Continuous</option>
<option value="OneShot">One-Shot</option>
</select>
</td>
</tr>
<tr>
<td>AE Type</td>
<td>
<select id="AEtypeDropDown">
<option value="">None</option>
<option value="Iris">Iris Only</option>
<option value="Shutter">Shutter Only</option>
<option value="Shutter,Iris">Shutter + Iris</option>
<option value="Iris,Shutter">Iris + Shutter</option>
</select>
</td>
</tr>
</table>
<button style="margin: 2vh 0 0 3.5vw;" onclick="AEmodeInputHandler()">Set AE Mode</button>
</div>
<div class="tableControl">
<h3>Contrast</h3>
<table>
<tr>
<td>Pivot</td>
<td><input type="range" max="1" min="0" step="0.001" id="CCcontrastPivotRange"></td>
</tr>
<tr>
<td>Adjust</td>
<td><input type="range" max="1" min="0" step="0.001" id="CCcontrastAdjustRange"></td>
</tr>
</table>
</div>
<div class="tableControl">
<h3>Color</h3>
<table>
<tr>
<td>Hue</td>
<td><input type="range" max="1" min="0" step="0.001" id="CChueRange"></td>
</tr>
<tr>
<td>Saturation</td>
<td><input type="range" max="1" min="0" step="0.001" id="CCsaturationRange"></td>
</tr>
<tr>
<td>Luma Contribution</td>
<td><input type="range" max="1" min="0" step="0.001" id="CClumaContributionRange"></td>
</tr>
</table>
</div>
</div>
</div>
@ -97,6 +294,11 @@
<!-- Footer Div -->
<div class="flexContainerH" id="footerContainer">
<button onclick="cameras.forEach((element) => {element.refresh()});">Refresh</button>
<div id="footerLinks">
<span><a id="documentationLink" href="#" target="_blank">YAML Documentation</a></span>
<span><a id="mediaManagerLink" href="#" target="_blank">Web Media Manager</a></span>
<span><a id="githubLink" href="#" target="https://github.com/DylanSpeiser/BM-Camera-Control-WebUI">GitHub</a></span>
</div>
</div>
</body>
</html>

View file

@ -1,3 +1,5 @@
/* ============= WHOLE PAGE STYLES ================== */
/* Load NotoSansDisplay Font from resources */
@font-face {
font-family: 'NotoSansDisplay';
@ -7,6 +9,7 @@
body {
font-family: 'NotoSansDisplay', sans-serif;
font-weight: 100;
margin: 0px;
overflow: hidden;
background: #181818;
@ -22,6 +25,91 @@ body {
display: inline-flex;
}
/* Inputs */
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);
text-align: center;
font-family: 'NotoSansDisplay', sans-serif;
outline: none;
margin: 0px 0.5vw;
}
input[type=text]:focus {
border: 1px solid rgb(150, 58, 0);
}
input[type=number] {
border-radius: 0.5vh;
background: rgb(30, 30, 30);
color: white;
height: 2em;
width: 4.666vw;
border: 1px solid rgb(20, 20, 20);
text-align: center;
font-family: 'NotoSansDisplay', sans-serif;
outline: none;
}
input[type=number]:focus {
border: 1px solid rgb(150, 58, 0);
}
input[type=range][orient=vertical] {
writing-mode: vertical-lr; direction: rtl;
width: 2vw;
height: 80%;
}
select {
border-radius: 0.5vh;
background: rgb(30, 30, 30);
color: white;
height: 2em;
width: 5vw;
border: 1px solid rgb(20, 20, 20);
text-align: center;
font-family: 'NotoSansDisplay', sans-serif;
outline: none;
}
select:focus {
border: 1px solid rgb(150, 58, 0);
}
button {
font-family: 'NotoSansDisplay', sans-serif;
background: #181818;
background: linear-gradient(0deg, #232323 0%, #404040 100%);
border: 0.3vh solid black;
outline: 0.3vh solid #404040;
color: white;
height: fit-content;
width: fit-content;
border-radius: 0.4em;
padding: 0.5vh 1vw;
margin: 1vh;
}
button:hover {
background: #313131;
background: linear-gradient(0deg, #313131 0%, #4d4d4d 100%);
}
button:active {
background: #181818;
box-shadow: inset 0 0 1em #090909;
}
input[type=file]:focus {
border: 1px solid rgb(150, 58, 0);
}
/* Horizontal Container Styles */
#headerContainer {
background: #181818;
@ -34,9 +122,9 @@ body {
}
#headerContainer h1 {
font-weight: 100;
color: white;
margin-left: 1.3vw;
font-weight: 100;
}
#cameraSelectContainer {
@ -44,6 +132,27 @@ body {
border: 1px solid black;
width: 100%;
height: 3.53vh;
color: #474747;
font-size: 1em;
align-items: center;
justify-content: center;
}
#cameraSelectContainer span {
height: fit-content;
}
#cameraSelectContainer .camSelectSeparator {
margin: 0px 0.5em;
}
.cameraSwitchLabel a {
text-decoration: none;
color: #474747;
}
.cameraSwitchLabel.selectedCam a {
color: #e66c01;
}
#allCamerasContainer {
@ -64,10 +173,26 @@ body {
height: 5vh;
position: fixed;
bottom: 0;
align-items: center;
justify-content: space-between;
}
#footerContainer button {
padding: 0.4em 0.8em;
font-size: x-small;
}
#footerLinks span {
margin-right: 1.25vw;
}
#footerLinks a {
text-decoration: none;
color: #e66c01;
}
/* Camera Controls Container */
.cameraControlsContainer {
#cameraControlsContainer {
width: 15vw;
height: 100%;
background: #282828;
@ -76,39 +201,98 @@ body {
flex-shrink: 0;
}
.cameraControlsContainer.selectedCam {
background: #323232;
}
.liveCam .cameraControlHeadContainer {
.liveCam {
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 {
#cameraControlHeadContainer {
width: 100%;
height: 5vh;
border-bottom: 2px solid black;
align-items: center;
color: white;
}
.cameraName {
font-weight: 100;
color: white;
h2 {
margin-inline-start: 0.6em;
margin-inline-end: 0.6em;
font-weight: 100;
}
#cameraName {
}
/* Color Correction Section */
.cameraControlColorCorrectionContainer {
#cameraControlColorCorrectionContainer {
width: 100%;
height: 33vh;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
#cameraControlLGGTabs {
margin-top: 2vh;
border: 1px solid #101010;
border-radius: 2.5vh;
overflow: hidden;
}
#cameraControlLGGTabs a {
background: #181818;
background: linear-gradient(0deg, #181818 0%, #303030 100%);
padding: 0.1vh 1.25vw 0.25vh 1.25vw;
border-left: 1px solid #101010;
text-decoration: none;
color: #474747;
}
#cameraControlLGGTabs a.selectedTab {
color: #e66c01;
}
.ccExposureSettingValueContainer .expAdjArr {
text-decoration: none;
color: #60606000;
}
.ccExposureSettingValueContainer:hover .expAdjArr {
color: #606060ff;
}
.ccExposureSettingValueContainer:hover .expAdjArr:hover {
color: #474747;
}
.ccExposureSettingValueContainer:hover .expAdjArr:active {
color: #e66c01;
}
#cameraControlColorCorrectionBottomContainer {
margin-bottom: 1em;
display: inline-flex;
align-items: center;
}
#cameraControlColorCorrectionBottomContainer button {
margin: 0px 0.5em;
}
#cameraControlColorCorrectionNumbersContainer span {
margin: 0px 0.5em;
text-decoration: underline 3px;
}
/* Exposure Section */
.cameraControlExposureContainer {
#cameraControlExposureContainer {
width: 100%;
height: 4.4vh;
height: 4.7vh;
background-color: #171717;
border-top: 1px solid #2d2d2d;
border-bottom: 1px solid #2d2d2d;
@ -117,11 +301,6 @@ body {
overflow: hidden;
}
.selectedCam .cameraControlExposureContainer {
border-top: 1px solid #3a3a3a;
border-bottom: 1px solid #3a3a3a;
}
.ccExposureSettingContainer {
display: flex;
color: white;
@ -141,7 +320,7 @@ body {
}
/* Lens Stuff */
.cameraControlLensContainer {
#cameraControlLensContainer {
width: 100%;
height: 41.9vh;
border-bottom: 1px solid black;
@ -159,19 +338,20 @@ body {
margin-bottom: 1em;
}
.lensSliderContainer button {
margin-top: 1em;
margin-bottom: 1em;
.circleButton {
width: 2em;
height: 2em;
border-radius: 1em;
padding: 0;
margin: 1em 0;
}
input[type=range][orient=vertical] {
-webkit-appearance: slider-vertical;
width: 2vw;
height: 80%;
#transportControls .circleButton {
margin: 0 0.5em;
}
/* Right side (expanded) */
.cameraControlsContainerExpanded {
#cameraControlsContainerExpanded {
width: 84.75vw;
height: 100%;
background: #282828;
@ -180,39 +360,43 @@ input[type=range][orient=vertical] {
flex-shrink: 0;
}
.cameraControlExpandedHeadContainer {
#cameraControlExpandedHeadContainer {
width: 100%;
height: 5vh;
border-bottom: 2px solid black;
align-items: center;
justify-content: center;
justify-content: space-between;
}
.timecodeLabel {
#cameraControlExpandedBodyContainer {
flex-direction: column;
display: inline-flex;
height: inherit;
justify-content: space-around;
}
#timecodeLabel {
}
/* Table Controls */
.tableControl {
margin-left: 1.5vw;
}
.tableControl h3 {
font-weight: 100;
color: white;
margin-inline-start: 0.6em;
margin-inline-end: 0.6em;
margin: 0.5vh 0vw;
}
/* Connection Settings */
.connectionContainer {
margin: 1.5vw;
table, td {
margin-left: 0.5vw;
/* border: 1px solid white; */
border-collapse: collapse;
padding: 0.1vw 1vw;
}
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);
td, tr {
align-items: center;
}

View file

@ -1,20 +1,38 @@
/* Global variables */
var cameras = [];
var ci = 0;
var ccMode = 0;
function bodyOnLoad() {
//let intervalID = setInterval(timerCallFunction, 1000);
let intervalIDOne = setInterval(timerCallFunction1, 1000); // Tem second timer for refreshing everything
let intervalIDTen = setInterval(timerCallFunction10, 10000); // Tem second timer for refreshing everything
let newCamHostname = document.getElementsByClassName("hostnameInput")[ci].value;
let newCamHostname = document.getElementById("hostnameInput").value;
if (newCamHostname) {
cameras[ci] = new BMDCamera(newCamHostname,ci);
}
}
// function timerCallFunction() {
// cameras.forEach((camera) => camera.everySecond());
// }
// One Second Timer Call
function timerCallFunction1() {
if (cameras[ci]) {
cameras[ci].getRecordState();
cameras[ci].getPlaybackState();
cameras[ci].getTimecode();
cameras[ci].updateUIRecordState();
cameras[ci].updateUIPlaybackState();
cameras[ci].updateUITimecode();
}
}
// Ten Second Timer Call
function timerCallFunction10() {
if (cameras[ci]) {
cameras[ci].refresh();
}
}
function textInputTrigger(element) {
if (event.key === 'Enter') {
@ -22,6 +40,124 @@ function textInputTrigger(element) {
}
}
function switchCamera(index) {
ci = index;
if (cameras[ci]) {
cameras[ci].refresh();
}
for (var i = 0; i < 8; i++) {
if (i == ci) {
document.getElementsByClassName("cameraSwitchLabel")[i].classList.add("selectedCam");
} else {
document.getElementsByClassName("cameraSwitchLabel")[i].classList.remove("selectedCam");
}
}
document.getElementById("cameraNumberLabel").innerHTML = "CAM"+(ci+1);
}
function setCCMode(mode) {
if (mode == 0) {
// Lift
} else if (mode == 1) {
// Gamma
} else {
// Gain
}
for (var i = 0; i < 3; i++) {
if (i == mode) {
document.getElementsByClassName("ccTabLabel")[i].classList.add("selectedTab");
} else {
document.getElementsByClassName("ccTabLabel")[i].classList.remove("selectedTab");
}
}
}
/* Control Calling Functions */
function decreaseND() {
cameras[ci].setND(cameras[ci].NDStop-2);
}
function increaseND() {
cameras[ci].setND(cameras[ci].NDStop+2);
}
function decreaseGain() {
cameras[ci].setGain(cameras[ci].gain-2);
}
function increaseGain() {
cameras[ci].setGain(cameras[ci].gain+2);
}
function decreaseShutter() {
let cam = cameras[ci];
if ('shutterSpeed' in cam.shutter) {
cam.setShutter({"shutterSpeed":cam.shutter.shutterSpeed+10});
} else {
cam.setShutter({"shutterAngle": cam.shutter.shutterAngle-1000});
}
}
function increaseShutter() {
let cam = cameras[ci];
if ('shutterSpeed' in cam.shutter) {
cam.setShutter({"shutterSpeed":cam.shutter.shutterSpeed-10});
} else {
cam.setShutter({"shutterAngle": cam.shutter.shutterAngle+1000});
}
}
function decreaseWhiteBalance() {
cameras[ci].setWhiteBalance(cameras[ci].WhiteBalance-50,cameras[ci].WhiteBalanceTint);
}
function increaseWhiteBalance() {
cameras[ci].setWhiteBalance(cameras[ci].WhiteBalance+50,cameras[ci].WhiteBalanceTint);
}
// 0: lift, 1: gamma, 2: gain, 3: offset
function setCCFromUI(which) {
let lumaFloat = parseFloat(document.getElementsByClassName("CClumaLabel")[which].innerHTML);
let redFloat = parseFloat(document.getElementsByClassName("CCredLabel")[which].innerHTML);
let greenFloat = parseFloat(document.getElementsByClassName("CCgreenLabel")[which].innerHTML);
let blueFloat = parseFloat(document.getElementsByClassName("CCblueLabel")[which].innerHTML);
let ccobject = {"red": redFloat, "green": greenFloat, "blue": blueFloat, "luma": lumaFloat};
if (which == 0) {
cameras[ci].setCCLift(ccobject);
} else if (which == 1) {
cameras[ci].setCCGamma(ccobject);
} else if (which == 2) {
cameras[ci].setCCGain(ccobject);
} else {
cameras[ci].setCCOffset(ccobject);
}
}
// 0: lift, 1: gamma, 2: gain, 3: offset
function resetCC(which) {
if (which == 0) {
cameras[ci].setCCLift({"red": 0.0, "green": 0.0, "blue": 0.0, "luma": 0.0});
} else if (which == 1) {
cameras[ci].setCCGamma({"red": 0.0, "green": 0.0, "blue": 0.0, "luma": 0.0});
} else if (which == 2) {
cameras[ci].setCCGain({"red": 1.0, "green": 1.0, "blue": 1.0, "luma": 1.0});
} else {
cameras[ci].setCCOffset({"red": 0.0, "green": 0.0, "blue": 0.0, "luma": 0.0});
}
}
function makeFakeCamera() {
cam = new BMDCamera("Studio-Camera-6K-Pro.local",0)
return Object.assign(cam,{
@ -32,7 +168,6 @@ function makeFakeCamera() {
"transportMode": {
"mode": "InputPreview"
},
"isPlaying": false,
"playbackState": {
"loop": false,
"position": 0,