342 lines
No EOL
23 KiB
HTML
342 lines
No EOL
23 KiB
HTML
<!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">
|
|
<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="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 class="CCResetButton circleButton" onclick="resetCC(0)" title="Reset Lift">⟳</button>
|
|
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" oninput="setCCFromUI(0)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" oninput="setCCFromUI(0)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" oninput="setCCFromUI(0)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" oninput="setCCFromUI(0)">0.00</span>
|
|
</div>
|
|
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(0)" title="Set Lift">➚</button>
|
|
</div>
|
|
|
|
<span>Gamma</span>
|
|
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
|
|
<button class="CCResetButton circleButton" onclick="resetCC(1)" title="Reset Gamma">⟳</button>
|
|
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" oninput="setCCFromUI(1)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" oninput="setCCFromUI(1)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" oninput="setCCFromUI(1)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" oninput="setCCFromUI(1)">0.00</span>
|
|
</div>
|
|
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(1)" title="Set Gamma">➚</button>
|
|
</div>
|
|
|
|
<span>Gain</span>
|
|
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
|
|
<button class="CCResetButton circleButton" onclick="resetCC(2)" title="Reset Gain">⟳</button>
|
|
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" oninput="setCCFromUI(2)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" oninput="setCCFromUI(2)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" oninput="setCCFromUI(2)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" oninput="setCCFromUI(2)">0.00</span>
|
|
</div>
|
|
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(2)" title="Set Gain">➚</button>
|
|
</div>
|
|
|
|
|
|
<span>Offset</span>
|
|
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
|
|
<button class="CCResetButton circleButton" onclick="resetCC(3)" title="Reset Offset">⟳</button>
|
|
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" oninput="setCCFromUI(3)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" oninput="setCCFromUI(3)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" oninput="setCCFromUI(3)">0.00</span>
|
|
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" oninput="setCCFromUI(3)">0.00</span>
|
|
</div>
|
|
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(3)" title="Set Offset">➚</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">◀</a>
|
|
<span id="ndFilterSpan" contenteditable="plaintext-only" oninput="cameras[ci].setND(parseInt(this.innerHTML))">0</span>
|
|
<a class="expAdjArr" href="#" onclick="increaseND()" id="NDR">▶</a>
|
|
</div>
|
|
</div>
|
|
<div class="ccExposureSettingContainer">
|
|
<span class="exposureControlLabel">GAIN</span>
|
|
<div class="ccExposureSettingValueContainer">
|
|
<a class="expAdjArr" href="#" onclick="decreaseGain()" id="GAL">◀</a>
|
|
<span id="gainSpan" contenteditable="plaintext-only" oninput="cameras[ci].setGain(parseInt(this.innerHTML))">+0db</span>
|
|
<a class="expAdjArr" href="#" onclick="increaseGain()" id="GAR">▶</a>
|
|
</div>
|
|
</div>
|
|
<div class="ccExposureSettingContainer">
|
|
<span class="exposureControlLabel">SHUTTER</span>
|
|
<div class="ccExposureSettingValueContainer">
|
|
<a class="expAdjArr" href="#" onclick="decreaseShutter()" id="SHL">◀</a>
|
|
<span id="shutterSpan" contenteditable="plaintext-only" oninput="handleShutterInput(this.innerHTML)">1/50</span>
|
|
<a class="expAdjArr" href="#" onclick="increaseShutter()" id="SHR">▶</a>
|
|
</div>
|
|
</div>
|
|
<div class="ccExposureSettingContainer">
|
|
<span class="exposureControlLabel" onclick="swapWBMode()" id="WBLabel">BALANCE</span>
|
|
<div class="ccExposureSettingValueContainer" id="WBValueContainer">
|
|
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalance()" id="WBL">◀</a>
|
|
<span id="whiteBalanceSpan" contenteditable="plaintext-only" oninput="cameras[ci].setWhiteBalance(parseInt(this.innerHTML),cameras[ci].whiteBalanceTint)">5600K</span>
|
|
<a class="expAdjArr" href="#" onclick="increaseWhiteBalance()" id="WBR">▶</a>
|
|
</div>
|
|
<div class="ccExposureSettingValueContainer dNone" id="WBTintValueContainer">
|
|
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalanceTint()" id="WBTL">◀</a>
|
|
<span id="whiteBalanceTintSpan" contenteditable="plaintext-only" oninput="cameras[ci].setWhiteBalance(cameras[ci].whiteBalance,parseInt(this.innerHTML))">0</span>
|
|
<a class="expAdjArr" href="#" onclick="increaseWhiteBalanceTint()" id="WBLR">▶</a>
|
|
</div>
|
|
</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" 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" 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" id="zoomRange" onmouseup="cameras[ci].setZoom(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="" title="Loop">↻</button>
|
|
<button class="circleButton" onclick="" title="Single Clip">S</button>
|
|
<button class="circleButton" onclick="" title="Back">⏴</button>
|
|
<button class="circleButton" onclick="" title="Forward">⏵</button> -->
|
|
<button class="circleButton" onclick="cameras[ci].record()" title="Record">⏺</button>
|
|
<!-- <button class="circleButton" onclick="cameras[ci].play()" title="Play">▶</button> -->
|
|
<button class="circleButton" onclick="cameras[ci].stopTransport(); cameras[ci].stopRecord();" title="Stop">⏹</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="Studio-Camera-6K-Pro.local" id="hostnameInput">
|
|
<button onclick='initCamera(document.getElementById("hostnameInput").value, ci)'>Connect</button>
|
|
<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" onchange="cameras[ci].setActivePreset(this.value+'.cset')">
|
|
<!-- Auto-populated by updateUIPresets() -->
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<button onclick="cameras[ci].setActivePreset(document.getElementById('presetsDropDown').value+'.cset')">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" 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="5" min="-5" step="0.001" id="CCcontrastPivotRange" onmouseup="cameras[ci].setCCContrast({'pivot': parseFloat(this.value)})"></td>
|
|
<td>
|
|
<span id="CCcontrastPivotLabel" contenteditable="plaintext-only" oninput="cameras[ci].setCCContrast({'pivot': parseFloat(this.innerHTML)})">0</span>
|
|
</td>
|
|
<td rowspan="2">
|
|
<button class="CCResetButton circleButton" onclick="resetCC(4)" title="Reset Contrast">⟳</button>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Adjust</td>
|
|
<td><input type="range" max="5" min="-5" step="0.001" id="CCcontrastAdjustRange" onmouseup="cameras[ci].setCCContrast({'adjust': parseFloat(this.value)})"></td>
|
|
<td>
|
|
<span id="CCcontrastAdjustLabel" contenteditable="plaintext-only" oninput="cameras[ci].setCCContrast({'adjust': parseFloat(this.innerHTML)})">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" onmouseup="cameras[ci].setCCColor({'hue': parseFloat(this.value)})"></td>
|
|
<td>
|
|
<span id="CCcolorHueLabel" contenteditable="plaintext-only" oninput="cameras[ci].setCCColor({'hue': parseFloat(this.innerHTML)})">0</span>
|
|
</td>
|
|
<td rowspan="3">
|
|
<button class="CCResetButton circleButton" onclick="resetCC(5)" title="Reset Color">⟳</button>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Saturation</td>
|
|
<td><input type="range" max="2" min="0" step="0.001" id="CCsaturationRange" onmouseup="cameras[ci].setCCColor({'saturation': parseFloat(this.value)})"></td>
|
|
<td>
|
|
<span id="CCcolorSatLabel" contenteditable="plaintext-only" oninput="cameras[ci].setCCColor({'saturation': parseFloat(this.innerHTML)})">0</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Luma Contribution</td>
|
|
<td><input type="range" max="1" min="0" step="0.001" id="CClumaContributionRange" onmouseup="cameras[ci].setCCLumaContribuion({'lumaContribution': parseFloat(this.value)})"></td>
|
|
<td>
|
|
<span id="CCcolorLCLabel" contenteditable="plaintext-only" oninput="cameras[ci].setCCLumaContribuion({'lumaContribution': parseFloat(this.innerHTML)})">0</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Footer Div -->
|
|
<div class="flexContainerH" id="footerContainer">
|
|
<div id="footerLeft">
|
|
<button onclick="cameras.forEach((element) => {element.refresh()});">Refresh</button>
|
|
<span id="refreshingText" class="refreshing">Refreshing...</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="#" target="https://github.com/DylanSpeiser/BM-Camera-Control-WebUI">GitHub</a></span>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |