async applyConstraints resizeMode none
Test
by jib1
HTML
<button id="go">Go!</button><br><br>
Camera: <select id="camera"></select><br>
Microphone: <select id="microphone"></select><br>
Height <input id="number" type="number" min="2" max="2160" value="720">
<input id="range" type="range" min="0" max="2160" value="720">
<div id="div2"><p>0 x 0 x 0.0</p></div>
<div id="div"></div>
<video id="video" autoplay></video>
JavaScript
const console = {log: msg => div.innerHTML += `${msg}<br>`};
const update = msg => div2.innerHTML = `<p>${msg}</p>`;
const wait = ms => new Promise(r => setTimeout(r, ms));
const frames = v => v.mozPaintedFrames || v.webkitDecodedFrameCount || 0;
range.oninput = () => apply(number.value = range.value);
number.oninput = () => apply(range.value = number.value);
let track, applying = false, height = 0;
async function apply(h) {
height = h;
if (applying) return;
try {
applying = true;
do {
h = height;
await track.applyConstraints({height, resizeMode: "none"});
} while (h != height);
} catch (e) {
console.log(e);
} finally {
applying = false;
}
}
go.onclick = async () => {
try {
video.srcObject = await getUserMedia({audio: true, video: true });
updateSelectors(video.srcObject.getTracks().map(t => t.getSettings().deviceId));
await new Promise(r => video.onloadedmetadata = r);
number.value = range.value = track.getSettings().height;
let t1 = 0, t2 = 1, f1 = 0, f2 = 0;
while (true) {
await wait(500);
t2 = video.currentTime; f2 = frames(video);
const hz = (f2 - f1) / (t2 - t1);
update(`${video.videoWidth} x ${video.videoHeight} x ${hz.toFixed(2)}`);
t1 = t2; f1 = f2;
}
} catch(e) {
console.log(e);
}
};
async function getUserMedia({video, audio}) {
if (video === true) {
video = {deviceId: localStorage.video, height: range.value};
}
if (audio === true) {
audio = {deviceId: localStorage.audio};
}
const stream = await navigator.mediaDevices.getUserMedia({video, audio});
for (const track of stream.getTracks()) {
localStorage[track.kind] = track.getSettings().deviceId;
}
track = stream.getVideoTracks()[0];
return stream;
}
async function replaceUserMedia(constraints, ...oldTracks) {
try {
return await getUserMedia(constraints);
} catch (e) {
if (e.name != "NotReadableError") throw e;
for (const track of oldTracks)...