Files
devops/docker/stash/scripts/video_merge.sh
2025-12-25 17:08:29 +08:00

125 lines
4.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# 功能绿联NAS通用视频无损合并脚本自动识别格式
# 支持格式MP4、AVI、WMV
# 使用要求:所有输入文件格式必须一致,最后一个参数为输出文件名
# 使用方法:./merge_video_unified.sh 1.mp4 2.mp4 merged.mp4或avi/wmv格式
# 定义颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # 恢复默认颜色
# 初始化变量
input_files=()
output_file=""
file_list="tmp_video_list.txt"
detected_format=""
supported_formats=("mp4" "avi" "wmv") # 支持的格式列表
# -------------------------- 步骤1解析与校验参数 --------------------------
# 1. 校验参数数量至少2个输入+1个输出
if [[ $# -lt 3 ]]; then
echo -e "${RED}错误:参数数量不足!格式:脚本名 输入1 输入2 ... 输出文件${NC}"
echo -e "${YELLOW}使用示例:${NC}"
echo -e " MP4./merge_video_unified.sh 1.mp4 2.mp4 merged.mp4"
echo -e " AVI./merge_video_unified.sh 1.avi 2.avi merged.avi"
echo -e " WMV./merge_video_unified.sh 1.wmv 2.wmv merged.wmv"
exit 1
fi
# 2. 提取输出文件(最后一个参数)和输入文件(前面所有参数)
output_file="${!#}"
input_files=("${@:1:$#-1}")
# -------------------------- 步骤2检测并校验输入文件格式 --------------------------
# 1. 检测第一个输入文件的格式
first_file="${input_files[0]}"
# 提取文件后缀(忽略大小写)
file_suffix=$(echo "$first_file" | awk -F '.' '{print tolower($NF)}')
# 2. 校验是否为支持的格式
if [[ ! " ${supported_formats[@]} " =~ " ${file_suffix} " ]]; then
echo -e "${RED}错误:不支持该格式!仅支持:${supported_formats[*]}${NC}"
exit 1
fi
detected_format="$file_suffix"
echo -e "${GREEN}已检测到输入文件格式:$detected_format${NC}"
# 3. 校验所有输入文件格式是否一致
for file in "${input_files[@]}"; do
# 检查文件是否存在
if [[ ! -f "$file" ]]; then
echo -e "${RED}错误:输入文件 $file 不存在!${NC}"
exit 1
fi
# 提取当前文件后缀
current_suffix=$(echo "$file" | awk -F '.' '{print tolower($NF)}')
# 对比格式是否一致
if [[ "$current_suffix" != "$detected_format" ]]; then
echo -e "${RED}错误:输入文件格式不一致!$file 不是 $detected_format 格式${NC}"
exit 1
fi
done
# -------------------------- 步骤3处理输出文件 --------------------------
# 1. 自动补全输出文件后缀
output_suffix=$(echo "$output_file" | awk -F '.' '{print tolower($NF)}')
if [[ "$output_suffix" != "$detected_format" ]]; then
output_file="${output_file}.${detected_format}"
echo -e "${YELLOW}提示:输出文件已自动补全为 ${detected_format} 格式:$output_file${NC}"
fi
# 2. 输出文件覆盖提示
if [[ -f "$output_file" ]]; then
read -p "提示:输出文件 $output_file 已存在,是否覆盖?(y/n) " choice
case "$choice" in
y|Y) echo -e "${YELLOW}即将覆盖输出文件 $output_file${NC}" ;;
*) echo -e "${GREEN}操作已取消${NC}"; exit 0 ;;
esac
fi
# -------------------------- 步骤4校验ffmpeg --------------------------
if ! command -v ffmpeg &> /dev/null; then
echo -e "${RED}错误未检测到ffmpeg请先安装${NC}"
exit 1
fi
# -------------------------- 步骤5执行合并 --------------------------
echo -e "${GREEN}=====================================${NC}"
echo -e "${GREEN}开始执行 ${detected_format} 格式无损合并${NC}"
echo -e "${GREEN}待合并文件(传入顺序):${NC}"
for i in "${!input_files[@]}"; do
echo " $((i+1)). ${input_files[$i]}"
done
echo -e "${GREEN}输出文件:$output_file${NC}"
echo -e "${GREEN}=====================================${NC}"
# 1. 生成临时文件列表
echo -e "${YELLOW}正在生成临时文件列表...${NC}"
> "$file_list" # 清空临时文件
for file in "${input_files[@]}"; do
abs_file=$(realpath "$file")
echo "file '$abs_file'" >> "$file_list"
done
echo -e "${GREEN}临时文件列表生成完成:$file_list${NC}"
# 2. 执行ffmpeg合并
echo -e "${YELLOW}正在合并 ${detected_format} 文件(无损拷贝,耗时取决于文件大小)...${NC}"
ffmpeg -f concat -safe 0 -i "$file_list" -c copy -y "$output_file"
# -------------------------- 步骤6结果判断与清理 --------------------------
if [[ $? -eq 0 ]]; then
echo -e "${GREEN}=====================================${NC}"
echo -e "${GREEN}${detected_format} 格式合并成功!输出文件:$output_file${NC}"
rm -f "$file_list"
echo -e "${GREEN}临时文件 $file_list 已清理${NC}"
echo -e "${GREEN}=====================================${NC}"
else
echo -e "${RED}=====================================${NC}"
echo -e "${RED}${detected_format} 格式合并失败!请确认所有文件编码/分辨率/帧率一致${NC}"
rm -f "$file_list"
echo -e "${RED}临时文件 $file_list 已清理${NC}"
echo -e "${RED}=====================================${NC}"
exit 1
fi