视频循环存储的实现
目录
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&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&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&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 处理
- 检查是x265编码器可能没有装
- ./configure --enable-libx265 --enable-libx264 --disable-x86asm --enable-gpl --pkg-config="pkg-config --static"
- 提示:ERROR: x264 not found using pkg-config
- sudo apt install pkg-config
- sudo apt install libx264-dev
- sudo apt install libx265-dev
- ./configure --enable-libx265 --enable-libx264 --disable-x86asm --enable-gpl
- make
- 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
相关文章:

视频循环存储的实现
目录 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视频存储…...

在centOS系统中使用docker部署Jenkins
1. 安装docker 1.1 下载Docker依赖组件 yum -y install yum-utils device-mapper-persistent-data lvm2 1.2 设置下载Docker的镜像源为阿里云 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 1.3 安装Docker服务 yum …...
Qt 将生成的exe文件自动复制到其它目录下
QT pro中加入文件拷贝方法_qt pro复制粘贴-CSDN博客 目标: 例如:在release模式下,exe文件生成于: "G:\test\build\release\shakeSensor.exe" 此时,我希望在生成该exe文件时, "G:\test\…...
openwrt下,用iptable转发端口访问远程的SMB服务
首先初步学习一下iptales的命令 iptales指令的详细教程:https://blog.csdn.net/weixin_44390164/article/details/120500075 实践一、转发地址与端口 外网远程服务上开放了SMB服务,端口号自定义的为44513,WINDOWS不能直接访问,…...

JVM类加载中的双亲委派机制
【1】什么是双亲委派 Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式,即把请求交由父类处理,…...

【OpenCV C++20 学习笔记】范围阈值操作
范围阈值操作 原理HSV颜色空间RGB与HSV颜色空间之间的转换 代码实现颜色空间的转换范围阈值操作 原理 HSV颜色空间 HSV(色相hue, 饱和度sarturation, 色明度value)颜色空间与RGB颜色空间相似。hue色相通道代表颜色类型;saturation饱和度通道代表颜色的饱和度&…...

【Material-UI】Checkbox组件:Indeterminate状态详解
文章目录 一、什么是Indeterminate状态?二、Indeterminate状态的实现1. 基本用法示例2. 代码解析3. Indeterminate状态的应用场景 三、Indeterminate状态的UI与可访问性1. 无障碍设计2. 用户体验优化 四、Indeterminate状态的最佳实践1. 状态同步2. 优化性能3. 提供…...

一文了解K8S(Kubernates)
一、K8S 1. 概述 Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。 Kubernetes 这个名字源于希腊…...

三星、小米和 OPPO设备实验室将采用Android设备流技术
早在 5 月份的年度开发者大会上,Google就发布了 Android 设备流测试版。开发人员可以在Google数据中心的真实物理设备上更轻松、更互动地测试自己的应用程序,这些设备会直接串流到 Android Studio。今天,Google宣布与三星、小米和 OPPO 合作扩…...
华为OD-D卷万能字符单词拼写
有一个字符串数组words和一个字符串chars。 假如可以用chars中的字母拼写出words中的某个“单词”(字符串),那么我们就认为你掌握了这个单词。 words的字符仅由 a-z 英文小写字母组成。 例如: abc chars 由 a-z 英文小写字母和 “?”组成。其…...

顶象文字点选模型识别
注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 文字点选如何训练,之前的文章说了很多遍了,这里只放现成的模型供查看,有需要成品联系…...

C#如何将自己封装的nuget包引入到项目中
问题 自己封装好了一个nuget包,但是不想上传到外网,想局域网使用,有两种方案 搭建私有nuget仓库放到离线文件夹中直接使用 第一种方式请请参考proget安装 下面主要是第二种方式 准备 新建类库项目 using System;namespace ClassLibrary…...
数据结构(学习)2024.8.8(栈,队列)
今天学习的是线性表里面的栈和队列 链表的相关知识可以查看http://t.csdnimg.cn/NX464 顺序表的相关知识可以查看http://t.csdnimg.cn/5IMAZ 目录 栈 栈的定义 栈的特点 顺序栈 结构体 顺序栈的相关操作案例 链式栈 结构体 链式栈的相关操作案例 总结 队列 队列…...
服务端开发常用知识(持续更新中)
Java方面 1 基础篇 1.1 网络基础 tcp三次握手和四次挥手-CSDN博客 tcp和udp区别,tcp拥塞控制算法和粘包问题-CSDN博客 http的发展历史,各版本的差异点,以及和https的区别-CSDN博客 2 jvm篇 3 多线程篇 4 mysql篇 5 redis篇 6 kafk…...
MySQL入门学习-运维与架构.复制过滤器
MySQL 复制过滤器是一种用于过滤复制数据的机制。它可以根据特定的规则,选择要复制的数据库、表或列,从而减少复制的数据量,提高复制性能。 一、以下是一些常见的 MySQL 复制过滤器: 1. 基于二进制日志的过滤器: 通过…...
【深度学习】生成领域里,Normalizing Flow、GAN、VAE、Diffusion Models的区别是什么?
文章目录 1. Normalizing Flow2. GAN (Generative Adversarial Networks)3. VAE (Variational Autoencoders)4. Diffusion Models总结1. Normalizing Flow公式代码示例2. GAN (Generative Adversarial Networks)公式代码示例3. VAE (Variational Autoencoders)公式代码示例4. D…...
Qt 串口通信(C++)
1. 基本概念 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接…...

聊聊AUTOSAR: 基于DaVinci的SecOC开发与配置
一、什么是SecOC 当前车载网络通讯环境越来越复杂,未采取任何安全保护的报文,一旦被伪造或者篡改,将非常危险。为了提升信息的安全性,AUTOSAR标准中引进了SecOC,加入了通讯认证机制,能够有效的辨别出信息是…...
.net6.0 重启控制台 命令
在.NET 6.0中,如果你想要创建一个命令行应用程序来重启当前运行的控制台,你可以使用System.Diagnostics命名空间下的Process类来启动一个新的进程,并结束当前进程。 以下是一个简单的示例代码,展示了如何实现重启控制台的功能&am…...

LVS 调度器 nat和DR模式
lvs-nat 修改请求报文的目标IP,多目标IP的DNAT 配置网络 LVS主机 注意网卡的顺序 (nat和主机模式) [rootlvs ~]# cat /etc/NetworkManager/system-connections/ens160.nmconnection [connection] idens160 typeethernet interface-nameens160 [ip…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...
boost::filesystem::path文件路径使用详解和示例
boost::filesystem::path 是 Boost 库中用于跨平台操作文件路径的类,封装了路径的拼接、分割、提取、判断等常用功能。下面是对它的使用详解,包括常用接口与完整示例。 1. 引入头文件与命名空间 #include <boost/filesystem.hpp> namespace fs b…...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架
文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理:检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目:RankRAG:Unifying Context Ranking…...