mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-14 23:28:30 +00:00
fix for obs remote
&remote=xxx should work again scroll added to remote pop up; lots of scenes supported now
This commit is contained in:
parent
a5c34cbbda
commit
10fa7e0a2a
66
convert.html
66
convert.html
@ -2,7 +2,7 @@
|
||||
<link rel="stylesheet" href="./main.css?ver=40" />
|
||||
<style>
|
||||
.container {
|
||||
max-width: 80%;
|
||||
max-width: min(80%,875px);
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@ -13,6 +13,18 @@
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #00538c;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #00538c;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #00538c;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 10px;
|
||||
box-shadow: 0 4px 8px 0 rgb(0 0 0 / 10%);
|
||||
@ -85,31 +97,45 @@
|
||||
<div id="info">
|
||||
<h1>Web-based Media Conversion Tools</h1>
|
||||
<div class="card">
|
||||
<h2>WebM to MP4 (fixed 1280x720 resolution) <span class='warning'>(very slow!)</span></h2>
|
||||
<h2>WebM (or MKV/FLV) to MP4 (fixed 1280x720 resolution) <span class='warning'>(very slow!)</span></h2>
|
||||
<div>
|
||||
<small>The same as: fmpeg -i input.webm -vf scale=1280:720 output.mp4</small>
|
||||
<input type="file" id="uploader" title="Convert WebM to MP4">
|
||||
<small>The same as: <i>fmpeg -i input.webm -vf scale="1280:720" output.mp4</i></small>
|
||||
<input type="file" accept=".mkv, .flv, .webm" id="uploader" title="Convert WebM to MP4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>WebM to MP4 files (no transcoding, attempts to force high resolutions)</h2>
|
||||
<h2>WebM to MP4 files (no transcoding, *attempts* to force high resolutions)</h2>
|
||||
<div>
|
||||
<small>The same as: <i>ffmpeg.exe -i concat:"<a href='cap.webm' target="_blank">cap.webm</a>|input.webm" -safe 0 -c copy -avoid_negative_ts 1 -strict experimental output.mp4</i></small>
|
||||
<input type="file" id="uploader3" accept=".webm" title="Convert WebM to MP4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>WebM to Audio-only files (opus or wav)</h2>
|
||||
<div>
|
||||
<input type="file" id="uploader4" accept=".webm" title="Convert WebM to OPUS">
|
||||
<small>The same as: <i>fmpeg -i input.webm -vn -acodec copy output.wav</i></small>
|
||||
<input type="file" id="uploader4" accept=".webm" title="Convert WebM to OPUS (or WAV)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>MKV (or FLV) to MP4 (no transcoding)</h2>
|
||||
<h2>MKV (or FLV/WebM) to MP4 (no transcoding)</h2>
|
||||
<div>
|
||||
<small>The same as: fmpeg -i INPUTFILE -vcodec copy -acodec copy output.mp4</small>
|
||||
<small>The same as: <i>fmpeg -i INPUTFILE -vcodec copy -acodec copy output.mp4</i></small>
|
||||
<input type="file" id="uploader2" accept=".mkv, .flv, .webm" title="Convert MKV (or FLV) to MP4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Having problems?</h2>
|
||||
<div>
|
||||
For larger files, over 2-gigabytes in size, the browser may not be able to properly process the video in memory.
|
||||
</div>
|
||||
<div>
|
||||
Please consider using FFmpeg <a href='https://ffmpeg.org/download.html' target="_blank">[get it free here]</a> to run these processes from the command-line instead. The corresponding commands are provided above, where you need to replace input.webm with your own file.
|
||||
</div>
|
||||
<div>
|
||||
Other users who find FFmpeg too challenging have had luck using the graphical <a href="https://handbrake.fr/" target="_blank">Handbrake</a> application instead.
|
||||
</div>
|
||||
</div>
|
||||
<div id="processing">
|
||||
<span id="message"></span>
|
||||
<video id="player" controls style="display:none"></video>
|
||||
@ -126,6 +152,13 @@
|
||||
<script src="./thirdparty/ffmpeg.min.js"></script>
|
||||
<script>
|
||||
|
||||
window.onerror = function backupErr(errorMsg, url=false, lineNumber=false) {
|
||||
console.error(errorMsg);
|
||||
alert("An error occured.\n\nIf your file is larger than 2-GB, you may need to run the FFmpeg commands locally or use Handbrake instead.");
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
function download(data, filename) {
|
||||
const blob = new Blob([data.buffer]);
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
@ -146,6 +179,11 @@
|
||||
|
||||
const transcode = async ({ target: { files } }) => {
|
||||
const { name } = files[0];
|
||||
console.log(files[0]);
|
||||
if (files[0].size>2147483648){
|
||||
alert("Warning: The largest file size currently supported is 2-GB.\n\nFor larger files, please instead consider using the FFmpeg commands locally or use Handbrake. ");
|
||||
return;
|
||||
}
|
||||
document.getElementById('uploader').style.display = "none";
|
||||
document.getElementById('uploader2').style.display = "none";
|
||||
document.getElementById('uploader3').style.display = "none";
|
||||
@ -163,6 +201,10 @@
|
||||
|
||||
const transmux = async ({ target: { files } }) => {
|
||||
const { name } = files[0];
|
||||
if (files[0].size>2147483648){
|
||||
alert("Warning: The largest file size currently supported is 2-GB.\n\nFor larger files, please instead consider using the FFmpeg commands locally or use Handbrake. ");
|
||||
return;
|
||||
}
|
||||
document.getElementById('uploader').style.display = "none";
|
||||
document.getElementById('uploader2').style.display = "none";
|
||||
document.getElementById('uploader3').style.display = "none";
|
||||
@ -181,6 +223,10 @@
|
||||
|
||||
const force1080 = async ({ target: { files } }) => {
|
||||
const { name } = files[0];
|
||||
if (files[0].size>2147483648){
|
||||
alert("Warning: The largest file size currently supported is 2-GB.\n\nFor larger files, please instead consider using the FFmpeg commands locally or use Handbrake. ");
|
||||
return;
|
||||
}
|
||||
const sourceBuffer = await fetch("./media/cap.webm").then(r => r.arrayBuffer());
|
||||
document.getElementById('uploader').style.display = "none";
|
||||
document.getElementById('uploader2').style.display = "none";
|
||||
@ -202,6 +248,10 @@
|
||||
|
||||
const convertToAudioOnly = async ({ target: { files } }) => {
|
||||
const { name } = files[0];
|
||||
if (files[0].size>2147483648){
|
||||
alert("Warning: The largest file size currently supported is 2-GB.\n\nFor larger files, please instead consider using the FFmpeg commands locally or use Handbrake. ");
|
||||
return;
|
||||
}
|
||||
document.getElementById('message').innerText = "Transcoding file... this will take a while";
|
||||
document.getElementById('processing').style.display = 'flex';
|
||||
await ffmpeg.load();
|
||||
|
||||
10
index.html
10
index.html
@ -82,7 +82,7 @@
|
||||
<link itemprop="url" href="./media/vdoNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=37"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=486"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=487"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<span id="electronDragZone" style="pointer-events: none; z-index:-10; position:absolute;top:0;left:0;width:100%;height:2%;-webkit-app-region: drag;min-height:20px;"></span>
|
||||
<div id="header">
|
||||
@ -1936,7 +1936,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="remoteOBSControl" class="customModelPopup" style="display:none; user-select: none;">
|
||||
<div id="remoteOBSControl" class="customModelPopup" style="display:none;">
|
||||
<div class="promptModalInner">
|
||||
<span class='modalClose' onclick="toggleOBSControls();">×</span>
|
||||
<span></span>
|
||||
@ -2136,7 +2136,7 @@
|
||||
|
||||
|
||||
var session = WebRTC.Media; // session is a required global variable if configuring manually. Run before loading main.js but after webrtc.js.
|
||||
session.version = "22.1b";
|
||||
session.version = "22.3🇺🇦";
|
||||
session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed
|
||||
|
||||
session.defaultPassword = "someEncryptionKey123"; // Change this password if self-deploying for added security/privacy
|
||||
@ -2208,11 +2208,11 @@
|
||||
// session.defaultBackgroundImages = ["./media/bg_sample1.webp", "./media/bg_sample2.webp"]; // for &effects=5 (virtual backgrounds)
|
||||
</script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=377"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=381"></script>
|
||||
<!--
|
||||
// If you wish to change branding, blank offers a good clean start.
|
||||
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
||||
-->
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=389"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=390"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
71
lib.js
71
lib.js
@ -1262,8 +1262,6 @@ function toggleOBSControls(){
|
||||
} else {
|
||||
getById("modalBackdrop").innerHTML = ''; // Delete modal
|
||||
getById("modalBackdrop").remove();
|
||||
zindex = 25;
|
||||
getById('remoteOBSControl').style.zIndex = 25;
|
||||
var modalTemplate = `<div id="modalBackdrop" style="z-index:24"></div>`;
|
||||
document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end
|
||||
document.getElementById("modalBackdrop").addEventListener("click", toggleOBSControls);
|
||||
@ -1551,10 +1549,10 @@ function manageSceneState(data, UUID){ // incoming obs details
|
||||
if (session.pcs[UUID].obsState.virtualcam){
|
||||
controlButton.classList.add("pressed");
|
||||
controlButton.dataset.obsAction = "stopVirtualcam";
|
||||
controlButton.innerText = "💻 stop virtual cam";
|
||||
controlButton.innerText = "💻 stop virtualcam";
|
||||
} else {
|
||||
controlButton.dataset.obsAction = "startVirtualcam";
|
||||
controlButton.innerText = "💻 start virtual cam";
|
||||
controlButton.innerText = "💻 start virtualcam";
|
||||
}
|
||||
|
||||
if (control<5){
|
||||
@ -1654,6 +1652,7 @@ function processOBSCommand(msg){
|
||||
if (msg.UUID && msg.obsCommand.action){
|
||||
var data = {}
|
||||
data.rejected = "obsCommand";
|
||||
//data.debug = msg.remote;
|
||||
session.sendRequest(data, msg.UUID); // this skips the server
|
||||
}
|
||||
warnlog("Denied access; remote does not match");
|
||||
@ -1663,6 +1662,7 @@ function processOBSCommand(msg){
|
||||
if (msg.UUID && msg.obsCommand.action){
|
||||
var data = {}
|
||||
data.rejected = "obsCommand";
|
||||
//data.debug = "no remote code provided";
|
||||
session.sendRequest(data, msg.UUID); // this skips the server
|
||||
}
|
||||
return false;
|
||||
@ -5364,12 +5364,47 @@ async function tapToFocus(x,y, force=false){
|
||||
sharpnessToolActive = false;
|
||||
}
|
||||
|
||||
session.remoteZoom = function(zoom){
|
||||
try {
|
||||
var track0 = session.streamSrc.getVideoTracks();
|
||||
track0 = track0[0];
|
||||
if (track0.getCapabilities){
|
||||
var capabilities = track0.getCapabilities();
|
||||
if (!capabilities.zoom){
|
||||
warnlog("No zoom supported on this device");
|
||||
return;
|
||||
}
|
||||
if (session.zoom==false){
|
||||
session.zoom = capabilities.zoom.min;
|
||||
}
|
||||
session.zoom+=zoom;
|
||||
if (session.zoom>capabilities.zoom.max){
|
||||
session.zoom = capabilities.zoom.max;
|
||||
} else if (session.zoom<capabilities.zoom.min){
|
||||
session.zoom = capabilities.zoom.min;
|
||||
}
|
||||
//updateCameraConstraints("zoom", session.zoom); // TODO: I should align the remote zoom and focus with the local one.
|
||||
track0.applyConstraints({advanced: [ {zoom: session.zoom} ]});
|
||||
}
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
};
|
||||
|
||||
session.remoteFocus = async function(focusDistance){
|
||||
try {
|
||||
var track0 = session.streamSrc.getVideoTracks();
|
||||
track0 = track0[0];
|
||||
if (track0.getCapabilities){
|
||||
var capabilities = track0.getCapabilities();
|
||||
|
||||
if (!capabilities.focusDistance){
|
||||
warnlog("No Focus supported on this device");
|
||||
return;
|
||||
} else if (!("min" in capabilities.focusDistance)){
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.focusDistance==false){
|
||||
session.focusDistance = capabilities.focusDistance.min;
|
||||
}
|
||||
@ -5769,6 +5804,7 @@ async function makeImages(startup=false){
|
||||
var width = 480;
|
||||
var height = 270;
|
||||
var timeout = 100; // the answer to everything.
|
||||
var quality = 0.66;
|
||||
|
||||
if (session.webPquality===0){
|
||||
width = 1920;
|
||||
@ -5779,21 +5815,21 @@ async function makeImages(startup=false){
|
||||
height = 720;
|
||||
timeout = 33;
|
||||
} else if (session.webPquality===2){
|
||||
width = 640;
|
||||
height = 360;
|
||||
width = 960;
|
||||
height = 540;
|
||||
timeout = 33;
|
||||
} else if (session.webPquality===3){
|
||||
width = 480;
|
||||
height = 270;
|
||||
width = 640;
|
||||
height = 360;
|
||||
timeout = 33;
|
||||
} else if (session.webPquality===4){
|
||||
width = 480;
|
||||
height = 270;
|
||||
timeout = 67;
|
||||
timeout = 33;
|
||||
} else if (session.webPquality===5){
|
||||
width = 480;
|
||||
height = 270;
|
||||
timeout = 100;
|
||||
timeout = 67;
|
||||
} else if (session.webPquality===6){
|
||||
width = 480;
|
||||
height = 270;
|
||||
@ -5810,6 +5846,7 @@ async function makeImages(startup=false){
|
||||
session.webPcanvas.width = width;
|
||||
session.webPcanvas.height = height;
|
||||
session.webPcanvas.timeout = timeout;
|
||||
session.webPcanvas.quality = quality;
|
||||
session.webPcanvasCtx = session.webPcanvas.getContext('2d', {alpha: false, desynchronized: true});
|
||||
session.webPcanvasCtx.fillStyle = "black";
|
||||
session.webPcanvasCtx.fillRect(0, 0, width, height);
|
||||
@ -5859,7 +5896,7 @@ async function makeImages(startup=false){
|
||||
if (!session.pcs[i].sendChannel.bufferedAmount){
|
||||
if (!arrayBuffer){
|
||||
session.webPcanvasCtx.drawImage(session.videoElement, 0, 0, session.webPcanvas.width, session.webPcanvas.height);
|
||||
arrayBuffer = dataURItoArraybuffer(session.webPcanvas.toDataURL("image/"+session.webp, 0.6));
|
||||
arrayBuffer = dataURItoArraybuffer(session.webPcanvas.toDataURL("image/"+session.webp, session.webPcanvas.quality));
|
||||
}
|
||||
session.pcs[i].sendChannel.send(arrayBuffer);
|
||||
}
|
||||
@ -8186,16 +8223,16 @@ function updateLocalStats(){
|
||||
if (stat.type == "transport"){
|
||||
if ("bytesSent" in stat) {
|
||||
if ("_bytesSent" in session.pcs[UUID].stats){
|
||||
if (session.pcs[UUID].stats._timestamp){
|
||||
if (session.pcs[UUID].stats._timestamp3){
|
||||
if (stat.timestamp){
|
||||
session.pcs[UUID].stats.total_sending_bitrate_kbps = parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSent)/(stat.timestamp - session.pcs[UUID].stats._timestamp));
|
||||
session.pcs[UUID].stats.total_sending_bitrate_kbps = parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSent)/(stat.timestamp - session.pcs[UUID].stats._timestamp3));
|
||||
}
|
||||
}
|
||||
}
|
||||
session.pcs[UUID].stats._bytesSent = stat.bytesSent;
|
||||
}
|
||||
if ("timestamp" in stat) {
|
||||
session.pcs[UUID].stats._timestamp = stat.timestamp;
|
||||
session.pcs[UUID].stats._timestamp3 = stat.timestamp;
|
||||
}
|
||||
} else if (stat.type == "outbound-rtp") {
|
||||
if (stat.kind == "video") {
|
||||
@ -8211,9 +8248,9 @@ function updateLocalStats(){
|
||||
lastFramesEncoded = session.pcs[UUID].stats._framesEncoded;
|
||||
lastTimestamp = session.pcs[UUID].stats._timestamp;
|
||||
} catch(e){}
|
||||
session.pcs[UUID].stats._FPS = parseInt(10*(stat.framesEncoded - lastFramesEncoded)/(stat.timestamp/1000 - lastTimestamp))/10;
|
||||
session.pcs[UUID].stats._FPS = parseInt(10*(stat.framesEncoded - lastFramesEncoded)/(stat.timestamp - lastTimestamp))/10;
|
||||
session.pcs[UUID].stats._framesEncoded = stat.framesEncoded;
|
||||
session.pcs[UUID].stats._timestamp = stat.timestamp/1000;
|
||||
session.pcs[UUID].stats._timestamp = stat.timestamp;
|
||||
session.pcs[UUID].stats.resolution = stat.frameWidth + " x " + stat.frameHeight + " @ " + session.pcs[UUID].stats._FPS;
|
||||
} else {
|
||||
session.pcs[UUID].stats.resolution = stat.frameWidth + " x " + stat.frameHeight;
|
||||
@ -8253,8 +8290,8 @@ function updateLocalStats(){
|
||||
if ("bytesSent" in stat) {
|
||||
if ("_bytesSentVideo" in session.pcs[UUID].stats){
|
||||
if (session.pcs[UUID].stats._timestamp1){
|
||||
session.pcs[UUID].stats.video_bitrate_kbps = parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSentVideo)/(stat.timestamp - session.pcs[UUID].stats._timestamp1));
|
||||
if (stat.timestamp){
|
||||
session.pcs[UUID].stats.video_bitrate_kbps = parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSentVideo)/(stat.timestamp - session.pcs[UUID].stats._timestamp1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
main.css
6
main.css
@ -3531,6 +3531,12 @@ input:checked + .slider:before {
|
||||
-ms-transform: translateX(16px);
|
||||
transform: translateX(16px);
|
||||
}
|
||||
#remoteOBSControl {
|
||||
user-select: none;
|
||||
z-index: 25;
|
||||
max-height: calc(100vh - 116px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#remoteOBSControl button {
|
||||
margin:5px;
|
||||
|
||||
14
main.js
14
main.js
@ -882,8 +882,19 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('fakeuser')) {
|
||||
log("ICE FILTER ENABLED");
|
||||
session.fakeUser = true;
|
||||
session.dataMode = true;
|
||||
session.autostart = true;
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('datamode') || urlParams.has('dataonly')) { // this disables all media in/out.
|
||||
session.dataMode = true;
|
||||
}
|
||||
|
||||
if (session.dataMode){
|
||||
session.cleanOutput=true;
|
||||
session.videoDevice = 0;
|
||||
session.audioDevice = 0;
|
||||
@ -892,7 +903,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.noaudio = [];
|
||||
session.noiframe = [];
|
||||
//session.webcamonly = true;
|
||||
session.dataMode = true;
|
||||
}
|
||||
|
||||
|
||||
@ -2736,6 +2746,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.icefilter = urlParams.get('icefilter');
|
||||
}
|
||||
|
||||
|
||||
|
||||
//if (!(ChromeVersion>=57)){
|
||||
// getById("effectSelector").disabled=true;
|
||||
// getById("effectSelector3").disabled=true;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user