From 8cc898b965f30f66b0441cdcd17775e5758a45be Mon Sep 17 00:00:00 2001 From: steveseguin Date: Thu, 22 Aug 2024 15:39:54 -0400 Subject: [PATCH] v26 beta --- cloudflare.html | 21 +- css/main.css | 166 +- index.html | 144 +- lib.js | 892 +- main.js | 72 +- mixer.html | 4 + rawdoc.html | 33932 +++++++++++++++++++++++++++++ recorder/index.html | 342 + recorder/testrecord-processor.js | 24 + thirdparty/CodecsHandler.js | 164 +- translations/cn.json | 2 +- webrtc.js | 2 +- whip.html | 20 +- 13 files changed, 35405 insertions(+), 380 deletions(-) create mode 100644 rawdoc.html create mode 100644 recorder/index.html create mode 100644 recorder/testrecord-processor.js diff --git a/cloudflare.html b/cloudflare.html index e6f1cce..405f3f9 100644 --- a/cloudflare.html +++ b/cloudflare.html @@ -124,22 +124,19 @@

What you can do with Cloudflare + VDO.Ninja?

-

Restream VDO.Ninja as an RTMP Output

-

Live Video Inputs (Cloudflare feature) can be set up to forward any input to another input. This can be a RTMP(S) service such as YouTube, Twitch or Facebook Live.

-

In theory you could publish from VDO.Ninja WHIP output to Cloudstream, and then to your RTMP destinations, like Youtube.

-

Meshcast-alternative

Instead of using Meshcast to broadcast video from director to guest, or guest to scene, you can use Cloudflare instead.

Meshcast, or any compatible WHIP/WHEP service, can help reduce CPU and network load of guests by offloading distribution to a server, compared to using the peer-to-peer default of VDO.Ninja -

Automatic isolated guest recording

-

Cloudflare will automatically record incoming videos, allowing you (in theory) to have a backup of each guest in a room.

+

VDO.Ninja has built-in support for Cloudflare's WHIP/WHEP, so setup and use is relatively easy.

+

Isolated guest recording remotely via WHEP

+

You can record the streams of each guest via WHEP remotely, without transcoding and without additional load on the guests.

This offers a redundant backup for your recordings, but also makes it easier to do higher quality VODs edits after the live ends.

-

SRT, HLS, DASH, MP4, WHIP/WHEP options

-

Lots input and output options, although if you're here, you're probably interested in the WHIP/WHEP mainly.

-

VDO.Ninja is compatible with WHEP and WHIP!

-

Very competitive pricing

-

There's a $5 entry tier, which is more than enough for testing.

-

Or pay $1 per 1000 minutes of streaming.

+

Raspberry.Ninja offers WHEP recording, via GStreamer for example, but FFMpeg builds may also support direct WHEP recording

+

Pricing

+

Cloudflare has decent pricing, however it's a bit obsecure at times what the limits actually are.

+

MediaMTX

+

If you prefer rolling your own SFU service, VDO.Ninja supports MediaMTX. (open-source!)

+

Just add &mediamtx=yourdomain.com to your VDO.Ninja publishing URLs to have it use your own MediaMTX server.

diff --git a/css/main.css b/css/main.css index 5cb2e44..c4afe3c 100644 --- a/css/main.css +++ b/css/main.css @@ -348,7 +348,7 @@ button.hint { cursor:pointer; text-align:right; color:#B3C7F9; - margin:5px; + margin: 0 5px; cursor: pointer; padding:3px; background-color: black; @@ -356,6 +356,18 @@ button.hint { border: solid #B3C7F9 1px; } +#closeChat { + cursor: pointer; + text-align: right; + color: #B3C7F9; + margin: 0 5px; + cursor: pointer; + padding: 3px 8px; + background-color: black; + border-radius: 50%; + border: solid #B3C7F9 1px; +} + /* Clicked buttons overwrite */ .red { background-color: #840000 !important; @@ -1206,6 +1218,12 @@ button.glyphicon-button.active.focus { align-items: center; } +.resizable-div { + border: 1px solid #ccc; + overflow: auto; + position: relative; +} + #subControlButtons { display: flex; position: absolute; @@ -1714,17 +1732,6 @@ input[type=range].thinSlider { position: relative; display: flex; } - -.inMessage { - color: #000; - margin: 3px; - border-radius: 3px; - background: #FFF; - padding: 5px; - text-align: left; - margin: 10px 3px; - border: 1px solid black; -} .actionMessage { color: #000; margin: 3px; @@ -1735,30 +1742,65 @@ input[type=range].thinSlider { margin: 10px 3px; border: 1px solid black; } +.inMessage, .outMessage { + margin-bottom: 10px; + padding: 5px; + border-radius: 5px; +} +.inMessage { + background-color: #e6e6e6; +} + .outMessage { - color: #000; - border-radius: 3px; - background: #c5d3ff; - padding: 5px; - text-align: right; - margin-bottom: 5px; - border: 1px solid black; + background-color: #c5d3ff; + text-align: right; } #chatBody { - z-index: 12; - background-color: #000A; - width: 100%; - border-radius: 5px; - overflow-y: scroll; - overflow-wrap: anywhere; - max-height: min(500px, 70vh); + flex-grow: 1; + overflow-y: auto; + padding: 10px; + background-color: #4d4d4d; + min-height: 50px; + border-color: #6b6767; + height: 300px; } #chatBody::-webkit-scrollbar { width: 0px; background: transparent; /* make scrollbar transparent */ } +.chat-input-area { + display: flex; + padding: 10px 10px 4px 10px; + background-color: #2a2a2a; +} +.resizer { + height: 5px; + background: #2a2a2a; + cursor: ns-resize; + position: relative; + overflow: hidden; + cursor: ns-resize; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.resizer::before { + content: ''; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 30px; + height: 2px; + background: linear-gradient(to right, #666 20%, transparent 20%, transparent 40%, #666 40%, #666 60%, transparent 60%, transparent 80%, #666 80%); +} + +.resizer:hover::before { + background: linear-gradient(to right, #999 20%, transparent 20%, transparent 40%, #999 40%, #999 60%, transparent 60%, transparent 80%, #999 80%); +} div#chatBody a { color: blue; text-decoration: underline; @@ -1770,25 +1812,37 @@ div#chatBody a { } #chatModule { - display: flex; - flex-wrap: wrap; - width: 100%; - max-width: min(500px, 100vw); - z-index: 3; - margin-bottom: 65px; - gap: 0px 5px; - pointer-events: auto; + position: fixed; + bottom: 10px; + right: 10px; + width: 400px; + max-width: 100%; + min-width: 100px; + background-color: #fff; + border: 1px solid #4f4e4e; + border-radius: 5px; + display: flex; + flex-direction: column; + max-height: 100vh; + z-index: 1000; } +.chat-header { + padding: 10px; + background-color: #2a2a2a; + display: flex; + justify-content: space-between; + align-items: center; + cursor: move; + color:white; +} + #chatInput { - color: #000; - background-color: #FFFE; - width: calc(100% - 160px); - padding: 1px 3px; - font-size: 100%; + flex-grow: 1; + margin-right: 5px; } .chatBarInputButton { - width: 50px; - margin: unset; + width: 50px; + margin: 0 5px; } #callerMenu { position: absolute; @@ -3395,6 +3449,11 @@ div#roomnotes2 { flex: 1 13%; } +.controlsGrid .row.eight > * { + flex: 1 10%; +} + + .controlsGrid button { display: flex; align-items: center; @@ -3580,7 +3639,6 @@ div#roomnotes2 { margin: 5px; font-size: 125%; } - #widget { position: absolute; width: 25%; @@ -3588,6 +3646,20 @@ div#roomnotes2 { right: 0; top: 0; } +#widget.left{ + right: unset!important; + left: 0!important; +} + +#directorlayout.widget { + position: absolute; + width: 75%; + left: 0; +} +#directorlayout.widget.left { + left: unset!important; + right: 0!important; +} #localMuteElement{ top: 1vh; right: 1vh; @@ -3681,13 +3753,7 @@ div#roomnotes2 { background-color:#0007; width:4vh; } -#widget { - position: absolute; - width: 25%; - height: 100%; - right: 0; - top: 0; -} + .pull-right { float: right; @@ -4705,7 +4771,7 @@ body.darktheme .outMessage{ background-color: #7f89a7; } body.darktheme .inMessage { - background-color: #b1b1b1; + background-color: #7e7d7d; } body.darktheme .actionMessage { background-color: #b1b1b1; diff --git a/index.html b/index.html index b31b544..2d0123c 100644 --- a/index.html +++ b/index.html @@ -40,7 +40,7 @@ - + @@ -87,9 +87,9 @@ - + - + - + + +

@@ -516,6 +523,9 @@ if (localStorage.getItem('bitrateGroupFlag')!==null){ if (localStorage.getItem('codecGroupFlag')!==null){ document.getElementById('codecGroupFlag').value = localStorage.getItem('codecGroupFlag'); } +if (localStorage.getItem('keyFrameRateFlag')!==null){ + document.getElementById('keyFrameRateFlag').value = localStorage.getItem('keyFrameRateFlag'); +} if (localStorage.getItem('svcGroupFlag')!==null){ document.getElementById('svcGroupFlag').value = localStorage.getItem('svcGroupFlag'); } @@ -586,6 +596,8 @@ function gohere1(){ localStorage.setItem('bitrateGroupFlag', document.getElementById('bitrateGroupFlag').value); localStorage.setItem('codecGroupFlag', document.getElementById('codecGroupFlag').value); + localStorage.setItem('keyFrameRateFlag', document.getElementById('keyFrameRateFlag').value); + localStorage.setItem('svcGroupFlag', document.getElementById('svcGroupFlag').value); localStorage.setItem('whipoutaudiobitrate', document.getElementById('whipoutaudiobitrate').value); @@ -617,6 +629,10 @@ function gohere1(){ if (document.getElementById('codecGroupFlag').value!=="default"){ codec = "&whipoutcodec="+document.getElementById('codecGroupFlag').value; } + var keyFrameRateFlag = ""; + if (document.getElementById('keyFrameRateFlag').value!=="0"){ + keyFrameRateFlag = "&whipoutkeyframe="+document.getElementById('keyFrameRateFlag').value; + } var svc = ""; if (document.getElementById('svcGroupFlag').value!=="0"){ svc = "&svc="+document.getElementById('svcGroupFlag').value; @@ -628,9 +644,9 @@ function gohere1(){ } if (document.getElementById('changeText1a').value){ - window.location = domain + "?push&whippush=" + encodeURIComponent(document.getElementById('changeText1').value) + "&whippushtoken=" + document.getElementById('changeText1a').value + codec + bitrate+whipoutaudiobitrate+vbrcbr+autogain+stereo+denoise+svc+e2ee; + window.location = domain + "?push&whippush=" + encodeURIComponent(document.getElementById('changeText1').value) + "&whippushtoken=" + document.getElementById('changeText1a').value + codec + bitrate+whipoutaudiobitrate+vbrcbr+autogain+stereo+denoise+svc+e2ee+keyFrameRateFlag; } else { - window.location = domain + "?push&whippush=" + encodeURIComponent(document.getElementById('changeText1').value) + codec + bitrate+whipoutaudiobitrate+vbrcbr+autogain+stereo+denoise+svc+e2ee; + window.location = domain + "?push&whippush=" + encodeURIComponent(document.getElementById('changeText1').value) + codec + bitrate+whipoutaudiobitrate+vbrcbr+autogain+stereo+denoise+svc+e2ee+keyFrameRateFlag; } } }