上一次用树莓派搭建了Nexus私服,终于让树莓派不再成为吃灰派了,这次用树莓派搭建视频监控平台,并实现视频画面推流到流媒体服务器。

树莓派相关文章:

  1. 树莓派搭建nexus2.x私服
  2. 树莓派搭建视频监控平台(本文)
  3. 树莓派视频监控平台实现录制归档
  4. 树莓派实现人脸打卡机

1. 安装nginx

要实现将视频画面推动到媒体服务器,需要搭建一个流媒体服务器,这里选择nginx + flv module 来搭建,需要用到的源码包如下:

nginx1.15.4.tar.gz
nginx-http-flv-module-1.2.6.tar.gz
openssl-1.1.0j.tar.gz
pcre-8.40.tar.gz

将上面所有的源码在/usr/local/src下面解压,然后配置并编译安装nginx。

cd nginx1.15.4
sudo ./configure \
--sbin-path=/usr/local/nginx/nginx \
--conf-path=/usr/local/nginx/nginx.conf \
--pid-path=/usr/local/nginx/nginx.pid \
--add-module=../nginx-http-flv-module-1.2.6 \
--with-http_flv_module --with-http_mp4_module \
--with-http_ssl_module \
--with-pcre=../pcre-8.40 \
--with-http_ssl_module \
--with-openssl=../openssl-1.1.0j

sudo make
sudo make install

安装完成后会在/usr/local/中多一个nginx目录,这里就是安装好的nginx,这里备份默认nginx配置nginx.conf,然后编写自己的nginx配置。

cd /usr/local/nginx
sudo mv nginx.conf nginx.conf.def
sudo vim nginx.conf

自己的nginx.conf如下:

worker_processes  1;
events {
    worker_connections  1024;
}
rtmp {
  server {
    listen 1935;
    application live {
      live on;
    }
  }
}

2. 测试推流

nginx + flv module 搭建完后可以是用 ffmpeg 测试推流,首先启动nginx。

cd /usr/local/nginx
sudo ./nginx

然后在windows平台中使用ffmpeg推流

ffmpeg.exe -ss 0 -i out.mp4 -acodec copy -f flv rtmp://192.168.1.26:1935/live/t1

最后用VLC播放视频流,如果以上所有操作没有出现错误,将可以在VLC中看到视频画面。

raspi-ffmpeg

3. 测试摄像头

要搞视频监控还需要一个摄像头,这里使用的是树莓派CSI接口中的摄像头,如果摄像头功能没有开启的话需要在树莓派开启。

sudo raspi-config

选择 5. Interfacing Options

raspi5

然后再选择 P1 Camera

raspip1

选择“是”,然后重启树莓派。

sudo reboot

树莓派重启之后,可以执行下面指令用摄像头截图,如果截图成功说明摄像头配置成功。

sudo modprobe bcm2835-v4l2
sudo raspistill -v -o camera.jpg

4. 平台开发

所有环境准备完成后,剩下的就是开发一个可以管理摄像头推流的平台了,这里选用JavaCV + JFinal来开发视频监控管理平台。

下载JFinal demo

从JFinal官网下载JFinal 4.9 demo for maven的源码,导入Eclipse开发工具,删除不需要的代码包括数据库配置等。

只留下我们需要的代码:

DemoConfig.java
IndexController.java
index.html

开发摄像头推流器

使用OpenCV采集摄像头的视频帧,然后使用FFmpeg推流,编码方式采用H264,帧率是25。

package com.demo.stream;
/**
 * @author itqn
 */
public class StreamSender implements Runnable {

  private static final int FPS = 25;
  private String rtmpUri;
  private OpenCVFrameGrabber grabber;
  private FFmpegFrameRecorder recorder;
  private boolean running = false;

  public int width;
  public int height;

  public StreamSender(String rtmpUri) {
    this.rtmpUri = rtmpUri;
    this.init();
  }

  @Override
  public void run() {
    running = true;
    long startTime = System.currentTimeMillis();
    long timestamp = 0;
    while (running) {
      timestamp = 1000 * (System.currentTimeMillis() - startTime);
      if (timestamp > recorder.getTimestamp()) {
        recorder.setTimestamp(timestamp);
      }
      try {
        recorder.record(grabber.grab());
      } catch (Throwable e) {
        close();
      }
      try {
        TimeUnit.MILLISECONDS.sleep(1000 / FPS);
      } catch (Exception ignore) {}
    }
  }
  
  public void close() {
    running = false;
    try {
      TimeUnit.SECONDS.sleep(1);
    } catch (Exception ignore) {}
    destroy();
  }

  private void init() {
    try {
      grabber = new OpenCVFrameGrabber(0);
      grabber.start();
      Frame frame = grabber.grab();
      width = frame.imageWidth;
      height = frame.imageHeight;
    
      recorder = new FFmpegFrameRecorder(rtmpUri, width, height);
      recorder.setFormat("flv");
      recorder.setFrameRate(FPS);
      recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
      recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
      recorder.setVideoOption("preset", "slow");
      recorder.setVideoOption("tune", "zerolatency");
      recorder.start();
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }
  
  private void destroy() {
    try {
      recorder.close();
    } catch (Throwable ignore) {}
    try {
      grabber.close();
    } catch (Throwable ignore) {}
  }
}

编写控制接口

调整一下IndexController的代码,新增启动监控和停止监控的接口。

public void start() {
  String rtmpUri = get("rtmpUri");
  if (StrKit.isBlank(rtmpUri)) {
    redirect("/?e=1");
    return;
  }
  try {
    StreamManager.INSTANCE.startSender(rtmpUri);
    redirect("/");
  } catch (Throwable e) {
    redirect("/?e=2");
  }
}

public void stop() {
  StreamManager.INSTANCE.stopSender();
  redirect("/");
}

编写播放页面

rtmp流播放采用videojs这个库

<!DOCTYPE html>
<html>
<head>
<title>树莓派视频监控</title>
<link href="/css/video-js.css" rel="stylesheet">
<script src="/js/video.js"></script>
</head>
<body>
  <video id="video" class="video-js vjs-default-skin" controls
     poster="http://vjs.zencdn.net/v/oceans.png" preload="auto"
     width="#(width)" height="#(height)" data-setup="{}">
    <source src="#(streamUri)" type="rtmp/flv">
  </video>
  <br>
  <br>
  <div style="color: #ff0000">#(e)</div>
  <div>
    <form action="/start">
      推流地址 : 
      <input name="rtmpUri" value="#(streamUri??\'rtmp://127.0.0.1:1935/hls/test\')"/>
      <br><br>
      <button>开启监控</button>
    </form>
    <br>
    <form action="/stop">
      <button>断开监控</button>
    </form>
  </div>
</body>
</html>

5. 部署平台

平台开发完成后需要将平台部署到树莓派中运行起来即可,JFinal默认的demo已经提供了启停脚本,所以只需要在Eclipse中执行 mvn install 即可。

打包成功后,在项目的target目录下面会有如下结构:

jfinal_demo_for_maven-release
\jfinal_demo_for_maven
\-\config
\-\lib
\-\webapp
\-\jfinal.sh
# 另外我们需要将target目录下的jfinal_demo_for_maven-4.9.jar复制到lib目录下。

将上面的jfinal_demo_for_maven整个目录FTP上传到树莓派中,启动平台:

sudo ./jfinal.sh start
# 这里可以改动jfinal.sh中指定的平台访问端口

启动成功后,可以在电脑上访问平台:

http://192.168.1.26:8080

然后填写推流地址,点击开始监控即可。

raspi-stream

这样,基于树莓派的视频监控平台就部署好了。如果要关闭视频监控,只需要点击页面上的 断开监控 即可。

6. 拓展玩法

这里为了实践我是自己在树莓派上搭建了一个基于nginx + flv module 的流媒体服务器,当然还有很多玩法。

比如:

a. 在线上服务器搭建流媒体服务器,然后将视频流推送到线上服务器,这样就可以实现远程视频监控。

b. 另外也可以将视频流推送到直播平台,实现直播。

=========================================================
项目源码可关注公众号 “HiIT青年” 发送 “raspi-video” 获取。

HiIT青年
关注公众号,阅读更多文章。

!文章被用户(百度账号:cuixiaoyande)抄袭,同时在头条号(头条号:cuixiaoyande)上也被此用户抄袭。
百家号文章
头条举报结果

版权声明:本文为itqn原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/itqn/p/13268916.html