樹莓派視頻監控平臺實現錄製歸檔

上一次用樹莓派搭建了視頻監控平臺,成功實現了利用樹莓派當監控攝像頭,可是隻能在線監控沒有存檔功能,此次針對上次的監控平臺進行了改造,實現了錄製歸檔功能。html

樹莓派相關文章:java

  1. 樹莓派搭建nexus2.x私服
  2. 樹莓派搭建視頻監控平臺
  3. 樹莓派視頻監控平臺實現錄製歸檔(本文)
  4. 樹莓派實現人臉打卡機

此次主要針對上次的平臺作如下幾點改造:ide

  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();
}

當視頻持續錄製是,須要限制視頻的大小,這裏視頻最長只錄制一小時,當錄製時長超過一小時後,歸檔從新錄製。this

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. 改造監控管理頁面

這裏直接改造上次的監控管理頁面,將佈局調整爲左右模式,並新增了「開啓錄製」和「中止錄製」按鈕、以及「錄製歸檔列表」的入口跳轉,總體頁面效果以下:code

stream-record.png

須要注意的是:要實現錄製,必須開啓監控,只有開啓了監控才能夠錄製。orm

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="/"> 查看視頻監控 >>> </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水印,不便之處請多包涵。

相關文章
相關標籤/搜索