2.6、实战案例(三)

文章导读:本节实现视频的录制和保存功能。推荐阅读方式:实操。

  为了更好的讲解代码,我们还是把软件界面展示出来,如下图2.6.1。

图 2.6.1 (软件界面截图)

   本节内容,我们来完成该软件的最后一个功能:视频的录制和保存。先说下视频的录制,在webrtc中如何实现视频的录制呢?主要依赖一个类——MediaRecorder,该类是一个全局类,使用的时候可以直接实例化,实例化时需要传入两个参数,第一个参数是流对象,即通过getUserMedia获取的流对象;第二个参数是录制的视频格式以及编码方式,示例代码如下。

let recordOption = {
    mimeType:"video/webm;codecs=vp8"
}
if(!MediaRecorder.isTypeSupported(recordOption.mimeType)){
    throw new Error("录制时不支持该格式"+recordOption.mimeType);
}
let recordObject = new MediaRecorder(mediaStream,recordOption)

 如上的代码,mediaStream是一个流对象,即本软件中cameraManager对象的mediaStream属性(记不住的同学自觉翻前几节文章来look look);recordOption则录制时的配置对象,其中mimeType属性描述录制视频的格式以及编码,其中“video/webm”表示录制的类型是视频,格式是webm;codecs=vp8表示采用vp8的编解码规范。recordObject是MediaRecorder实例化后的对象,当然,仅创建了对象还不会立即录制,还得手动调用启动录制,代码如下。

recordObject.start(10)

 start方法还传进了一个参数10,表示每片数据时长为10毫秒,即一段完整的视频由多个“10毫秒”长的片段组成的。在录制的过程中,我们如何存储数据?这里就要提到recordObject对象中的一个回调方法——ondataavailable,每隔一段的时间就触发一次,每触发一次就说明完成了一片数据的采集,这里的start方法我们传入参数10,就表示每10毫秒ondataavailable会被触发一次。代码如下。

recordObject.ondataavailable = (e)=>{
    if(e && e.data && e.data.size){
        // 这里把数据片缓存起来
    }
}

停止录制的方法也很简单,直接调用其stop方法,代码如下。

recordObject.stop();

以上就是视频录制的核心功能方法,现在我们将其集成到软件中。从业务的角度来看,录制功能可以看做是单独业务,于是这里创建一个对象来管理录制业务——recordManager。该对象有两个方法,两个属性。两个方法:开始录制startRecord、结束录制stopRecord。两个属性:数据缓存对象buffer(用于临时存储二进制视频数据)、recordObject对象存放MediaRecorder的实例化后的对象。代码结构如下。

// 录制管理对象
const recordManager = {
    // 二进制数据的数组
    buffer:[],

    //录制实例
    recordObject:null,
    
    // 开始录制
    startRecord(){
        
    },
    
    // 停止录制
    stopRecord(){
        
    }
    
}

 先来实现第一个方法——startRecord。分析下其运行过程:首先清空缓存,防止上一次录制时残留一些垃圾数据影响本次录制;其次实例化一个MediaRecorder对象,同时设置其数据回调函数;最后启动录制,并且更新系统状态为“录制中”。代码如下。

// 开始录制
    startRecord(){
        this.buffer = [];//清空数据
        if(!cameraManager.mediaStream){
            throw new Error("录制失败,mediaStream读取失败");
        }
        let recordOption = {
            mimeType:"video/webm;codecs=vp8"
        }
        if(!MediaRecorder.isTypeSupported(recordOption.mimeType)){
            throw new Error("录制时不支持该格式"+recordOption.mimeType);
        }
        this.recordObject = new MediaRecorder(cameraManager.mediaStream,recordOption)
        // 录制时数据回调
        this.recordObject.ondataavailable = (e)=>{
            if(e && e.data && e.data.size){
                this.buffer.push(e.data);
            }
        }
        this.recordObject.start(10)
        statusManager.startedRecord()//更改系统状态
    },

如上代码所示, 在实例化MediaRecorder对象之前,考虑到当前环境对指定的格式——“video/webm;codecs=vp8”的支持情况,所以调用了isTypeSupported方法判断。this.recordObject.ondataavailable 是完成一个数据片录制的回调,我们可以在这个回调函数中缓存数据。至此,开始录制功能完成,接下来实现停止录制功能。

  分析下停止录制功能的运行流程:首先停止录制;其次创建下载对象,并且下载数据到本地;最后,清空缓存,并还原系统的状态为“摄像头已打开”。实现的代码如下。

// 停止录制
    stopRecord(){
        if(!this.recordObject){
            return;
        }
        this.recordObject.stop();
        let blob = new Blob(this.buffer,{type:"video/webm"});
        let url = URL.createObjectURL(blob);
        let a = document.createElement("a");
        a.href = url;
        a.download = "record.webm"
        a.click();
        this.buffer = [];
        statusManager.openedCamera();
    }

至此,开始录制和停止录制的功能编写完毕,这两个方法都需要在eventManager(事件管理对象)中通过监听“开始录制”、“结束录制”两个按钮来调用,这里就不在演示,接下来展示recordManager的完整代码。

// 录制管理对象
const recordManager = {
    // 二进制数据的数组
    buffer:[],

    //录音实例
    recordObject:null,
    
    // 开始录制
    startRecord(){
        this.buffer = [];//清空数据
        if(!cameraManager.mediaStream){
            throw new Error("录制失败,mediaStream读取失败");
        }
        let recordOption = {
            mimeType:"video/webm;codecs=vp8"
        }
        if(!MediaRecorder.isTypeSupported(recordOption.mimeType)){
            throw new Error("录制时不支持该格式"+recordOption.mimeType);
        }
        this.recordObject = new MediaRecorder(cameraManager.mediaStream,recordOption)
        // 录制时数据回调
        this.recordObject.ondataavailable = (e)=>{
            if(e && e.data && e.data.size){
                this.buffer.push(e.data);
            }
        }
        this.recordObject.start(10)
        statusManager.startedRecord()//更改系统状态
    },
    
    // 停止录制
    stopRecord(){
        if(!this.recordObject){
            return;
        }
        this.recordObject.stop();
        let blob = new Blob(this.buffer,{type:"video/webm"});
        let url = URL.createObjectURL(blob);
        let a = document.createElement("a");
        a.href = url;
        a.download = "record.webm"
        a.click();
        this.buffer = [];
        statusManager.openedCamera();
    }
    
}

 最后。总结下:第一、本节的新内容 :MediaRecorder类的运用(实例化、start和stop的调用以及数据回调函数ondataavailable的使用);第二、下载数据时用到了Blob类,该类是JS中用来处理二进制大文件的,如果你对此不熟悉,建议查阅些资料。下载数据的逻辑是通过创建一个a元素并且模拟点击来实现的。

  到这里,本软件的所有功能已经实现完毕了,为了给大家更多的练习的机会,有些功能我并没有实现或者说没有细化,比如音频参数的配置,我只是简单的配置否启用,实际上音频的采集时还是有一些可配置的参数,所以下节补充音视频采集的相关内容以及桌面录制的相关内容,并布置本章的实战练习任务。

 

posted on 2020-03-12 22:19  Rajan  阅读(386)  评论(0编辑  收藏  举报
扫码和作者预约吧