Tutorial de FFmpeg na marra - Lição 2 (Codecs, Containers e Rate Control)

Tutorial de FFmpeg na marra - Lição 2 (Codecs, Containers e Rate Control)

Victor Carneiro (@vitinhocarneiro)

a.k.a. Não sabe usar o FFmpeg? Vem aprender agora!!!


Lição anterior (O Básico do Básico)
Próxima lição (Resolução, Taxa de quadros e qualidade de imagem)

Lição 2 - Codecs, Containers e Rate Control

Na última lição falamos um pouco sobre a história do FFmpeg, como instalar, e conceitos básicos sobre o uso dele.

E muitos de vocês devem ter ficado sobre este cliffhanger:

Nesta lição nós vamos aprender conceitos básicos de codificação de vídeo e como eles se aplicam no FFmpeg. E endereçar esta dúvida em parte.

Vamos falar dos três C's alicerces da codificação de vídeo - Codecs, Containers e Controle de taxa (Rate Control).

O que é um codec?

Um codec pode significar duas coisas:

  1. Um padrão que define métodos matemáticos e formatos para se codificar e decodificar um fluxo de multimídia, seja ele vídeo ou áudio.
  2. Um programa, biblioteca ou circuito digital que codifica ou decodifica um fluxo de mídia segundo tal padrão.

Destaquei aqui as palavras "codificar" e "decodificar". A palavra codec vem da junção dos termos coder e decoder, que significam "codificador" e "decodificador".

Destaquei também a palavra "padrão". Porque essa padronização é essencial para que um fluxo criado por um codificador possa ser interpretado corretamente por um decodificador.

Em suma: um codec é um padrão que define uma maneira de se codificar/decodificar um fluxo de mídia. E também significa um programa que efetua essa operação.

Importante ressaltar: É costume nos referirmos a um fluxo de mídia pelo nome "bitstream". Porque um fluxo de mídia digital literalmente é um fluxo de bits (bit-stream) a baixo nível.

Mas qual é a diferença entre um codec e outro? Pra quê precisamos ter vários codecs???

Codecs diferentes usam métodos e algoritmos diferentes. Eles se diferenciam, principalmente, pela eficiência de codificação/compressão. Esse termo significa a quantidade de informação que um codec consegue expressar em uma determinada quantidade de bits. Quanto mais informação, mais qualidade temos, e dizemos que este codec é mais eficiente, pois ele precisa de menos bits pra atingir um certo nível de qualidade.

Além disso, existe a questão da complexidade. Codecs diferentes usam algoritmos diferentes, e certos algoritmos demandam mais operações para a sua execução. E quando falamos de multimídia, falamos de execução em tempo real. O decoder precisa ser capaz de decodificar o fluxo de mídia em tempo real - caso contrário, ocorrem travamentos e engasgos. Logo, se um processador/circuito não tem poder de processamento o suficiente pra executar o algoritmo de decodificação em tempo real, é necessário usar um codec que use um algoritmo mais simples.

E ainda temos a questão do suporte. Essa questão é mais proeminente quando falamos de decodificação em hardware - ou seja, circuitos de decodificação. Por exemplo - se estamos vendo um vídeo em um computador atual, o processador é capaz de rodar praticamente qualquer algoritmo de decodificação de vídeo, então se usam algoritmos atuais e complexos, como o H.264, o H.265 ou o VP9. Já em um MP4 player ou aparelho de DVD, o circuito de decodificação só é feito pra decodificar alguns codecs de vídeo - no caso de um DVD player, por exemplo, por padrão só existe suporte aos codecs MPEG-1 e MPEG-2.

E nesse exemplo acima, isso não leva em conta a questão de complexidade - se apresentamos a um aparelho de DVD um fluxo de vídeo em MPEG-2 com resolução de 1920x1080, ele simplesmente vai se recusar a decodificar o vídeo, porque o circuito não tem potencial para decodificar um vídeo de tamanha resolução/complexidade, mesmo que o padrão MPEG-2 oficialmente ofereça suporte a ela. (isso não leva em conta o fato de que os cabos de vídeo de um DVD player só transmitem vídeo analógico em 480i 😛)

Ok, e no FFmpeg?

Depois de todo esse papinho teórico, vejamos como escolher um codec no FFmpeg.

O FFmpeg usa o argumento -codec para selecionar um codec para o fluxo atual. Também existe o alias -c para o mesmo propósito. Como parâmetro, passamos o identificador interno do codec usado pelo FFmpeg - você pode obter uma lista deles usando o comando ffmpeg -encoders.

Podemos - e devemos - limitar o escopo desse argumento usando modificadores. Eles são colocados à direita do argumento, e são separados pelo caractere ":". Exemplos:

-codec:v libx264 - Seleciona o H.264 ( libx264) como codec de vídeo

-codec:a libvorbis - Seleciona o Vorbis ( libvorbis) como codec de áudio

-codec:a:0 libmp3lame - Seleciona o MP3 ( libmp3lame) como codec de áudio da bitstream de áudio de número zero (útil quando se trabalha com mais de uma stream de áudio)

-codec:a:1 ac3 - Seleciona o Dolby AC3 ( ac3 / liba52) como codec de áudio da bitstream de áudio de número um

-codec:2 libfdk_aac - Seleciona o AAC* ( aac / libvo_aacenc / libfaac / libaacplus / libfdk_aac) como codec de áudio da bitstream de número 2. Essa sintaxe não é recomendada - se a bitstream de número 2 não for uma bitstream de áudio, o comando retornará um erro.


*O FFmpeg tem certos problemas em relação a encoders do codec AAC, que discutiremos em outra aula. Vale apenas notar aqui que o codec de identificador aac é experimental, e para usá-lo você deve passar o seguinte argumento para habilitá-lo: -strict experimental




Importante notar que há ainda a sintaxe deprecada -vcodec e -acodec. Não é recomendada o uso dela por ser antiga e deprecada - e porque provavelmente será removida em algum release próximo do FFmpeg. (sendo sincero, ela está deprecada há anos e ainda não foi removida - mas não usem, por favor)

Tá, mas e como é que eu vou saber qual codec usar?

Aí que é a questão mais complexa.

Depende muito do propósito para o qual você quer codificar o vídeo, e em qual dispositivo ele será tocado.

Se você está codificando um vídeo pra tocar em um DVD player, televisão, PSP, MP4 player, enfim, qualquer dispositivo embarcado, você deve procurar o manual dele pra saber quais codecs ele suporta e escolher o codec correto.

Já se você está codificando um vídeo para enviar para a Internet, por exemplo, talvez você nem precise recodificar o vídeo. Dê uma olhada nos codecs suportados pelo serviço aonde ele será hospedado. No Youtube, por exemplo, qualquer codec suportado pelo FFmpeg é aceito, logo você nem precisa recodificar.

Por outro lado, se você quer comprimir um vídeo, isto é, reduzir o tamanho, você deve escolher um codec que seja eficiente o bastante pro seu propósito, e que não demore mais pra codificar do que a sua paciência aguenta. Em geral, a escolha certa pra esses casos é o H.264 - é um codec bem eficiente, um dos mais comuns hoje em dia, suportado por muitos dispositivos e softwares, e o encoder x264 ( libx264 no FFmpeg) é muito bem otimizado - tão otimizado que a velocidade de codificação chega a superar até codecs mais simples como o MPEG-2 ( mpeg2video), Theora ( libtheora) ou o MPEG-4 ( mpeg4 / libxvid). Mas dependendo do caso, você pode querer usar um codec mais eficiente como o H.265 ou o VP9.

Existem ainda mais casos para a escolha de um codec. Em todo caso, vale o bom senso e o melhor amigo do usuário de Internet - o Google. (ou DuckDuckGo para os que preferirem, rsrs)

Abaixo uma lista dos codecs de vídeo mais comumente usados, por ordem de popularidade (juntamente com seus identificadores no FFmpeg):

  • H.264 ( libx264)
  • VP9 ( libvpx-vp9)
  • VP8 ( libvpx)
  • MPEG-4 ( mpeg4 / libxvid)
  • H.265 ( libx265)
  • MPEG-2 ( mpeg2video)
  • Theora ( libtheora)
  • Dirac ( libschroedinger)


(Ufa. Terminamos a seção de codecs.)

O que é um container?

Quando temos um arquivo de vídeo, ele não contém apenas um fluxo de vídeo. Ele geralmente contem no mínimo um fluxo de áudio junto. Em certos casos o arquivo pode conter vários fluxos de áudio, fluxos de legendas e até marcadores de capítulos.

É aqui que entra o container.

O container nada mais é do que a estrutura de arquivo onde todos os fluxos são multiplexados e indexados. É graças ao container que você só precisa abrir um arquivo pra ter vídeo e áudio ao mesmo tempo, que você pode pular pra qualquer ponto do vídeo a hora que quiser, e os fluxos ficam perfeitamente sincronizados (normalmente, né... às vezes pegamos arquivos com problemas de sincronia).

O container também é conhecido como formato de arquivo. (não confunda com a extensão que vai depois do nome, como .mp4/.mkv/.ogg/.3gp/.etc..., embora eles sejam similares)

Qual a diferença entre um container e outro?

Na prática, a diferença principal são os recursos que cada container suporta. Recursos como - os diferentes codecs suportados, o suporte a múltiplos fluxos de áudio, o suporte a fluxos de legenda embutidos, o suporte a marcações de capítulos, resiliência a erros de transmissão, e se ele pode ser usado para streaming de vídeo ao vivo.

E como vou saber qual container usar?

Novamente, depende do caso.

Se você está codificando um vídeo pra colocar em um dispositivo embarcado, você precisa ver quais containers ele suporta (e quais codecs dentro de cada container - importante!).

Em outros casos, é suficiente usar um container que tenha os recursos que você precisa.

Porém, quando se compartilha material na internet, é comum o uso de diferentes containers de acordo com os codecs para facilitar a identificação. Por exemplo, estas são escolhas comuns:

  • Container AVI/Video For Windows ( .avi) - Vídeo em MPEG-4 ( mpeg4 / libxvid) com áudio em MP3 ( libmp3lame), AAC ( leia acima) ou (raramente) AC3 ( ac3 / liba52)
  • Container MP4 ( .mp4) - Vídeo em H.264 ( libx264) com áudio em AAC
  • Container MKV/Matröska ( .mkv) - Vídeo em H.264 ( libx264) ou H.265 ( libx265), com áudio em AAC ou AC3, possívelmente com várias trilhas de áudio e legendas embutidas
  • Container WebM ( .webm) - Vídeo em VP8 ( libvpx) ou VP9 ( libvpx-vp9), com áudio em Vorbis ( libvorbis) ou Opus ( libopus)

No FFmpeg:

Geralmente, o FFmpeg reconhece o container que você quer usar apenas pela extensão do arquivo de saída. Mas há casos em que você vai precisar definir isso na mão - para isso usa-se o argumento -f. Ele não tem modificadores, apenas leva o identificador de formato interno do FFmpeg (você pode obter uma lista deles usando o comando ffmpeg -formats).

Exemplos:

  • ffmpeg -i video.mp4 -f image2 frame_%5d.png (dica - esse comando extrai todos os frames de um vídeo para imagens PNG! A sintaxe dele será abordada em detalhes mais tarde.)
  • ffmpeg -i video.mp4 -codec:v libtheora -q:v 6 -f matroska - | ffplay - (esse é um caso especial em que somos obrigados a especificar o formato - estamos usando o fluxo de saída "-" para redirecionar o conteúdo para a saída padrão (stdout), e redirecionando-a para o programa ffplay - um dos utilitários que acompanha o FFmpeg)

Lembra da minha citação no início da aula?

Agora você sabe que -f s16le é uma definição de formato.

Para ser mais específico, s16le é um formato de áudio raw - ele não tem exatamente um container, sendo simplesmente um fluxo de bits puro no codec PCM 16-bit - que é uma das formas mais básicas que existe de se representar áudio.

O parâmetro -ar 44100 é essencial pelo fato do arquivo ser completamente cru, sem nenhum cabeçalho - ele informa ao FFmpeg que a taxa de am0stragem do áudio é de 44100 Hz.

Não se preocupe se você não entendeu o trecho acima, nós falaremos especificamente sobre codificação de áudio em uma outra aula.


(essa seção foi mais simples. Ufa!)

Rate Control (controle de taxa)

Agora vem a parte realmente complexa da codificação de vídeo. Essa é a parte que requer feeling e muita prática.

O que diabos é controle de taxa? Prometo que vou tentar explicar de maneira inteligível.

A principal razão pra se terem criado codecs de multimídia, além da compressão, é pela necessidade do streaming - que é reproduzir mídia a partir de um local onde a taxa de acesso/transmissão é limitada.

Em outras palavras, quando a quantidade de bits que você pode ler a cada segundo é limitada.

Isso é um caso clássico da era do CD - o primeiro codec de vídeo da história, o Cinepak ( cinepak - sim, o FFmpeg tem encoder pra ele), foi criado para o propósito de se fazer streaming de vídeo a partir de CD - onde a taxa de leitura de dados era limitada a aproximadamente 1228 kbps.

Daí surgiu a noção de controle de taxa - o propósito era justamente controlar a taxa com que era necessário ler bits da fonte de dados onde a mídia era armazenada, para evitar engasgos.

Como se "controla taxa"?

Uma das maneiras de se controlar a taxa de um vídeo é justamente pela taxa de bits por segundo (bitrate). Impor uma bitrate de 1000kbps literalmente significa que pra cada segundo de vídeo, em média, serão lidos 1000 kilobits - 1 milhão de bits.

(e antes que perguntem - 1 kilobit por segundo é 1000 bits por segundo. A unidade composta por 1024 bits é o kibibit (kib). E o FFmpeg não é Windows pra misturar as duas unidades de medida - quando se fala de streaming, unidades SI são o padrão, ou seja, múltiplos de 1000.)

E qual efeito isso tem na qualidade? Bom, quanto mais bits por segundo, mais informação o codec consegue expressar, logo, maior a qualidade. Poooorém, existe um grande problema com taxas de bits...

O problema é que uma taxa de bits não define diretamente a qualidade. Ou seja, 1000kbps pra um vídeo pode gerar uma qualidade ótima, mas pra outro vídeo pode gerar uma qualidade terrível. Por quê?

Veremos isso com detalhes mais à frente, mas a quantidade de bits necessária pra se expressar um vídeo varia de acordo com o vídeo em si. Em geral, cenas com pouco movimento e poucos detalhes, pouca coisa mudando na tela, precisam de menos bits; por outro lado, cenas com muito movimento, ruído, detalhes se mexendo, coisas indo pra um lado e pro outro, confete caindo, cortes o tempo todo, precisam de muuuitos bits.

Lembra que acima eu destaquei que a taxa de bits significa a média de bits por segundo de vídeo? Então, é exatamente por essa razão. A complexidade de um vídeo varia o tempo todo, então os codecs usam menos bits para cenas menos complexas, e mais bits para cenas mais complexas. E sim, às vezes um vídeo pode conter mais bits em um segundo do que a fonte pode oferecer - e é por isso que existe o buffer de vídeo. Ele armazena uma quantidade de bits extraídas pela fonte, e esse buffer é constantemente enchido pela fonte. O codec é livre pra usar esse buffer na taxa que ele quiser - até que ele acabe e ele seja obrigado a limitar-se à taxa de bits máxima. (Não se preocupe com como controlar isso agora! Veremos isso em mais detalhes em outra aula.)

Para controlar a taxa de bits no FFmpeg, usamos o argumento -b. Ele pode ser aplicado tanto a vídeo quanto a áudio, usando os modificadores vistos acima. Exemplos:

  • -b:v 1000k - define uma bitrate de 1000kbps para o fluxo de vídeo
  • -b:a 128k - define uma bitrate de 128kbps para o fluxo de áudio
  • -b:a:0 160k - define uma bitrate de 160kbps para o fluxo de áudio de número zero
  • -b:v 2.5m - define uma bitrate de 2.5Mbps (2500kbps) para o fluxo de vídeo
  • -b:a 4700 - define uma bitrate de 4700bps (4,7kbps) para o fluxo de áudio. ATENÇÃO com o prefixo!!!

Existe ainda o alias -bitrate, e a sintaxe deprecada -vb e -ab.

Então existe uma maneira melhor de se fazer controle de taxa?

Sim. A maneira que veremos agora é o "QP" - Quantization Parameter, ou parâmetro de quantização. Esse carinha com nome esquisito é um número que expressa a quantidade de detalhes que o codec vai jogar fora do vídeo. Ou seja, ele é um controle muito mais preciso de qualidade do que a taxa de bits, já que um valor de QP corresponde aproximadamente a um certo nível de qualidade.

Vale ressaltar que o QP expressa quanto o codec vai jogar fora detalhes do vídeo - então quanto maior o valor do QP, menor a qualidade do vídeo.

E a escala de QP varia de acordo com o codec de vídeo em si - e com algumas outras coisas que não veremos agora, pois não são muito importantes ainda.

Por exemplo, no MPEG-4, a escala de QP vai de 1.0 até 31.0 - onde 1.0 é a maior qualidade possível e 31.0 é a menor qualidade possível.

Já no H.264, a escala de QP inclui o zero e vai de 1.0 até 51.0, ou até 63.0 no x264 64-bit - zero representa codificação lossless (sem perdas), e cada incremento de 6.0 no QP representa aproximadamente uma redução pela metade da taxa de bits resultante.

Porém, o controle de taxa por QP tem um empecilho - a taxa de bits varia muito o tempo todo, e pode alcançar valores altos - algo que você absolutamente não quer em streaming de vídeo ou qualquer cenário onde a taxa de bits tem um limite superior. Felizmente existem maneiras de mitigar esse problema, que veremos mais tarde.

Para controlar o QP no FFmpeg, usamos o argumento -q (há também a forma alternativa -qscale). Como na bitrate, é boa prática aplicar modificadores - tenha em mente, porém, que nem todos os codecs de áudio suportam codificação por "QP" (aliás, a terminologia em áudio é diferente, não se usa o termo QP).

Exemplo:

  • -q:v 3.5 - define um QP constante de 3.5 para a stream de vídeo.

QP parece uma grande maravilha, né? Você dá um número e ele te dá uma qualidade. Mas agora veremos uma maneira ainda melhor de se fazer controle de taxa.

Constant Rate Factor - CRF

(não confunda com Clube de Regatas do Flamengo.)

O CRF é um recurso presente apenas em codecs de vídeo mais novos, como o H.264, H.265, VP8, VP9, Daala e AOM-AV1 (estes dois últimos ainda em fase experimental).

O que é o CRF?

Basicamente, codecs mais novos implementam uma política de controle de taxa chamada de Rate Factor. O Rate Factor é muito parecido com o QP no sentido de que ele corresponde aproximadamente a um nível de qualidade - porém, ele tem mais exatidão e é mais eficiente em termos de compressão do que o QP.

Por quê? Basicamente, o Rate Factor é um controle por QP variável. Ele define um nível médio de QP - mas usa algoritmos psicovisuais para quantizar (i.e. jogar detalhes fora) com mais intensidade as áreas do vídeo onde não se notaria tanto a perda de qualidade, e quantizar menos as áreas do vídeo onde se poderia notar facilmente perda de qualidade. Ele basicamente usa o QP de uma forma bem melhor e que economiza bits, priorizando qualidade.

Para controlar o CRF no FFmpeg, usamos o argumento -crf. Não há modificadores para ele, pois ele se aplica somente a vídeo. Simplesmente passa-se um valor de Rate Factor (QP médio) como parâmetro. Exemplo:

  • -crf 23.0 - define um Rate Factor constante de 23.0 para a stream de vídeo.

E aí?

Agora, é necessário que você pratique bastante para se acostumar com o uso do FFmpeg e as técnicas de controle de taxa.

A metodologia de exercícios é a seguinte:

  • Baixe vídeos da Internet e saia convertendo eles em níveis de qualidade e formatos diferentes. (dica - pegue vídeos curtos!)
  • Pegue dispositivos pela sua casa e converta vídeos para serem tocados neles. Depois de converter, teste. Se não funcionar, veja o que pode está errado. Pesquise na Internet.
  • Preste muita atenção não só na qualidade, mas no tamanho do arquivo de saída e na taxa de bits final reportada pelo FFmpeg.

A cada lição serão introduzidos novos conceitos, e é necessário que você pratique o uso deles para se acostumar.

Evite ao máximo fazer Ctrl+C Ctrl+V de comandos do FFmpeg da Internet. A razão pra isso é que você precisa se acostumar a escrever comandos cada vez mais longos. Conforme você aprender mais recursos e for usando-os, você criará comandos mais e mais longos, e é essencial que você se acostume desde cedo a lidar com isso.

Conclusão

Nesta aula nós vimos conceitos essenciais de codificação de vídeo e sua aplicação no FFmpeg. E apesar da lição ter sido longa, nós só vimos o básico deles. Ainda há muito a aprender.

Me desculpe se você acha que as aulas são longas demais - mas eu acho primordial que os conceitos sejam explicados de forma clara para um melhor entendimento, e como consequência o texto acaba ficando bem verboso. Se você não entender algo direito, releia. Caso tenha dúvidas, pode me contatar pelos canais que listarei abaixo.

Lição 1 - O Básico do Básico
Lição 3 (Resolução, Taxa de quadros e qualidade de imagem)

Dúvidas? Perguntas?

Caso você queira me perguntar algo, tirar uma dúvida, fazer um elogio ou uma crítica, pode me contatar pelos canais abaixo:

E-mail: victorcarneiro2009@gmail.com
Telegram: @vitinhocarneiro

Por favor, caso você mande e-mail, peço que você identifique claramente no assunto da mensagem que está falando desse tutorial, para que eu possa identificar seu e-mail mais facilmente e te responder rápido.

Índice

Lição 1 - O Básico do Básico
Lição 2 - Codecs, Containers e Rate Control
Lição 3 - Resolução, Taxa de quadros e Qualidade de Imagem
Lição 4 - em breve!

Por Victor Carneiro - 28/02/2017. Revisado em 01/03/2017. Conteúdo licenciado sob a licença MIT - disponível aqui.

Report Page