type
Post
status
Published
date
Sep 6, 2024
slug
summary
tags
category
icon
password
Property
Sep 6, 2024 03:02 AM
Language
使用 ffmpeg,完成多个 mp4 文件合并
自从买了 Downie 之后,就不敢去优酷下载视频,因为他们家下载回来的都是小文件,还需要合并。而 Mac 下我有找不到能合并多个 mp4 文件的工具,只能作罢。
后来发现优酷上下载回来的视频质量还是很高的,所以还是决定在考虑下合并 mp4。之前也听说过通过 ffmpeg 工具可以完成,并且可以非常高速的完成合并。这次就再搜索查找了下。
当时看的文章比较多也比较杂,这次搜索后,主要参考了一篇文章。在此基础上,我稍微整理了下。
见此:使用FFmpeg合并MP4视频
首先是安装 ffmpeg 工具,Windows/MacOS/Linux 都可以。可以自行搜索安装方法。
其中 MacOS 下的方法是:
1 | brew install ffmpeg |
下文的脚本,以 MacOS 为准。Linux 应该通用。Windows 没用过,不确定。
将多个 mp4 小文件,合并为一个大文件,方法有两种:mpeg 拼接,ts 拼接(推荐)。
mpeg 拼接
需要先将小 mp4 文件转码为 mpeg 文件,之后 mpeg 直接拼接,最后再转码回 mp4。
此方法速度比较慢,并且最终生成的文件比较大。例如 6 个小 mp4 文件,累计 240MB,通过此方法,最终 mp4 文件会变成 640MB 左右。整个操作用时超过 1 分钟。
ffmpeg -i a1.mp4 -qscale 4 a1.mpg ffmpeg -i a2.mp4 -qscale 4 a2.mpg cat a1.mpg a2.mpg| ffmpeg -f mpeg -i - -qscale 6 -vcodec mpeg4 output.mp4
速度慢也就算了,关键是变大太多了。果断舍弃此方案。
ts 拼接(推荐)
整个方法先把 mp4 封装成 ts 格式,之后 ts 直接拼接,最后在转化为 mp4。
此方法速度快,最终文件基本上等于小文件的总和。例如 6 个小 mp4 文件,累计 240MB,通过此方法,最终 mp4 文件也在 240MB 左右。整个操作用时 10 秒。
#! /bin/bash # 将 mp4 文件封装为 ts 格式 ffmpeg -i a1.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb 1.ts ffmpeg -i a2.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb 2.ts ffmpeg -i a3.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb 3.ts ffmpeg -i a4.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb 4.ts # 拼接 ts 并导出最终 mp4 文件 ffmpeg -i "concat:1.ts|2.ts|3.ts|4.ts" -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4 # 删除过程中生成的 ts 文件 rm *.ts
具体操作方案:
- 使用 Transnomino(MacOS 下我找到的唯一一个免费且好用的批量更名软件)。先将目录下的 mp4 进行改名,当然也可以使用 MacOS 自带的批量改名功能。改名为
a1.mp4,a2.mp4…;
- 编辑上面的脚本,把它保存到 mp4 目录内,名字无所谓,比如
a.sh;
- 终端中,cd 到 mp4 的目录,执行
bash a.sh,等待即可;
- 最终即可生成 output.mp4 合并好的文件了。
–END–
现在有如下需求,目录里有类似以下文件目录,要求按照指定输入目录,指定输出目录(没有填写则与输入目录相同)按照名称(如Darling彭彭)自动按照时间升序进行转换ts然后合并成对应名称(如Darling彭彭)mp4
-rw-rw-rw- 1 root root 349M Sep 5 11:26 Darling彭彭2024-09-05T11_10_03.mp4 -rw-rw-rw- 1 root root 1.1G Sep 5 12:25 Darling彭彭2024-09-05T11_40_58.mp4 -rw-rw-rw- 1 root root 293M Sep 5 12:38 Darling彭彭2024-09-05T12_25_30.mp4 -rw-rw-rw- 1 root root 1.1G Sep 5 13:25 Darling彭彭2024-09-05T12_41_17.mp4 -rw-rw-rw- 1 root root 375M Sep 5 13:42 Darling彭彭2024-09-05T13_25_28.mp4 -rw-rw-rw- 1 root root 1.1G Sep 5 14:26 Darling彭彭2024-09-05T13_42_55.mp4 -rw-rw-rw- 1 root root 377M Sep 5 14:43 Darling彭彭2024-09-05T14_26_57.mp4 -rw-rw-rw- 1 root root 1.1G Sep 5 15:27 Darling彭彭2024-09-05T14_43_08.mp4 -rw-rw-rw- 1 root root 371M Sep 5 15:43 Darling彭彭2024-09-05T15_27_26.mp4 -rw-rw-rw- 1 root root 1.1G Sep 5 16:27 Darling彭彭2024-09-05T15_43_20.mp4 -rw-rw-rw- 1 root root 375M Sep 5 16:43 Darling彭彭2024-09-05T16_27_23.mp4 -rw-rw-rw- 1 root root 406M Sep 5 17:00 Darling彭彭2024-09-05T16_43_31.mp4 -rw-rw-rw- 1 root root 1.1G Sep 5 20:48 中午吃什么2024-09-05T20_19_50.mp4 -rw-rw-rw- 1 root root 716M Sep 5 21:08 中午吃什么2024-09-05T20_48_41.mp4 -rw-rw-rw- 1 root root 400M Sep 5 21:19 中午吃什么2024-09-05T21_08_59.mp4 -rw-rw-rw- 1 root root 1.1G Sep 5 21:48 中午吃什么2024-09-05T21_19_59.mp4 -rw-rw-rw- 1 root root 881M Sep 5 22:13 中午吃什么2024-09-05T21_48_12.mp4
经过一番努力有如下的脚本:
#!/bin/bash # 检查是否传递了输入目录参数 if [ -z "$1" ]; then echo "请提供输入目录路径作为第一个参数,例如:./script.sh /path/to/input" exit 1 fi input_directory=$1 # 检查是否传递了输出目录参数,如果没有则使用输入目录作为默认输出目录 if [ -z "$2" ]; then output_directory="$input_directory" else output_directory=$2 fi # 查找目录中所有不带时间戳的文件前缀并去重 file_groups=$(ls "$input_directory" --ignore="*.ts" | grep -oP '^[^\dT]+(?=[\d\-T_]+\.mp4$)' | sort | uniq) # 检查是否找到匹配的文件组 if [ -z "$file_groups" ]; then echo "没有找到符合条件的文件" exit 1 fi # 对每个前缀进行分组处理 for prefix in $file_groups; do echo "正在处理前缀: $prefix" # 查找该组中的所有文件,按时间顺序排序 files=$(ls -1t --reverse "$input_directory"/*"${prefix}"*.mp4) # 初始化计数器和文件列表 count=1 ts_files="" # 遍历该组中的每个文件并转换为 ts 格式 for file in $files; do ts_file="$count.ts" ffmpeg -i "$file" -vcodec copy -acodec copy -vbsf h264_mp4toannexb "$ts_file" ts_files="$ts_files|$ts_file" count=$((count + 1)) done # 移除第一个 "|" 符号 ts_files=${ts_files#|} # 合并所有 ts 文件并导出最终 mp4 文件,文件名为前缀 output_file="${output_directory}/${prefix}.mp4" ffmpeg -i "concat:$ts_files" -acodec copy -vcodec copy -absf aac_adtstoasc "$output_file" # 删除生成的 ts 文件 rm *.ts echo "前缀 $prefix 的文件已成功合并为 $output_file" done
- Author:Qi
- URL:https://blog.ltq.im/article/5fc010ac-ae39-4dd5-b475-fa8dc993e876
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!