Кодирование видео, последовательно, входной файл = данные предыдущего потока

ffmpeg -i /file.mp4 -deadline good -movflags +frag_keyframe -map_metadata -1                                        
-c:a libopus -c:v libvpx-vp9 -row-mt 1 -frame-parallel 1 -pix_fmt yuv420p                             
-map 0:a:0 -b:a:0 128k  
-map 0:v:0 -filter:v:0 scale=-1:144 -r 30 -b:v:0 60k 
-map 0:v:0 -filter:v:1 scale=-1:240 -r 40 -b:v:1 150k
-map 0:v:0 -filter:v:2 scale=-1:360 -r 50 -b:v:2 276k                                          
-init_seg_name "init-$RepresentationID$.$ext$"                    
-media_seg_name "sg-$RepresentationID$-$Number%05d$.$ext$"                                         
-dash_segment_type webm                                         
-use_template 1 -use_timeline 1 -seg_duration 9                               
-adaptation_sets "id=0, streams=v id=1, streams=a"                                       
-f dash /video/manifest.mpd

Берем входноe видео с размером кадра 360px, создаем 3 потока качества 144,240,360.

Ок, работает.

Как я понимаю, данный код, работает следующим образом.

Для каждого потока берет входной файл

/file.mp4 -> 144
/file.mp4 -> 240
/file.mp4 -> 360

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

В таком случаи, потребуется изменить порядок, не от меньшего к большему, а от большего разрешения к меньшему. Но как сделать, чтобы для кодирования последующего пока, данные брались из предбудущего?

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

/file.mp4 -> 360
360 -> 240
240 -> 144

Если входное видео имеет высоту 240, будет лишним преобразовывать видео в 360, стартовое разрешение будет 240.

Как быть в таком случаи, чтобы исключить поток 360? Каждый раз писать подобный код, исключая по одному потоку, делая проверку по высоте, весьма накладно и пугает...

Попытался так:

f"""ffmpeg -i /uploads/test.mp4 -deadline good -movflags +frag_keyframe -map_metadata -1 \
-map 0:a:0 -c:a libopus -b:a 128k \
-c:v libvpx-vp9 -speed 2 -tile-columns 2 -frame-parallel 1 -pix_fmt yuv420p \
-filter_complex \
"[0:v:0]scale='if(gte(ih,2160),-1,iw)':'if(gte(ih,2160),2160,ih)'[v2160]; \
 [v2160]scale='if(gte(ih,1440),-1,iw)':'if(gte(ih,1440),1440,ih)'[v1440]; \
 [v1440]scale='if(gte(ih,1080),-1,iw)':'if(gte(ih,1080),1080,ih)'[v1080]; \
 [v1080]scale='if(gte(ih,720),-1,iw)':'if(gte(ih,720),720,ih)'[v720]; \
 [v720]scale='if(gte(ih,480),-1,iw)':'if(gte(ih,480),480,ih)'[v480]; \
 [v480]scale='if(gte(ih,360),-1,iw)':'if(gte(ih,360),360,ih)'[v360]; \
 [v360]scale='if(gte(ih,240),-1,iw)':'if(gte(ih,240),240,ih)'[v240]; \
 [v240]scale='if(gte(ih,144),-1,iw)':'if(gte(ih,144),144,ih)'[v144]" \
-map "[v2160]" -b:v:0 8000k -minrate:v:0 6000k -maxrate:v:0 10000k -bufsize:v:0 16000k -r:v:0 30 \
-map "[v1440]" -b:v:1 6000k -minrate:v:1 4500k -maxrate:v:1 7500k -bufsize:v:1 12000k -r:v:1 30 \
-map "[v1080]" -b:v:2 4000k -minrate:v:2 3000k -maxrate:v:2 5000k -bufsize:v:2 8000k -r:v:2 30 \
-map "[v720]" -b:v:3 2500k -minrate:v:3 2000k -maxrate:v:3 3000k -bufsize:v:3 5000k -r:v:3 30 \
-map "[v480]" -b:v:4 1500k -minrate:v:4 1200k -maxrate:v:4 2000k -bufsize:v:4 4000k -r:v:4 25 \
-map "[v360]" -b:v:5 1000k -minrate:v:5 800k -maxrate:v:5 1500k -bufsize:v:5 3000k -r:v:5 25 \
-map "[v240]" -b:v:6 600k -minrate:v:6 500k -maxrate:v:6 800k -bufsize:v:6 1600k -r:v:6 25 \
-map "[v144]" -b:v:7 400k -minrate:v:7 300k -maxrate:v:7 600k -bufsize:v:7 1200k -r:v:7 25 \
-init_seg_name "init-\$RepresentationID\$\.\$ext\$" \
-media_seg_name "sg-\$RepresentationID\$\-\$Number%05d\$\.\$ext\$" \
-dash_segment_type webm \
-use_template 1 -use_timeline 1 -seg_duration 9 \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
-f dash /manifest.mpd"""

В ответе ошибка

[out#0/dash @ 0x8456ed0] Output with label 'v2160' does not exist in any defined filter graph, or was already used elsewhere.
Error opening output file /manifest.mpd.
Error opening output files: Invalid argument

Мол не существует поток, пробовал множество вариантов команды, все одна и таже ошибка.


Ответы (1 шт):

Автор решения: Intelligent Shade of Blue

Это не полный ответ, но возможно даст вам необходимый толчек... Вы можете использовать -filter_complex:

ffmpeg -i earth.mp4 -filter_complex "
    [0:v]scale=-1:360,split=2[u360][v360];
    [u360]scale=-1:240,split=2[u240][v240];
    [u240]scale=-1:144[v144]" \
-map "[v360]" -c:v h264 v360.mkv \
-map "[v240]" -c:v h264 v240.mkv \
-map "[v144]" -c:v h264 v144.mkv

Принцип работы: Берем изначальный поток и уменьшаем его до высоты 360 пикс (u360). Делаем две копии (t360 and v360). Одна будет использоваться кодеком. Вторую уменьшаем до 240 пикс (t240). Делаем две копии (u240 and v240). И т.д.

UPDATE:

Чтобы селективно выбирать потоки в зависимости от разрешения входного файла, я бы сделал что-то вроде такого:

#!/bin/bash

codec=(
    -i "$1"
    -deadline good -movflags +frag_keyframe -map_metadata -1
    -c:a libopus -b:a 128k -map a:0
    -c:v libvpx-vp9 -speed 2 -tile-columns 2 -frame-parallel 1 -pix_fmt yuv420p
)
stream=(
    ["2160"]="-b:v:X 8000k -minrate:v:X 6000k -maxrate:v:X 10000k -bufsize:v:X 16000k -r:v:X 30"
    ["1440"]="-b:v:X 6000k -minrate:v:X 4500k -maxrate:v:X  7500k -bufsize:v:X 12000k -r:v:X 30"
    ["1080"]="-b:v:X 4000k -minrate:v:X 3000k -maxrate:v:X  5000k -bufsize:v:X  8000k -r:v:X 30"
     ["720"]="-b:v:X 2500k -minrate:v:X 2000k -maxrate:v:X  3000k -bufsize:v:X  5000k -r:v:X 30"
     ["480"]="-b:v:X 1500k -minrate:v:X 1200k -maxrate:v:X  2000k -bufsize:v:X  4000k -r:v:X 25"
     ["360"]="-b:v:X 1000k -minrate:v:X  800k -maxrate:v:X  1500k -bufsize:v:X  3000k -r:v:X 25"
     ["240"]="-b:v:X  600k -minrate:v:X  500k -maxrate:v:X   800k -bufsize:v:X  1600k -r:v:X 25"
     ["144"]="-b:v:X  400k -minrate:v:X  300k -maxrate:v:X   600k -bufsize:v:X  1200k -r:v:X 25"
)
output=(
    -init_seg_name 'init-$RepresentationID$.$ext$'
    -media_seg_name 'sg-$RepresentationID$-$Number%05d$.$ext$'
    -dash_segment_type webm
    -use_template 1 -use_timeline 1 -seg_duration 9
    -adaptation_sets "id=0,streams=v id=1,streams=a"
    -f dash manifest.mpd
)

# stream heights sorted numerically in reverse order
hh=$(printf "%s\n" ${!stream[@]} | sort -rn)
# input file height
ih=$(ffprobe -of flat -select_streams v:0 -show_entries stream=height "$1" 2>/dev/null | cut -d= -f2)

filter=
param=()

n=0 # stream index
s="0:v:0"
for h in $hh; do
    ((h > ih)) && continue

    filter+="[$s]scale=-1:$h,split[u$h][v$h];"
    param+=(-map "[v$h]" `echo ${stream[$h]} | sed "s/X/$n/g"`)
    s="u$h"
    ((n++))
done
# remove last split, as it's not needed
filter=$(echo $filter | sed "s/,split\[$s\]//")

ffmpeg -i "$1" "${codec[@]}" -filter_complex "$filter" "${param[@]}" "${output[@]}"

Я думаю код довольно само-объясним, поэтому представляю как есть.

→ Ссылка