如何通过WebRTC开发实时互动AI视频应用

640?wx_fmt=png

640?wx_fmt=png

// HTTP服务器接收来自ffmpeg的MPEG-TS流

var streamServer = http.createServer( function(request, response) {
    request.on('data', function(data){
        socketServer.broadcast(data);
    });
    request.on('end',function(){
        console.log('close');
    });

}).listen(STREAM_PORT);
ffmpeg -f v4l2 -framerate 25 -video_size 640x480 -i /dev/video0 -f mpegts -codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 http://127.0.0.1:8081

640?wx_fmt=png

if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
  console.log("不支持 enumerateDevices() .");
  return;
}
// 列出相机和麦克风.
 navigator.mediaDevices.enumerateDevices()
    .then(function (devices) {
        devices.forEach(function (device) {
            console.log(device.kind + ": " + device.label +
                " id = " + device.deviceId);
        });
    })
    .catch(function (err) {
        console.log(err.name + ": " + err.message);
    });

640?wx_fmt=png

1. MediaDevices.getUserMedia()

640?wx_fmt=png

var video = document.createElement('video');
var constraints = {
  audio: false,
  video: true
};

function successCallback(stream) {
  window.stream = stream;  //MediaStream对象
  video.srcObject = stream;
}

function errorCallback(error) {
  console.log('navigator.getUserMedia error: ', error);
}

function getMedia(constraints) {
  if (window.stream) {
    video.src = null;
    window.stream.getVideoTracks()[0].stop();
  }
  navigator.mediaDevices.getUserMedia(
    constraints
  ).then(
    successCallback,
    errorCallback
  );
}

640?wx_fmt=png

  • constraints

比如你想要使用1280x720的摄像头分辨率:
{
  audio: true,
  video: { width: 1280, height: 720 }
}

{
  audio: true,
  video: {
    width: { min: 1280 },
    height: { min: 720 }
  }
}

{
  audio: true,
  video: {
    width: { ideal: 1280 },
    height: { ideal: 720 }
  }
}
当你的设备存在多个摄像头时,可以优先选择前置:
{ audio: true, video: { facingMode: "user" } }
或者强制使用后置摄像头:
{
    audio: true,
    video: {
        facingMode: {
            exact: "environment"
        }
    }
}
任性的你也许只想要某个特定设备,那你需要用 deviceId 来约束,浏览器会优先获取此设备。
{ video: { deviceId: myPreferredCameraDeviceId } }
好了,以上将返回你需要的媒体设备。

640?wx_fmt=png

  • 常见异常抛出    

var promise = navigator.mediaDevices.getUserMedia({
    video: true,
    audio: false
});

promise.then(function (MediaStream) {
    video.srcObject = MediaStream;
}).catch(err => {
    if (err.name == 'NotFoundError' || err.name == 'DeviceNotFoundError') {
        // 找不到满足请求参数的媒体类型
        console.log(err.name, 'require track is missing');
    } else if (err.name == 'NotReadableError' || err.name == 'TrackStartError') {
        // 设备已经授权,但是某个硬件、浏览器或者网页层面发生的错误导致设备无法被访问
        console.error(err.name, 'webcam or mic are already in use');
    } else if (err.name == 'OverconstrainedError' || err.name == 'ConstraintNotSatisfiedError') {
        // 指定的要求无法被设备满足,此异常是一个类型为OverconstrainedError的对象
        console.error(err.name, 'constraints can not be satisfied by avb.device');
    } else if (err.name == 'NotAllowedError' || err.name == 'PermissionDeniedError') {
        // 用户拒绝了浏览器实例的访问请求
        console.error(err.name, 'permission denied in browser');
    } else if (err.name == 'TypeError' || err.name == 'TypeError') {
        // constraints对象未设置,或者都被设置为false
        console.error(err.name, 'empty constraints object');
    } else {
        // 其他错误
        console.error(err.name, 'other errors');
    }
});
2. MediaDevices.getDisplayMedia()

navigator.getDisplayMedia({ video: true })
  .then(stream => {
    // 成功回调的流,将它赋给video元素;
    videoElement.srcObject = stream;
  }, error => {
    console.log("Unable to acquire screen capture", error);
  });
  • constraints

  • 异常    

3. getUserMedia与getDisplayMedia比较

其他

function drawImage(drawImageRate) {
  context.drawImage(video, 0, 0, width, height);
  let base64Image = canvas.toDataURL('image/jpeg', 1); //格式为image/jpeg或image/webp时,从0到1的区间定制图的质量
  ... //压缩等处理后
  window.rws.send(JSON.stringify({ image: base64Image }));
}

window.drawInter = setInterval(drawImage, drawImageRate = 1000);

    关于canvas画布转换成img图像,除了base64外,也可以选择Blob格式,因为是二进制的,对后端更加友好。

canvas.toBlob(callback, mimeType, qualityArgument)

这里是关于抽帧的小demo(https://chhxin.github.io/webrtc-demo/)

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值