树莓派视频监控平台实现录制归档

摘要:
上一次我们用复盆子派构建视频监控平台时,我们成功地实现了使用复盆子派的监控摄像头,但只有在线监控,没有存档功能。这次我们修改了最后一个监控平台,以实现记录和归档功能。在流中断的情况下,视频记录模块使用监控线程。如果超过两分钟没有录制视频帧,则停止当前录制。记录器通过调用ping方法实现心跳:publicvoid run(){while{try{TimeUnit.MINUTES.sleep;}捕获{}如果{destroy();}}publicvoid ping(){timestamp=System.currentTimeMillis();}当连续录制视频时,需要限制视频大小,此处的视频最多只能录制一小时。当录制时间超过一小时时,请再次存档并录制。

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

树莓派相关文章:

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

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

  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. 改造监控管理页面

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

stream-record.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播放已录制的视频画面:

stream-record-play

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

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

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

  1. 视频列表显示页面开发
<body>
  <a href="http://t.zoukankan.com/"> 查看视频监控 >>> </a> 
  <br>
  <br>
  <div>
    <table border="1">
      <tr>
        <td>视频名称</td>
        <td>视频大小</td>
        <td>录制时间</td>
      </tr>
      #for(v : fList)
      <tr>
        <td>#(v.name)</td>
        <td>#(v.size)</td>
        <td>#(v.time)</td>
      </tr>
      #end
    </table>
  </div>
</body>
  1. 归档视频列表接口开发
public void index() {
  List<VideoVO> 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");
}

最终效果如下:

stream-record-list

6. 拓展玩法

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

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

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

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

由于上次发表的文章,被人盗用发布在头条上,这里我在文章的图片加了LOGO水印,不便之处请多包涵。

免责声明:文章转载自《树莓派视频监控平台实现录制归档》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇VBS基本知识memcpy多字节字节赋值问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

linux 树莓派 debian ffmpeg alsa v4l2 录制音频 视频 cannot open audio device 无法播放 声音模糊 画面卡顿 ALSA buffer xrun Thread message queue blocking -pix_fmt

一个基本的命令: ffmpeg -f alsa -i <device> out.mp3 其中, -f 表示设置格式,有format的意思,out.mp3前面可以加上 -f mp3, 因为带了mp3后缀,就省略了。 alsa 表示alsa音频驱动程序的编码格式,它保证后面的音频流可以由alsa解码。具体可根据驱动程序选择。(alsa主页https...

基于openEuler的OpenSSL编译安装和编程基础(无树莓派)

OpenEuler树莓派基础实验 远程登录openEuler,我们看一下openEuler默认有没有安装OpenSSL,如下图所示,openEuler默认已经安装好了OpenSSL: OpenSSL编译安装 1.我们去OpenSSL官网下载最新版本OpenSSL 1.1.1k的源码openssl-1.1.1k.tar.gz,然后把代码上传到openEul...

树莓派打造音乐播放机

给树莓派装上系统接入网络完成各种配置后,第一件事就想把它连接上音箱当做音乐播放机来使用。树莓派官方系统已经有安装aplay软件可以播放音频文件。不过aplay支持的音频格式的支持不够完整,比如对mp3就不能很好支持。这里介绍几个音频播放软件的简单使用。 实验环境 硬件:树莓派3b一台 操作系统:Raspbian with Desktop   一、apl...

树莓派 配置 OMV 搭建 NAS(六) 多用户多权限共享文件夹

前言 前文讲述了 树莓派 配置 OMV 搭建 NAS(五) 设置共享权限 ,本文接着来讲如何实现 多用户多权限的共享 。 添加用户组 点击侧边栏 “访问权限管理 -> 用户组” 点击 “添加” 在 “添加用户组” 的 “常规” 中,填写名称(必须是英文)、注释。 在 “添加用户组” 的 “成员” 中,选中要添加的成员。 可...

树莓派搭建bt下载机、即是安装transmission

Transmission是一种BitTorrent客户端, 安装:sudo apt-get install transmission-daemon 给用户授权:sudo usermod -a -G pi debian-transmission 设置Transmission的配置文件:sudo vim /etc/transmission-daemon/s...

Raspberry PI 树莓派 远程登录 和 远程桌面

1. 设置 ① 用网线使树莓派与电脑连接; ② 给树莓派配置一个鼠标、键盘、显示器; ③ 将树莓派的SD卡写入操作系统; ④ 开机启动树莓派,在显示器上会显示树莓派的开机启动界面; ⑤ 在terminal终端中输入sudo nano /etc/dhcpcd.conf,出现编辑文件窗口,其中输入如下配置信息: 键盘敲入Ctrl+O,Enter保存,Ctrl...