Home  >  Article  >  Web Front-end  >  Record video without Flash - HTML5 intermediate and advanced

Record video without Flash - HTML5 intermediate and advanced

高洛峰
高洛峰Original
2016-10-15 16:38:521927browse

前言

HTML5的权限越来越大了,浏览器可以直接调用摄像头、麦克风了,好激动啊。我们要用纯洁的HTML代码造出自己的天地。

视频采集

本篇介绍的栗子 都是在chrome 47 版本以上的,低版本的可能会出现白屏和错误。

1.安全环境

随着Chrome版本的升高,安全性问题也越来越被重视,较新版本的Chrome浏览器在调用一些API时需要页面处在安全环境中。本篇文章所介绍的API函数,都需要在安全环境中执行。如果处在非安全环境下 ( http页面 ) 这些API就会有意想不到的问题。

比如 getUserMedia()就会报出警告,并执行出错。而在设备枚举enumerateDevices()时,虽然不会报错,但是他隐藏了设备label。

getUserMedia() no longer works on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.

根据谷歌的意思,常用的安全环境有如下

http://localhost

http://127.0.0.1

https 开头的地址页面

如果你做了一个视频测试的页面,想嘚瑟给局域网的其他人,但是又没有域名证书怎么办?
这时候只能通过修改其他人的hosts文件了
比如你的测试服务器IP地址是192.168.2.18,那么其他人的hosts文件修改如下:

#localhost 127.0.0.1
localhost 192.168.2.18

当使用别人的Chrome浏览器访问 http://localhost/[getUserMedi...时,就会顺利的执行这些API了。

但是移动端的浏览器并不认localhost,就算你修改了hosts ,移动端的浏览器根本不理你,解析都不解析。所以想在手机上测试,只能老老实实申请个证书了。

2.设备枚举

在开启摄像头之前,先要把可以使用的麦克风和摄像头 ( 输入设备 ) 列出来,如果没有这两样设备也就无法继续。

代码如下:

<label for="audioDevice"> 录音设备: </label><select id="audioDevice">
  </select><br><label for="videoDevice"> 录影设备: </label><select id="videoDevice">
  </select><script>navigator.mediaDevices.enumerateDevices().then(function (data) {
  data.forEach(function (item) {    if(item.kind=="audioinput"){ //麦克风
     document.getElementById("audioDevice").innerHTML +=  "<option value=&#39;"+ item.deviceId +"&#39;>" + item.label + " </option> "
    }else if(item.kind=="videoinput"){ //摄像头
     document.getElementById("videoDevice").innerHTML +=  "<option value=&#39;"+ item.deviceId +"&#39;>" + item.label + " </option> "
    }
  })
},function (error) {  console.log(error);
})</script>

效果如下图,和浏览器自己获取的一模一样。

Record video without Flash - HTML5 intermediate and advanced

注意:上图的实例中,浏览器地址栏最右边的摄像头标识是需要使用 getUserMedia()函数时才会出现。

<script>
    var getUserMedia = navigator.webkitGetUserMedia; //Chrome浏览器的方法
    getUserMedia.call(navigator, {
      video:true, // 开启音频
      audio:true  // 开启视频
    }, function(stream){        console.log(stream); // 成功获取媒体流
    }, function(error){        //处理媒体流创建失败错误
    });</script>

这时候可以通过浏览器给出的菜单下拉选择设备。

3.设置参数,预览

我们可以通过代码来指定使用哪个摄像头和麦克风设备。也可以通过代码设置视频的宽、高和帧率。

代码如下:

<video id="video" autoplay></video> <!-- 一定要有 autoplay -->

<script>
var getUserMedia = navigator.webkitGetUserMedia ;

getUserMedia.call(navigator, {
  "audio":{
        "mandatory":{
            "sourceId":"" // 指定设备的 deviceId
        }
    },
  "video":{
        "optional":[ 
            {"minWidth":400},
            {"maxWidth":400},  // 数字类型,固定宽度
            {"minHeight":220}, 
            {"maxHeight":220},  // 数字类型,固定高度
            {"frameRate":"12"}  // 帧率
        ],"mandatory":{
        "sourceId":"" // 指定设备的 deviceId
        }
      }
}, function(stream){
    //绑定本地媒体流到video标签用于输出
    document.getElementById("video").src = URL.createObjectURL(stream);
}, function(error){
    //处理媒体流创建失败错误
});

</script>

输出的视频流通过blob对象链接绑定到video标签输出。

这个deviceId就是从上文设备枚举 enumerateDevices() 获取到的。
两种设备,如果有一个deviceId填写不正确,就会报出一个DevicesNotFoundError的错误。而且一旦指定了设备后,浏览器自己的设备选择就会变成灰色不可选。

视频的宽高,并不会因为填写的数值比例不合法而失真。比如你设定了宽度30,高度100,那么他会从视频中心截取 30x100 的画面,而不是把原画面挤压到这个30x100的尺寸。

效果如下:

Record video without Flash - HTML5 intermediate and advanced

如果您的预览一片漆黑,或者只有一个小黑点,那么说明您的摄像头正在被占用...

吐槽:这个getUserMedia()函数的参数,w3的官方文档链接如下:
https://www.w3.org/TR/mediaca...
可是Chrome并没有遵循它,而且差距还挺大...

视频保存

1. 格式支持

Chrome浏览器是大力推广webm的视频格式的。可以用MediaRecorder.isTypeSupported("video/webm")来测试是否支持这种类型的编码。如果返回true,那么我们录制的视频就可以被保存为这种指定的格式。如果不指定,那么将会使用浏览器自动指定的文件格式。文档原话如下

If this paramater is not specified, the UA will use a platform-specific default format.

但是这个默认值却无法直接获取,全靠猜...

2. 视频录制 MediaRecorder

我们使用 MediaRecorder来录制视频,参数是通过getUserMedia()获取的媒体流。

通过绑定ondataavailable事件,来获取视频片段数据,并在内存中累积。

录制的开始和结束分别使用 start和stop 函数。

执行start之后会周期性触发ondataavailable事件。

执行stop之后会停止触发ondataavailable事件。

录制结束后,把累计的片段数据保存为blob对象,并从浏览器下载存为视频文件。

代码如下:

<script>

var getUserMedia = navigator.webkitGetUserMedia ;
var g_stream = null, g_recorder = null;
function startPreview(){
  getUserMedia.call(navigator, {
    video:true,
    audio:true
  }, function(stream){
      g_stream = stream;
  }, function(error){
  
  });
}

function stopRecording(){
  g_recorder.stop();
}

function startRecording(){
  var chunks = [];
  g_recorder = new MediaRecorder(g_stream,{mimeType:"video/webm"});
  g_recorder.ondataavailable = function(e) {
    chunks.push(e.data);
  }
  g_recorder.onstop = function(e) {
    var blob = new Blob(chunks, { &#39;type&#39; : &#39;video/webm&#39; });
    var audioURL = URL.createObjectURL(blob);
    window.open(audioURL);
  }
  g_recorder.start();
}
</script>


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn