Сценарий Bash для запуска FFmpeg concat для файлов MP4 пакетами по 5

Мне нравится создавать сценарий Bash для объединения файлов MP4 с помощью FFmpeg партиями по 5 файлов за раз для каталога с 100 файлов MP4, так что после этого будет 20 файлов, например:

001_005.mp4, 006_010.mp4, и так далее ...

вместо одного файла, состоящего из всех 100 файлов.

Содержание mylist.txt:

file 001.mp4
file 002.mp4
file 003.mp4
file 004.mp4
file 005.mp4
............
file 099.mp4
file 100.mp4

Хотя я нашел команду, которая отлично работает ( из этого потока StackOverflow ), она создаст только 1 файл, содержащий все 100 файлов.

#!/bin/bash

cd /home/admn/Downloads/MP4_Files;

# Create mylist.txt:
for f in *.mp4
do
    echo "file $f" >> mylist.txt
done;

# Concatenate files:
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4;

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

Все файлы имеют одинаковое разрешение (1080p), аудио- и видеокодеки.

ОС: Ubuntu MATE 21.04

версия ffmpeg: 4.3.2-0 + deb11u1ubuntu1

3
задан 4 June 2021 в 21:24

3 ответа

Я думаю, что следующий сценарий сработает.

  • Сначала попробуйте его как есть и проверьте, что он делает то, что вы хотите
  • Затем удалите echo из строки с ffmpeg, чтобы заставить его делать свое дело.

Проверьте, что содержимое временных файлов xaa' ... xat` совпадает с именами (и содержимым) выходных файлов.

#!/bin/bash

> mylist.txt
for f in *.mp4
do
 echo "file '$f'" >> mylist.txt
done

< mylist.txt sort -t \' -n -k2 | split -l 5

k=1
for j in x*
do
 inc=$(wc -l "$j" | cut -d ' ' -f 1)
 m=$(printf "%03d" $((k)))
 n=$(printf "%03d" $((k+inc-1)))
 name="${m}_${n}.mp4"
 echo ffmpeg -f concat -safe 0 -i "$j" -c copy "$name"
 k=$((k+5))
done
3
ответ дан 28 July 2021 в 11:32

Предполагая, что mylist.txt существует в вашем текущем рабочем каталоге, вы можете сделать что-то вроде этого,

LINES=$(cat mylist.txt | wc -l)
BATCH_SIZE=5
BATCHES=$(($LINES/$BATCH_SIZE))             

for ((i=0;i<$BATCHES;i++))
do
  cat mylist.txt | head -n $((($i+1)*$BATCH_SIZE)) | tail -n $BATCH_SIZE > slist.txt
  ffmpeg -f concat -safe 0 -i slist.txt -c copy $(($i*$BATCH_SIZE+1))_$((($i+1)*$BATCH_SIZE)).mp4
done
rm slist.txt
0
ответ дан 28 July 2021 в 11:32

Другое решение - использовать вложенные циклы.

Пока остаются файлы, внутренний цикл использует $ {@: 1: 5} , чтобы взять следующий фрагмент (до) 5 файлов.

#!/bin/bash
cd /home/admn/Downloads/MP4_Files;

shopt -s failglob
set -- *.mp4
while [[ $# -gt 0 ]]; do
    from=$(basename "$1" .mp4)
    for f in "${@:1:5}"; do
        #not essential in your case, but use @Q to quote/escape special characters
        echo "file ${f@Q}" >> mylist.txt
        shift
    done
    to=$(basename "$f" .mp4)
    ffmpeg -f concat -safe 0 -i mylist.txt -c copy "${from}_${to}.mp4"
    rm mylist.txt
done
1
ответ дан 28 July 2021 в 11:32

Другие вопросы по тегам:

Похожие вопросы: