webrtc视频流设置码率、分辨率和帧率

4,056 阅读3分钟

浏览器进行webrtc推流的时候,有时候需要保证视频清晰度,那就需要设置视频推送时的码率以及分辨率,下面是设置码率和分辨率的方法以及帧率的方法

设置码率

获取peerConnection的senders,遍历senders中获取类型为video的sender,通过setParameters设置sender的params就能操控码率:params.encodings[0].maxBitrate = 1024 * 1024 * 10; // 设置码率为10MB

const video = document.createElement('video');
video.crossOrigin = 'anonymous';
video.src = '视频地址';
video.muted = true; // 静音才能实现自动播放
video.preload = 'auto';
video.loop = true;

video.onloadedmetadata = () => {
  let stream = null;
  try {
    stream = video.captureStream();
    console.log('音视频流', stream);

    // 创建webrtc
    const peerConnection = new RTCPeerConnection(null);

    stream.getTracks().forEach((track) => {
      peerConnection.addTrack(track, stream);
    });

    const senders = peerConnection.getSenders();

    // 遍历每个 sender
    senders.forEach(async (sender) => {
      // 找到视频的 sender
      if (sender && sender.track.kind === 'video') {
        const params = sender.getParameters();
        params.encodings[0].maxBitrate = 1024 * 1024 * 10; // 设置码率为10MB
        await sender.setParameters(params);
      }
    });
  } catch (error) {}
};

设置分辨率

设置分辨率只用操作视频流的宽高就能设置分辨率

方法一

我们可以通过操作源流的分辨率,或者通过canvas重新调整视频流的宽高

如:视频流只有1280*720,想要调整为1920*1080的分辨率

1.创建一个canvas,设置宽高为1920*1080

2.通过requestAnimationFrame和ctx.drawImage(video, 0, 0, 1920, 1080)将视频帧绘制到canvas上

const video = document.createElement('video');
video.crossOrigin = 'anonymous';
video.src = '视频地址';
video.muted = true; // 静音才能实现自动播放
video.preload = 'auto';
video.loop = true;

...
// 绘制视频帧
ctx = canvas.getContext("2d");
ctx.drawImage(video, 0, 0, 1920, 1080)

3.获取canvas的流stream:video.captureStream

获取到是stream就是调整后分辨率为1920*1080的流

方法二

可以直接操作视频流轨道数据,通过applyConstraints去设置轨道信息

const video = document.createElement('video');
video.crossOrigin = 'anonymous';
video.src = '视频地址';
video.muted = true; // 静音才能实现自动播放
video.preload = 'auto';
video.loop = true;

video.onloadedmetadata = () => {
  let stream = null;
  try {
    stream = video.captureStream();
    console.log('音视频流', stream);

    // 创建webrtc
    const peerConnection = new RTCPeerConnection(null);

    stream.getTracks().forEach((track) => {
      peerConnection.addTrack(track, stream);
    });

    // 设置分辨率为1920*1080
    const constraints = {
      width: { min: 1280, ideal: 1920 },
      height: { min: 720, ideal: 1080 },
      advanced: [{ width: 1920, height: 1080 }, { aspectRatio: 1.333 }],
    };
    const videoTrack = stream.getVideoTracks()[0]; // 获取视频轨道
    videoTrack
      .applyConstraints(constraints)
      .then(() => {
        console.log('分辨率设置成功');
        console.log(
          '更新后的 constraints=',
          stream.getVideoTracks()[0].getConstraints(),
        );
      })
      .catch(error => {
        console.error('分辨率设置失败:', error);
      });
  } catch (error) {}
};

设置帧率

帧率是画面每帧刷新的速度,如果我们设置成60帧,那就是每16.6666666ms刷新一次画面(1000/60 = 16.6666666)

我们控制帧率的方法有两种,一种是控制视频源的帧率,一种是通过setParameters设置sender的params控制:parameters.encodings[0].maxFramerate = 30; // 设置帧率为30

方法一

如果我们是通过canvas去绘制而获取到是视频流,那我们控制绘制的速度,就能控制帧率

import TestVideo from './test.mp4';

...

ctx = this.$refs.canvasRef.getContext("2d");

const video = document.createElement('video');
video.crossOrigin = 'anonymous';
video.src = TestVideo;
video.muted = true; // 静音才能实现自动播放
video.preload = 'auto';
video.loop = true;

let maxFramerate = 60; // 设置帧率为60

// 当maxFramerate等于20,实际fps是17.68
const delay = 1000 / (maxFramerate / (17.68 / 20)); // 60帧的话即16.666666666666668
setInterval(() => {
  ctx.drawImage(video, 0, 0, 1920, 1080); //绘制视频
}, delay);

当页面被最小化或者切换页签后,setInterval是不会继续后台执行的,所以切换页签后,webrtc推流会停止,如果想在页签最小化之后还能推送视频画面,需要用webworker继续执行setInterval,可以用worker-timers库

方法二

maxFramerate设置的值能在源视频流的帧率范围内生效,比如源视频流帧率为30,maxFramerate的生效值只能是0-30,你设置maxFramerate=60,最后的结果还是30

const video = document.createElement('video');
video.crossOrigin = 'anonymous';
video.src = '视频地址';
video.muted = true; // 静音才能实现自动播放
video.preload = 'auto';
video.loop = true;

video.onloadedmetadata = () => {
  let stream = null;
  try {
    stream = video.captureStream();
    console.log('音视频流', stream);

    // 创建webrtc
    const peerConnection = new RTCPeerConnection(null);

    stream.getTracks().forEach((track) => {
      peerConnection.addTrack(track, stream);
    });

    const senders = peerConnection.getSenders();

    // 遍历每个 sender
    senders.forEach(async (sender) => {
      // 找到视频的 sender
      if (sender && sender.track.kind === 'video') {
        const params = sender.getParameters();
        params.encodings[0].maxFramerate = 30; // 默认帧率为30
        await sender.setParameters(params);
      }
    });
  } catch (error) {}
};