视频循环存储的实现

目录

1. 三方工具

2. 视频存储的实现 

2.1 分段存储 - 比如每15分钟

2.2 对齐到15分钟整边界

2.3 循环存储的实现 video_space_daemon.sh

3.封装

 3.1 主执行程序,修订版

3.2 创建服务 

3.3 service关联的执行脚本文件

4.额外的工作

附录A: ffmpeg视频存储,运行时错误处理 

1.运行ffmpeg存储视频时

1.1 处理

附录B 服务创建加载以及运行时异常处理 

1.service无法enable

1.1 处理


1. 三方工具

建议使用ffmpeg,这个工具多平台可用,命令行和API都有提供,非常便捷。下载的位置:

Download FFmpeg

我工作在debian环境,下载对应的源码后编译:

./configure

make

make install

2. 视频存储的实现 

2.1 分段存储 - 比如每15分钟

下面的脚本里 MIN_PER_FILE控制的是每个视频文件的最大尺寸

#usage: video_recorder <video_file_path> <min_per_file> <rtsp_path>
RTSP_URL_WITH_PASSWORD='rtsp://admin:xxxx@192.168.0.6:554/Streaming/Channels/101?transportmode=unicast&amp;profile=Profile_1'
MIN_PER_FILE=03
VIDEO_FILE_PATH='/tmp/video/' #include postfix
mkdir -p $VIDEO_FILE_PATH
ffmpeg -rtsp_transport tcp -i $RTSP_URL_WITH_PASSWORD -c:v libx265 -preset fast -crf 28 -t 00:$MIN_PER_FILE:00 $VIDEO_FILE_PATH$(date +"%Y%m%d%H%M%S").mp4

这个命令执行时因为环境的原因,可能会提示错误,我这边的一个纠错参见附录A,正确调用后:

Output #0, mp4, to '/tmp/video/20240807094508.mp4':
  Metadata:
    title           : Media Presentation
    encoder         : Lavf61.1.100
  Stream #0:0: Video: hevc (hev1 / 0x31766568), yuvj420p(pc, bt709, progressive), 1920x1080, q=2-31, 10 fps, 10240 tbn
      Metadata:
        encoder         : Lavc61.3.100 libx265
      Side data:
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
frame= 1555 fps= 10 q=31.9 size=   12288KiB time=00:02:35.30 bitrate= 648.2kbits/s speed=   1x 

估算,最终的视频文件尺寸,单通道.h265大概每15分钟45~50MBytes.

2.2 对齐到15分钟整边界

虽然命令行已经提供了分段存储,比如15分钟一个文件的功能,但是它没有对齐到15分钟整边界,可以看到这个逻辑。注意那个重启视频录制进程的工作使用systemctl的语法来实现的,这个在第3节封装部分会引入。

#!/bin/bash# 获取传递的参数数量
num_args=$#if [ $num_args -ne 1 ]; thenecho "usage: $0 <chIdxbase1>"exit 1
elseCHIDX_BASE1=$(printf "%02d" "$1")
fi# 变量
SERVICE_NAME="guide_video_storage_ch"$CHIDX_BASE1# 获取当前时间的秒数
now=$(date +%s)# 获取当前分钟数和秒数
minute=$(date +%M)
second=$(date +%S)
minute=$(echo $minute | sed 's/^0*//')  # 移除前导0
second=$(echo $second | sed 's/^0*//')  # 移除前导0# 计算最近 15 分钟整边界
remainder=$((minute % 15))
if (( remainder == 0 && second == 0 )); thentarget_time=$nowecho $target_time
elseif (( remainder == 0 )); then# 当前时间在整边界时刻,但秒数不为0target_time=$((now + (60 - second)))echo $target_timeelse# 计算下一个整边界的时间next_minute=$(( (minute + (15 - remainder)) % 60 ))next_hour=$(date +%H)if ((minute + (15 - remainder) >= 60)); thennext_hour=$(echo $next_hour | sed 's/^0*//')  # 移除前导0next_hour=$(( (next_hour + 1) % 24 ))fi# 计算目标时间target_time=$(date -d "$next_hour:$next_minute:00" +%s)echo $target_timefi
fi# 计算需要等待的秒数
seconds_to_wait=$((target_time - now))# 输出等待时间
echo "等待 $seconds_to_wait 秒"
sleep $seconds_to_wait#重启脚本
sudo systemctl restart $SERVICE_NAME

2.3 循环存储的实现 video_space_daemon.sh

为了防止出现磁盘快速磨损,使用了回差的概念。

#!/bin/bashVIDEO_FILE_PATH='/tmp/video/' #include postfix
mkdir -p $VIDEO_FILE_PATHCH_CNTS=5
DIRECTORY=$VIDEO_FILE_PATH
MAX_SIZE_MB=$((50*$CH_CNTS))
CTRL_SIZE_MB=$(awk "BEGIN {print $MAX_SIZE_MB * 0.8}")
TEMP_FILE="/tmp/file_sizes.txt"# 计算目录中所有文件的总大小
total_size=$(du -sm "$DIRECTORY" | cut -f1)# 如果总大小超过最大允许值
if [ "$total_size" -gt "$MAX_SIZE_MB" ]; then# 列出文件大小和路径,按时间排序(最旧的文件在前)find "$DIRECTORY" -type f -printf '%T+ %s %p\n' | sort | awk '{print $2, $3}' > "$TEMP_FILE"# 删除最旧的文件,直到总大小低于 90MBwhile [ "$total_size" -gt "$CTRL_SIZE_MB" ]; dooldest_file=$(head -n 1 "$TEMP_FILE" | awk '{print $2}')file_size=$(head -n 1 "$TEMP_FILE" | awk '{print $1}')# 删除文件rm "$oldest_file"# 更新总大小total_size=$((total_size - file_size / 1024 / 1024))# 重新列出文件tail -n +2 "$TEMP_FILE" > "$TEMP_FILE.tmp" && mv "$TEMP_FILE.tmp" "$TEMP_FILE"done# 删除临时文件rm "$TEMP_FILE"
fi

3.封装

因为视频源可能会出问题,所以需要有看护程序,最终使用Service来处理进程的遇错自动重启。然后用一个看护程序,来对齐到15分钟整边界。这里有全部的代码:

 3.1 主执行程序,修订版

#!/bin/bash
#usage: gpVideoRecorder <video_file_path> <min_per_file> <rtsp_path> <chIdxbase1># 函数:确保目录路径以斜杠结尾
ensure_trailing_slash() {local dir=$1if [[ "$dir" != */ ]]; thenecho "${dir}/"elseecho "$dir"fi
}# 获取传递的参数数量
num_args=$#if [ $num_args -eq 0 ]; thenVIDEO_FILE_PATH='/tmp/video/' #include postfixMIN_PER_FILE=03RTSP_URL_WITH_PASSWORD='rtsp://admin:xxxxx@192.168.0.6:554/Streaming/Channels/101?transportmode=unicast&amp;profile=Profile_1'CH_STR="ch"$(printf "%02d" "0")_
elif [ $num_args -ne 4 ]; thenecho "usage: $0 <video_file_path> <min_per_file> <rtsp_path> <chIdxbase1>"
elseVIDEO_FILE_PATH=$1MIN_PER_FILE=$2RTSP_URL_WITH_PASSWORD=$3CH_STR="ch"$(printf "%02d" "$4")_
fi# 确保目录存在
mkdir -p $VIDEO_FILE_PATH
# 确保目录路径以斜杠结尾
VIDEO_FILE_PATH=$(ensure_trailing_slash "$VIDEO_FILE_PATH")/echo $VIDEO_FILE_PATH$CH_STR$(date +"%Y%m%d%H%M%S").mp4
ffmpeg -rtsp_transport tcp -i $RTSP_URL_WITH_PASSWORD -c:v libx265 -preset fast -crf 28 -t 00:$MIN_PER_FILE:00 $VIDEO_FILE_PATH$CH_STR$(date +"%Y%m%d%H%M%S").mp4

3.2 创建服务 

#!/bin/bash# 获取传递的参数数量
num_args=$#if [ $num_args -ne 1 ]; thenecho "usage: $0 <chIdxbase1>"exit 1
else# 使用 printf 将数字格式化为两位数CHIDX_BASE1=$(printf "%02d" "$1")
fi# 变量
PROGRAM_DIR="/etc/program"
SERVICE_NAME="guide_video_storage_ch"$CHIDX_BASE1
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
#service_name lookslike guide_video_storage_ch01# 1. 创建目录
if [ ! -d "$PROGRAM_DIR" ]; thenecho "创建目录 $PROGRAM_DIR"sudo mkdir -p "$PROGRAM_DIR"
fi# 2. 创建服务文件
echo "创建服务文件 $SERVICE_FILE"
cat <<EOL | sudo tee "$SERVICE_FILE"
[Unit]
Description=video streamer local storage service[Service]
ExecStart=sudo -E /home/app/common/start_video_recording.sh $CHIDX_BASE1
Restart=always
RestartSec=5
User=root[Install]
WantedBy=multi-user.target
EOL# 3. 重新加载 systemd 配置
echo "重新加载 systemd 配置"
sudo systemctl daemon-reload# 4. 启动服务
echo "启动服务 ${SERVICE_NAME}"
sudo systemctl start "${SERVICE_NAME}"# 5. 设置服务开机启动
echo "设置服务开机启动"
sudo systemctl enable "${SERVICE_NAME}"echo "服务 ${SERVICE_NAME} 创建并启动完成。"

3.3 service关联的执行脚本文件

因为service不支持同时启动多个命令,所以要有这个.sh,注意那个背景进程的消灭。理论上不这样做也可以。毕竟视频文件截断的动作是从video_split_daemon.sh发出的。

#这里会对齐至整边界
sudo /home/app/common/video_split_daemon.sh 5&
# 获取 p1 的进程 ID
SPLIT_PID=$!#space_dameon只执行一次无需关心
sudo /home/app/common/video_space_daemon.sh &#这里的文件记录长度可以略长(注意rtsp的用户名密码的规则:)
sudo /home/app/common/gpVideoRecorder /tmp/video 30 'rtsp://admin:a1234567@192.168.0.6:554/Streaming/Channels/101?transportmode=unicast&amp;profile=Profile_1' 5# 在脚本退出时终止后台进程 p1
trap 'kill $SPLIT_PID' EXIT

 注意最终的那个调用需要是个阻塞命令。

3.4 整个环境运行时的截屏

上面刚经历过一次重启,时间是从xx:45开始的,对齐到45分整边界,视频文件列表:
 

切换前列表切换后

能看到循环存储已经生效。 所有的可执行文件列表:

4.额外的工作

在实际使用时,至少还有如下工作要做:

  • json配置文件解析和开机boot
  • mqtt远程命令执行接口
  • 状态信息redis缓存

这个环节不再赘述。

附录A: ffmpeg视频存储,运行时错误处理 

1.运行ffmpeg存储视频时

Unrecognized option 'preset'.
Error splitting the argument list: Option not found

1.1 处理

  1.  检查是x265编码器可能没有装
  2. ./configure --enable-libx265 --enable-libx264 --disable-x86asm --enable-gpl --pkg-config="pkg-config --static"
    1. 提示:ERROR: x264 not found using pkg-config
  3. sudo apt install pkg-config
  4. sudo apt install libx264-dev
  5. sudo apt install libx265-dev
  6. ./configure --enable-libx265 --enable-libx264 --disable-x86asm --enable-gpl
  7. make
  8. make install
     

附录B 服务创建加载以及运行时异常处理 

1.service无法enable

Failed to enable unit: Unit file /etc/systemd/system/guide_video_storage_ch05.service is masked.

1.1 处理

在更新.service前,一定记得要先disable。如果出现mask:

sudo systemctl unmask guide_video_storage_ch05

sudo systemctl stop guide_video_storage_ch05

sudo systemctl disable guide_video_storage_ch05

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/395732.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

矩阵算法的介绍和实现

一. 介绍 首先我们要清楚矩阵是什么&#xff1a;矩阵是一个按照长方阵列排列的复数或实数集合 1> 定义 定义&#xff1a;mn矩阵为mn个数排成的m行n列的表格&#xff0c;当mn时&#xff0c;矩阵A称为n阶方阵或者n阶矩阵。零矩阵&#xff1a;矩阵所有元素都为0。同型矩阵&a…

一个简单的录音软件(利用QT录音,ffmpeg进行音频重采样,fdk-aac编码)

录音软件是一种非常有用的工具&#xff0c;可以帮助我们记录和存储语音信息。在本文中&#xff0c;我们将介绍一个简单的录音软件&#xff0c;该软件利用QT进行录音&#xff0c;使用ffmpeg进行音频重采样&#xff0c;并使用fdk-aac编码。 一、 环境介绍 1、QT版本: QT5.…

SuccBI+低代码文档中心 — 可视化分析(仪表板)(上)

有关仪表板的设计器&#xff1a; 查询设置 由于仪表板的设计器是所见即所得的&#xff0c;可以将当前制作的内容和数据的查询结果实时展示在界面中&#xff0c;当引入到仪表板的模型数据量较大时&#xff0c;为了提高设计器界面的查询性能&#xff0c;提供了以下两种方法&…

Azure openai connection with javascript

题意&#xff1a;使用JavaScript与Azure OpenAI进行连接 问题背景&#xff1a; I have created my chatbot with javascript and used open ai. I need to change it to azure open ai but can not find the connection details for javascript. This is how i connect with p…

基于C#调用文心一言大模型制作桌面软件(可改装接口)

目录 开发前的准备账号注册应用创建应用接入开始开发创建项目设计界面使用 AK,SK 生成鉴权签名窗体代码百度智能云千帆大模型平台什么是百度智能云千帆大模型平台模型更新记录开发前的准备 账号注册 访问百度智能云平台,通过百度账号登录或手机号验证。 点此跳转百度智能云平…

数值分析【4】

目录 ​编辑第六章 数值积分微分 龙贝格 高斯求积 查表&#xff1f; 插值求导 两点 ​编辑 三点​编辑 第七章 ode 龙哥库塔 线性多步法 第八章 eig 幂法&#xff1a;v-》Av-》AAv-》……​编辑 反幂法 每次成得是A逆&#xff0c;这样得到摸最小的特征值​编辑 Q…

ubuntu大模型GPU版本安装及部署

版本查看&#xff1a; nvidia-smi 离线下载地址&#xff1a; 下载 NVIDIA 官方驱动 | NVIDIA (选型) Linux x64 (AMD64/EM64T) Display Driver | 535.146.02 | Linux 64-bit | NVIDIA(选型结果) 下载 NVIDIA 官方驱动 | NVIDIA apt-get update 禁用nouveau(nouveau是通用的…

【深度学习|目标跟踪】快速入门卡尔曼滤波!

卡尔曼滤波详解 申明一、什么是卡尔曼滤波1.1 卡尔曼滤波的使用场景1.2 卡尔曼滤波的定义 二、卡尔曼滤波公式详解&#xff08;无推导&#xff09;三、卡尔曼滤波的简单应用 申明 本博客参考了b站up主“华南小虎队”的卡尔曼滤波教学视频以及Lauszus Kristian Sloth Lauszus的卡…

企业微信无法正常启动 报错0xc0000142

解决办法&#xff1a; 1、根据处理器不同位数打开如下目录 32位&#xff1a;C:\Windows\System32 64位&#xff1a;C:\Windows\SysWOW64 我电脑是64位的&#xff0c;就打开&#xff1a;C:\Windows\SysWOW64&#xff0c;然后搜索&#xff1a;kernel32.dll 2、复制一份这个文件至…

Advanced IP Scanner - 网络扫描工具介绍

Advanced IP Scanner 是一款免费、快速且用户友好的网络扫描工具。它能够帮助用户扫描局域网&#xff08;LAN&#xff09;中的所有设备&#xff0c;提供详细的设备信息&#xff0c;包括IP地址、MAC地址、设备名称和厂商信息。该工具对IT管理员和普通用户都非常有用&#xff0c;…

2024剪辑神器盘点:四大热门剪辑软件推荐!

亲爱的朋友们&#xff0c;想要制作出精彩短视频&#xff0c;却苦于找不到合适的剪辑工具&#xff1f;别担心&#xff0c;今天要向大家推荐几款剪辑软件&#xff0c;它们能帮助大家更好地完成视频创作&#xff01; 福昕视频剪辑 链接&#xff1a;www.pdf365.cn/foxit-clip/ 对…

【爬虫实战】利用代理爬取电商数据

文章目录 前言工具介绍实战获取网站数据编写代码数据展示 推荐总结 前言 当今电商平台正经历着快速的转型与升级。随着技术的进步和用户需求的多样化&#xff0c;电商不仅从简单的在线购物演变为综合性的购物生态系统&#xff0c;还融合了人工智能、大数据和云计算等先进技术。…

zdppy+vue3+onllyoffice开发文档管理系统项目实战 20240808 上课笔记

遗留的问题 1、实现删除的功能 2、分享的功能暂时往后放&#xff0c;因为目前没有用户&#xff0c;等有了用户之后再考虑做 3、增加新建和导入按钮 zdppy的学习计划 机器学习平台&#xff0c;QQ音乐的开源项目&#xff0c;https://github.com/tencentmusic/cube-studio&#…

手表运动报告生成以及手机展示

一.运动报告组成部分 一般一份运动健康的报告包括以下信息&#xff1a; 1.运动轨迹区。2.报告数据区。(运动总体概览&#xff0c;如距离&#xff0c;时长&#xff0c;训练表现等)3.曲线图表区。(心率曲线&#xff0c;海拔曲线&#xff0c;速度&#xff0c;配速曲线) 二.组成部…

3.OpenFeign与负载均衡

文章目录 什么是 OpenFegin0penFeign 与 Ribbon.对 consumer 的改造超时配置请求响应的压缩设置选择远程调用的底层实现技术OpenFegin 整合 LoadBalancer 负载均衡负载均衡策略的更换小结 前面消费者对于微服务的消费是通过 RestTemplate 完成的,这种方式的弊端是很明显的:消费…

Qt实现圆形窗口

重新实现paintEvent()函数。 效果如下&#xff1a; 效果为蓝色区域&#xff0c;背景是vs接面&#xff0c;代码直接复制可用&#xff0c;留给有需要的人。 #ifndef CircleWidget_h__ #define CircleWidget_h__#include <QWidget>class CCircleWidget : public QWidget {Q…

学习vue3 三,组件基础,父子组件传值

组件基础 每一个.vue 文件都可以充当组件来使用 每一个组件都可以复用 父组件引入之后可以直接当标签使用 案例&#xff1a; App.vue <script setup lang"ts"> import BaseRefAndReactive from "./components/BaseRefAndReactive.vue";</sc…

MySQL——数据表的基本操作(二)查看数据表

使用 SQL 语句创建好数据表后,可以通过查看数据表结构的定义,以确认数据表的定义是否正确。在 MySQL中,查看数据表的方式有两种,具体如下。 1、使用 SHOW CREATE TABLE 查看数据表 在 MySQL 中,SHOW CREATE TABLE语句不仅可以查看创建表时的定义语句还可以查看表的字符编码。S…

PLL基本原理、设计及应用

PLL基本原理 锁相环&#xff08;Phase-Locked Loop, PLL&#xff09;是一种基本的反馈控制系统&#xff0c;广泛应用于电子通信、信号处理、时钟同步等多个领域。PLL通过反馈机制锁定输入信号的频率和相位&#xff0c;从而实现输出信号与输入信号的同步。其基本工作原理可以概…

使用AI绘图工具生成风景图像的教程

随着人工智能技术的飞速发展&#xff0c;AI绘图工具在图像生成和艺术创作方面变得越来越强大&#xff0c;无论你是一个设计师、艺术家&#xff0c;还是仅仅对生成艺术感兴趣的爱好者&#xff0c;AI绘图工具都可以帮助你轻松地创作出惊艳的风景图像。 在这篇教程中&#xff0c;…