首页 > 编程知识 正文

抖音上那些声控视频怎么录制(webrtc开源项目)

时间:2023-05-03 14:18:57 阅读:70678 作者:2715

虽然因“在线视频通话”而烦恼,但措手不及,直到最近还接触了网络视频技术。 虽然还没有这样的实力,但“打假”解决了另一个困扰我的问题:音视频录制!

webRTC实战一(声音有点不稳定。 因为是晚上录制的,很抱歉,视频主要是为了演示)。

什么是网络

根据MDN的说明,“webrtc (web real-timecommunication )”是一种实时通信技术,互联网APP应用和网站可以在不通过中间介质的情况下在浏览器之间进行点对点(peer-- time ) 任何其他WebRTC都包含这些标准,使用户可以在不安装插件或第三方软件的情况下创建对等数据共享和电话会议。 ”

归纳起来,其实有四点:

对跨平台(主要是通过浏览器实时传输音视频引擎) webRTC进行了一点深入的学习,结果不仅是“音视频录制、视频通话”,还有“摄像头、音乐播放器、共享远程桌面、即时当然,它是在结合许多其他技术的基础上完成的。

但是,在这些当中,像是照相机、脸部识别、桌面共享等,我们似乎很熟悉。 这是因为RTC使用的是基于音频视频流的API!

网络音视频数据采集实现数据传输最重要的是数据采集,这里有一个非常重要的API :

let promise=navigator.media devices.getuser media (contain ts ); 该API要求用户允许使用媒体输入。 媒体输入生成MediaStream,并且将视频轨道从硬件或虚拟视频源(诸如照相机、视频采集设备、屏幕共享服务等)传输到所请求的轨道媒体类型

返回Promise对象,如果成功,则resolve回调到媒体流对象。 如果用户拒绝使用权限或所需的媒体源不可用,promise将在reject中调用PermissionDeniedError或NotFoundError。

这里最重要的是“轨道”。 因为它是基于“流动”的。 得到的是MediaSource对象。 这是流对象。 也就是说,要使用此结果,必须使用srcObject属性或通过url.createObjectURL ()将其转换为URL。

返回到API本身,可以获得当前页面上所有音频视频通道的集合,可以理解为根据接口分为不同的“轨道”,可以设置它们和输出设置。

在这篇文章中,可以看到实现“拍照”的部分被用于这个API

让我们先在页面上写下视频元素:

视频autoplayplaysinlineid=' player ' /视频为什么在这里使用视频元素?

虽然需要获取音频视频流,但与HTML5相关的元素只有视频和音频。 只有视频元素可以同时获取这两个。 如果只需要音频流,则可以完全使用audio元素。

根据上面getUserMedia API的用法,可以轻松地编写以下语法:

navigator.media devices.getuser media (constraints ).then (gotmediastream ).catch (手持设备错误); 啊,突然想起来了。 还没有介绍contraints参数。

webRTC检索约束条件“约束条件”是控制对象的几个设置。 约束有两种:视频约束和音频约束。

webRTC中常用的视频约束包括:

widthheightaspectRatio :宽高比frameRatefacingMode :相机反转(前后相机) )这种配置主要是因为对于移动终端来说,浏览器只有前置相机() resizeMode )

体积:音量采样速率:采样率sampleSize :采样大小echoCancellation :回声消除设置autoGainControl :自动增益noiseSuppression :噪声通过代码,我们可以更清楚地看到它:

dictionarymediastreamcontraints () booleanormediatrackcontaints )视频=false; (boolean or MediaTrackContaints ) audio=false;对音视频约束的采集

如果视频/音频仅设置为bool类型

只是简单决定是否要采集如果video/audio是Media Track,则可进一步设置比如:视频的分辨率、帧率、音频的音量、采样率等

根据上面说明,我们可以在代码中完善一下配置项 —— 当然,通常使用这种API第一件事是要判断用户当前浏览器是否支持:

if(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia){console.log('getUserMedia is not supported!');return;}else{var constraints={// 这里也可以直接:video:false/true,则知识简单的表示不采集/采集视频video:{width:640,height:480,frameRate:60},// 这里也可以直接:audio:false/true,则只是简单的表示不采集/采集音频audio:{noiseSuppression:true,echoCancellation:true}}navigator.mediaDevices.getUserMedia(constraints).then(gotMediaStream).catch(handleError);}

下面就该实现getUserMedia API 成功和失败时的回调函数了,这里我们要先搞懂“在回调时要干什么” —— 其实无非是将“获取到的流”交出去:给全局变量保存起来或者直接作为video/audio的srcObject值(成功)或者抛出错误(失败)

var videoplay=document.querySelector('#player');function gotMediaStream(stream){// 【1】videoplay.srcObject=stream;// 【2】// return navigator.mediaDevices.enumerateDevices();}function handleError(err){console.log('getUserMedia error:',err);}

注释中用了一个API:mediaDevices.enumerateDevices()。MediaDevices方法列举了所有可用的媒体输入和输出设备(如麦克风、相机、耳机等)。返回的承诺通过描述设备的MediaDevice 信息阵列得到解决。
我们也可以把它看做上面说的“轨道集合”。比如这里如果你把注释按promise方式写出,就会发现它是一个数组,里面包含了三个“轨道”。两个audio(输入、输出)一个video:

而pgyx输出stream参数后你会发现

在一些场景下,通过这个API我们可以将一些设备配置暴露给用户

至此视频中的第一个效果——实时捕获音视频就完成了。
这也是下面的基础:不能捕获,又怎么录制呢?

我们先再加一些需要的节点:

<video id="recplayer" playsinline></video><button id="record">Start Record</button><button id="recplay" disabled>Play</button><button id="download" disabled>Download</button>

前面说了,经过捕获后得到的是一个“流”对象,那么接收时也一定需要一个能拿到流并进行操作的API :MediaStream API!

MDN上是这样介绍的:“MediaRecorder 是 MediaStream Recording API 提供的用来进行媒体轻松录制的接口, 他需要通过调用 MediaRecorder() 构造方法进行实例化。”
因为是 MediaStream Recording API 提供的接口,所以它有一个构造函数:

MediaRecorder.MediaRecorder():创建一个新的MediaRecorder对象,对指定的MediaStream 对象进行录制,支持的配置项包括设置容器的MIME 类型 (例如"video/webm" 或者 “video/mp4”)和音频及视频的码率或者二者同用一个码率

根据MDN上提供的方法,我们可以得到一个比较清晰的思路:先调用构造函数,将前面获取到的流传入,经过API的解析后拿到一个对象,在规定的时间切片下将他们依次传入数组中(因为至此工作基本就已经完成了,用数组接收方便以后转为Blob对象操作):

function startRecord(){// 定义一个接收数组buffer=[];var options={mimeType:'video/webm;codecs=vp8'}// 返回一个Boolean值,来表示设置的MIME type 是否被当前用户的设备支持.if(!MediaRecorder.isTypeSupported(options.mimeType)){console.error(`${options.mimeType} is not supported`);return;}try{mediaRecorder=new MediaRecorder(window.stream,options);}catch(e){console.error('Fail to create');return;}mediaRecorder.ondataavailable=handleDataAvailable;// 时间片// 开始录制媒体,这个方法调用时可以通过给timeslice参数设置一个毫秒值,如果设置这个毫秒值,那么录制的媒体会按照你设置的值进行分割成一个个单独的区块mediaRecorder.start(10);}

这里面有两点需要注意的地方:

获取的stream流:因为之前捕获音视频的函数必然要封装起来,所以这里如果再要使用就一定要把这个流对象设置为全局对象 —— 笔者直接将其挂载到了window对象上,在前面代码中注释[1]的地方接收对象: window.stream=stream;这里定义了一个buffer数组,和mediaRecorder对象一样,考虑到要在ondataavailable 方法中的使用以及在完成后需要停止继续捕获录制音视频流,也放在全局下声明变量 var buffer;var mediaRecorder;

ondataavailable方法就是在录制数据准备完成后才触发的。yhdxlz我们需要做的就是按照之前的思路将切片好的数据依次存入

function handleDataAvailable(e){// console.log(e)if(e && e.data && e.data.size>0){buffer.push(e.data);}}//结束录制function stopRecord(){mediaRecorder.stop();}

然后调用:

let recvideo=document.querySelector('#recplayer');let btnRecord=document.querySelector('#record');let btnPlay=document.querySelector('#recplay');let btnDownload=document.querySelector('#download');// 开始/停止录制btnRecord.onclick=()=>{if(btnRecord.textContent==='Start Record'){startRecord();btnRecord.textContent='Stop Record';btnPlay.disabled=true;btnDownload.disabled=true;}else{stopRecord();btnRecord.textContent='Start Record';btnPlay.disabled=false;btnDownload.disabled=false;}}// 播放btnPlay.onclick=()=>{var blob=new Blob(buffer,{type: 'video/webm'});recvideo.src=window.URL.createObjectURL(blob);recvideo.srcObject=null;recvideo.controls=true;recvideo.play();}// 下载btnDownload.onclick=()=>{var blob=new Blob(buffer,{type:'video/webm'});var url=window.URL.createObjectURL(blob);var a=document.createElement('a');a.href=url;a.style.display='none';a.download='recording.webm';a.click();}

文章到这里视频中的功能就基本实现了,但是还有一点问题:如果只想要录制音频,这时候在你说话的时候因为捕获流一直在工作所以其实这时候有两个声源 —— 你的声音和捕获到的你的声音。
所以我们需要将捕获时的声音关掉!
但是如果你根据前面说的在getUserMedia API中添加 volume:0 是不会有任何效果的 —— 因为至今还没有任何浏览器对这个属性支持。

但是联想到我们承载音视频的是一个video/audio容器,所以我们其实可以直接用其对应DOM节点的volume属性控制:

// 在前面代码中注释为【2】的地方添加代码videoplay.volume=0;

大功告成!

本文完整代码已开源到GitHub:study_for_webRTC ,欢迎阅读、下载 & star!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。