Qual é uma maneira eficiente de fazer um crossfade de vídeo com o FFmpeg?

11

Fazer um crossfade entre duas partes do conteúdo de vídeo é realmente bastante complicado no FFmpeg. Não há filtro "crossfade" como existe para o áudio.

Qual é uma maneira eficiente de fazer isso?

Mark Gerolimatos
fonte
Boa pergunta auto-respondida!
JakeGould
Esta resposta precisa ficar muito mais upvotes ... Mark, eu amo tanto você para sempre se você adicionou cross-fading para o áudio também ...
Merc
Assim que eu descobrir como, vou adicioná-lo. Eu acho que o crossfade de áudio é fácil, acredito que existe um filtro simples para isso.
Mark Gerolimatos
Eu simplesmente adicionei [0:a][1:a] acrossfade=d=1 [audio]ao filtro e depois -map "[audio]" ao comando e funcionou. Se quiser, faça um teste e atualize a resposta!
Merc
Possível duplicado de crossfade entre 2 vídeos usando ffmpeg
r_alex_hall

Respostas:

17

Versão TL; DR:

Este exemplo executa apenas vídeo, assumindo que os dois clipes de vídeo tenham a mesma resolução, taxa de quadros etc. Isso criará um desvanecimento de 1 segundo entre fadeoutclip e fadeinclip. Suponha que o fadeoutclip tenha 10 segundos de duração. Observe que isso está formatado para maior clareza: é realmente uma linha de código.

ffmpeg -i fadeoutclip.mp4 -i fadeinclip.mp4 -an \
-filter_complex "\
    [0:v]trim=start=0:end=9,setpts=PTS-STARTPTS[firstclip]; \
    [1:v]trim=start=1,setpts=PTS-STARTPTS[secondclip]; \
    [0:v]trim=start=9:end=10,setpts=PTS-STARTPTS[fadeoutsrc]; \
    [1:v]trim=start=0:end=1,setpts=PTS-STARTPTS[fadeinsrc]; \
    [fadeinsrc]format=pix_fmts=yuva420p, \
                fade=t=in:st=0:d=1:alpha=1[fadein]; \
    [fadeoutsrc]format=pix_fmts=yuva420p, \
                fade=t=out:st=0:d=1:alpha=1[fadeout]; \
    [fadein]fifo[fadeinfifo]; \
    [fadeout]fifo[fadeoutfifo]; \
    [fadeoutfifo][fadeinfifo]overlay[crossfade]; \
    [firstclip][crossfade][secondclip]concat=n=3[output] \
    " \
-map "[output]" <add in encoding part here>

Versão completa:

Aqui está uma explicação do que se tratava:

Especificação de entrada ... óbvio

ffmpeg -i fadeoutclip.mp4 -i fadeinclip.mp4 -an

Criando um filter_complex: supondo que você já entenda os complexos de filtro:

-filter_complex

Primeiro, dividimos os dois fluxos em dois pedaços, cada um usando o filtro de compensação : o conteúdo e a seção de desbotamento cruzado. O desbotamento é dividido em seção de conteúdo e desbotamento, enquanto o desbotamento é cortado na seção e no conteúdo de desbotamento. Total de quatro seções.

Observe que, estritamente falando, não precisamos quebrar as seções de desbotamento cruzado: podemos especificar o desbotamento e o desbotamento nos tempos dos dois videoclipes. No entanto, ao fazer isso, nós:

  • Siga a metodologia normalmente usada pelos editores de vídeo da GUI
  • Evite a complexidade frustrante overlaydo uso do filtro
  • Certifique-se de que a solução seja o mais genérica possível (código reutilizável)
  • Permita-nos pré-processar e pós-processar a seção de crossfade conforme necessário (não feito aqui)

Cada uma dessas quatro seções especifica: hora de início (segundos), hora de término (segundos) e o setpts=PTS-STARTPTSfiltro misterioso , que basicamente faz com que cada subclipe de vídeo inicie em 0 segundos. Isso será vital ao recompô-los.

Observe que os s=0especificadores são redundantes e o setptsfiltro para esses s=0TAMBÉM é redundante. No entanto, ambos são especificados de forma redundante para permitir que a hora de início seja alterada de 0, sem interromper o complexo do filtro. Além disso, o segundo clipe de conteúdo é executado até o final, portanto a e=parte (end =) não é especificada.

    [0:v]trim=s=0:e=9,setpts=PTS-STARTPTS[firstclip];
    [1:v]trim=s=1,setpts=PTS-STARTPTS[secondclip];
    [0:v]trim=s=9:e=10,setpts=PTS-STARTPTS[fadeoutsrc];
    [1:v]trim=s=0:e=1,setpts=PTS-STARTPTS[fadeinsrc];

Em seguida, especificamos o desbotamento e desbotamento: primeiro adicionamos um canal alfa (transparência) às duas seções de desbotamento, especificando um formato de pixel deyuva420p . Você pode realmente usar qualquer formato que forneça um canal alfa.

Em seguida neste filtro subcomplexo temos de especificar um para fade out, e um para fade in. Os alpha=1meios que o vídeo em si não vai escurecer, apenas a quantidade transparência "fade". stsignifica começar, dsignifica duração.

    [fadeinsrc]format=pix_fmts=yuva420p,      
                fade=t=in:st=0:d=1:alpha=1[fadein];
    [fadeoutsrc]format=pix_fmts=yuva420p,
                fade=t=out:st=0:d=1:alpha=1[fadeout];

O que é isso ?: O fifofiltro garante que haja espaço no buffer disponível no complexo de filtros. Surpreendentemente, esse NÃO é o padrão. Se você não fizer isso, o crossfade poderá falhar se a saída do estágio acima substituir o filtro de sobreposição abaixo. Sim, eu sei o que você está pensando agora. É realmente um bug do FFMPEG .

    [fadein]fifo[fadeinfifo];
    [fadeout]fifo[fadeoutfifo];

Agora, sobreponha as duas seções de desvanecimento: Ao garantir que as duas seções de desvanecimento cruzado sejam do mesmo tamanho, não precisamos nos preocupar com as opções bastante desagradáveis ​​que o filtro de sobreposição utiliza (e, portanto, as ignoramos aqui):

    [fadeoutfifo][fadeinfifo]overlay[crossfade];

Finalmente, alinhamos nossos três segmentos usando o filtro concat .

    [firstclip][crossfade][secondclip]concat=n=3[output]

E agora, mapeie o painel de saída como sua fonte de vídeo.

NÃO SE ESQUEÇA de definir o formato de pixel PARA O QUE VOCÊ NORMALMENTE usa (normalmente yuv420p), pois a seção de crossfade o definirá yuv420no canal de saída! (como não o especificamos, você pode usar os argumentos de sobreposição) Obviamente, se você QUER yuv420, então está bem :-)

-map "[output]" <add your normal encoding part here>

Você pode recombinar o áudio posteriormente (fora do escopo das perguntas e respostas)

Mark Gerolimatos
fonte
1
No ultimo ffmpeg, ele precisa ser trim=start=0:end=9(em vez de trim=st=0:e=9,..
15/12/15
Mas, falando sério, essa terá que ser a melhor resposta no FFMPEG que eu já vi e a explicação mais clara do ffmpeg de todos os tempos.
Merc
Cara, isso vai subir na minha cabeça :-) Obrigado pelos adereços !!!!
Mark Gerolimatos
Não se preocupe. Atualize a resposta especialmente com = trim = start = 0, pois agora ele não funciona com o ffmpeg mais recente
Merc
A versão mais recente do ffmpeg me dá este erro: Filter setpts has an unconnected outputpara o script. Eu já mudei os parâmetros de corte para começar e terminar.