将摄像头内容实时放在网页上播放

Posted by echo069 on February 23, 2017

测试

测试摄像头是否可用

fswebcam这是一款小型摄像头程序。首先来安装它

sudo apt install fswebcam

然后进入设备目录查看电脑配置的摄像头

cd /dev/
ls video*

我的电脑只有一个摄像头viedo0

输入以下代码可以抓取摄像头画面,我将它保存在了用户目录的图片里

fswebcam --device /dev/video0 ~/图片/001.jpeg

以上就完成了利用fswebcam抓取当前图像

测试摄像头能否抓取当前视频信息

首先安装ffmpeg(FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。)

然后修改ffserver的配置文件,创建一个文件夹,在里面创建一个名为ffserver.conf的文件,把以下内容复制进去:

HTTPPort 8090
HTTPBindAddress 0.0.0.0
MaxHTTPConnections 100
MaxClients 10
MaxBandwidth 7000
CustomLog -

######### Definition of the live feeds #########
<Feed feed1.ffm>
File /tmp/feed1.ffm
FileMaxSize 200K
ACL allow 192.168.43.0 192.168.43.255
</Feed>

######### Definition of the stream #########
<Stream test1.mpg>
Feed feed1.ffm
Format mpeg
VideoBitRate 200
VideoBufferSize 40
VideoFrameRate 25
VideoSize 320x240
VideoGopSize 12
VideoCodec mpeg1video
NoAudio
ACL allow 192.168.0.0 192.168.255.255
</Stream>

######### stat.html #########
<Stream stat.html>
Format status
ACL allow 192.168.0.0 192.168.255.255
ACL allow 127.0.0.1
</Stream>

输入:ffserver -f ~/ffserver/ffserver.conf

然后打开浏览器输入以下:localhost:8090/stat.html 此时网页变成如下样式

然后输入

ffmpeg -i /dev/video http://localhost:8090/feed1.ffm

可以观察到网页内容有细微变化,下面出现RECEIVE_DATA字样。

它表示正在接收摄像头传输的数据,然后输入以下命令:

ffplay -v info -i http://localhost:8090/test1.mpg

此时第一阶段任务完成,我们可以看到实时的视频内容,视频会出现一定延迟。此时只证明可以从电脑端看到视频信息。然后我们可以关掉ffplay这个终端,接下来是让是让视频能够在网页上播放

将视频搬到网页上

创建一个client文件夹

因为要播放视频所以要把jsmpeg.min.js库放在里面。里面的index.html内容如下:

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="jsmpeg.min.js"></script>
    <title>title</title>
</head>

<body>

<h1>Demo</h1>

<canvas id="video-canvas"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById("video-canvas");
    var url = "ws://" + document.location.hostname + ":8082/";
    var player = new JSMpeg.Player(url, {canvas: canvas});
</script>

</body>

</html>

安装websocket

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

首先输入如下命令来安装websocket

npm init
npm install ws@2.3.1
[cat package.json]

创建一个websocket文件夹

里面的websocket-relay.js文件写入如下:

// Use the websocket-relay to serve a raw MPEG-TS over WebSockets. You can use
// ffmpeg to feed the relay. ffmpeg -> websocket-relay -> browser
// Example:
// node websocket-relay yoursecret 8081 8082
// ffmpeg -i <some input> -f mpegts http://localhost:8081/yoursecret

var fs = require('fs'),
    http = require('http'),
    WebSocket = require('ws');

if (process.argv.length < 3) {
    console.log(
        'Usage: \n' +
        'node websocket-relay.js <secret> [<stream-port> <websocket-port>]'
    );
    process.exit();
}

var STREAM_SECRET = process.argv[2],
    STREAM_PORT = process.argv[3] || 8081,
    WEBSOCKET_PORT = process.argv[4] || 8082,
    RECORD_STREAM = false;

// Websocket Server
var socketServer = new WebSocket.Server({port: WEBSOCKET_PORT, perMessageDeflate: false});
socketServer.connectionCount = 0;
socketServer.on('connection', function(socket) {
    socketServer.connectionCount++;
    console.log(
        'New WebSocket Connection: ',
        socket.upgradeReq.socket.remoteAddress,
        socket.upgradeReq.headers['user-agent'],
        '('+socketServer.connectionCount+' total)'
    );
    socket.on('close', function(code, message){
        socketServer.connectionCount--;
        console.log(
            'Disconnected WebSocket ('+socketServer.connectionCount+' total)'
        );
    });
});
socketServer.broadcast = function(data) {
    socketServer.clients.forEach(function each(client) {
        if (client.readyState === WebSocket.OPEN) {
            client.send(data);
        }
    });
};

// HTTP Server to accept incomming MPEG-TS Stream from ffmpeg
var streamServer = http.createServer( function(request, response) {
    var params = request.url.substr(1).split('/');

    if (params[0] !== STREAM_SECRET) {
        console.log(
            'Failed Stream Connection: '+ request.socket.remoteAddress + ':' +
            request.socket.remotePort + ' - wrong secret.'
        );
        response.end();
    }

    response.connection.setTimeout(0);
    console.log(
        'Stream Connected: ' +
        request.socket.remoteAddress + ':' +
        request.socket.remotePort
    );
    request.on('data', function(data){
        socketServer.broadcast(data);
        if (request.socket.recording) {
            request.socket.recording.write(data);
        }
    });
    request.on('end',function(){
        console.log('close');
        if (request.socket.recording) {
            request.socket.recording.close();
        }
    });

    // Record the stream to a local file?
    if (RECORD_STREAM) {
        var path = 'recordings/' + Date.now() + '.ts';
        request.socket.recording = fs.createWriteStream(path);
    }
}).listen(STREAM_PORT);

console.log('Listening for incomming MPEG-TS Stream on http://127.0.0.1:'+STREAM_PORT+'/<secret>');
console.log('Awaiting WebSocket connections on ws://127.0.0.1:'+WEBSOCKET_PORT+'/');

输入命令

进入websocket文件夹,打开终端输入如下命令:

node websocket-relay.js <secret>

(secret中随便写几个数字用来识别。)

再打开一个新的终端输入以下命令;

ffmpeg -i http://localhost:8090/test1.mpg -f mpegts -vcodec mpeg1video http://localhost:8081/<secret>

最后进入创建的client文件夹里打开终端输入http-server就可以刷新网页看到视频了。

接下来要使服务器端和客户端连接起来,并且通过客户端的操作,使服务端能够打印出消息。所以我们需要再创建一个文件夹(服务器端)分别来存放控制台代码,并且在客户端里写入相应的请求。

将客户端与服务器端连接起来

客户端(client)

我要实现的功能:

设置四个按钮(上下左右),通过点击按钮在控制台输出点击的方向(上下左右)和时间长度

所以这里要用到jquery里的post(post() 方法通过 HTTP POST 请求从服务器载入数据。),所以要安装jquery,还要在client文件夹里放入一个”jquery-3.3.1.min.js”的文件。

文件代码如下(这里只写一个按钮):

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>title</title>
    <script src="jquery-3.3.1.min.js"></script>
    <script src="jsmpeg.min.js"></script>
<style>
#up{
    position:absolute;
    left:180px;
    top:50px;
}
</style>
</head>
<body>

<h1>Demo</h1>

<div><button type="button" class="btn" id="up">Up</button></div>
<div><canvas id="video-canvas"></canvas></div>

<script type="text/javascript">
    var canvas = document.getElementById("video-canvas");
    var url = "ws://" + document.location.hostname + ":8082/";
    var player = new JSMpeg.Player(url, {canvas: canvas});
</script>


<script type="text/javascript">
var up1 = new Date();
var up_d = new Date();

var upButton = document.getElementById('up');
    upButton.onmousedown = function(){
        up1 = new Date();
    }
    upButton.onmouseup = function(){
        var up2 = new Date();
        up_d=up2-up1;
         $.post("127.0.0.1:3000/test", 
            { 
                direction: "up",
                range: up_d 
             });
    }
</script>
</body>
</html>

服务器端(jquery-server)

再创建一个名为jquery-server的文件夹,里面的index.js里写入如下代码:

const express = require('express'); 
var bodyParser = require('body-parser');

const app = express()
app.use(bodyParser.urlencoded({extended:false}))
app.post('/test',function(request,response){  
  var direction = request.body.direction;
  var duration = request.body.range;
  console.log("direction:"+direction+", duration:"+duration);
    });
});

app.listen(3000)

连接

在jquery-server文件夹里打开终端输入:node index.js 在client文件夹里打开终端输入:http-server

打开网页刷新并且点击按钮就可以在控制台看到输出的信息了。

问题

一.

内容:我们打开chrome,点击网页按钮,发现只能点击六次,之后再点击就无法输出信息了,同时换用火狐浏览器发现只能点击九次。

原因:客户端发送请求给服务器,而服务器端没有做出回应导致客户端不再发送请求,也就无法打印信息。

解决方法: 在post里面返回响应,加入 response.send(“OK”);这一句就好了。

二.

内容: 火狐浏览器运行没有报错,但是谷歌显示出现了Access-Control-Allow-Origin,也就是跨域问题。

原因:端口不同导致的

解决办法:依然在post里加入一句: response.header(‘Access-Control-Allow-Origin’, ‘*’);

以上只是按照自己的理解暂时编辑,之后在进行补充。