Redimensionando vídeos com ffmpeg / avconv para caber no player de tamanho estático

65

Eu tenho um player de vídeo html 5 com 700px de largura e 400px de altura. Estou tentando avconvusar o ffmpeg para redimensionar (mantendo a proporção) e certificando-me de que ela se encaixa no meu player.

A entrada pode ser um arquivo de qualquer tamanho, por isso preciso redimensionar os maiores, mas centralizar os menores com barras pretas. Até agora, tentei: -se -aspectvi padser usado com o -vfswitch, mas não entendo como ele funciona o suficiente para obter o que eu preciso.

Imagens

Esta é uma idéia aproximada do que eu preciso. Não tenho certeza se é possível. É quase como a largura máxima / altura máxima do CSS. Sei que isso pode ser apenas um amontoado de palavras, mas se alguém entender o que estou falando, agradeceria ajuda, obrigado.

Comando avconv:

avconv -y -i control.avi -vcodec libx264 -b 2000k -bufsize 20M -acodec aac -strict experimental -ar 44100 -ab 256k bigbuck_out.mp4

Jamie Taylor
fonte
4
Escreverei uma resposta mais tarde, mas pensei em mencionar o seguinte: Recodificar um vídeo apenas para adicionar pilares ou caixas de correio é uma péssima idéia. Você não apenas perderá a qualidade nesse processo (ou aumentará desnecessariamente o tamanho do arquivo), como também impossibilitará a eliminação das barras posteriormente. Idealmente, seu player deve simplesmente cuidar disso e redimensionar o vídeo enquanto o exibe. Qual é o seu caso de uso, se posso perguntar?
slhck 6/02/2013
Armazenamos o arquivo original em um bucket S3, de modo que não há problema, e estamos recodificando de qualquer maneira, pois aceitamos um amplo escopo de tipos de vídeo; todos eles precisam acabar como arquivos h.264 mp4 adequados para transmitir através de um navegador. Então, você sugeriria redimensionar o vídeo e criar pilares / caixas de correio em html / css? Obrigado
Jamie Taylor
11
Como proprietário da resposta aceita, sugiro que você não aceite minha postagem e aceite a resposta de LordNeckbeard, pois é a mais recente e muito mais simples.
Slhck 7/11
@ Sllck, eu estava considerando, com a sua benção, eu vou fazê-lo.
Jamie Taylor

Respostas:

52

Um método simples é usar a force_original_aspect_ratioopção no filtro de escala .

imagem original
Imagem original. Representa um vídeo com proporção de 640x480, 4: 3.

Nesses exemplos, a imagem original será redimensionada para caber em uma saída de proporção de aspecto 16: 9, preservando a proporção original. Para fazer isso, você pode:

Pillarbox ou letterbox

imagem pillarboxed
Imagem com colunas. Ajustar uma entrada de 640x480 (4: 3) em uma saída de 1280x720 (16: 9).

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output
  • Isso aumentará a imagem. Se você deseja evitar o aumento de escala, veja o exemplo abaixo.

  • O letterboxing ocorreria se a proporção de entrada fosse maior que a proporção de saída. Por exemplo, uma entrada com proporção de 2,35: 1 ajustada a uma saída 16: 9 resultará em letterboxing.

O mesmo que acima, mas sem aumento de escala

sem aumento de escala
Entrada de 640x480 (4: 3) na saída de 1280x720 (16: 9) sem aumento de escala.

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

Colheita

insira a descrição da imagem aqui
Imagem recortada. Formato de entrada 4: 3, formato de saída 16: 9.

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720" output
llogan
fonte
E para eu adicionar um preenchimento em branco?
Tiago Ferezin
@TiagoFerezin O que é um "preenchimento em branco"?
llogan 9/04
desculpe, preencha com outra cor em vez de preto, como exemplo
Tiago Ferezin 9/04
2
@TiagoFerezin Ah, sim. Fácil de fazer. Nos exemplos que usam o filtro de almofada, você pode adicionar a coloropção, como pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=red(ou você pode usar o hexadecimal, se preferir). Veja a lista de cores .
llogan
61

Aqui está o comando que adicionaria pilar ou caixa de correio para uma largura de saída fixa. É um pouco longo, mas você precisará especificar o preenchimento de alguma forma.

Primeiro, em seu shell, defina a largura e a altura da saída:

width=700
height=400

Em seguida, execute o comando:

ffmpeg -i in.mp4 -filter:v "scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih), pad=$width:$height:($width-iw*min($width/iw\,$height/ih))/2:($height-ih*min($width/iw\,$height/ih))/2" out.mp4

Isso é reduzido ao essencial necessário para redimensionar e compactar - adicione suas outras opções de vídeo e áudio como achar melhor. Observe que os números para widthe heightdevem ser divisíveis por 2 para funcionar na maioria dos codecs.

Aqui está a explicação do que está acontecendo:

  • Dimensionamento:
    • Primeiro, precisamos descobrir se a escala deve ser feita em largura ou altura.
    • Para fazer isso, dividimos a largura da saída pela largura da entrada e a altura da saída pela altura da entrada. Isso nos dará os fatores de escala para cada dimensão.
    • Em seguida, verificamos qual é o menor (com min()) e escolhemos apenas esse fator para redimensionar.
    • Por fim, multiplicamos a largura e a altura da entrada por esse fator ( iw*min(…):ih*min(…)).
  • Preenchimento:
    • $width:$height é a largura e altura da saída
    • Para descobrir onde colocar o vídeo resultante, precisamos subtrair a largura escalada da largura máxima de saída e a altura escalada da altura máxima de saída.
    • As larguras e alturas dimensionadas são as expressões do scalefiltro.
    • Dividimos o deslocamento resultante por 2 para adicionar bordas nos dois lados.
slhck
fonte
3
@JamieTaylor Considere adicionar -movflags +faststartao exemplo do slhck. Ele permitirá que o vídeo baixado progressivamente comece a reprodução antes de ser baixado completamente e também consulte o Guia de codificação FFmpeg e x264 e o Guia de codificação FFmpeg e AAC para obter mais instruções e exemplos de codificação.
Llogan
Você pode encurtar o filtro do bloco para isso, acho:pad=$width:$height:(ow-iw)/2:(oh-ih)/2"
jdi
11
@jdi Isso não funcionará se você estiver fazendo downscaling, porque resultará em valores negativos para ow-iw.
slhck 9/02/2015
Obrigado pelo ponto de partida! No entanto, para obter uma proporção adequada para vídeos com uma proporção de amostra! = 1, toda ocorrência de "iw" precisa ser multiplicada por "sar", substituindo CADA ocorrência de "iw" por "(sar * iw)" na expressão de filtro funciona para mim.
schieferstapel
@ slhck Ei, eu estou tentando no android, mas ele não parece estar funcionando, você pode me ajudar com isso !!! ffmpeg -i input.mp4 -filter: v scale = 640 * min (700 / 640.400 / 360): 360 * min (700 / 640.400 / 360), pad = 700: 400: (700-640 * min (700 / 640.400 / 360)) / 2: (400-360 * min (700 / 640.400 / 360)) / 2 output.mp4
Nisarg
8

Parece-me que você precisa fazer isso em três etapas:

  1. Verifique a proporção da entrada
  2. Dimensione vídeos com DAR> 7/4 em largura (altere a largura para 700 e dimensione a altura para manter a proporção) e dimensione aqueles com DAR <7/4 em altura
  3. Coloque o vídeo de forma que ele caiba no espaço 700: 400.

O FFmpeg / avconv pode fazer o dimensionamento / preenchimento com filtros de vídeo em uma única etapa, transcodificando apenas uma vez. Por exemplo, para gravar um vídeo 16: 9, redimensione-o em largura e, em seguida, envie os resultados para a caixa de correio:

ffmpeg -i input.avi -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
-c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k output.mp4

... mas para o primeiro passo (detectando a proporção e comparando-a com o 7: 4 que você precisa), você terá que usar algum tipo de script.

ffprobe input.avi 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0-9]*\)].*/\1/p'

... você obtém a proporção do vídeo, que será semelhante a '16: 9' ou '4: 3'. Em um script bash, eu usaria algo como:

#!/bin/bash

##  Get the aspect ratio in the form x/y
dar=$(ffprobe test0.mp4 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0:9]*\)].*/\1/p' | sed 's|:|/|')
##  use bc to do x/y*100 (bash can't handle floats)
DAR=$(bc <<< 'scale=2; $dar*100')

##  ${DAR%.00} will remove the trailing .00 left by bc
if [ ${DAR%.00} -ge 175 ]; then
    ffmpeg -i "$1" -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
else
    ffmpeg -i "$1" -filter:v 'scale=-1:400,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
fi

exit 0

Obviamente, você terá que adaptá-lo às suas necessidades.

evilsoup
fonte
11
É possível fazer isso em uma única etapa, veja minha resposta.
slhck
@slhck Agora ficou mais fácil. Veja a resposta com o mullet da guitarra.
Llogan
@LordNeckbeard Thanks! Eu vi recentemente essa opção, torna muito mais fácil.
Slhck #