WebRTC視訊解析度設定

AnRFDev 發表於 2021-12-07

前面我們能夠開啟攝像頭getUserMedia()時會傳入引數,在引數裡我們可以指定寬高資訊。通過寬高引數控制輸出的視訊解析度。

html

在頁面上擺放一些元素,下面是主要部分

<div id="container">
    <div id="buttons">
        <button id="stop">停止</button>
        <button id="b320">320x240</button>
        <button id="b240-320">240x320</button>
        <button id="b640">640x480</button>
        <button id="b1280">1280x720</button>
        <button id="b1920">1920x1080</button>
        <button id="b2048">2048x1152</button>
    </div>
    <div id="videoblock" style="display: none">
        <p id="dimensions" style="height: 1em;"></p>
        <video playsinline autoplay style="background: none;height: auto;width: auto;"></video>
        <div id="width">
            <label>Width <span></span>px:</label>
            <input type="range" min="0" max="7680" value="0">
        </div>
        <input id="isFullWidth" type="checkbox">視訊寬度100%<br>
        <input id="aspectlock" type="checkbox">鎖定寬高比<br>
    </div>
    <p id="msg" style="display: none;"></p>
</div>

<script src="../js/adapter-latest.js" async></script> <!-- 使用本地的介面卡 -->
<script src="js/main.js" async></script>
  • button 一些按鈕用來選擇解析度
  • videoblock 用來顯示視訊,預設隱藏
  • dimensions 用來現實視訊的一些資訊
  • video 寬高先設定為auto
  • #width input 滑動選擇視訊的寬度
  • isFullWidth 讓video寬度為100%
  • msg 顯示錯誤資訊

js

拿到一些元素

const dimensionsInfo = document.querySelector('#dimensions');
const video = document.querySelector('video');
let stream;

const videoblock = document.querySelector('#videoblock'); // 視訊區域
const messagebox = document.querySelector('#msg');

const widthInput = document.querySelector('div#width input');
const widthOutput = document.querySelector('div#width span');
const aspectLock = document.querySelector('#aspectlock');
const fullWidSetting = document.querySelector('#isFullWidth');

啟動視訊

先把拿到流的處理方法寫出來

function gotStream(mediaStream) {
  stream = window.stream = mediaStream; // 給控制檯
  video.srcObject = mediaStream;
  messagebox.style.display = 'none';
  videoblock.style.display = 'block';
  const track = mediaStream.getVideoTracks()[0];
  const constraints = track.getConstraints();
  console.log('當前constraints: ' + JSON.stringify(constraints));
  if (constraints && constraints.width && constraints.width.exact) {
    widthInput.value = constraints.width.exact;
    widthOutput.textContent = constraints.width.exact;
  } else if (constraints && constraints.width && constraints.width.min) {
    widthInput.value = constraints.width.min;
    widthOutput.textContent = constraints.width.min;
  }
}

拿到視訊流後,track.getConstraints()獲取資訊,顯示出當前資訊並修改ui。

以按鈕320為例

document.querySelector('#b320').onclick = () => {
  const c320 = {
    video: { width: { exact: 320 }, height: { exact: 240 } }
  };
  startPlay(c320);
};

function startPlay(constraints) {
  stopStream();
  clearMsg();
  videoblock.style.display = 'none';
  navigator.mediaDevices.getUserMedia(constraints)
    .then(gotStream)
    .catch(e => {
      showErrMsg('getUserMedia報錯 ' + e, JSON.stringify(constraints));
    });
}

function stopStream() {
  if (stream) {
    stream.getTracks().forEach(track => {
      track.stop();
    });
  }
}
  • 定義配置c320,設定寬為320,高偉240
  • 先把視訊停下來
  • 呼叫getUserMedia並把引數配置傳進去

還可以監聽video的變化

let currentWidth = 0;
let currentHeight = 0;

// 顯示視訊尺寸資訊
function displayVideoDimensions(whereSeen) {
  if (video.videoWidth) {
    dimensionsInfo.innerText = '實際video尺寸: ' + video.videoWidth +
      'x' + video.videoHeight + 'px.';
    if (currentWidth !== video.videoWidth ||
      currentHeight !== video.videoHeight) {
      console.log(whereSeen + ': ' + dimensionsInfo.innerText);
      currentWidth = video.videoWidth;
      currentHeight = video.videoHeight;
    }
  } else {
    dimensionsInfo.innerText = '拿不到video的寬度';
  }
}

// 載入meta資訊
video.onloadedmetadata = () => {
  displayVideoDimensions('loadedmetadata');
};

// 修改了尺寸
video.onresize = () => {
  displayVideoDimensions('resize');
};

載入資訊或者尺寸改變的時候顯示出來。

定義了多種常見的解析度

document.querySelector('#b640').onclick = () => {
  const c640 = {
    video: { width: { exact: 640 }, height: { exact: 480 } }
  };
  startPlay(c640);
};

document.querySelector('#b1280').onclick = () => {
  const c1280 = {
    video: { width: { exact: 1280 }, height: { exact: 720 } }
  };
  startPlay(c1280);
};

滑動調整

我們放置了一個inputtype="range",它可以左右滑動。滑動的時候我們改變視訊設定的寬度。寬度資訊也顯示在介面上。

widthInput.onchange = onConstraintChange;

function onConstraintChange(e) {
  widthOutput.textContent = e.target.value;
  const track = window.stream.getVideoTracks()[0];
  let constraints;
  if (aspectLock.checked) {
    constraints = {
      width: { exact: e.target.value },
      aspectRatio: {
        exact: video.videoWidth / video.videoHeight
      }
    };
  } else {
    constraints = { width: { exact: e.target.value } };
  }
  clearMsg();
  console.log('使用配置 ' + JSON.stringify(constraints));
  track.applyConstraints(constraints)
    .then(() => {
      console.log('配置成功');
      displayVideoDimensions('applyConstraints');
    })
    .catch(err => {
      showErrMsg('配置失敗 ', err.name);
    });
}

改變的寬度寫在constraints裡,注意需要指定exact引數。
window.stream.getVideoTracks()[0]獲取到track(視訊軌)。
呼叫track.applyConstraints(constraints)讓修改後的引數生效。同樣這裡可以監聽配置是否成功。

點不同的按鈕,可以看到視訊的尺寸不同。

在電腦顯示器上測試,選擇尺寸過大時,會報錯OverconstrainedError

小結

本次示例也是getUserMedia()方法的使用。前面開啟攝像頭我們只指定了video: true。在這個示例裡我們指定了寬高資訊。並以此控制輸出的視訊解析度。
視訊正在顯示的時候,也可以用track.applyConstraints方法來修改視訊的解析度。

效果

網頁效果預覽

原文連結WebRTC視訊解析度設定