Como posso ajustar um vídeo para um determinado tamanho, mas não o aprimore com o FFmpeg?

13

Preciso ajustar os vídeos para 640x360 (o máximo que o player do meu telefone aguenta), preservando a proporção , mas também quero que o vídeo seja inalterado se for menor que 640x360 (não faz sentido aumentar a escala depois de tudo).

Existe uma maneira de obter esse comportamento usando a linha de comando do ffmpeg?

sashoalm
fonte
Eu não acho que isso possa ser feito apenas no ffmpeg, mas se você estiver disposto a criar um script, isso definitivamente pode ser feito.
evilsoup
Eu já o escrevi, mas queria limpar meu código, caso não seja necessário.
sashoalm
Provavelmente é possível com um filtro de escala que usa funções como, min(…)mas definitivamente mais fácil, com um script simples que analisa as dimensões. Veja meu comando aqui para obter um exemplo do que pode ser feito: superuser.com/questions/547296/…
slhck 16/13

Respostas:

9

Com as versões mais recentes do ffmpeg, você pode usar a opção scaledo filtro force_original_aspect_ratio. Por exemplo, para ajustar um vídeo em 1280 × 720, sem upscaling (consulte esta postagem para mais informações):

ffmpeg -i input.mp4 -filter:v "scale='min(1280,iw)':min'(720,ih)':force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4

Aqui, o scalefiltro é escalado para 1280 × 720 se o vídeo de entrada for maior que isso. Se for menor, não será aumentado. O padfiltro é necessário para levar a saída de vídeo para 1280 × 720, caso sua proporção ou tamanho seja diferente do tamanho de destino.


Nas versões mais antigas do ffmpeg, há uma solução alternativa para hackers. Primeiro, defina a largura, altura e proporção da sua saída. Isso nos poupará digitando.

width=640; height=360
aspect=$( bc <<< "scale=3; $width / $height") # <= floating point division

Agora, vamos aplicar o comando de filtro super complexo que Jim Worrall escreveu :

ffmpeg -i input.mp4 -vf "scale = min(1\,gt(iw\,$width)+gt(ih\,$height)) * (gte(a\,$aspect)*$width + \
lt(a\,$aspect)*(($height*iw)/ih)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*iw : \
min(1\,gt(iw\,$width)+gt(ih\,$height)) * (lte(a\,$aspect)*$height + \
gt(a\,$aspect)*(($width*ih)/iw)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*ih" \
output.mp4

Eu realmente não vou explicar o que tudo isso faz, mas basicamente você pode alimentar qualquer vídeo, e ele só diminui a escala, não aumenta a escala. Se você quiser, pode dissecar o filtro em suas expressões individuais. Pode ser possível encurtar isso, mas funciona assim também.

slhck
fonte
11
+1, mas esse é um comando realmente horrível: P
evilsoup
Eu sei direito? Passei dez minutos tentando dividi-lo em partes lógicas e inserindo alguns valores, mas desisti. É um pouco velho e talvez seja possível escrevê-lo de forma muito mais concisa do que isso.
slhck
13

Uma versão mais legível pode ter a seguinte aparência:

-filter_complex "scale=iw*min(1\,min(640/iw\,360/ih)):-1"

640 / iw é o fator de escala horizontal e 360 ​​/ ih é o fator de escala vertical

Você deseja ajustar a imagem em escala dentro da caixa de saída e manter a proporção (armazenamento). Você faz isso selecionando o menor fator de escala com a função mínima: min (640 / iw, 360 / ih)

Você deseja impedir qualquer aumento de escala (ou seja, um fator de escala> 1,0) para adicionar outra função mínima: min (1, min (640 / iw, 360 / ih))

O próximo passo é calcular a resolução de saída multiplicando o fator de escala com a largura e a altura da entrada:
largura da saída = iw * min (1, min (640 / iw, 360 / ih))
altura da saída = ih * min (1, min (640 / iw, 360 / ih))

O último passo é construir o comando filter. Não há necessidade de especificar a altura da saída, você pode especificar -1 e o ffmpeg manterá a proporção, aplicando o mesmo fator de escala da largura.

immerzl
fonte
A + Funciona imediatamente. A solução da resposta selecionada não preservou a proporção. Apertou os quadros.
287352 07/07/19
5

Eu também tive o mesmo problema, mas resolvi ajustando o vídeo em um quadrado de 640x640 (por causa de vídeos verticais feitos com smartphones).

Então, usando a lógica immerzi e algumas pesquisas, acabo com isso:

-vf "scale=iw*min(1\,if(gt(iw\,ih)\,640/iw\,(640*sar)/ih)):(floor((ow/dar)/2))*2"

a última parte é para ter uma altura divisível por 2 que é necessária por muitos codificadores.

Shebuka
fonte