前言
音频与视频信息的捕捉一直是Web开发中的一个难点。许多年来,我们一直依赖浏览器插件来实现这个需求,随着HTML 5推出,这种情况有所改变。因为,HTML5提供了许多可以访问硬件设备的API,例如:访问GPS设备的Geolocation API、访问accelerometer设备的Orientation API、访问GPU设备的WebGL API、访问音频播放设备的Web Audio API等等。这些API功能非常强大,使用这些API,开发者可以直接通过编写JavaSccript脚本代码来访问底层硬件设备,这也使得通过网页实现音视频的录制变成现实。

1.1 H5网页实现音视频录制的方法

H5网页实现录音(像)的方法有以下几种:

第一种方法:依赖于浏览器插件(Flash 或 Silverlight)实现。

第二种方法:通过Web Api中的MediaRecorder接口实现。MediaRecorder API由w3c制定并致力推进,但ios和微软反应冷淡,所以目前的兼容性都不理想。目前,主要的试验田在chrome和firefox,移动端兼容安卓内置的chrome内核浏览器,Safari/Edge等浏览器一直没有实现。

第三种方法:通过Web Api中的MediaDevices接口提供的getUserMedia方法,并结合AudioContext接口有关方法实现。这个方法涉及到WebRTC的一系列Web API,从采集、编码到通信层面都有,相对要复杂得多,但兼容性好,已经得到了所有主流浏览器的支持。

1.2 使用MediaRecorder类实现前端音视频录制

1.2.1 MediaRecorder类能够录制哪些数据源?
任何媒体形式的标签,对应的数据源都可以录制成音视频。包括 <audio>, <video>,<canvas>, 其中 <audio>, <video>可以来自网络媒体文件,也可以来自本机设备采集。而<canvas>的内容则更加自由,任何绘制在画布上的用户操作,2d或3d图像,都可以进行录制。它为web提供了更多可能性,我们甚至可以把一个h5游戏流程录成视频,保存落地或进行实况传输。

1.2.2 MediaRecorder类录制出来是什么格式的数据?
是经过标准编码后的媒体流数据,可以注入video标签,也可以打包生成文件,还可以进一步做流级别的数据处理,比如画面识别、动态插入内容、播放跳转控制等等。

1.2.3 MediaRecorder类常用的方法
使用MediaRecorder录音录像时,需要严格遵守API说明中的函数调用先后顺序,否则不能成功执行。MediaRecorder类的常用方法:

· MediaRecorder() 构造方法
· getMaxAmplitude() 得到目前为止最大的幅度
· prepare() 准备录音机
· release() 释放MediaRecorder对象
· reset() 重置MediaRecorder对象,使其为空闲状态
· setAudioEncoder() 设置音频编码
· setAudioSource() 设置音频源
· setCamera() 设置摄像机
· setMaxDuration() 设置最大期限
· setMaxFileSize() 设置文件的最大尺寸
· setOnErrorListener() 错误监听
· setOutputFile() 设置输出文件
· setOutputFormat() 设置输出文件的格式
· setPreviewDisplay() 设置预览
· setVideoEncoder() 设置视频编码
· setVideoFrameRate() 设置视频帧的频率
· setVideoSize() 设置视频的宽度和高度(分辨率)
· setVideoSource() 设置视频源
· start() 开始录制
· stop() 停止录制

1.2.4 MediaRecorder录制音视频的主要流程和代码

ios js Audio 没有声音 javascript audio_js

① 打开摄像头

HTML5的getUserMedia API为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备。

语法:navigator.mediaDevices.getUserMedia(constraints,onSuccess,onError);

containers:指定请求的媒体类型,主要包含video和audio,至少要有一个类型被指定。

onSuccess:onSuccess是一个自定义的函数。当正确打开摄像头或麦克风,并捕获到视(音)频流时,回调此函数。视频流会作为默认参数传递给onSuccess。

onError:onError是一个自定义函数。如果浏览器无法找到指定的媒体类型或者无法满足相对应的参数要求,回调此函数。错误信息会作为默认参数传递给onError。

下面一段代码展现了getUserMedia接口与相关参数具体使用方法。

//不同的浏览器访问硬件设备的方法不同,首先要找到与浏览器匹配的方法
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

let constrains = {     //用来定义音视频格式、状态
    audio:true,
    video:true
}

if (navigator.getUserMedia) {  //判断是否找到与浏览器匹配的方法
    navigator.getUserMedia(constrains, onSuccess, onError);   //打开摄像头或麦克风,并获取视频流
} else {
    alert("你的浏览器无法访问到用户的媒体设备");
}
        
function onSuccess(stream) {    //摄像头正常打开时,回调此函数
     console.log(stream);
}

function onError(error) {      //调用摄像头异常时,回调此函数
    console.log("访问用户媒体设备失败:", error.name, error.message);
}

② 展示视频

getUserMedia API成功打开摄像头,捕获到的媒体流stream是blob数据,将它赋值给标签的srcObject,就能够直接将摄像头的视频展示出来。

<body>
  <video id="video" width="500" height="500" autoplay></video>
</body>

JS代码

//调用媒体设备成功时的回调函数
function onSuccess(stream){
    oVideo.srcObject = stream;  //将视频流设置为video元素的源,直接播放视频
}

③ 从摄像头采集视频

现在,我们只是从摄像头获取了图像,并把它展现了出来,但还无法控制它,也无法把图像采集下来。怎么才能实现视频录制呢,这就要用到MediaRecorder对象,首先创建MediaRecorder对象。

语法: var mediaRecorder = new MediaRecorder(stream,option)

说明:MediaRecorder接收两个参数,第一个是stream音视频流。第二个是option配置参数,option参数包括音频码率、视频码率、编码格式。下面给一个参考值,必要时大家可查阅相关资料具体设置。

var mediaRecorder = new MediaRecorder(stream, {
    audioBitsPerSecond : 128000,  // 音频码率
    videoBitsPerSecond : 100000,  // 视频码率
    mimeType : 'video/webm;codecs=h264' // 编码格式
  })

为了完成音视频的采集,MediaRecorder提供了三个重要的方法:
MediaRecorder.start(): 开始录制视频。
MediaRecorder.stop(): 停止录制视频, 同时触发dataavailable事件。停止录制视频后,其后出现的视频不再被记录。
ondataavailable事件: MediaRecorder.stop触发该事件,该事件可用于获取记录的视频数据。
通俗地理解,当MediaRecorder.start()这个方法被调用时,便开始记录视频数据。当MediaRecorder.stop() 方法被调用时,立即停止记录视频数据,同时触发dataavailable事件。这时候用户便可以从该事件的data属性,取出录制的视频数据(Blob数据)。

最后源代码

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        window.onload=function(){

            //访问用户媒体设备(摄像头和麦克风)的兼容方法
            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

            if (navigator.getUserMedia){  //判断浏览器是否支持访问媒体设备
                navigator.getUserMedia({video:true,audio:true},onSuccess,onError);   //打开摄像头或麦克风,并获取视频流
            } else {
                alert("你的浏览器不支持访问用户媒体设备");
            }


            var oVideo = document.getElementById("video");
            var oStart = document.getElementById("start");
            var oStop = document.getElementById("stop");
            var oSave = document.getElementById("save");
            var blob;   //采集的Blob格式的视频数据

            //调用媒体设备成功时的回调函数
            function onSuccess(stream){
                oVideo.srcObject = stream;  //将视频流设置为video元素的源,直接播放视频
                var mediaRecorder = new MediaRecorder(stream,{ //创建MediaStream 对象用来进行视频录制操作,有两个参数第一个是stream音视频流,第二个是配置参数
                    audioBitsPerSecond : 128000,  // 音频码率
                    videoBitsPerSecond : 100000,  // 视频码率
                    mimeType : 'video/webm;codecs=h264' // 编码格式
                });

                oStart.onclick = function(){  //开始录像
                    mediaRecorder.start();
                }

                oStop.onclick = function(){   //停止录像
                    mediaRecorder.stop();
                }

                oSave.onclick =function(){   //保存视频
                    // 下载视频
                    let a = document.createElement('a'); //创建<a>标签
                    a.href = URL.createObjectURL(blob);  //将视频数据的地址赋予href属性
                    a.download = `test.mp4`;            //将视频数据保存在当地,文件名为"test.mp4"
                    a.click();
                }

                  // 事件,开始录像时捕获数据,结束录像时将捕获的数据,传递到BLOB中,当此动作完成后,触发ondataavailable
                  mediaRecorder.ondataavailable = function (e) {
                      blob = new Blob([e.data], { 'type' : 'video/mp4' })
                  }
            }

            //调用媒体设备异常时的回调函数
            function onError(error){
                console.log("访问用户媒体设备失败:",error.name,error.message);
            }
        }
    </script>
</head>
<body>
    <!--video用于显示媒体设备的视频流,自动播放-->
    <video id="video" autoplay style="width: 600px;height: 450px"></video>
    <br>
    <input type="button" value="开始录像" id="start" />
    <input type="button" value="停止录像" id="stop" />
    <input type="button" value="保存视频" id="save" />
</body>
</html>

1.3 使用AudioContext实现前端音视频录制