当前位置: 首页 > news >正文

视频循环存储的实现

目录

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

相关文章:

视频循环存储的实现

目录 1. 三方工具 2. 视频存储的实现 2.1 分段存储 - 比如每15分钟 2.2 对齐到15分钟整边界 2.3 循环存储的实现 video_space_daemon.sh 3.封装 3.1 主执行程序&#xff0c;修订版 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博客 目标&#xff1a; 例如&#xff1a;在release模式下&#xff0c;exe文件生成于&#xff1a; "G:\test\build\release\shakeSensor.exe" 此时&#xff0c;我希望在生成该exe文件时&#xff0c; "G:\test\…...

openwrt下,用iptable转发端口访问远程的SMB服务

首先初步学习一下iptales的命令 iptales指令的详细教程&#xff1a;https://blog.csdn.net/weixin_44390164/article/details/120500075 实践一、转发地址与端口 外网远程服务上开放了SMB服务&#xff0c;端口号自定义的为44513&#xff0c;WINDOWS不能直接访问&#xff0c;…...

JVM类加载中的双亲委派机制

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

【OpenCV C++20 学习笔记】范围阈值操作

范围阈值操作 原理HSV颜色空间RGB与HSV颜色空间之间的转换 代码实现颜色空间的转换范围阈值操作 原理 HSV颜色空间 HSV(色相hue, 饱和度sarturation, 色明度value)颜色空间与RGB颜色空间相似。hue色相通道代表颜色类型&#xff1b;saturation饱和度通道代表颜色的饱和度&…...

【Material-UI】Checkbox组件:Indeterminate状态详解

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

一文了解K8S(Kubernates)

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

三星、小米和 OPPO设备实验室将采用Android设备流技术

早在 5 月份的年度开发者大会上&#xff0c;Google就发布了 Android 设备流测试版。开发人员可以在Google数据中心的真实物理设备上更轻松、更互动地测试自己的应用程序&#xff0c;这些设备会直接串流到 Android Studio。今天&#xff0c;Google宣布与三星、小米和 OPPO 合作扩…...

华为OD-D卷万能字符单词拼写

有一个字符串数组words和一个字符串chars。 假如可以用chars中的字母拼写出words中的某个“单词”&#xff08;字符串&#xff09;&#xff0c;那么我们就认为你掌握了这个单词。 words的字符仅由 a-z 英文小写字母组成。 例如: abc chars 由 a-z 英文小写字母和 “?”组成。其…...

顶象文字点选模型识别

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

C#如何将自己封装的nuget包引入到项目中

问题 自己封装好了一个nuget包&#xff0c;但是不想上传到外网&#xff0c;想局域网使用&#xff0c;有两种方案 搭建私有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区别&#xff0c;tcp拥塞控制算法和粘包问题-CSDN博客 http的发展历史&#xff0c;各版本的差异点&#xff0c;以及和https的区别-CSDN博客 2 jvm篇 3 多线程篇 4 mysql篇 5 redis篇 6 kafk…...

MySQL入门学习-运维与架构.复制过滤器

MySQL 复制过滤器是一种用于过滤复制数据的机制。它可以根据特定的规则&#xff0c;选择要复制的数据库、表或列&#xff0c;从而减少复制的数据量&#xff0c;提高复制性能。 一、以下是一些常见的 MySQL 复制过滤器&#xff1a; 1. 基于二进制日志的过滤器&#xff1a; 通过…...

【深度学习】生成领域里,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. 基本概念 串口通信&#xff08;Serial Communications&#xff09;的概念非常简单&#xff0c;串口按位&#xff08;bit&#xff09;发送和接收字节。尽管比按字节&#xff08;byte&#xff09;的并行通信慢&#xff0c;但是串口可以在使用一根线发送数据的同时用另一根线接…...

聊聊AUTOSAR: 基于DaVinci的SecOC开发与配置

一、什么是SecOC 当前车载网络通讯环境越来越复杂&#xff0c;未采取任何安全保护的报文&#xff0c;一旦被伪造或者篡改&#xff0c;将非常危险。为了提升信息的安全性&#xff0c;AUTOSAR标准中引进了SecOC&#xff0c;加入了通讯认证机制&#xff0c;能够有效的辨别出信息是…...

.net6.0 重启控制台 命令

在.NET 6.0中&#xff0c;如果你想要创建一个命令行应用程序来重启当前运行的控制台&#xff0c;你可以使用System.Diagnostics命名空间下的Process类来启动一个新的进程&#xff0c;并结束当前进程。 以下是一个简单的示例代码&#xff0c;展示了如何实现重启控制台的功能&am…...

LVS 调度器 nat和DR模式

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

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...