更全的:https://juejin.cn/post/7089275800913969159

制表符:

─ ━│┃╌╍╎╏┄ ┅┆┇┈ ┉┊┋┌┍┎┏┐┑┒┓└ ┕┖┗ ┘┙┚┛├┝┞┟┠┡┢┣ ┤┥┦┧┨┩┪┫┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╪ ╫ ╬═║╒╓╔ ╕╖╗╘╙╚ ╛╜╝╞╟╠ ╡╢╣╤ ╥ ╦ ╧ ╨ ╩ ╳╔ ╗╝╚ ╬ ═ ╓ ╩ ┠ ┨┯ ┷┏ ┓┗ ┛┳ ⊥ ﹃ ﹄┌ ╮ ╭ ╯╰

RDB(Redis Database)是 Redis 提供的一种持久化策略,它通过将 Redis 在某个时间点上的数据集快照写入磁盘来实现持久化。RDB 持久化策略的核心思想是定期生成数据快照,并将其保存到磁盘文件中。以下是 RDB 持久化策略的详细说明:

RDB 持久化的优点

1.高效性:

RDB 文件是经过压缩的二进制文件,占用磁盘空间小,适合备份和恢复。
恢复数据时,RDB 文件的加载速度通常比 AOF 快。
2.适合备份:

RDB 文件可以方便地用于数据迁移或灾难恢复。
3.对性能影响较小:

RDB 持久化是通过 fork 子进程来完成的,主进程不需要参与 I/O 操作,因此对 Redis 的性能影响较小。

RDB 持久化的缺点

1.数据可能丢失:

RDB 是定期生成快照,如果 Redis 在两次快照之间崩溃,可能会丢失最后一次快照之后的数据。
2.不适合实时性要求高的场景:

由于 RDB 是定时快照,无法做到实时持久化,因此不适合对数据完整性要求极高的场景。

RDB 持久化的配置

RDB 持久化的配置主要通过 Redis 配置文件(redis.conf)中的以下参数进行控制:

1.save:

定义触发 RDB 快照的条件。例如:

save 900 1      # 900 秒内至少有 1 个 key 被修改,则触发快照
save 300 10     # 300 秒内至少有 10 个 key 被修改,则触发快照
save 60 10000   # 60 秒内至少有 10000 个 key 被修改,则触发快照

可以配置多个 save 规则,满足任意一个条件就会触发快照。
2.dbfilename:

指定 RDB 文件的名称,默认为 dump.rdb。
3.dir:

指定 RDB 文件的保存路径,默认为 Redis 的工作目录。
4.stop-writes-on-oome:

当 Redis 内存不足时,是否停止写操作以生成 RDB 文件。默认值为 yes
5.rdbcompression:

是否对 RDB 文件进行压缩,默认值为 yes。
6.rdbchecksum:

是否对 RDB 文件进行校验,默认值为 yes。

RDB 持久化的工作流程

1.Redis 主进程检查是否满足 save 条件。
2.如果满足条件,Redis 主进程会 fork 一个子进程。
3.子进程负责将内存中的数据写入 RDB 文件。
4.子进程完成写操作后,主进程替换旧的 RDB 文件。
5.子进程退出,主进程继续处理客户端请求。

RDB 持久化的触发方式

1.自动触发:

根据 save 配置规则自动触发快照。
2.手动触发:

使用 SAVE 命令:阻塞主进程,直到快照完成。
使用 BGSAVE 命令:异步触发快照,主进程可以继续处理客户端请求。

RDB 持久化的适用场景

数据备份和恢复。
对数据完整性要求不高,但需要快速恢复数据的场景。
数据集较大,且写操作频率较低的场景。
RDB 与 AOF 的对比
特性 RDB AOF
持久化方式 快照 日志追加
文件大小 较小 较大
恢复速度 快 慢
数据完整性 可能丢失部分数据 更完整,最多丢失 1 秒数据
对性能影响 较小 较大
适用场景 备份、快速恢复 数据完整性要求高

AOF(Append Only File)持久化机制详解

1. AOF 的核心原理
AOF 通过记录 Redis 执行的所有写操作命令(如 SET、DEL 等)来持久化数据,而非直接保存数据快照。Redis 重启时,会重新执行 AOF 文件中的命令以恢复数据。

记录内容:仅记录写操作命令,不记录读操作。
追加模式:以文本形式追加到文件末尾,支持实时同步。
2. AOF 的工作流程
1.命令追加:写命令被追加到 AOF 缓冲区。
2.文件同步:根据 appendfsync 参数配置,将缓冲区内容同步到磁盘:

  • always:每次写入后立即同步(数据最安全,性能最差)。
  • everysec(默认):每秒同步一次(平衡性能与安全性)。
  • no:由操作系统决定同步时机(性能最佳,数据风险最高)。

3.文件重写:AOF 文件过大时,Redis 会生成新的 AOF 文件,仅保留最小命令集以压缩体积。
4.数据恢复:重启时加载 AOF 文件并逐条执行命令。
3. AOF 的优缺点
优点 缺点
高数据安全性:最多丢失 1 秒数据(everysec)或单条命令(always)。 文件体积大:记录所有命令,长期积累可能导致文件过大。
可恢复性强:支持手动修复损坏的 AOF 文件(如使用 redis-check-aof)。 恢复速度慢:需逐条执行命令,数据量大时耗时较长。
实时性高:写操作实时记录,适合对数据完整性要求高的场景。 磁盘 I/O 压力大:频繁写入可能影响性能。
4. AOF 的配置与优化
启用 AOF:在 redis.conf 中设置 appendonly yes。
同步策略:通过 appendfsync 调整同步频率(推荐 everysec)。
自动重写:通过 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 控制重写条件(如文件增长 100% 且超过 64MB 时触发)。
混合持久化:结合 RDB 快照与 AOF 日志,提升恢复速度与数据安全性(需 Redis 4.0+)。

总结
RDB 持久化是一种高效且适合备份的持久化策略,但在数据完整性和实时性方面存在一定局限性。在实际应用中,可以根据需求选择 RDB、AOF 或两者结合使用,以达到最佳的性能和数据安全性。

按文件大小拆分

./split-video.sh huge-video.mov 64000000 "-c:v libx264 -crf 23 -c:a copy -vf scale=960:-1"

split-video.sh 脚本内容:

#!/bin/bash
# Short script to split videos by filesize using ffmpeg by LukeLR

if [ $# -ne 3 ]; then
    echo 'Illegal number of parameters. Needs 3 parameters:'
    echo 'Usage:'
    echo './split-video.sh FILE SIZELIMIT "FFMPEG_ARGS'
    echo 
    echo 'Parameters:'
    echo '    - FILE:        Name of the video file to split'
    echo '    - SIZELIMIT:   Maximum file size of each part (in bytes)'
    echo '    - FFMPEG_ARGS: Additional arguments to pass to each ffmpeg-call'
    echo '                   (video format and quality options etc.)'
    exit 1
fi

FILE="$1"
SIZELIMIT="$2"
FFMPEG_ARGS="$3"

# Duration of the source video
DURATION=$(ffprobe -i "$FILE" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)

# Duration that has been encoded so far
CUR_DURATION=0

# Filename of the source video (without extension)
BASENAME="${FILE%.*}"

# Extension for the video parts
#EXTENSION="${FILE##*.}"
EXTENSION="mp4"

# Number of the current video part
i=1

# Filename of the next video part
NEXTFILENAME="$BASENAME-$i.$EXTENSION"

echo "Duration of source video: $DURATION"

# Until the duration of all partial videos has reached the duration of the source video
while [[ $CUR_DURATION -lt $DURATION ]]; do
    # Encode next part
    echo ffmpeg -i "$FILE" -ss "$CUR_DURATION" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"
    ffmpeg -ss "$CUR_DURATION" -i "$FILE" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"

    # Duration of the new part
    NEW_DURATION=$(ffprobe -i "$NEXTFILENAME" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)

    # Total duration encoded so far
    CUR_DURATION=$((CUR_DURATION + NEW_DURATION))

    i=$((i + 1))

    echo "Duration of $NEXTFILENAME: $NEW_DURATION"
    echo "Part No. $i starts at $CUR_DURATION"

    NEXTFILENAME="$BASENAME-$i.$EXTENSION"
done

按时长拆分

ffmpeg -i "input_video.MTS" -ss 164 -f segment -segment_time 120 -vcodec copy -c:a copy -reset_timestamps 1 output_video%d.MTS
#! /bin/bash
#use: ./split.sh ./Captures/di_er_shi_tiao.mp4 0 60 ./diershitiao/video_

ffmpeg -i $1 -ss $2 -f segment -segment_time $3 -vcodec copy -c:a copy -reset_timestamps 1 ${4}%d.mp4

按场景分镜拆分:
python库安装

pip install --upgrade scenedetect[opencv]

window批处理命令: split.bat

scenedetect --input %1 --output %2 detect-content split-video

#用法
split.bat  xx.mp4 your_out_dir_xxx

下面介绍7种使用FFmpeg分割视频的方法。

01 将视频分割成帧

ffmpeg -i video.mp4 thumb%04d.jpg -hide_banner

此命令允许您从视频中提取特定帧,这些帧是组成视频的图像文件。例如视频以每秒24帧的速度运行,则意味着在视频播放时,每秒有24张图像显示在屏幕上。此命令可用于将视频分割为帧并提取单个帧。

02 按大小拆分视频

./split-video.sh huge-video.mov 64000000 "-c:v libx264 -crf 23 -c:a copy -vf scale=960:-1"

在命令中,数字64000000表示64MB,这意味着您的视频将被拆分为每个大小为64MB的块。您可以更改该数字以指定大小。

此命令允许您将较大的视频剪切为特定文件大小的较小视频。当您的视频很大,但只需要特定大小的特定部分用于上传或共享时,这个命令就很有用。其中split-video.sh是依赖于ffmpeg的shell脚本,脚本代码如下:

#!/bin/bash
# Short script to split videos by filesize using ffmpeg by LukeLR

if [ $# -ne 3 ]; then
    echo 'Illegal number of parameters. Needs 3 parameters:'
    echo 'Usage:'
    echo './split-video.sh FILE SIZELIMIT "FFMPEG_ARGS'
    echo 
    echo 'Parameters:'
    echo '    - FILE:        Name of the video file to split'
    echo '    - SIZELIMIT:   Maximum file size of each part (in bytes)'
    echo '    - FFMPEG_ARGS: Additional arguments to pass to each ffmpeg-call'
    echo '                   (video format and quality options etc.)'
    exit 1
fi

FILE="$1"
SIZELIMIT="$2"
FFMPEG_ARGS="$3"

# Duration of the source video
DURATION=$(ffprobe -i "$FILE" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)

# Duration that has been encoded so far
CUR_DURATION=0

# Filename of the source video (without extension)
BASENAME="${FILE%.*}"

# Extension for the video parts
#EXTENSION="${FILE##*.}"
EXTENSION="mp4"

# Number of the current video part
i=1

# Filename of the next video part
NEXTFILENAME="$BASENAME-$i.$EXTENSION"

echo "Duration of source video: $DURATION"

# Until the duration of all partial videos has reached the duration of the source video
while [[ $CUR_DURATION -lt $DURATION ]]; do
    # Encode next part
    echo ffmpeg -i "$FILE" -ss "$CUR_DURATION" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"
    ffmpeg -ss "$CUR_DURATION" -i "$FILE" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"

    # Duration of the new part
    NEW_DURATION=$(ffprobe -i "$NEXTFILENAME" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)

    # Total duration encoded so far
    CUR_DURATION=$((CUR_DURATION + NEW_DURATION))

    i=$((i + 1))

    echo "Duration of $NEXTFILENAME: $NEW_DURATION"
    echo "Part No. $i starts at $CUR_DURATION"

    NEXTFILENAME="$BASENAME-$i.$EXTENSION"
done

03 将视频分割为相等持续时间的部分

ffmpeg -i "input_video.MTS" -ss 164 -f segment -segment_time 120 -vcodec copy -c:a copy -reset_timestamps 1 output_video%d.MTS
#! /bin/bash
#use: ./split.sh ./Captures/di_er_shi_tiao.mp4 0 60 ./diershitiao/video_

ffmpeg -i $1 -ss $2 -f segment -segment_time $3 -vcodec copy -c:a copy -reset_timestamps 1 ${4}%d.mp4

此命令可用于将视频分割为多个持续时间相同的部分。这对于需要或偏好特定视频持续时间的社交媒体网站非常有用。

04 按场景拆分视频

split.sh -d 0.5 -o /tmp/parts -f file.mp4

这个命令检测单个场景并不总是很准确,但可以试试。split.sh 的内容如下:

# Splits video to separate scenes files when full black frames are found in the video
# Inspired by https://gist.github.com/achesco/4dc2ebf13378a0a61fc26c7fe01f539e
# Who got inspired by https://stackoverflow.com/a/38205105

#!/bin/bash

file=""
out="./"
dur=0.05
stripaudio=""
ratio=1.00
th=0.05
add=0.00
trim=0.00

usage () {
  echo "Usage: $(basename $0) [[[-o folder] [-d black duration]] | [-h]] -f file.mp4"
  echo
  echo "Options:"
  echo "-f, --file          Input file"
  echo "-o, --out           Outpup files folder path, default"
  echo "                    to current folder"
  echo "-d, --dur           Duration for black detection in seconds. 0.05 default (practical single frame)"
  echo "-r, --ratio        ffmpeg pic_th : Set the threshold for considering a picture black. 1.00 default"
  echo "-th, --threshold   ffmpeg pix_th : Set the threshold for considering a pixel black. 0.00 default."
  echo "-t, --trim          Substracts to splitting timestamp in seconds. 0 default"
  echo "-a, --add           Adds to splitting timestamp in seconds. 0 default"
  echo "-sa, --strip-audio  Strip audio"
  echo "-h, --help          Display this help message"
  echo
  echo "Example: split.sh -d 0.5 -o /tmp/parts -f file.mp4"
  echo "Splits file.mp4 file to scenes with black frames during more than 0.5 second"
  echo "and saves output parts to /tmp/parts folder"
}

if [ "$1" = "" ]; then
  usage
fi

while [ "$1" != "" ]; do
  case $1 in
    -f | --file )
      shift
      file=$1
      ;;
    -d | --dur )
      shift
      dur=$1
      ;;
    -r | --ratio )
      shift
      ratio=$1
      ;;
    -th | --threshold )
      shift
      th=$1
      ;;
    -o | --out )
      shift
      out=$1
      ;;
    -t | --trim )
      shift
      trim=$1
      ;;
    -a | --add )
      shift
      add=$1
      ;;
    -sa | --strip-audio )
      stripaudio="-an"
      ;;
    -h | --help )
      usage
      exit
      ;;
    * )
      usage
      exit 1
  esac
  shift
done

cut_part () {
  duration_flag=""
  if [[ "$3" != "" ]]; then
    duration_flag="-t"
  fi
  echo "cutting from $1 during $3"
  printf -v fileout "$out/%04d_%s" $2 $filename
  ffmpeg -y -loglevel error -hide_banner -i $file -ss $1 $stripaudio $duration_flag $3 $fileout < /dev/null
}

filename=`basename $file`
mkdir -p $out
timefrom=0
i=1

ffmpeg -i $file -vf blackdetect=d=$dur:pic_th=$ratio:pix_th=$th -f null - 2> ffout
black_start=( $(grep blackdetect ffout | grep black_start:[0-9.]* -o | grep "[0-9]*(\.[0-9]*)?" -oE) )
black_duration=( $(grep blackdetect ffout | grep black_duration:[0-9.]* -o | grep "[0-9]*(\.[0-9]*)?" -oE) )
> timestamps
for ii in "${!black_start[@]}"; do
  half=$(bc -l <<< "${black_duration[$ii]}/2")
  middletime=$(bc -l <<< "${black_start[$ii]} + $half")
  echo $middletime | LC_ALL=en_US.UTF-8 awk '{printf "%f", $0}' >> timestamps
  echo "" >> timestamps
done

while read -r timestamp; do
  duration=`bc -l <<< "$timestamp-$timefrom+$add-$trim" | LC_ALL=en_US.UTF-8 awk '{printf "%f", $0}'`
  cut_part $timefrom $i $duration
  timefrom=`bc -l <<< "$timestamp+$add-$trim" | LC_ALL=en_US.UTF-8 awk '{printf "%f", $0}'`
  i=`expr $i + 1`
done < timestamps

if [[ "$timefrom" != 0 ]]; then
  cut_part $timefrom $i
fi

另外还有一个python 替代方案——scenedetect。

#安装场景检测所需模块

pip install scenedetect[opencv] -i https://pypi.tuna.tsinghua.edu.cn/simple

#检验是否已安装场景检测所需模块
pip list

click 
colorama
numpy 
opencv-python
scenedetect   0.5.5
tqdm

使用方式

scenedetect --input my_video.mp4 --output my_video_scenes --stats my_video.stats.csv 
time --start 00:05:00 --end 00:06:00 \
detect-content #对输入视频执行内容检测算法
list-scenes # 打印场景列表并输出到CSV文件
split-video # 使用ffmpeg或mkvMerge分割输入视频

测试

scenedetect --input /Users/zgq/Downloads/video.mp4 --output /Users/zgq/Downloads/my_video_scenes time --start 00:00:00 --end 00:01:00 detect-content split-video

05 按时间或持续时间分割视频

ffmpeg -ss 00:00:00 -t 00:50:00 -i largefile.mp4 -acodec copy \-vcodec copy smallfile.mp4

上面的命令将视频从开始的50分钟分割。你也可以随意改变参数。只需重复该过程,就可以把剩余部分的视频得分割成多个部分。

06 按宽度分割视频

ffmpeg -i input.mp4 -filter:v "crop=iw*(5/10):ih*(5/10):iw:0" output.mp4

在上面的例子中,视频将被裁剪为原高度和宽度的一半。要保持相同的高度,只需将ih组件的参数更改为10/10。您还可以通过在上面示例中的引号内使用:keep_aspect=1参数来保持长宽比。命令如下:

ffmpeg -i input.mp4 -filter:v "crop=iw*(5/10):ih*(5/10):iw:0:keep_aspect=1" output.mp4

07 FFmpeg水平分割视频

这本质上和上一个是相同的裁剪功能,但不是将其裁剪为更小的宽度,而是保持宽度不变,并将视频的高度降低50%。以下两个命令,一个是不带高宽比例,一个带高宽比例:
``
ffmpeg -i input.mp4 -filter:v "crop=iw(5/10):ih(5/10):iw:0" output.mp4

ffmpeg -i input.mp4 -filter:v "crop=iw(5/10):ih(5/10):iw:0:keep_aspect=1" output.mp4

在正则表达式中,?=, ?<=, ?!, 和 ?<!零宽度断言(lookaround assertions)的一部分。它们用于在匹配过程中进行某种条件判断,但并不会消耗字符(即不包括在最终的匹配结果中)。下面我将详细介绍它们的用法:

1. ?=: 正向前瞻(Positive Lookahead)

正向前瞻 ?= 用于匹配某个位置,要求其后面跟着某个模式,但不会包含该模式。

  • 语法X(?=Y)

    • 这个模式会匹配字符 X,但只有在字符 X 后面跟着 Y 时才会匹配。
    • Y 不会被包含在匹配结果中。
  • 示例
$pattern = '/\d(?=\D)/';
$string = "123a456";
preg_match($pattern, $string, $matches);
print_r($matches);

在这个例子中,(?=\D) 是一个正向前瞻,它检查数字后面是否跟着非数字字符。最终匹配的结果是数字 3,因为它后面是字母 a,符合条件。

2. ?<=: 反向前瞻(Positive Lookbehind)

反向前瞻 ?<= 用于匹配某个位置,要求其前面是某个模式,但不会包含该模式。

  • 语法(?<=Y)X

    • 这个模式会匹配字符 X,但只有在字符 X 前面是 Y 时才会匹配。
    • Y 不会被包含在匹配结果中。
  • 示例
$pattern = '/(?<=\d)a/';
$string = "123a456";
preg_match($pattern, $string, $matches);
print_r($matches);

在这个例子中,(?<=\d) 是一个反向前瞻,它检查字母 a 前面是否是数字。最终匹配的结果是字母 a,因为它前面是数字 3,符合条件。

3. ?!: 负向前瞻(Negative Lookahead)

负向前瞻 ?! 用于匹配某个位置,要求其后面跟着某个模式。

  • 语法X(?!Y)

    • 这个模式会匹配字符 X,但只有在字符 X 后面跟着 Y 时才会匹配。
    • Y 不会被包含在匹配结果中。
  • 示例
$pattern = '/\d(?!\d)/';
$string = "123a456";
preg_match($pattern, $string, $matches);
print_r($matches);

在这个例子中,(?!\d) 是一个负向前瞻,它检查数字后面是否跟着另一个数字。最终匹配的结果是数字 3,因为它后面跟着字母 a,不符合 \d(数字)模式。

4. ?<!: 负向反向前瞻(Negative Lookbehind)

负向反向前瞻 ?<! 用于匹配某个位置,要求其前面是某个模式。

  • 语法(?<!Y)X

    • 这个模式会匹配字符 X,但只有在字符 X 前面Y 时才会匹配。
    • Y 不会被包含在匹配结果中。
  • 示例
$pattern = '/(?<!\d)a/';
$string = "123a456";
preg_match($pattern, $string, $matches);
print_r($matches);

在这个例子中,(?<!\d) 是一个负向反向前瞻,它检查字母 a 前面是否是数字。最终匹配的结果是字母 a,因为它前面是字母 3,符合条件。


总结

断言描述示例匹配内容
?=正向前瞻:匹配后面跟着某个模式的位置\d(?=\D)数字后跟非数字
?<=反向前瞻:匹配前面是某个模式的位置(?<=\d)a数字后面的字母 a
?!负向前瞻:匹配后面不跟某个模式的位置\d(?!\d)单个数字后不是数字
?<!负向反向前瞻:匹配前面不跟某个模式的位置(?<!\d)a非数字前面的字母 a

这些零宽度断言非常有用,可以在不影响匹配的内容的情况下,进行更灵活的条件判断,帮助你精确控制正则匹配的范围。