Eu tenho um script Bash que executa o FFmpeg em um determinado arquivo de vídeo e - junto com muitas outras coisas - adiciona uma marca d'água PNG usando uma sobreposição. Eu gostaria de poder aplicar a marca d'água apenas em alguns vídeos, ativando ou desativando-a por meio da entrada do usuário, mas a única maneira que conheço de fazer isso é ramificar condicionalmente dois comandos FFmpeg separados - um que adiciona uma marca d'água e um isso não.
Aqui estão os dois comandos para comparação.
Com marca d'água:
ffmpeg -y -i "$1" -i "outro.mp4" -loop 1 -i "../Watermark/watermark3.png" \
-movflags +faststart \
-preset ultrafast \
-filter_complex \
"color=black:16x16:d=$total[base]; \
[0:v]scale=-2:'max(1080,ih)',setpts=PTS-STARTPTS[v0]; \
[1:v]fade=in:st=0:d=$fadeduration:alpha=1,setpts=PTS-STARTPTS+(($fadetime)/TB)[v1]; \
[2:v]lut=a=val*0.7,fade=in:st=5:d=2:alpha=1,fade=out:st=$length1:d=2:alpha=1[v2]; \
[base][v0]scale2ref[base][v0]; \
[base][v0]overlay[tmp]; \
[tmp][v1]overlay,setsar=1[tmp2]; \
[v2][tmp2]scale2ref=w=oh*mdar:h=ih*0.1[wm_scaled][video]; \
[video][wm_scaled]overlay=W-w-50:50:format=auto:shortest=1[outv]; \
[0:a][1:a]acrossfade=d=$fadeduration[outa]" \
-map "[outv]" -map "[outa]" -c:v libx264 -c:a libopus -crf 17 "$output"
Sem marca d'água:
ffmpeg -y -i "$1" -i "outro.mp4" -loop 1 -i "../Watermark/watermark3.png" \
-movflags +faststart \
-preset ultrafast \
-filter_complex \
"color=black:16x16:d=$total[base]; \
[0:v]scale=-2:'max(1080,ih)',setpts=PTS-STARTPTS[v0]; \
[1:v]fade=in:st=0:d=$fadeduration:alpha=1,setpts=PTS-STARTPTS+(($fadetime)/TB)[v1]; \
[base][v0]scale2ref[base][v0]; \
[base][v0]overlay[tmp]; \
[tmp][v1]overlay,setsar=1[tmp2]; \
[tmp2]setsar=1[outv]; \
[0:a][1:a]acrossfade=d=$fadeduration[outa]" \
-map "[outv]" -map "[outa]" -c:v libx264 -c:a libopus -crf 17 "$output"
Isso não é o ideal porque exigiria que eu mantivesse dois comandos diferentes que são 90% idênticos, o que viola o princípio DRY e resulta em duas vezes a manutenção. Sem mencionar que eu também precisaria de outras duas permutações do comando toda vez que quisesse habilitar condicionalmente outro recurso da mesma maneira, portanto, não é à prova de futuro e muito propenso a se tornar um código espaguete rápido.
Existe algo no FFmpeg que me permita ativar/desativar condicionalmente um determinado filtro com base na entrada do usuário? Se não, qual é a melhor maneira de realizar algo assim?
Nos testes iniciais, pensei que isso seria bastante complicado, mas acabou sendo mais simples do que o esperado - pode ser tratado inteiramente no Bash, envolvendo cada fluxo que referencia o fluxo condicional em uma variável.
O verdadeiro problema - como pigeonburger adivinhou - está em cuidar de todas as referências ao stream, especialmente a final que dá saída ao vídeo: a variável deste stream precisa ter seu conteúdo definido condicionalmente, e no meu caso também envolve o uso de um "dummy " filtro como
setsar=1
para evitar um erro de fluxo vazio.Depois disso, a parte mais difícil é garantir que todos os rótulos de fluxo correspondam em ambas as condições - caso contrário, eles precisarão ser renomeados condicionalmente, assim como no fluxo final.
O exemplo abaixo pergunta ao usuário se ele deseja aplicar uma marca d'água ao vídeo: se algo diferente de
N
oun
for inserido, ele aplica a marca d'água definindo os fluxos necessários e executando o comando FFmpeg com eles.Embora provavelmente esteja longe de ser tão robusto ou sucinto quanto um programador Bash melhor do que eu possa fazer, é definitivamente mais sucinto e mais sustentável do que a alternativa de mexer com dois comandos separados.