使用 ffmpeg 连续录制 RTSP 流。我可以优化它以不损坏 SD 卡吗?

使用 ffmpeg 连续录制 RTSP 流。我可以优化它以不损坏 SD 卡吗?

我有一个带 RTSP 流的 IP 摄像头。我决定使用 ffmpeg(版本 3.2.14-1~deb9u1)在装有 Armbian 的 Odroid-N2 设备上录制流。我创建了一个 .sh 脚本,该脚本每分钟由 Croon 启动一次。它会检查所选摄像头的 ffmpeg 录制是否处于活动状态,并删除超过 7 天的文件:

#!/bin/bash
RecordPathAndFind='/home/mona/CameraRecordings/Camera1/'
SegmentTime=900
MinutesAfterDeleteOldFiles=10080
DaysSecurityLimit=31

tempoutput=$(ps aux | grep ffmpeg | grep $RecordPathAndFind)
if [ ${#tempoutput} -ge 5 ];
then
      echo "FFMPEG with record command is already running. Skipping.\n"
else
      echo "FFMPEG with record command is not running. Starting now...\n"
      FFMPEGSTART=$(su - mona -c "cd /home/mona; /usr/bin/screen -dmS ffmpegcamera1 ffmpeg -rtsp_transport udp -i 'rtsp://admin:[email protected]:554/onvif1' -vcodec copy -c:a aac -map 0 -f segment -segment_time $(echo $SegmentTime) -segment_format mp4 -strftime 1 $(echo $RecordPathAndFind)%Y-%m-%d_%H-%M-%S.mp4")
fi

currenthourminutes=$(date +%M)
if [ "$currenthourminutes" == "00" ]; then
    echo "Current Minute is 00. Checking for old files to delete.\n"
    FILESDELETECOMMAND=$(find $(echo $RecordPathAndFind) -maxdepth 1 -type f -mmin +$(echo $MinutesAfterDeleteOldFiles) -mtime -$(echo $DaysSecurityLimit) -name '*.mp4' -ls -exec rm {} \;)
else
    echo "Current Minute is NOT 00. Skipping.\n"
fi

脚本运行良好,但我担心此设备中的 SD 卡的使用寿命。我检测到 ffmpeg 正在不断写入 mp4 文件(文件大小一直在增长)。我认为如果 ffmpeg 等待 ~1MiB 再将其刷新到磁盘会更好。

我尝试了不同的 ffmpeg 设置(添加“blocksize”、“flush_packets”、“reorder_queue_size”和其他一些我现在想不起来了的设置),不幸的是,它什么也没改变。mp4 文件大小一直在增加(甚至增加了几 KB)。

第一个问题是:当 ffmpeg 一直在写入文件(当前环境)时,我是否应该担心 microSD 卡的寿命?

第二个问题是:还有其他我遗漏的 ffmpeg 优化设置吗?

如果我对 SD 卡寿命的担心是正确的,您能否推荐一些其他可以添加到我的脚本中(或在系统中进行更改)以延长用于录制目的的微型 SD 卡(或 USB 记忆棒)的使用寿命?我正在考虑使用 ramdisk,然后手动移动文件,但是如果系统重启、挂起或断电,这可能会导致文件丢失。

编辑:这是我用来检查文件大小变化的命令:

root@odroidn2:/home/mona/CameraRecordings/Camera1# printf "`date +"%m-%d-%y_%H:%S:%N"` `echo "Bytes:"` `stat --printf "%s\n" 2019-07-10_18-01-00.mp4`\n"
07-10-19_18:28:616623697 Bytes: 28443805
07-10-19_18:29:497492966 Bytes: 28453943
07-10-19_18:29:811378969 Bytes: 28458099
07-10-19_18:30:162532642 Bytes: 28724960
07-10-19_18:30:513455929 Bytes: 28730146
07-10-19_18:30:832042221 Bytes: 28734694
07-10-19_18:31:204934593 Bytes: 28739202
07-10-19_18:31:587997659 Bytes: 28744450
07-10-19_18:32:056139192 Bytes: 28750415
07-10-19_18:32:490959812 Bytes: 28755253
07-10-19_18:32:836352316 Bytes: 28757934
07-10-19_18:33:209513158 Bytes: 28762371
07-10-19_18:33:595689070 Bytes: 29021552
07-10-19_18:33:970968755 Bytes: 29026202
07-10-19_18:34:412742761 Bytes: 29031995
07-10-19_18:34:825309867 Bytes: 29037579
07-10-19_18:35:219852935 Bytes: 29043515
07-10-19_18:35:598878409 Bytes: 29046993
07-10-19_18:35:994067048 Bytes: 29051547
07-10-19_18:36:383952621 Bytes: 29055235
07-10-19_18:36:822644535 Bytes: 29331875
07-10-19_18:37:233137175 Bytes: 29336695
07-10-19_18:37:617277956 Bytes: 29343653
07-10-19_18:38:022776087 Bytes: 29348487
07-10-19_18:38:630347795 Bytes: 29357002
07-10-19_18:39:304204108 Bytes: 29364381

我可以看到文件大小在 1 秒内增加了 10138 字节(10 千字节)。

答案1

我通过使用由 croon 执行的自写脚本解决了我的问题:

* * * * * /home/mona/mona_ffmpeg_camera1_record.sh
#!/bin/bash
RecordPathAndFind='/home/mona/CameraRecordings/Tmps_Camera1/'
RecordPathCopyTo='/srv/dev-disk-by-uuid-XXX/Camera1_Recordings/'
#900 = 15 mins
SegmentTime=900
#7 days = 10080
MinutesAfterDeleteOldFiles=10080
DaysSecurityLimit=31
DeleteOldFiles=false
MakeRamDisk=true
CopyFilesToHDD=true

tempoutput=$(ps aux | grep ffmpeg | grep $RecordPathAndFind)
if [ ${#tempoutput} -ge 5 ];
then
      echo "FFMPEG with record command is already running. Skipping.\n"
      #Check if ffmpeg didn't hang:
      PIDOfFFmpeg=$(ps aux | grep ffmpeg | grep $RecordPathAndFind | grep -v 'SCREEN' | awk '{print $2}')
      echo "Found existing ffmpeg PID: $PIDOfFFmpeg.\n"
      #ModificationTime=$(stat -L -c %Y /proc/$PIDOfFFmpeg/fd/4);
      ModificationTime=$(stat -L -c %Y /proc/$PIDOfFFmpeg/fd/2);
      echo "Last File modification time: $ModificationTime.\n"
      if [ $ModificationTime -le $(($EPOCHSECONDS - 60)) ];
      then
        echo "Very old modification time. Restarting ffmpeg at next run.\n"
        kill $PIDOfFFmpeg
        #Backup existing files:
        FILES_TO_COPY=$(ls -lt "$RecordPathAndFind" | awk '{ print $9 }' | tail -n +2)
        FILES_COUNT=0
        for f in $FILES_TO_COPY; do
          echo "Currently processing file: $f"
          FILES_COUNT=$FILES_COUNT+1
          if [[ $FILES_COUNT -gt 0 ]]; then
             echo "File not skipped, copying..."
             cp "$RecordPathAndFind$f" "$RecordPathCopyTo"
             echo "Removing file..."
             rm "$RecordPathAndFind$f"
          fi
        done
      fi
    
      #test `stat -L -c %Y /proc/$PIDOfFFmpeg/fd/4` -ge $(($EPOCHSECONDS - 60)) || kill $PIDOfFFmpeg
else
      if [ "$MakeRamDisk" = true ] ; then
      echo "Mounting Ramdisk...\n"
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      umount -A $(echo $RecordPathAndFind)
      mount -t tmpfs -o size=1024m tmpfs $(echo $RecordPathAndFind)
      fi
      
      if ping -c 1 192.168.1.111 &> /dev/null
      then
      echo "FFMPEG with record command is not running. Starting now...\n"
      FFMPEGSTART=$(su - mona -c "cd /home/mona; /usr/bin/screen -dmS ffmpegcamera1 ffmpeg -rtsp_transport udp -i 'rtsp://admin:[email protected]:554/onvif1' -vcodec copy -c:a aac -map 0 -use_wallclock_as_timestamps 1 -f segment -segment_time $(echo $SegmentTime) -segment_format mp4 -strftime 1 $(echo $RecordPathAndFind)%Y-%m-%d_%H-%M-%S.mp4")
      #echo $FFMPEGSTART
      else
      echo "ERROR. Pinging 192.168.1.111 failed. Will retry in 1 minute...\n"
      fi
fi

currenthourminutes=$(date +%M)
if [ "$DeleteOldFiles" = true ] ; then
if [ "$currenthourminutes" == "00" ]; then
    echo "Current Minute is 00. Checking for old files to delete.\n"
    FILESDELETECOMMAND=$(find $(echo $RecordPathAndFind) -maxdepth 1 -type f -mmin +$(echo $MinutesAfterDeleteOldFiles) -mtime -$(echo $DaysSecurityLimit) -name '*.mp4' -ls -exec rm {} \;)
else
    echo "Current Minute is NOT 00. Skipping.\n"
fi
fi

if [ "$CopyFilesToHDD" = true ] ; then

SIZE=$(du -s -B1 "$RecordPathAndFind" | cut -f1)
echo "Folder size is: $SIZE"
#900MiB
COPY_WHEN_SIZE_BYTES=943718400
#COPY_WHEN_SIZE_BYTES=401219456

if [[ $SIZE -gt $COPY_WHEN_SIZE_BYTES ]]; then
echo 'Folder Size is greater than: '$COPY_WHEN_SIZE_BYTES' bytes. Copying...'
FILES_TO_COPY=$(ls -lt "$RecordPathAndFind" | awk '{ print $9 }' | tail -n +2)
FILES_COUNT=0
for f in $FILES_TO_COPY; do
  echo "Currently processing file: $f"
  FILES_COUNT=$FILES_COUNT+1
  if [[ $FILES_COUNT -gt 1 ]]; then
     echo "File not skipped, copying..."
     cp "$RecordPathAndFind$f" "$RecordPathCopyTo"
     echo "Removing file..."
     rm "$RecordPathAndFind$f"
  fi
done
fi

fi

其工作方式如下:

  • 该脚本检测另一个实例是否已在运行(这应该改进,但现在对我来说已经足够了)。
  • 它将 15 分钟的部分记录到 RAM 磁盘(我设置了大约 1GB,因为我的设备有 4GB RAM)。
  • 当 RAM 磁盘几乎已满时,它会将文件从中复制到旧的 2.5 英寸 HDD(通过 USB 连接),并启用省电功能,因此它每隔几个小时仅旋转几秒钟。
  • 如果发生断电,这可能会导致 RAM 磁盘中的数据丢失,但我更喜欢这种方法,因为它非常安静,并且旋转的磁盘不会在晚上打扰我:)

我已经使用这种方法大约 2 年了,我很高兴,因为我没有损坏任何 SD 卡。

相关内容