gUM/gDM h264 downscale maxbitrate
by jib1
HTML
<script src="https://webrtchacks.github.io/adapter/adapter-latest.js"></script>
<script src="https://hg.mozilla.org/mozilla-central/raw-file/tip/dom/media/webrtc/tests/mochitests/sdpUtils.js"></script>
Height <input id="heightNumber" type="number" min="2" max="1920" value="1080" size="5"><input id="heightRange" type="range" min="2" max="1920" value="1080">
Framerate <input id="fpsNumber" type="number" min="1" max="120" value="30" size="3"><input id="fpsRange" type="range" min="1" max="120" value="30"><br>
Downscale <input id="downscaleNumber" type="number" min="0.01" max="1" value="1" step="0.01" size="4"><input id="downscaleRange" type="range" min="0.01" max="1" value="1" step="0.01">
Decimate <input id="decimateNumber" type="number" min="1" max="120" value="120" size="4"><input id="decimateRange" type="range" min="1" max="120" value="120">
Max bitrate <input id="rateNumber" type="number" min="2" max="9000000" value="2000000" size="9"><input id="rateRange" type="range" min="2" max="9000000" value="2000000"><br><br>
<button id="gdm">gDM!</button>
<button id="gum">gUM!</button>
<label><input type="checkbox" id="h264" checked>h264</label>
<button id="button2">Renegotiate direction</button>
<button id="button3">ReplaceTrack(null)</button>
<div id="div"></div>
<table>
<tr>
<td>Receiver</td>
<td>Sender</td>
</tr>
<tr>
<td id="v2info">0x0</td>
<td id="v1info">0x0</td>
</tr>
<tr>
<td id="v2brinfo">0 bps</td>
<td id="v1brinfo">0 bps</td>
</tr>
<tr>
<td><video id="v2" autoplay></video></td>
<td><video id="v1" autoplay muted></video></td>
</tr>
</table>
CSS
body { white-space: nowrap; font-family: monospace; }
JavaScript
const console = { log: msg => div.innerHTML += `${msg}<br>` };
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
const update = (div, msg) => div.innerHTML = msg;
const pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();
heightRange.oninput = () => applyIt(heightNumber.value = heightRange.value);
heightNumber.oninput = () => applyIt(heightRange.value = heightNumber.value);
downscaleRange.oninput = () => applyIt(downscaleNumber.value = downscaleRange.value);
downscaleNumber.oninput = () => applyIt(downscaleRange.value = downscaleNumber.value);
fpsRange.oninput = () => applyIt(fpsNumber.value = fpsRange.value);
fpsNumber.oninput = () => applyIt(fpsRange.value = fpsNumber.value);
decimateRange.oninput = () => applyIt(decimateNumber.value = decimateRange.value);
decimateNumber.oninput = () => applyIt(decimateRange.value = decimateNumber.value);
rateRange.oninput = () => applyIt(rateNumber.value = rateRange.value);
rateNumber.oninput = () => applyIt(rateRange.value = rateNumber.value);
const applyIt = () => apply(heightNumber.value, downscaleNumber.value, fpsNumber.value, decimateNumber.value, rateNumber.value);
let track, applying = false, height = heightNumber.value, scale, fps, decimate, rate, nulltrack = false;
async function apply(h, s, f, d, r) {
height = h;
scale = s;
fps = f;
decimate = d;
rate = r;
if (applying || !track) return;
try {
applying = true;
do {
h = height;
s = scale;
f = fps;
d = decimate;
r = rate;
const [sender] = pc1.getSenders();
const params = sender.getParameters();
params.encodings[0].scaleResolutionDownBy = 1 / s;
params.encodings[0].maxFramerate = d;
params.encodings[0].maxBitrate = r;
await Promise.all([
track.applyConstraints({height: h, frameRate: f}),
sender.setParameters(params),
]);
} while (h != height || s != scale || f != fps || d !=...