无需Flash录视频——HTML5中级进阶

ImaWDMB 7年前
   <h3><strong>前言</strong></h3>    <p>HTML5的权限越来越大了,浏览器可以直接调用摄像头、麦克风了,好激动啊。我们要用纯洁的HTML代码造出自己的天地。</p>    <h3><strong>视频采集</strong></h3>    <p>本篇介绍的栗子 都是在chrome 47 版本以上的,低版本的可能会出现白屏和错误。</p>    <p><strong>1.安全环境</strong></p>    <p>随着Chrome版本的升高,安全性问题也越来越被重视,较新版本的Chrome浏览器在调用一些API时需要页面处在安全环境中。 <strong>本篇文章所介绍的API函数,都需要在安全环境中执行。</strong> 如果处在非安全环境下 ( http页面 ) 这些API就会有意想不到的问题。</p>    <p>比如 getUserMedia() 就会报出警告,并执行出错。而在设备枚举 enumerateDevices() 时,虽然不会报错,但是他隐藏了设备label。</p>    <p>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.</p>    <p>根据谷歌的意思,常用的安全环境有如下</p>    <ul>     <li>http://localhost</li>     <li>http://127.0.0.1</li>     <li>https 开头的地址页面</li>    </ul>    <p>如果你做了一个视频测试的页面,想嘚瑟给局域网的其他人,但是又没有域名证书怎么办?</p>    <p>这时候只能通过修改其他人的hosts文件了</p>    <p>比如你的测试服务器IP地址是192.168.2.18,那么其他人的hosts文件修改如下:</p>    <pre>  <code class="language-javascript">#localhost 127.0.0.1  localhost 192.168.2.18</code></pre>    <p>当使用别人的Chrome浏览器访问 http://localhost/[getUserMediaTestPage]时,就会顺利的执行这些API了。</p>    <p>但是移动端的浏览器并不认localhost,就算你修改了hosts ,移动端的浏览器根本不理你,解析都不解析。</p>    <p>所以想在手机上测试,只能老老实实申请个证书了。</p>    <p><strong>2.设备枚举</strong></p>    <p>在开启摄像头之前,先要把可以使用的麦克风和摄像头 ( 输入设备 ) 列出来,如果没有这两样设备也就无法继续。</p>    <p>代码如下:</p>    <pre>  <code class="language-javascript"><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='"+ item.deviceId +"'>" + item.label + " </option> "      }else if(item.kind=="videoinput"){ //摄像头       document.getElementById("videoDevice").innerHTML +=  "<option value='"+ item.deviceId +"'>" + item.label + " </option> "      }    })  },function (error) {    console.log(error);  })  </script></code></pre>    <p>效果如下图,和浏览器自己获取的一模一样。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2a8d3796c835f80c30e34c417fae5bd3.png"></p>    <p style="text-align:center">这里写图片描述</p>    <p>注意:上图的实例中,浏览器地址栏最右边的摄像头标识是需要使用 getUserMedia() 函数时才会出现。</p>    <pre>  <code class="language-javascript"><script>      var getUserMedia = navigator.webkitGetUserMedia; //Chrome浏览器的方法      getUserMedia.call(navigator, {        video:true, // 开启音频        audio:true  // 开启视频      }, function(stream){          console.log(stream); // 成功获取媒体流      }, function(error){          //处理媒体流创建失败错误      });  </script></code></pre>    <p>这时候可以通过浏览器给出的菜单下拉选择设备。</p>    <p>3.设置参数,预览</p>    <p>我们可以通过代码来指定使用哪个摄像头和麦克风设备。</p>    <p>也可以通过代码设置视频的宽、高和帧率。</p>    <p>代码如下:</p>    <pre>  <code class="language-javascript"><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></code></pre>    <p>输出的视频流通过blob对象链接绑定到video标签输出。</p>    <p>这个 deviceId 就是从上文设备枚举 enumerateDevices() 获取到的。</p>    <p>两种设备,如果有一个 deviceId 填写不正确,就会报出一个 DevicesNotFoundError 的错误。而且一旦指定了设备后,浏览器自己的设备选择就会变成灰色不可选。</p>    <p>视频的宽高,并不会因为填写的数值比例不合法而失真。</p>    <p>比如你设定了宽度30,高度100,那么他会从视频中心截取 30x100 的画面,而不是把原画面挤压到这个30x100的尺寸。</p>    <p>效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/78e911a20d53e4a93fd0be642858234b.png"></p>    <p style="text-align:center">这里写图片描述</p>    <p>如果您的预览一片漆黑,或者只有一个小黑点,那么说明您的摄像头正在被占用...</p>    <p>可是Chrome并没有遵循它,而且差距还挺大...</p>    <h3><strong>视频保存</strong></h3>    <p><strong>1. 格式支持</strong></p>    <p>Chrome浏览器是大力推广webm的视频格式的。可以用 MediaRecorder.isTypeSupported("video/webm") 来测试是否支持这种类型的编码。如果返回true,那么我们录制的视频就可以被保存为这种指定的格式。如果不指定,那么将会使用浏览器自动指定的文件格式。文档原话如下</p>    <p>If this paramater is not specified, the UA will use a platform-specific default format.</p>    <p>但是这个默认值却无法直接获取,全靠猜...</p>    <p><strong>2. 视频录制 MediaRecorder</strong></p>    <p>我们使用 MediaRecorder 来录制视频,参数是通过 getUserMedia() 获取的媒体流。</p>    <ul>     <li>通过绑定 ondataavailable 事件,来获取视频片段数据,并在内存中累积。</li>     <li>录制的开始和结束分别使用 start 和 stop 函数。</li>     <li>执行 start 之后会周期性触发 ondataavailable 事件。</li>     <li>执行 stop 之后会停止触发 ondataavailable 事件。</li>     <li>录制结束后,把累计的片段数据保存为blob对象,并从浏览器下载存为视频文件。</li>    </ul>    <p>代码如下:</p>    <pre>  <code class="language-javascript"><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, { 'type' : 'video/webm' });      var audioURL = URL.createObjectURL(blob);      window.open(audioURL);    }    g_recorder.start();  }  </script></code></pre>    <p>注意:本例并没有填写视频文件头,所以保存出来的视频文件没有时间轨,无法快进和跳跃。</p>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/231f6c92f3fb</p>    <p> </p>