利用websoket+video+canvas實現簡易的web視頻功能


    今天就同事提出關於網頁視頻功能的實現問題,到家以后苦思冥想后決定根據自己的思路試驗一下,果然簡陋的視頻功能就出爐了,如下代碼如有勘誤、寫錯的地方請指正,臨時工代碼也請各位看客見諒。

   例子有很多不足,我是將image的base64l整個送到node然后派發給各個客戶端,數據量有點大,希望這方面有人能指點我一下謝謝。

   准備知識(注url不是官方的,是我寫例子是看的)

      1、w3c媒體相關api知識(https://developer.mozilla.org/zh-CN/docs/WebRTC/navigator.getUserMedia)

      2、 canvas

      3、安裝nodejs及ws模塊

      4、了解基本的websocket的機制以及相關api(http://ued.sina.com.cn/?p=900)

   大概思路:

 

 

   1、根據瀏覽器相關的api獲取媒體流,getUserMedia在各個瀏覽器api名字不一樣,還有那些版本支持可以找相關文檔

    代碼:

       html代碼:<video id="video"></video>
  
    js代碼:;(function($) { $.video = function(s) { var s = $.extend({ video: true, audio: true, goStream: goStream, noStream: noStream, callBack: null, videoId: 'video' }, s), video = $('#' + s.videoId), canvas = $('#' + s.canvasId), getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); if(!getUserMedia) { alert('不支持'); return false; } function noStream(err) { if(err.PERMISSION_DENIED) { alert('用戶拒絕了瀏覽器請求媒體的權限'); } else if(err.NOT_SUPPORTED_ERROR) { alert('constraint中指定的媒體類型不被支持'); } else if(err.MANDATORY_UNSATISFIED_ERROR) { alert('指定的媒體類型未接收到媒體流'); } console.log(err); } function goStream(stream) { video[0].src = URL.createObjectURL(stream); if(typeof s.callBack == 'function') { s.callBack(video[0]); } stream.oninactive = noStream; } getUserMedia.call(navigator, {video: s.video, audio: s.audio}, s.goStream, s.noStream); } })(jQuery);
     $(function() {      
        $.video({callBack: function(video){
          video.play();
        });
      });

    經過上一步驟基本上網頁上已經呈現出來您視頻頭所捕獲的圖像了

  2、 讓canvas繪制視頻頭捕捉的圖像      

         var canvas = document.getElementById('canvas');
         var ctx = canvas.getContext("2d");

         $.video({callBack: function(video) {
               video.addEventListener('play', function(){
                    var $this = this;
                    setInterval(function() {
                        ctx.drawImage(video, 0, 0);
                        var image = canvas.toDataURL("image/png");
              //繪制到頁面去代碼略 }, 500); },false);   video.play();
}});

  經過上一步驟網頁就會看到一個視頻頭步驟的頭像,一個canvas動態繪制的圖像

   3、既然本地已經沒有問題下,那么就讓其他人跟我一起視頻吧    

   在我最開始的時候我想着架php服務器,輪訓的方式請求去推和拉下來一針一針的圖片,但是每次請求和服務器要處理下來開銷很大,所以替代的當然是現在比較流行的websocket

   當然由於本人沒了解過websocket所以也不能說websocket對於這個例子有什么優勢。我只是聽同事說這個比用笨重的服務器處理好,我就本着看看了解一下的態度,寫了下面幾行生硬的代碼。

    記得你要有node,如果你不會node一定要看(http://www.nodebeginner.org/index-zh-cn.html

    服務器端代碼:

  

var http = require('http');
var app = http.createServer(function(req, res) {
}).listen(8888);
var WebSocketServer =require('ws').Server;
var wss = new WebSocketServer( { server : app });
wss.on('connection', function(ws) {
    var clients = wss.clients, len = clients.length, i =0;
    for(; i< len; i++) {
       clients[i].send(JSON.stringify({'type':'system', 'msg': 'connection'}));
    }
    ws.on('message', function(data, flags) {
        var clients = wss.clients, len = clients.length, i =0;
        console.log(data);
        for(; i< len; i++) {
            clients[i].send(data);
        }
    });
    ws.on('close', function(e) {
        if(e == 10001) {
            console.log('現有終端連接數:' + wss.clients.length);
        }
        console.log('colse');
    })
});

  客戶端代碼:

    function get_uuid() {
             var uuid = '';
            for (var i = 0; i < 32; i++) {
                uuid += Math.floor(Math.random() * 16).toString(16);
            }
            return uuid;
        }
        var uuid = get_uuid();
        $(function() {
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext("2d");
            var a = webSocketFuc();
            $.video({callBack: function(video) {
                video.addEventListener('play', function(){
                    var $this = this;
                    setInterval(function() {
                        ctx.drawImage(video, 0, 0);
                        var image = canvas.toDataURL("image/png");
                        a.send(JSON.stringify({type: 'image', uuid: uuid, msg: image, }));
                    }, 500);
                },false);
                video.play();

            }});
            $(document).on('click','#send', function() {
                var msg = $('#test').val();
                a.send(JSON.stringify({'type': 'chat', msg: msg}));

            })
        })

        function webSocketFuc() {
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext("2d");
            var wsServer = 'ws://192.168.1.100:8888',
                wss = new WebSocket(wsServer);
                wss.binaryType = "arraybuffer";
                wss.onopen = function() {
                     console.log('open');
                }

                wss.onclose = function() {
                    console.log('close');
                }
                /* 可以傳送json和字符串還有二進制數據 */
                wss.onmessage = function(ev) {
                    //video.src = URL.createObjectURL(data);
                    var json_arr = JSON.parse(ev.data);
                    if(json_arr.type == 'image' ) {
                        if(json_arr.uuid != uuid) {
                            var image = new Image();
                            image.src = json_arr.msg;
                            image.onload = function() {
                                ctx.drawImage(image, 100, 83);
                            }
                        }
                    } else {
                        console.log(json_arr.msg);
                    }
                }
                wss.onerror = function(err) {
                     console.log(err);
                }
            return wss;
        }

 基本上告一段落。

下面是全部代碼:這里有一些我還沒做完和一些其他想法,微困就咱不整理了,我就粘出來污染一下大家的眼睛吧

<!DOCTYPE html>
<head>
    <title>視頻測試</title>
    <meta charset="utf-8">
    <script src="js/jquery.min.js"></script>
</head>
<body>
    <div>該例子 在支持html的video標簽的前提下,還要支持Navigator.getUserMedia(標准,各個瀏覽器接口不同)前提下</div>
    <a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator.getUserMedia">MozillaAPI</a>
    <a href="http://mozilla.com.cn/post/45435/">參見例子</a>
    <br/>
    <video id="video"></video>
     <canvas  id="canvas" width="500px" height="500px"></canvas>
     <input id="test"/>
     <button id="send">發送</button>
    <script>
         var title = 'memoryza';
        ;(function($) {
            $.video =  function(s) {
                var s = $.extend({
                        video: true,
                        audio: true,
                        goStream: goStream,
                        noStream: noStream,
                        callBack: null,
                        videoId: 'video'
                    }, s),
                    video = $('#' + s.videoId),
                    canvas = $('#' + s.canvasId),
                    getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);

                if(!getUserMedia) {
                    alert('不支持');
                    return false;
                }
                 function noStream(err) {
                        if(err.PERMISSION_DENIED) {
                            alert('用戶拒絕了瀏覽器請求媒體的權限');
                        } else if(err.NOT_SUPPORTED_ERROR) {
                            alert('constraint中指定的媒體類型不被支持');
                        } else if(err.MANDATORY_UNSATISFIED_ERROR) {
                            alert('指定的媒體類型未接收到媒體流');
                        }
                        console.log(err);
                }
                function goStream(stream) {
                    video[0].src = URL.createObjectURL(stream);
                    if(typeof s.callBack == 'function') {
                        s.callBack(video[0]);
                    }
                    stream.oninactive = noStream;
                }
                getUserMedia.call(navigator, {video: s.video, audio: s.audio}, s.goStream, s.noStream);
            }

        })(jQuery);
    </script>
    <script>
        function get_uuid() {
             var uuid = '';
            for (var i = 0; i < 32; i++) {
                uuid += Math.floor(Math.random() * 16).toString(16);
            }
            return uuid;
        }
        var uuid = get_uuid();
        $(function() {
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext("2d");
            var a = webSocketFuc();
            $.video({callBack: function(video) {
                video.addEventListener('play', function(){
                    var $this = this;
                    setInterval(function() {
                        ctx.drawImage(video, 0, 0);
                        var image = canvas.toDataURL("image/png");
                        a.send(JSON.stringify({type: 'image', uuid: uuid, msg: image, }));
                    }, 500);
                },false);
                video.play();

            }});
            $(document).on('click','#send', function() {
                var msg = $('#test').val();
                a.send(JSON.stringify({'type': 'chat', msg: msg}));

            })
        })

    </script>
    <script>
        function webSocketFuc() {
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext("2d");
            var wsServer = 'ws://192.168.1.100:8888',
                wss = new WebSocket(wsServer);
                wss.binaryType = "arraybuffer";
                wss.onopen = function() {
                     console.log('open');
                }

                wss.onclose = function() {
                    console.log('close');
                }
                /* 可以傳送json和字符串還有二進制數據 */
                wss.onmessage = function(ev) {
                    //video.src = URL.createObjectURL(data);
                    var json_arr = JSON.parse(ev.data);
                    if(json_arr.type == 'image' ) {
                        if(json_arr.uuid != uuid) {
                            var image = new Image();
                            image.src = json_arr.msg;
                            image.onload = function() {
                                ctx.drawImage(image, 100, 83);
                            }
                        }
                    } else {
                        console.log(json_arr.msg);
                    }
                }
                wss.onerror = function(err) {
                     console.log(err);
                }
            return wss;
        }
    </script>
</body>
</html>

  再改,文件傳輸協議、數據校驗、二進制處理

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM