ffmpeg - Как параллельно конвертировать огромное количество файлов?

Мне нужно преобразовать около 1,5 ТБ или аудиофайлы в формате flac или wav. Их нужно преобразовать в mp3-файлы, сохранив важные метаданные, обложку и т. д., а битрейт должен быть 320k.

Только это легко:

ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 "$mp3File" < /dev/null

Но проблема в том, чтобы сделать это быстрее. Команда сверху использует только 12,5% ЦП. Я бы предпочел использовать 80%. Итак, я поиграл с флагом потоков, но это не делает его быстрее или медленнее:

ffmpeg -i "$flacFile" -ab 320k -map_metadata 0 -id3v2_version 3 -vsync 2 -threads 4 "$mp3File" < /dev/null

Но он использует мой процессор только на 13%. Я думаю, что он использует только один поток. Кстати, у моего процессора 8 физических ядер (+ гиперпоточность).

Итак, моя идея сейчас состоит в том, чтобы каким-то образом одновременно запускать несколько экземпляров ffmpeg, но я понятия не имею, как это сделать правильно.

Это мой текущий скрипт, который берет все файлы 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, что слишком много.


person Forivin    schedule 12.07.2019    source источник
comment
Вы можете использовать параллельный инструмент gnu: gnu.org/software/parallel   -  person Olivier Darrouzet    schedule 12.07.2019
comment
поищите здесь [bash] xargs и прочитайте несколько ответов. xargs уже должен быть в вашей системе, тогда как вам, скорее всего, придется установить gnuparallel. Удачи.   -  person shellter    schedule 12.07.2019


Ответы (1)


Что-то вроде этого:

#!/bin/bash

SOURCE_DIR="/home/fedora/audiodata_flac"
TARGET_DIR="/home/fedora/audiodata_mp3"
export SOURCE_DIR
export TARGET_DIR

doone() {
    flacFile="$1"
    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
person Ole Tange    schedule 13.07.2019
comment
добавить добавить опцию -0 (или --null): parallel -0 doone - person Wiimm; 13.07.2019
comment
Спасибо за ответ, можете ли вы сказать мне, сколько параллельных экземпляров будет создано вашим кодом? - person Forivin; 14.07.2019