上一次用树莓派搭建了Nexus私服,终于让树莓派不再成为吃灰派了,这次用树莓派搭建视频监控平台,并实现视频画面推流到流媒体服务器。
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=http://www.likecs.com/usr/local/nginx/nginx \ --conf-path=http://www.likecs.com/usr/local/nginx/nginx.conf \ --pid-path=http://www.likecs.com/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中看到视频画面。
3. 测试摄像头要搞视频监控还需要一个摄像头,这里使用的是树莓派CSI接口中的摄像头,如果摄像头功能没有开启的话需要在树莓派开启。
sudo raspi-config选择 1. Interfacing Options
然后再选择 P1 Camera
选择“是”,然后重启树莓派。
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) {} } }编写控制接口