Problemas com vídeos e TVs - General - Mente Binária
Problemas com vídeos e TVs
By fredericopissarra, December 30, 2019 in General
fredericopissarra 259
Tenho uma antiga TV Sony Bravia de 42"... Tive certos problemas com ela em relação à vídeos que posso "tocar", via pendrive:
Se o vídeo têm um bitrate muito alto, nada feito;
Se o vídeo não estiver nos containers MPEG-1, MPEG-2, MPEG-4 ou WMV, nada feito;
Se o vídeo estiver num aspect ratio diferente de 16/9, a imagem distorce.
O último parece ser verdadeiro para todas as TVs em que testei o player de vídeo embutido nelas. Aparentemente o SAR (source aspect ratio) e DAR (display aspect ratio) não são respeitados se o DAR não for 16/9 ou 4/3.
ffmpeg ao resgate:
Bem... eis a linha de comando para conversão de um vídeo qualquer para um formato que pode ser "universal" para todas as TVs e, ainda assim, criar o menor arquivo possível, sem perda de qualidade significativa... O primeiro passo é calcular o bitrate correto para o vídeo. Isso pode ser feito com a seguinte equação:
Como exemplo, para um vídeo em 1280x720 @ 29.97 fps, o bitrate ficará em 1.998 Mb/s.
O outro passo é determinar a resolução do vídeo original. Podemos usar o próprio ffmpeg para isso, mas prefiro usar o mediainfo:
$ mediainfo --inform='Video;%Width%' videoin.mp4
$ mediainfo --inform='Video;%Height%' videoin.mp4
Se, escalonando o vídeo obtivermos o tamanho vertical menor que a resolução máxima vertical, estamos no caminho certo. Por exemplo... suponha que tenhamos um vídeo com uma resolução maluca como 1316x638. Se quisermos, aqui, uma resolução HD (1280x720) o vídeo terá que ser escalonado para 1280x620:
$ bc <<< 'scale=3; 1280/(1316/638)'
620.756
Como o valor é par, ignoramos a parte fracionária...
Agora, estamos prontos para recodificar o vídeo:
$ ffmpeg -hwaccel cuvid -i videoin.mp4 \
-c:v h264_nvenc -r ntsc \
-maxrate 1.998M -bufsize 1.998M -b:v 1.998M \
-vf 'scale=1280:620:flags=lanczos,pad=1280:720:0:(720-620)/2:black,setdar=16/9' \
-c:a ac3 -b:a 128k -ac 2 -ar 44.1k -async 1 \
videoout.mp4
Aqui uso os CUDA cores da placa de vídeo nVidia para decodificar os frames (-hwaccel cuvid) e o encoder da placa de vídeo para recodificá-los (-c:v h264_nvenc). Ajusto o bitrate fixo (constant bitrate) para 1.998 Mb/s, ajusto o framerate para o padrão NTSC (30000/1001 fps). Uso o filtro de escalonamento dos frames para ajustar a resolução que quero (1280x620), usando o método 'lanczos' de extrapolação para minimizar os artefatos que podem surgir no escalonamento e depois uso o filtro 'pad' para preencher o espaço de 100 pixels com um fundo preto, colocando a imagem exatamente no meio desse grande quadro de 1280x720... Por fim, ajusto os aspect ratios SAR e DAR, ajustanto o DAR para 16/9.
Você pode deixar que o próprio ffmpeg calcule o escalonamento vertical modificando o filtro scale para 'scale=1280:-1:flags=lanczos', mas se o tamanho vertical for ímpar o ffmpeg pode reclamar. Prefiro eu mesmo ajustar o valor desejado, mesmo porque ele será usado no filtro pad... Só tenha certeza que o tamanho vertical será menor ou igual a 720 (no caso da resolução 1280x720)...
No que tange o áudio, minha TV não suporta AAC, então uso AC3 e acho o bitrate de 128 kb/s suficiente, mas converto o sampling rate para 44.1 kHz para diminuir o stream de áudio, bem como garanto que a saída seja 'stereo' (-ac 2)... Como estou modificando o framerate do vídeo, aplico também o filtro de áudio de sincronização a cada 1 segundo (-async 1).
O arquivo videoout.mp4 conterá o vídeo no container MPEG-4 (o ffmpeg pega pela extensão), usando codecs h264 e ac3 e estará na resolução 1280x720 com DAR setado em 16/9... Vídeo "pequeno" (com essa técnica consigo um vídeo com tamanho de 28% do vídeo original, dependendo do caso), que tocará sem distorções e excelente qualidade.
Se você gosta de assistir vídeos em FullHD (1920x1080), basta modificar os cálculos de acordo.
PS: Se você não tem uma placa nVidia pode tentar usar um decoder VAAPI (Intel) ou não usar a aceleração (retire o -hwaccel cuvid, acima)... Ainda, terá que modificar o encoder para 'libx264', ao invés de 'h264_nvenc'.
Edited December 30, 2019 by fredericopissarra
Existia um erro no texto com relação ao uso dos filtros scale e pad, em sequência... Corrigi o texto...
O problema era que as pseudo-variáveis ih e iw do filtro pad levam em consideração a altura e comprimento, respectivamente, do vídeo de entrada (não do vídeo escalonado - ao que parece)... daí, substituí pelos valores fixos ao invés de usar as variáveis.
Considerações sobre aspect rations comuns. São 2: WideScreen (16/9) e LetterBox (4:3). O segundo é o aspecto das antigas TVs com CRTs. Uma resolução de 640x480 tem aspecto 4:3, por exemplo. Se formos fazer padding sempre para Widescreen isso tem que ser levado em consideração:
No caso de um vídeo widescreen, mas com aspecto diferente de 16:9 (resolução não padrão), barras horizontais devem ser colocadas. Mas, note que elas não consumirão muito do espaço útil da tela (a não ser que a resolução vertical seja mesmo pequena). O escalonamento do vídeo original deve ser feito de forma que o width seja o mesmo do espaço do padding...
No caso do formato letterbox (4:3), barras verticais devem ser adicionadas (a centralização do vídeo será feita horizontalmente e o vídeo original deve ser escalonado para fazer com que height seja o mesmo do espaço do padding)... Mas, note que muito do espaço útil é perdido: