BM-Camera-Control-WebUI/index.html
DylanSpeiser 5ad7289977 1.4.1
Big fix
2024-10-30 15:06:52 -04:00

349 lines
No EOL
25 KiB
HTML

<!-- (c) 2024 Dylan Speiser -->
<!DOCTYPE html>
<html>
<head>
<!-- Page title and metadata -->
<title>Camera Control WebUI for Blackmagic Cameras</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="BMDevice.js"></script>
<script src="web-ui.js"></script>
<!------ Page Content ------>
<!-- Header Div -->
<div class="flexContainerH" id="headerContainer">
<h1>Camera Control WebUI for Blackmagic Cameras</h1>
</div>
<!-- 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" id="cameraControlsContainer">
<div class="flexContainerH" id="cameraControlHeadContainer">
<h2 id="cameraNumberLabel">CAM1</h2>
</div>
<div class="flexContainerH" id="cameraControlColorCorrectionContainer">
<!-- <div class="flexContainerH" id="cameraControlLGGTabs">
<a href="#" class="ccTabLabel selectedTab" onclick="">Lift</a>
<a href="#" class="ccTabLabel" onclick="">Gamma</a>
<a href="#" class="ccTabLabel" onclick="">Gain</a>
</div> -->
<span style="margin-top: 0.5em;">Lift</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button class="CCResetButton 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" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">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 class="CCResetButton 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" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">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 class="CCResetButton 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" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">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 class="CCResetButton 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" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
</div>
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(4)" title="Set Offset">&#10138</button>
</div>
</div>
<div class="flexContainerH" id="cameraControlExposureContainer">
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">FILTER</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseND()" id="NDL">&#9664</a>
<span id="ndFilterSpan" contenteditable="plaintext-only" onkeydown="NDFilterInputHandler()" onmousedown="NDFilterInputHandler()">0</span>
<a class="expAdjArr" href="#" onclick="increaseND()" id="NDR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">GAIN</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseGain()" id="GAL">&#9664</a>
<span id="gainSpan" contenteditable="plaintext-only" onkeydown="GainInputHandler()" onmousedown="GainInputHandler()">+0db</span>
<a class="expAdjArr" href="#" onclick="increaseGain()" id="GAR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">SHUTTER</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseShutter()" id="SHL">&#9664</a>
<span id="shutterSpan" contenteditable="plaintext-only" onkeydown="handleShutterInput()" onmousedown="handleShutterInput()">1/50</span>
<a class="expAdjArr" href="#" onclick="increaseShutter()" id="SHR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel" onclick="swapWBMode()" title="Click here to swap between WB and Tint" id="WBLabel">BALANCE</span>
<div class="ccExposureSettingValueContainer" id="WBValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalance()" id="WBL">&#9664</a>
<span id="whiteBalanceSpan" contenteditable="plaintext-only" onkeydown="WBInputHandler()" onmousedown="WBInputHandler()">5600K</span>
<a class="expAdjArr" href="#" onclick="increaseWhiteBalance()" id="WBR">&#9654</a>
</div>
<div class="ccExposureSettingValueContainer dNone" id="WBTintValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalanceTint()" id="WBTL">&#9664</a>
<span id="whiteBalanceTintSpan" contenteditable="plaintext-only" onkeydown="WBTInputHandler()" onmousedown="WBTInputHandler()">0</span>
<a class="expAdjArr" href="#" onclick="increaseWhiteBalanceTint()" id="WBLR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<button id="AWBButton" class="circleButton" title="Make the camera do an Auto Whitebalance" onclick="cameras[ci].doAutoWhitebalance()">AW</button>
</div>
</div>
<div class="flexContainerH" id="cameraControlLensContainer">
<div class="lensSliderContainer">
<span>FOCUS</span>
<input type="range" orient="vertical" max="1" min="0" step="0.001" id="focusRange" oninput="cameras[ci].PUTdata('/lens/focus', {normalised: 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" id="irisRange" oninput="cameras[ci].PUTdata('/lens/iris', {normalised: 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" id="zoomRange" oninput="cameras[ci].PUTdata('/lens/zoom', {normalised: parseFloat(this.value)})">
<span id="zoomMMLabel">XXmm</span>
</div>
</div>
</div>
<div class="flexContainerV" id="cameraControlsContainerExpanded">
<div class="flexContainerH" id="cameraControlExpandedHeadContainer">
<h2 id="cameraName">CAMERA NAME</h2>
<div id="formatDisplay">
<span id="formatCodec">CODEC</span>
<span id="formatResolution">RESOLUTION</span>
<span id="formatFPS">FPS</span>
</div>
<div id="transportControls">
<!-- These will be sticky buttons for loop, single clip, record -->
<button class="circleButton" onclick="loopHandler('Loop')" title="Loop" id="loopButton">&#8635</button>
<button class="circleButton" onclick="loopHandler('Single Clip')" title="Single Clip" id="singleClipButton">S</button>
<button class="circleButton" onclick="cameras[ci].seek(false)" title="Back">&#9204</button>
<button class="circleButton" onclick="cameras[ci].seek(true)" title="Forward">&#9205</button>
<button class="circleButton" onclick="cameras[ci].toggleRecord()" title="Record" style="color: red;">&#9210</button>
<button class="circleButton" onclick="cameras[ci].play()" title="Play">&#9654</button>
<button class="circleButton" onclick="cameras[ci].stop()" title="Stop">&#9209</button>
</div>
<h2 id="timecodeLabel">TIMECODE</h2>
</div>
<div class="flexContainerV" id="cameraControlExpandedBodyContainer">
<div class="tableControl">
<h3>Connection</h3>
<table>
<tr>
<td>Hostname</td>
<td>
<input type="text" placeholder=" Camera-Name-Here.local" id="hostnameInput" onclick="hostnameInputHandler()" onkeydown="hostnameInputHandler()" style="text-align: left;">
<button onclick="initCamera()">Connect</button>
<input type="checkbox" id="secureCheckbox">
<span id="secureCheckboxLabel">Use HTTPS</span>
<span id="connectionErrorSpan"></span>
</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>
<tr>
<td colspan="2">
<p id="manualRequestResponseP">Send manual API requests using the above controls. See <a href="https://documents.blackmagicdesign.com/DeveloperManuals/RESTAPIforBlackmagicCameras.pdf?_v=1696143610000" target="_blank" style="color: #6e6e6e;">documentation</a> for details.</p>
</td>
</tr>
</table>
</div>
<div class="tableControl">
<h3>Presets</h3>
<table>
<tr>
<td>Preset Select</td>
<td>
<select id="presetsDropDown" onmousedown="unsavedChanges.push('presets')" onchange="presetInputHandler()">
<!-- Auto-populated by updateUIPresets() -->
</select>
</td>
<td>
<button onclick="presetInputHandler()">Restore from Preset</button>
</td>
</tr>
</table>
</div>
<div class="tableControl">
<h3>Exposure</h3>
<table>
<tr>
<td>ISO</td>
<td><input type="number" id="ISOInput" step="100" onkeydown="ISOInputHandler()" onmousedown="unsavedChanges.push('ISO')"></td>
</tr>
<tr>
<td>AE Mode</td>
<td>
<select id="AEmodeDropDown" onmousedown="unsavedChanges.push('AutoExposure')">
<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" onmousedown="unsavedChanges.push('AutoExposure')">
<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" oninput="cameras[ci].PUTdata('/colorCorrection/contrast', {pivot: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC4')});"></td>
<td>
<span id="CCcontrastPivotLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(4)" onmousedown="CCInputHandler(4)">0</span>
</td>
<td rowspan="2">
<button class="CCResetButton circleButton" onclick="resetCC(4)" title="Reset Contrast">&#10227</button>
</td>
</tr>
<tr>
<td>Adjust</td>
<td><input type="range" max="2" min="0" step="0.001" id="CCcontrastAdjustRange" oninput="cameras[ci].PUTdata('/colorCorrection/contrast', {adjust: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC4')});"></td>
<td>
<span id="CCcontrastAdjustLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(4)" onmousedown="CCInputHandler(4)">0</span>
</td>
</tr>
</table>
</div>
<div class="tableControl">
<h3>Color</h3>
<table>
<tr>
<td>Hue</td>
<td><input type="range" max="1" min="-1" step="0.001" id="CChueRange" oninput="cameras[ci].PUTdata('/colorCorrection/color', {hue: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC5')});"></td>
<td>
<span id="CCcolorHueLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">0</span>
</td>
<td rowspan="3">
<button class="CCResetButton circleButton" onclick="resetCC(5)" title="Reset Color">&#10227</button>
</td>
</tr>
<tr>
<td>Saturation</td>
<td><input type="range" max="2" min="0" step="0.001" id="CCsaturationRange" oninput="cameras[ci].PUTdata('/colorCorrection/color', {saturation: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC5')});"></td>
<td>
<span id="CCcolorSatLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">0</span>
</td>
</tr>
<tr>
<td>Luma Contribution</td>
<td><input type="range" max="1" min="0" step="0.001" id="CClumaContributionRange" oninput="cameras[ci].PUTdata('/colorCorrection/lumaContribution', {lumaContribution: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC5')});"></td>
<td>
<span id="CCcolorLCLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">0</span>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<!-- Footer Div -->
<div class="flexContainerH" id="footerContainer">
<div id="footerLeft">
<span class="">(v 1.4.1)</span>
<span id="activeElementSpan"></span>
</div>
<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="https://github.com/DylanSpeiser/BM-Camera-Control-WebUI" target="_blank">GitHub</a></span>
</div>
</div>
</body>
</html>