badboy录制时为什么有的页面显示不全_树莓派视频监控平台实现录制归档

上一次用树莓派搭建了视频监控平台,成功实现了利用树莓派当监控摄像头,但是只能在线监控没有存档功能,这次针对上次的监控平台进行了改造,实现了录制归档功能。

这次主要针对上次的平台做以下几点改造:

  1. 新增视频流录制模块
  2. 调整监控管理页面
  3. 新增录制归档列表页面

1. 开发视频流录制模块

视频录制模块不像视频推流模块那样,可以一直不停止的工作(推流),因为录制模块需要考虑录制视频的大小和断流等因素,所以在必要的时候需要录制流程进行处理。

针对断流的情况,视频录制模块使用一个监控线程,当超过两分钟未录制视频帧时,停止当前录制,录制器通过调用ping方法来实现心跳:

public void run() {  while (true) {    try {      TimeUnit.MINUTES.sleep(2);    } catch (InterruptedException ignore) {    }    if (System.currentTimeMillis() - timestamp > 2 * 60 * 1000) {      destroy();    }  }}public void ping() {  timestamp = System.currentTimeMillis();}

当视频持续录制时,需要限制视频的大小,这里视频最长只录制一小时,当录制时长超过一小时后,归档重新录制。

if (System.currentTimeMillis() - startTime > MAX_RECORD_TIME) {  destroy();}if (recorder == null) {  init(frame.imageWidth, frame.imageHeight);}

这里的录制模块是单例,所以当对象创建的时候,就创建监听线程并启动它,以下是完成的实现:

public class StreamRecorder {  public static final StreamRecorder INSTANCE = new StreamRecorder();  private static final int FPS = 25;  private static final int MAX_RECORD_TIME = 60 * 60 * 1000;  private long startTime;  private FFmpegFrameRecorder recorder;  private AtomicBoolean wait = new AtomicBoolean(false);  private StreamRecorder() {    new Thread(this.new ALiveWatcher()).start();  }  public void record(Frame frame) {    if (wait.get() || frame == null) {      return;    }    if (System.currentTimeMillis() - startTime > MAX_RECORD_TIME) {      destroy();    }    if (recorder == null) {      init(frame.imageWidth, frame.imageHeight);    }    long timestamp = 1000 * (System.currentTimeMillis() - startTime);    if (timestamp > recorder.getTimestamp()) {      recorder.setTimestamp(timestamp);    }    try {      recorder.record(frame);    } catch (Exception e) {      destroy();    }  }  private void init(int width, int height) {    try {      startTime = System.currentTimeMillis();      String f = Const.RECORD_DIR + File.separator + startTime + ".flv";      recorder = new FFmpegFrameRecorder(f, width, height);      recorder.setFormat("flv");      recorder.setFrameRate(FPS);      recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);      recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);      recorder.start();    } catch (Throwable e) {      throw new RuntimeException(e);    }  }  public void destroy() {    if (recorder == null) {      return;    }    try {      wait.set(true);      TimeUnit.SECONDS.sleep(1);      recorder.close();      recorder = null;    } catch (Throwable ignore) {    } finally {      wait.set(false);    }  }  class ALiveWatcher implements Runnable {    private long timestamp;    @Override    public void run() {      while (true) {        try {          TimeUnit.MINUTES.sleep(2);        } catch (InterruptedException ignore) {        }        if (System.currentTimeMillis() - timestamp > 2 * 60 * 1000) {          destroy();        }      }    }    public void ping() {      timestamp = System.currentTimeMillis();    }  }}

2. 改造监控管理页面

这里直接改造上次的监控管理页面,将布局调整为左右模式,并新增了“开启录制”和“停止录制”按钮、以及“录制归档列表”的入口跳转,整体页面效果如下:

588b600557fe8b830881ec47a5b39dd5.png

需要注意的是:要实现录制,必须开启监控,只有开启了监控才可以录制。

3. 开发录制控制接口

跟上次开发监控控制接口一样,在IndexController中新增两个接口用于控制“开启录制”和“停止录制”。

public void startRecord() {  StreamManager.INSTANCE.startRecord();  redirect("/");}public void stopRecord() {  StreamManager.INSTANCE.stopRecord();  redirect("/");}

上面的StreamManager是视频流管控中心,在这里往推流器注册一个视频帧消费者,然后将视频帧塞给录制器实现录制。

private void registerFrameConsumer() {  if (sender == null) {    return;  }  sender.registerFrameConsumer(f -> {    if (record) {      StreamRecorder.INSTANCE.record(f);    }  });}

所以当开启录制时,只需要将record置为true即可。

public void startRecord() {  record = true;}

而停止录制时则将record置为false,同时关闭录制。

public void stopRecord() {  record = false;  StreamRecorder.INSTANCE.destroy();}

4. 播放录制视频

视频录制后会以开始录制时间戳为名称存放在录制目录中(程序设置的是:/home/pi/RevVideo),录制的视频格式是FLV,采用JavaCV录制FLV无法直接使用HTML5的video播放,要播放录制的视频,可以用树莓派自带的媒体播放工具VLC, 下面视频VLC播放已录制的视频画面:

0319d68d2ee2c24a3e4cca9efacc7c68.png

至此,视频监控平台就实现了录制归档功能。

5. 开发视频归档列表页面

为了方便查看树莓派中录制的视频列表,可以开发一个简单的页面用于显示已经录制的视频,实现这个功能只需要简单的两步即可。

  1. 视频列表显示页面开发
   查看视频监控 >>>    

视频名称 视频大小 录制时间 #for(v : fList) #(v.name) #(v.size) #(v.time) #end
  1. 归档视频列表接口开发
public void index() {  List fList = new ArrayList<>(20);  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  File dir = new File(Const.RECORD_DIR);  File[] fArray = dir.listFiles(f -> f.getName().endsWith(".flv"));  if (fArray != null) {    for (File f : fArray) {      VideoVO vo = new VideoVO();      vo.setName(f.getName());      vo.setSize(f.length());      vo.setTime(sdf.format(new Date(Long.parseLong(f.getName().replace(".flv", "")))));      fList.add(vo);    }  }  setAttr("fList", fList);  render("index.html");}

最终效果如下:

64755417a1a110929c706d9adc86e0dd.png

6. 拓展玩法

虽然这个视频监控平台已经实现了监控和录制功能,但仍有部分缺陷,如果有兴趣可以进行拓展。比如:

  1. 录制视频使用ffmpeg进行转码,然后使用HTML5-video标签进行播放回看。
  2. 录制视频提供删除和定期清理功能。
  3. 录制视频提供下载功能。

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


~~~关注微信公众号:HiIT青年~~~

~~~阅读更多文章~~~

使用Electron开发桌面应用

Electron应用打包、自动升级

使用树莓派搭建nexus私服

VSCode、VBox搭建C/C++开发环境

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值