路径问题与FFMPEG Bash脚本连接和编码跨多个子文件夹



我正在尝试为Mac OSx终端编写一个bash脚本,将一系列GoPro . mp4视频从sd卡直接压缩到本地网络服务器上更小的。mp4。GoPro将。mp4保存在存储卡的100GOPRO文件夹中。拍摄结束后,我会通过该文件夹,手动将每个游戏的。mp4放入100GOPRO文件夹中的子文件夹中,命名为A1, A2, A3等。

文件夹结构

/GoPro/DCIM/100GOPRO/
-------/A1/
-----GX01xxx1.mp4
-----GX01xxx2.mp4
-------/A2/
-----GX01xxx3.mp4
-----GX01xxx4.mp4
-----GX01xxx5.mp4
-----GX01xxx6.mp4

我想然后想从100GOPRO文件夹中运行一个脚本,它将执行以下步骤:

  1. 在每个子文件夹中,自动创建一个文件。txt,其中包含子文件夹的。mp4的名称,格式为连接文件(每行有"file 'GX01xxx3.mp4'")
  2. 传递该子文件夹的file.txt作为ffmpeg的输入以重新编码并保存到名称为A1.mp4或A2.mp4的网络文件夹
  3. 为每个子文件夹重复操作并退出。

我在子文件夹的file.txt的动态路径上挂了。我的代码只是在100GOPRO文件夹中创建了一个file.txt,并将所有子文件夹的内容附加到这个长组合文本文件中。然后输出将创建正确的第一个MP4,但第二个MP4包含文件夹1和2,然后3包含1、2和3,等等。

下面是我运行的脚本:
#!/bin/bash
for f in A*/*.mp4 ; do
echo file '$f' >> list.txt ;
done && ffmpeg -f concat -safe 0 -i list.txt /Volume/Server/Videos/A$f.mp4 && rm list.txt

显然,在echo如何保存在子文件夹A*的路径,如何调用该子文件夹的file.txt作为ffmpeg的输入,以及如何以文件夹命名输出失败。

谢谢你提供的任何帮助。

我用@suvayo的代码让它以两种方式工作!谢谢你。

当我不知道如何让printf创建一个没有包含路径的文件列表时,我能够通过使用echo在目录循环中嵌套另一个循环来使其工作。我把多余的5个字符"/A2/"从input .txt路径中使用{f:5}:

#!/bin/bash
for d in $(find . -maxdepth 1 -type d -name 'A*'); do
for f in $d/*.mp4 ; do
echo file '${f:5}' >> ./$d/inputs.txt
done
ffmpeg -f concat -safe 0 -i $d/inputs.txt /Volumes/Server/Videos/${d:2}.mp4
done
然而,更优雅的方法是使用@suvayo的两个版本的答案的组合。(当我刚刚使用for d in A*; do时,输出文件名不正确)
#!/bin/bash
for d in $(find . -maxdepth 1 -type d -name 'A*'); do
printf "file '%s'n" $(cd $d && echo *.mp4) > $d/inputs.txt
ffmpeg -f concat -safe 0 -i $d/inputs.txt /Volumes/Server/Videos/${d:2}.mp4
done

这太好了。最后,每个文件夹都包含合并后的原始。mp4文件,以及用于将这些文件连接在一起的inputs.txt文件。希望我不是一个新手,这样我就可以给更多的答案投票了。

基本上,您需要获取目录,然后为该目录创建文件列表。如果需要更多的控制,可以使用find,或者为了简单起见,可以使用shell glob(但这可能会意外地与其他文件匹配)。

for d in $(find . -maxdepth 1 -type d -name 'A*'); do
printf "file '%s'n" $(cd $d && echo *.mp4) > $d/inputs.txt
ffmpeg -f concat -safe 0 -i $d/inputs.txt /Volume/Server/Videos/${d:2}.mp4
done

或使用shell glob的以下循环:

for d in A*; do
# same code as above
done

  • 查找符合A*的目录,并且仅限于1级深度的子目录;注意,当使用默认的查找命令(BSD版本)时,在MacOS上指定目录(.)是必要的,但是对于GNU版本(安装在brew或Linux上),默认目录是当前目录(.)
  • 由于ffmpeg期望文件路径相对于列表,我们将cd放入子shell中的目录,并使用glob*.mp4生成文件列表,printf将其格式化为文件列表,但迭代它
  • ffmpeg命令是您指定的,输出文件名使用目录名,除了它修剪了前两个字符(转换./A1->A1)

将文件列表保存到bash数组中,然后遍历该数组。根据您的喜好调整ffmpeg调用。

#!/usr/bin/env bash
declare -a files=( $(find A* -type f -name *.mp4) )
for file in "${files[*]}"; do
fbase=${file%.mp4}
ffmpeg -f concat -safe 0 -i "$file" "/Volume/Server/Videos/A${fbase}.mp4"
done

最新更新