FFMPEG (libx264) "altura não divisível por 2"

188

Estou tentando codificar um vídeo .mp4 de um conjunto de quadros usando o FFMPEG usando o codec libx264.

Este é o comando que estou executando:

/usr/local/bin/ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4

Às vezes, recebo o seguinte erro:

[libx264 @ 0xa3b85a0] height not divisible by 2 (520x369)

Depois de pesquisar um pouco, parece que o problema tem algo a ver com o algoritmo de dimensionamento e pode ser corrigido adicionando um argumento -vf.

No entanto, no meu caso, não quero fazer nenhum dimensionamento. Idealmente, quero manter as dimensões exatamente iguais às molduras. Algum conselho? Existe algum tipo de proporção que o h264 impõe?

Andy Hin
fonte
@AleksandrDubinsky Mas a resposta de LordNeckbeard não preserva a largura e a altura originais. Aqui precisamos especificar manualmente a largura ou a altura .. e se usar -vf scale = -2: ih ou -vf scale = iw: -2 trabalho se ambos altura e largura são uneven..Please explicar como que a resposta é mais ideal .. obrigado?
varmashrivastava
1
@varmashrivastava Bem, a maneira como o SO funciona é que originalmente pode ter havido uma pergunta e, em seguida, o Google envia várias pessoas com uma pergunta diferente que depois sequestram a página. É o que é, tente não lutar contra isso. A resposta correta para a pergunta original é -vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2", que nem sequer é uma das respostas. A resposta correta para a pergunta de todos os outros é a de LordNeckbeard.
Aleksandr Dubinsky
@varmashrivastava Fui em frente e resolvi a primeira resposta. Espero que não seja vandalizado pelos mods.
Aleksandr Dubinsky
@AleksandrDubinsky thanks..and user pode usar em "scale="vez de, "pad="se ele / ela não quer pixels de preenchimento colorido?
Varmashrivastava

Respostas:

269

A resposta para a pergunta original que não deseja dimensionar o vídeo é:

-vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

Comando:

ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

Basicamente, .h264 precisa de dimensões uniformes, para que este filtro:

  1. Divida a altura e a largura originais por 2
  2. Arredonde-o para o pixel mais próximo
  3. Multiplique por 2 novamente, tornando-o um número par
  4. Adicione pixels de preenchimento preto até esse número

Você pode alterar a cor do preenchimento adicionando parâmetro de filtro :color=white. Veja a documentação do pad .

Andy Hin
fonte
3
Não é um bug. Não importa que você não esteja realizando a escala, pois a saída herdará o tamanho do quadro da entrada.
llogan
5
Para o registro, eu estava apenas fazendo algo em que criei um vídeo a partir de uma imagem, e ele usou yuvj444p como formato de pixel; não se importava com o tamanho do vídeo. Então eu precisei convertê-lo para yuv420p, e então ele se preocupou com o tamanho do vídeo. Procurei o yuv420p na wikipedia, acho que é um formato de cor com vários pixels, que precisa que a imagem tenha um tamanho específico. Não sei por que isso importa compactado, no entanto.
Lahwran 18/10/2015
7
Provavelmente, é melhor usar o teclado em vez da escala para adicionar uma linha / coluna preta. Escalar uma imagem em um pixel irá desfocá-la.
perfil completo de Glenn Maynard
5
@NickeManarin, este filtro deve trabalhar para adicionar 1 pixel de preenchimento de branco para a dimensão vertical, com o vídeo posicionado superior esquerdo: -vf pad="width=iw:height=ih+1:x=0:y=0:color=white". A documentação do ffmpeg pad está aqui: ffmpeg.org/ffmpeg-filters.html#pad-1 .
Mark Berry
4
Aqui está uma solução que só acrescenta um pixel de preenchimento de dimensões que são estranho: -vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2".
Danneu
250

Apenas use -2

Na documentação do filtro de balança :

Se um dos valores estiver -ncom n > 1, o filtro de escala também usará um valor que mantém a proporção da imagem de entrada, calculada a partir da outra dimensão especificada. Depois disso, porém, verifique se a dimensão calculada é divisível ne ajuste o valor, se necessário.

Exemplos

Defina a largura como 1280 e a altura será calculada automaticamente para preservar a proporção, e a altura será divisível por 2:

-vf scale=1280:-2

O mesmo que acima, mas com uma altura declarada; deixando a largura a ser tratada pelo filtro:

-vf scale=-2:720

"divisível por 2"

Conforme exigido por x264, o "divisível por 2 para largura e altura" é necessário para saídas subamostradas de croma YUV 4: 2: 0. 4: 2: 2 precisaria de "divisível por 2 para largura" e 4: 4: 4 não tem essas restrições. No entanto, a maioria dos players não baseados em FFmpeg pode decodificar adequadamente apenas 4: 2: 0; é por isso que você geralmente vê ffmpegcomandos com a -pix_fmt yuv420popção ao exibir vídeo H.264.

Embargo

Infelizmente, você não pode usar -2largura e altura, mas se você já especificou uma dimensão, usar -2é uma solução simples.

llogan
fonte
14
Eu acho que isso deve ser marcado como a resposta certa, porque não há "truques" envolvidos. Whish para upvote mais de uma vez
Lucam
1
Por que -vf scale=-2:-2não funciona? No meu caso, quero preservar o tamanho do arquivo original o máximo possível. O que funcionou para mim foi -vf scale=-2:ih. Mas não funciona se ambos os lados estiverem desiguais.
Pascal
2
@tuner O valor resultante de -2depende do valor declarado da outra dimensão.
Llogan
3
no meu caso, isso me deu o seguinte erro: Size values less than -1 are not acceptable.mas a resposta de @Zbyszek funcionou perfeitamente.
Julien
1
@ Julien Isso não éffmpeg . Você pode baixar uma compilação estática .
Llogan
64

Se você deseja definir alguma largura de saída e ter a mesma proporção que o original

scale=720:-1 

e para não cair com esse problema, você pode usar

scale="720:trunc(ow/a/2)*2"

(Apenas para pessoas que pesquisam como fazer isso com dimensionamento)

Zbyszek
fonte
16
E para uma altura fixa éscale="trunc(oh*a/2)*2:720"
Tom
20

O problema com as scalesoluções aqui é que elas distorcem a imagem / vídeo de origem, que quase nunca é o que você deseja.

Em vez disso, descobri que a melhor solução é adicionar um bloco de 1 pixel à dimensão ímpar. (Por padrão, o preenchimento é preto e difícil de notar.)

O problema com as outras padsoluções é que elas não generalizam sobre dimensões arbitrárias, porque sempre acolchoam.

Esta solução adiciona apenas um bloco de 1 pixel à altura e / ou largura se forem ímpares:

-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"

Isso é ideal porque sempre faz a coisa certa, mesmo quando não é necessário preenchimento.

danneu
fonte
As soluções de escala alteram a contagem de pixels em 1, no máximo. Isso dificilmente distorce a imagem. Se você estiver preocupado com a velocidade de filtragem, use scale=iw+mod(iw,2):ih+mod(ih,2):flags=neighbor. Isso só pode aumentar cada dimensão em 1, se necessário, e duplicará a última linha / coluna.
Gyan
@Gyan É muito tempo desde que eu tive o problema que esta resolvido (a minha resposta foi extraído a partir de um comentário que fiz há muito tempo), mas lembro-me que a escala por um único pixel se introduzir artefatos visuais perceptíveis sob algumas condições que é por isso que eu incomodado em primeiro lugar. Não me lembro exatamente, talvez uma quantidade desproporcional de desfoque de uma única mudança de pixel? Talvez apenas em alguns formatos de vídeo / imagem? Tudo o que posso dizer é que processei milhares de vídeos com essa correção e foi a transformação favorável.
21919 danneu
19

Provavelmente, devido ao fato de o vídeo H264 geralmente ser convertido do espaço RGB para YUV como 4: 2: 0 antes de aplicar a compactação (embora a conversão de formato em si seja um algoritmo de compactação com perda, resultando em economia de 50% de espaço).

O YUV-420 começa com uma imagem RGB (vermelho verde azul) e a converte em YUV (basicamente um canal de intensidade e dois canais "matiz"). Os canais de Matiz são subamostrados criando uma amostra de matiz para cada quadrado 2X2 desse matiz.

Se você tiver um número ímpar de pixels RGB na horizontal ou na vertical, terá dados incompletos para a última coluna ou linha de pixels no espaço de matiz subamostrado do quadro YUV.

Adisak
fonte
2
Outro fato interessante ... quando você decodifica com as coisas do Microsoft Media Foundation, precisa usar múltiplos de 16 para o H264. Portanto, o vídeo 1080P decodifica em um buffer com 1088 de altura (embora você ignore as últimas 8 linhas).
Adisak
2

LordNeckbeard tem a resposta certa, muito rápido

-vf scale=1280:-2

Para android, não se esqueça de adicionar

"-preset ultrafast" and|or "-threads n"
fallouter
fonte
Você não precisa declarar tópicos: isso é tratado automaticamente. Acredito que a lentidão do Andriod ao codificar para o H.264 se deva às pessoas que usam o popular "WritingMinds / ffmpeg-android", que usa --disable-asmem seu script de construção x264 . Isso resulta em lentidão desnecessária e significativa (você pode verificar o log do ffmpeg e, se mostrar using cpu capabilties: none!, é ruim). Não sei por que eles adicionaram isso, mas não sou desenvolvedor de Android.
Llogan
1

Você também pode usar a bitandfunção em vez de trunc:

bitand (x, 65534)

fará o mesmo trunc(x/2)*2e é mais transparente na minha opinião.
(Considere 65534 um número mágico aqui;))


Minha tarefa era dimensionar automaticamente muitos arquivos de vídeo para meia resolução .

scale=-2,ih/2levar a imagens ligeiramente desfocadas

razão:

  • vídeos de entrada tiveram sua relação de aspecto de exibição (DAR) definida
  • scale escala as dimensões reais do quadro
  • durante a visualização, os tamanhos dos novos vídeos precisam ser corrigidos usando o DAR, o que, no caso de vídeos com baixa resolução (360x288, DAR 16: 9), pode causar desfoque

solução:

-vf "scale='bitand(oh*dar, 65534)':'bitand(ih/2, 65534)', setsar=1"

explicação:

  • altura da saída = altura da entrada / 2
  • output_width = output_height * original_display_aspect_ratio
  • agora output_width e output_height agora são arredondados para o número menor mais próximo divisível por 2
  • setsar=1significa que as dimensões de saída agora são finais, nenhuma correção de proporção deve ser aplicada

Alguém pode achar isso útil.

endigo
fonte