ffmpeg - 如何并行转换大量文件?
ffmpeg - How to convert massive amounts of files in parallel?
我需要转换大约 1.5TiB 或 flac 或 wav 格式的音频文件。它们需要转换成mp3文件,保留重要的元数据和封面艺术等,比特率需要320k。
仅此一项就很简单:
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 "$mp3File" < /dev/null
但问题是让它变得更快。上面的命令只使用了 CPU 的 12.5%。我宁愿使用 80%。所以我玩弄了线程标志,但它并没有使它变快或变慢:
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 -threads 4 "$mp3File" < /dev/null
但它只使用了我的 CPU 13%。我认为它只使用一个线程。我的 CPU 有 8 个物理内核顺便说一下(+ 超线程)。
所以我现在的想法是以某种方式同时拥有多个 ffmpeg 运行ning 实例,但我不知道如何正确地做到这一点。
这是我当前的脚本,用于从一个目录(递归地)获取所有 flac/wav 文件,并将它们转换为具有完全相同结构的新目录中的 mp3 文件:
#!/bin/bash
SOURCE_DIR="/home/fedora/audiodata_flac"
TARGET_DIR="/home/fedora/audiodata_mp3"
echo "FLAC/WAV files will be read from '$SOURCE_DIR' and MP3 files will be written to '$TARGET_DIR'!"
read -p "Are you sure? (y/N)" -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]] ; then # Continue if user enters "y"
# Find all flac/wav files in the given SOURCE_DIR and iterate over them:
find "${SOURCE_DIR}" -type f \( -iname "*.flac" -or -iname "*.wav" \) -print0 | while IFS= read -r -d '' flacFile; do
if [[ "$(basename "${flacFile}")" != ._* ]] ; then # Skip files starting with "._"
tmpVar="${flacFile%.*}.mp3"
mp3File="${tmpVar/$SOURCE_DIR/$TARGET_DIR}"
mp3FilePath=$(dirname "${mp3File}")
mkdir -p "${mp3FilePath}"
if [ ! -f "$mp3File" ]; then # If the mp3 file doesn't exist already
echo "Input: $flacFile"
echo "Output: $mp3File"
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 "$mp3File" < /dev/null
fi
fi
done
fi
我的意思是我想我可以将 &
附加到 ffmpeg 命令,但这会导致成千上万的 ffmpeg 实例同时 运行,这太多了。
像这样:
#!/bin/bash
SOURCE_DIR="/home/fedora/audiodata_flac"
TARGET_DIR="/home/fedora/audiodata_mp3"
export SOURCE_DIR
export TARGET_DIR
doone() {
flacFile=""
if [[ "$(basename "${flacFile}")" != ._* ]] ; then # Skip files starting with "._"
tmpVar="${flacFile%.*}.mp3"
mp3File="${tmpVar/$SOURCE_DIR/$TARGET_DIR}"
mp3FilePath=$(dirname "${mp3File}")
mkdir -p "${mp3FilePath}"
if [ ! -f "$mp3File" ]; then # If the mp3 file doesn't exist already
echo "Input: $flacFile"
echo "Output: $mp3File"
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 "$mp3File" < /dev/null
fi
fi
}
export -f doone
# Find all flac/wav files in the given SOURCE_DIR and iterate over them:
find "${SOURCE_DIR}" -type f \( -iname "*.flac" -or -iname "*.wav" \) -print0 |
parallel -0 doone
我需要转换大约 1.5TiB 或 flac 或 wav 格式的音频文件。它们需要转换成mp3文件,保留重要的元数据和封面艺术等,比特率需要320k。
仅此一项就很简单:
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 "$mp3File" < /dev/null
但问题是让它变得更快。上面的命令只使用了 CPU 的 12.5%。我宁愿使用 80%。所以我玩弄了线程标志,但它并没有使它变快或变慢:
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 -threads 4 "$mp3File" < /dev/null
但它只使用了我的 CPU 13%。我认为它只使用一个线程。我的 CPU 有 8 个物理内核顺便说一下(+ 超线程)。
所以我现在的想法是以某种方式同时拥有多个 ffmpeg 运行ning 实例,但我不知道如何正确地做到这一点。
这是我当前的脚本,用于从一个目录(递归地)获取所有 flac/wav 文件,并将它们转换为具有完全相同结构的新目录中的 mp3 文件:
#!/bin/bash
SOURCE_DIR="/home/fedora/audiodata_flac"
TARGET_DIR="/home/fedora/audiodata_mp3"
echo "FLAC/WAV files will be read from '$SOURCE_DIR' and MP3 files will be written to '$TARGET_DIR'!"
read -p "Are you sure? (y/N)" -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]] ; then # Continue if user enters "y"
# Find all flac/wav files in the given SOURCE_DIR and iterate over them:
find "${SOURCE_DIR}" -type f \( -iname "*.flac" -or -iname "*.wav" \) -print0 | while IFS= read -r -d '' flacFile; do
if [[ "$(basename "${flacFile}")" != ._* ]] ; then # Skip files starting with "._"
tmpVar="${flacFile%.*}.mp3"
mp3File="${tmpVar/$SOURCE_DIR/$TARGET_DIR}"
mp3FilePath=$(dirname "${mp3File}")
mkdir -p "${mp3FilePath}"
if [ ! -f "$mp3File" ]; then # If the mp3 file doesn't exist already
echo "Input: $flacFile"
echo "Output: $mp3File"
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 "$mp3File" < /dev/null
fi
fi
done
fi
我的意思是我想我可以将 &
附加到 ffmpeg 命令,但这会导致成千上万的 ffmpeg 实例同时 运行,这太多了。
像这样:
#!/bin/bash
SOURCE_DIR="/home/fedora/audiodata_flac"
TARGET_DIR="/home/fedora/audiodata_mp3"
export SOURCE_DIR
export TARGET_DIR
doone() {
flacFile=""
if [[ "$(basename "${flacFile}")" != ._* ]] ; then # Skip files starting with "._"
tmpVar="${flacFile%.*}.mp3"
mp3File="${tmpVar/$SOURCE_DIR/$TARGET_DIR}"
mp3FilePath=$(dirname "${mp3File}")
mkdir -p "${mp3FilePath}"
if [ ! -f "$mp3File" ]; then # If the mp3 file doesn't exist already
echo "Input: $flacFile"
echo "Output: $mp3File"
ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 "$mp3File" < /dev/null
fi
fi
}
export -f doone
# Find all flac/wav files in the given SOURCE_DIR and iterate over them:
find "${SOURCE_DIR}" -type f \( -iname "*.flac" -or -iname "*.wav" \) -print0 |
parallel -0 doone