Задача вытащить звук из видео с youtube и разбить на файлы, продолжительностью несколько минут. Решаться данная задача будет с помощью ffmpeg (будет применяться установка в Docker контейнер для того чтобы использовать готовый скрипт разбивки файла).
Автоматизированное разбитие файла
- Скачать видео используя savefrom.net (в примерах ниже файл сохраняется с именем sample.avi)
- Установить в Docker контейнер ffmpeg (инструкция указана для Dockerfile)
RUN apt-get install -y ffmpeg
- Переместить файл с скаченным видео в папку, которая будет видна в контейнере
- Запустить контейнер
- Войти в контейнер
- Перейти в папку с видео
- Извлечь звук, выполнив:
ffmpeg -i sample.avi -q:a 0 -map a sample.mp3
- Сохранить скрипт в папку с видео (например в файл split):
#!/bin/bash # Written by Alexis Bezverkhyy <alexis@grapsus.net> in 2011 # This is free and unencumbered software released into the public domain. # For more information, please refer to <http://unlicense.org/> function usage { echo "Usage : ffsplit.sh input.file chunk-duration [output-filename-format]" echo -e "\t - input file may be any kind of file reconginzed by ffmpeg" echo -e "\t - chunk duration must be in seconds" echo -e "\t - output filename format must be printf-like, for example myvideo-part-%04d.avi" echo -e "\t - if no output filename format is given, it will be computed\ automatically from input filename" } IN_FILE="$1" OUT_FILE_FORMAT="$3" typeset -i CHUNK_LEN CHUNK_LEN="$2" DURATION_HMS=$(ffmpeg -i "$IN_FILE" 2>&1 | grep Duration | cut -f 4 -d ' ') DURATION_H=$(echo "$DURATION_HMS" | cut -d ':' -f 1) DURATION_M=$(echo "$DURATION_HMS" | cut -d ':' -f 2) DURATION_S=$(echo "$DURATION_HMS" | cut -d ':' -f 3 | cut -d '.' -f 1) # fix error DURATION_H=${DURATION_H#0} DURATION_M=${DURATION_M#0} DURATION_S=${DURATION_S#0} let "DURATION = ( DURATION_H * 60 + DURATION_M ) * 60 + DURATION_S" if [ "$DURATION" = '0' ] ; then echo "Invalid input video" usage exit 1 fi if [ "$CHUNK_LEN" = "0" ] ; then echo "Invalid chunk size" usage exit 2 fi if [ -z "$OUT_FILE_FORMAT" ] ; then FILE_EXT=$(echo "$IN_FILE" | sed 's/^.*\.\([a-zA-Z0-9]\+\)$/\1/') FILE_NAME=$(echo "$IN_FILE" | sed 's/^\(.*\)\.[a-zA-Z0-9]\+$/\1/') OUT_FILE_FORMAT="${FILE_NAME}-%03d.${FILE_EXT}" echo "Using default output file format : $OUT_FILE_FORMAT" fi N='1' OFFSET='0' let 'N_FILES = DURATION / CHUNK_LEN + 1' while [ "$OFFSET" -lt "$DURATION" ] ; do OUT_FILE=$(printf "$OUT_FILE_FORMAT" "$N") echo "writing $OUT_FILE ($N/$N_FILES)..." ffmpeg -i "$IN_FILE" -vcodec copy -acodec copy -ss "$OFFSET" -t "$CHUNK_LEN" "$OUT_FILE" let "N = N + 1" let "OFFSET = OFFSET + CHUNK_LEN" done
При копирование скрипта в Windows необходимо преобразовать символы переноса из CRLF (окончания строк в Windows) в LF (окончания строк в Unix). Сделать это можно в Nodepad++ (Правка -> Формат Конца Строк -> Преобразовать в UNIX-формат (LF)).
- Запустить скрипт в контейнере:
./split sample.mp3 300 sample_%04d.mp3
Эта позволит получить множество файлов вида sample_00XX.mp3, продолжительностью 300 секунд.
Ручное разбитие файла
В случае отсутствия возможности воспользоваться контейнером либо работе в Windows, можно воспользоваться ручным разбиением файлов:
ffmpeg -ss 0 -t 300 -i sample.mp3 sample_0001.mp3
В указанной команде параметры означают:
-ss 0 — Начать с 0 секунды
-t 300 — Продолжительность 30 секунд от места начала
Автоматизация извлечения звука и разбития на части
Для объединения действий по извлечению звука из видео и разбитию на части с сохранением результата в папке с именем входного файла предназначен скрипт audio.sh:
#!/bin/bash if [ $# -ne 1 ] then echo "Usage: '$0' audio source file" exit fi sourceFile=$1 targetName=`expr match "$1" '\(.*\)\.'` audioFileName=${targetName}.mp3 echo ${sourceFile} echo ${audioFileName} ffmpeg -i $sourceFile -q:a 0 -map a $audioFileName mkdir $targetName ./split ${audioFileName} 300 ${targetName}/$targetName%04d.mp3 rm ${audioFileName}
Пример использования:
./audio.sh video.mp4
В результате работы будет создана папка video, содержащая набор звуковых файлов.
Множественное разбитие файлов на составные части
Для последовательного разбития нескольких файлов можно воспользоваться скриптом (group.sh):
#!/bin/bash ./audio.sh file1.mp4 rm file1.mp4 ./audio.sh file2.mp4 rm file2.mp4
Можно воспользоваться скриптом (split-all.sh), который автоматически найдет файлы *.mp4 и разобьет их на части (после разбиения исходные файлы удаляются):
#!/bin/bash for file in `find -name "*.mp4"` do ./audio.sh $file rm $file done
Устранение ошибок при запуске bash скриптов
Если не удается запустить bash скрипты приведенные выше, рекомендуется ознакомиться с методом, описанным тут.