FFmpeg mp4 to webm, сделать 10-секундную компиляцию на основе длины


1

Допустим, у меня есть input.mp412 минут. Я хотел бы взять 4 раза 2,5 секунды от входа в один файл, output.webm.

Итак, сначала 2,5 секунды на отметке 2,5 минуты, вторые 2,5 секунды на отметке 5 минут, затем то же самое на отметке 7,5 секунды и, наконец, последние 2,5 секунды на отметке 10 минут. Затем выведите все это в один output.webmфайл.

И если это возможно, возможно ли это так, чтобы при input.mp4изменении длины я получал эти 4 части из расчета на длину вместо того, чтобы они всегда были стандартными 2,5, 5, 7,5 и 10?

Ответы:


1

Создание клипа для компиляции на основе фрагментов видео с использованием ffmpeg

Обратите внимание, что следующее основано на ответе ptQa с изменениями, поэтому он заслуживает одобрения, если этот ответ полезен.

Следующее fffmpegзаклинание даст вам 10 секунд VP8 webm с разрезами на отметке 2,5,5 7,5 и 10 минут:

ffmpeg -hide_banner -i "input.mp4" -filter_complex " \
[0:v]trim=start=150:duration=2.5,setpts=PTS-STARTPTS[av];\
[0:a]atrim=start=150:duration=2.5,asetpts=PTS-STARTPTS[aa];\
[0:v]trim=start=300:duration=2.5,setpts=PTS-STARTPTS[bv];\
[0:a]atrim=start=300:duration=2.5,asetpts=PTS-STARTPTS[ba];\
[0:v]trim=start=450:duration=2.5,setpts=PTS-STARTPTS[cv];\
[0:a]atrim=start=450:duration=2.5,asetpts=PTS-STARTPTS[ca];\
[0:v]trim=start=900:duration=2.5,setpts=PTS-STARTPTS[dv];\
[0:a]atrim=start=900:duration=2.5,asetpts=PTS-STARTPTS[da];\
[av][aa][bv][ba][cv][ca][dv][da]concat=n=4:v=1:a=1[outv][outa]" \
-map [outv] -map [outa] -c:v libvpx -crf 10 -b:v 1M -c:a libvorbis  out.webm

Это делает четыре использования каждым из аккуратных и atrim фильтров, и , наконец , объединяет подклипы с помощью Concat фильтра.

Параметры кодирования - это то, что предлагается в руководстве по libvpxкодированию из вики FFmpeg .

Бонус: переменная отделка в зависимости от длины ввода

Это выполнимо с небольшим количеством сценариев, используя, ffprobeчтобы получить продолжительность, например:

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4

Это возвращает длину клипа в секундах, которая может быть разделена на 5, а затем умножена на 1, 2, 3 и 4, чтобы получить позиции четырех одинаково расположенных отрезков соответственно.

Обратите внимание на производительность

Хотя создание клипа таким способом является аккуратным в том смысле, что оно точно вырезает вложенные клипы из входного видео, оно медленное .

Более быстрый подход заключается в использовании поиска ввода и потоковой копии для создания вложенных клипов, прежде чем объединять их вместе и кодировать.

Тем не менее, если вам нужна точная продолжительность или производительность не является проблемой, использование нескольких trimфильтров будет хорошо работать.

Скрипт для генерации клипа trimдля любой длины ввода и любого количества срезов / субклипов

#!/bin/bash
# clip.sh - create a clip of short sequences of a passed-in media file
# takes one argument, the input file
# can customise number of cuts, total length of clip
# clips will be evenly-spaced in input file

SUBCLIPS=4 # number of clips to make up clip
OUTPUTLENGTH=10 # output file length, in seconds
OUTPUTFILE=out.webm # name

cliplength=$(echo "$OUTPUTLENGTH/$SUBCLIPS"| bc -l)

if [ -e "$1" ]; then
        videofile="$1"
else
        echo "file not found: $1"
        exit 1
fi

ffmpeg_preamble="ffmpeg -hide_banner -i '$videofile' -filter_complex \""

duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$videofile")

cutfilters=""
concatfilter=""

for cutno in $( seq 1 $SUBCLIPS ); do
    cut=$(echo "(1 / ($SUBCLIPS+1)) * $cutno" | bc -l)
    let cutchar=$cutno+96 # ascii value so we get max 26 cuts rather than 10
    cutletter=$(printf "\x$(printf %x $cutchar)")
    cutpos=$(echo "$duration * $cut" |bc)
    cutfilters=$(printf "%s[0:v]trim=start=%f:duration=%f,setpts=PTS-STARTPTS[%sv];" "$cutfilters" "$cutpos" "$cliplength" "$cutletter")
    cutfilters=$(printf "%s[0:a]atrim=start=%f:duration=%f,asetpts=PTS-STARTPTS[%sa];" "$cutfilters" "$cutpos" "$cliplength" "$cutletter")
    concatfilter=$(printf "%s[%sv][%sa]" "$concatfilter" "$cutletter" "$cutletter")
done

# concat the cuts together

concatfilter=$(printf "%sconcat=n=%s:v=1:a=1[outv][outa]" "$concatfilter" "$SUBCLIPS")

ffmpeg_webmopts=" -c:v libvpx -crf 10 -b:v 1M -c:a libvorbis "
ffmpeg_postscript="\" -map [outv] -map [outa] $ffmpeg_webmopts '$OUTPUTFILE'"

# Chance to cancel before we start

printf "***(hit ctrl+c to cancel)***\n\nExecuting: %s%s%s%s\n" "$ffmpeg_preamble" "$cutfilters" "$concatfilter" "$ffmpeg_postscript"
sleep 3
eval $(echo "$ffmpeg_preamble $cutfilters $concatfilter $ffmpeg_postscript")

Я написал сценарий для автоматизации бонусной части, после того, как она будет приведена в порядок, я отредактирую этот ответ, чтобы включить его
bertieb

Спасибо! Понял с этим :). Взял продолжительность с помощью ffprobe, затем просто добавил переменные плюс вычислил время (делая это с помощью php). Работает отлично, большое спасибо еще раз!
EmJeiEn

Рад помочь, это было интересное упражнение для меня - я не написал сценарий для создания графа фильтра! Если вы делаете это в php, а производительность более критична, чем точная продолжительность, вы можете подумать об использовании поиска и временных файлов для вырезания + объединения (но это, вероятно, отдельный вопрос)
bertieb

Я определенно рассмотрю это в этом случае, да, производительность действительно важна для меня. Это работает как мечта, но для этого требуется время, чтобы работать даже на мощном сервере.
EmJeiEn

Согласитесь, это займет довольно много времени. В этом случае я могу проверить поиск + потоковое копирование вложенных клипов и затем перекодирование. Если это приведет к заметной разнице, я
напишу
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.