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

10

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

Qual é uma maneira eficiente de fazer isso?

    
por Mark Gerolimatos 15.11.2015 / 23:47

1 resposta

16

TL; versão DR:

Este exemplo executa somente vídeo, presumindo 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. Note que isto é 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>

"Que diabos?" Versão:

Aqui está uma explicação sobre o assunto:

Especificação de entrada ... óbvia

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

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

-filter_complex

Primeiro, dividimos os dois fluxos em duas partes usando o filtro de recorte : o conteúdo e a seção de cross fade. O fade out é dividido em conteúdo e fade section, enquanto o fade in é cortado na seção de fade e conteúdo. Total de quatro seções.

Note que, estritamente falando, nós não temos para quebrar as seções cross fade: podemos simplesmente especificar o fade out e desaparecer em tempos para os dois clipes de vídeo. No entanto, ao fazer isso, nós:

  • siga a metodologia normalmente usada pelos editores de vídeo da GUI
  • evite a complexidade frustrante do uso do filtro overlay
  • garantir que a solução seja a mais geral possível (por exemplo, código reutilizável)
  • nos permitem 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: horário de início (segundos), horário de término (segundos) e o misterioso setpts=PTS-STARTPTS filter , que basicamente faz com que cada subclipe de vídeo comece em 0 segundos. Isso será vital ao recompô-los.

Observe que os especificadores s=0 são redundantes e o filtro setpts para os s=0 é ALTERAMENTE redundante. No entanto, ambos são especificados de forma redundante para permitir que a hora de início seja alterada de 0 sem quebrar o complexo do filtro. Além disso, o segundo clipe de conteúdo é executado até o final, portanto, e= part (end =) não é especificado.

    [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 aparecimento e desaparecimento gradual: Primeiramente, adicionamos um canal alfa (transparência) a ambas as seções de atenuação por especificando um formato de pixel de yuva420p . Você pode realmente usar qualquer formato que forneça um canal alfa.

A seguir, neste subcomplexo de filtros, especificamos um para desaparecer e outro para desaparecer. O alpha=1 significa que o vídeo em si não escurecerá, apenas a quantidade de transparência "desaparecerá". st significa início, d significa 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 filtro fifo garante que haja espaço de buffer disponível no complexo de filtros. Surpreendentemente, este NÃO é o padrão. Se você não fizer isso, o crossfade poderá falhar se a saída do estágio acima exceder o filtro de sobreposição abaixo. Sim, eu sei o que você está pensando agora. Na verdade, é um bug do FFMPEG .

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

Agora, sobreponha as duas seções de fade: Certificando-se de que duas seções de crossfade são do mesmo tamanho, não precisamos nos preocupar com as opções mais desagradáveis que o filtro de sobreposição exige (e assim nós os ignoramos aqui):

    [fadeoutfifo][fadeinfifo]overlay[crossfade];

Por fim, alinhamos nossos três segmentos usando o filtro de concat .

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

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

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

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

Você pode recombinar o áudio posteriormente (fora do escopo deste Q & A)

    
por 15.11.2015 / 23:47