linux - 提取音频,再次操作和合并

标签 linux bash shell audio ffmpeg

我正在使用 Spleeter从音频中删除音乐。

我的目标是构建一个脚本,使从视频中提取音频的过程自动化,在提取的音频上执行 Spleeter,然后将经过处理的音频合并回视频,替换原始音频。

我遇到的主要问题是我没有足够的内存来处理整个提取的音频。我需要将它分成多个部分并在每个部分上执行 Spleeter。

然后将处理后的片段连接在一起并将结果合并到视频中。

这是我尝试过的:

#!/bin/bash

cd ~/Desktop/Video-convert

# create audio from video
ffmpeg -i *.mp4 output.mp3

# Split the audio into pieces
ffmpeg -i output.mp3 -f segment -segment_time 120 -c copy output_%03d.mp3


# Execute Spleeter upon each sample
FILES=~/Desktop/Video-convert/*.mp3

for f in $FILES
do
  spleeter separate -i $f -o output_vocal
done

# delete unneeded audios
rm *.mp3
cd output_vocal

# ===========================================================
# the problem starts here
# ===========================================================

# concatenate manipulated audios together
find . -name 'vocals.wav' -exec echo {} >> mylist.txt \;

ffmpeg -f concat -safe 0 -i mylist.txt -c copy vocal.mp3

mv vocal.mp3 ../

cd ../

# merge the audio back to video
ffmpeg -i *.mp4 -i vocal.mp3 \
-c:v copy -c:a aac -strict experimental \
-map 0:v:0 -map 1:a:0 vocal-vid.mp4

一切正常,直到必须将音频连接在一起。 Spleeter 将结果输出到 声乐.wav & 伴奏.wav 在与已处理音频命名相同的子文件夹中。

文件树如下所示:
output_vocal
- output_000
----- vocal.wav
----- accompaniment.wav
- output_001
----- vocal.wav
----- accompaniment.wav
- output_002
----- vocal.wav
----- accompaniment.wav

如您所见,问题在于命名。我的目标是连接所有 声乐.wav 成一个 mp3 音频。

然后合并最终的人声.mp3 的音频*.mp4 视频。

唯一的问题是围绕 Spleeter 输出结果音频的方式。

最佳答案

您遇到的问题是 ffmpeg 的 concat demuxer 需要一个包含指令的输入文件,而不是一个简单的文件列表。

您的 find调用创建一个文件,如:

output_vocal/output_000/vocal.wav
output_vocal/output_001/vocal.wav
output_vocal/output_002/vocal.wav

而 ffmpeg 的 concat demuxer 确实需要一个文件,例如:
file output_vocal/output_000/vocal.wav
file output_vocal/output_001/vocal.wav
file output_vocal/output_002/vocal.wav

另请注意 find不一定按字母顺序返回文件,而您很可能希望按该顺序连接文件。

最后,在连接 WAV 文件时,不能使用 copy编解码器生成 MP3 文件(因为 WAV/RIFF 编解码器不是 MP3)。但无论如何您都不需要中间 MP3 文件

这是一个更新的脚本,
- 为所有中间文件使用临时目录
- 遍历 cmdline 提供的所有 mp4 文件(而不是硬编码输入目录)
- 为每个输入文件“XXX.mp4”创建一个“XXX_voc.mp4”文件(覆盖任何现有文件)

#!/bin/bash

for infile in "$@"
do
  outfile=${infile%.mp4}_voc.mp4

  # create a temp-directory to put our stuff to
  TMPDIR=$(mktemp -d)

  # create audio from video
  ffmpeg -i "${infile}" "${TMPDIR}/output.mp3"

  # Split the audio into pieces
  ffmpeg -i "${TMPDIR}/output.mp3" -f segment -segment_time 120 -c copy "${TMPDIR}/output_%03d.mp3"

  # Execute Spleeter upon each sample
  find "${TMPDIR}" -maxdepth 1 -type f -name "output_*.mp3" \
    -exec spleeter separate -i {} -o "${TMPDIR}/output_vocal" ";"

  # find all 'vocal.wav' files generated by spleeter, sort them, 
  # prefix them with 'file ', and put them into output.txt
  find "${TMPDIR}/output_vocal" -type f -name "vocal.wav" -print0 \
  | sort -z \
  | xargs -0 -I{} echo "file '{}'" \
  > "${TMPDIR}/output.txt"
  # concatenate the files and create an MP3 file
  ffmpeg -f concat -safe 0 -i "${TMPDIR}/output.txt" -c copy "${TMPDIR}/vocal.wav"

  # merge the audio back to video
  ffmpeg -y -i "${infile}" -i "${TMPDIR}/vocal.wav" \
    -c:v copy -c:a aac -strict experimental \
    -map 0:v:0 -map 1:a:0 "${outfile}"

  rm -rf "${TMPDIR}"
done

关于linux - 提取音频,再次操作和合并,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59840282/

相关文章:

python - 从 Bash 使用 STDIN 运行 Python

c - 需要帮助将命令行 ";"选项实现到 C-Shell 脚本中

linux - 文件中包含整数的行数

linux - 如何将值传递给另一个代码以在 linux 中执行进程

bash - $做什么? $0 $1 $2 在 shell 脚本中是什么意思?

bash - 与 echo 一样缩进行

linux - 链接时未定义对符号 'socket@GLIBC_2.4' 的引用

linux - 使用sudo时如何保持环境变量

linux - 如何同时运行两个程序,但它们位于不同的目录中? (Tcsh 外壳)

linux - 使用 bash 脚本从具有相同文件夹名称 XML 的不同位置删除超过 4 周的 xml 文件