我喜欢创建一个 Bash 脚本,使用 FFmpeg 连接 MP4 文件,对于包含 100 个 MP4 文件的目录,每次批量连接 5 个文件,这样之后就会有 20 个文件,如下所示:
001_005.mp4、006_010.mp4 等等……
而不是仅仅包含全部 100 个文件的 1 个文件。
mylist.txt的内容:
file 001.mp4
file 002.mp4
file 003.mp4
file 004.mp4
file 005.mp4
............
file 099.mp4
file 100.mp4
虽然我找到了一个可以正常工作的命令(来自此 StackOverflow 线程),它将只创建 1 个包含全部 100 个文件的文件。
#!/bin/bash
cd /home/admn/Downloads/MP4_Files;
# Create mylist.txt:
for f in *.mp4
do
echo "file $f" >> mylist.txt
done;
# Concatenate files:
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4;
那么,我该如何修改 ffmpeg 命令以便它每次批量连接 5 个文件。
所有文件都具有完全相同的分辨率(1080p)、音频和视频编解码器。
操作系统:Ubuntu MATE 21.04
ffmpeg版本:4.3.2-0+deb11u1ubuntu1
答案1
我认为下面的脚本会起作用。
- 首先按原样尝试一下,检查它是否能达到你想要的效果
echo
然后从行中删除ffmpeg
以使其发挥作用。
检查临时文件 xat` 的内容是否xaa' ...
与输出文件的名称(和内容)匹配。
#!/bin/bash
> mylist.txt
for f in *.mp4
do
echo "file '$f'" >> mylist.txt
done
< mylist.txt sort -t \' -n -k2 | split -l 5
k=1
for j in x*
do
inc=$(wc -l "$j" | cut -d ' ' -f 1)
m=$(printf "%03d" $((k)))
n=$(printf "%03d" $((k+inc-1)))
name="${m}_${n}.mp4"
echo ffmpeg -f concat -safe 0 -i "$j" -c copy "$name"
k=$((k+5))
done
答案2
另一种解决方案是使用嵌套循环。
只要还有剩余的文件,内循环就会${@:1:5}
取出下一片(最多) 5 个文件。
#!/bin/bash
cd /home/admn/Downloads/MP4_Files;
shopt -s failglob
set -- *.mp4
while [[ $# -gt 0 ]]; do
from=$(basename "$1" .mp4)
for f in "${@:1:5}"; do
#not essential in your case, but use @Q to quote/escape special characters
echo "file ${f@Q}" >> mylist.txt
shift
done
to=$(basename "$f" .mp4)
ffmpeg -f concat -safe 0 -i mylist.txt -c copy "${from}_${to}.mp4"
rm mylist.txt
done
答案3
假设mylist.txt
存在于您当前的工作目录中,您可以执行以下操作,
LINES=$(cat mylist.txt | wc -l)
BATCH_SIZE=5
BATCHES=$(($LINES/$BATCH_SIZE))
for ((i=0;i<$BATCHES;i++))
do
cat mylist.txt | head -n $((($i+1)*$BATCH_SIZE)) | tail -n $BATCH_SIZE > slist.txt
ffmpeg -f concat -safe 0 -i slist.txt -c copy $(($i*$BATCH_SIZE+1))_$((($i+1)*$BATCH_SIZE)).mp4
done
rm slist.txt