domingo, 26 de fevereiro de 2017

Recuperando um arquivo corrompido da Newtek Tricaster TC40

A Tricaster TC40 (ou simplesmente como Tricaster 40) faz suas gravações em QuickTime MOV. A questão é que se algo acontece com o sistema que interrompe a gravação do arquivo você terá um arquivo ilegível. MOV, tal como MP4 e outros formatos, escrevem as informações sobre a leitura do arquivo e a localização de cada pacote de áudio e vídeo no extremo final do arquivo, o que causa ele ficar irreconhecível caso o processo não aconteça até o final como deveria. Mas há uma forma manual de recuperar e recompor este arquivo danificado.

O primeiro passo são os scripts em Python que escrevi para extrair e separar os blocos de vídeo e áudio do arquivo danificado. Lembrando que:

  • Não sou um programador profissional. Faço isso de acordo com as minhas necessidade imediatas. O código poderia ser muito mais otimizado, amigável, rápido, mas não tenho o conhecimento ou tempo pra isso.
  • Este código funciona estritamente de acordo com as características observadas na configuração de arquivo utilizado por mim, que é um arquivo com vídeo em MPEG-2 4:2:2 I-frames e dois canais de áudio estéreo PCM, o segundo sendo completamente mudo. Em diferentes situações o código pode necessitar uma total reescrita.

Script: extract-audio.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os.path

def read_in_chunks(infile, chunk_size=4):
 packet = False
 bloco_audio = b""
 infile.seek(512)
 for chunk in iter(lambda: infile.read(chunk_size), ''):
  if chunk == b"\x00\x00\x01\xb3":
   if bloco_audio != b"":
    if bloco_audio[-4608:] == (b"\x00" * 4608):
     yield bloco_audio[-9216:-4608]
   bloco_audio = chunk
   continue
  bloco_audio += chunk

infile = open(sys.argv[1], "rb")
path = os.path.dirname(sys.argv[1])+"/"+os.path.splitext(os.path.split(sys.argv[1])[1])[0]+"_audio.raw"
out = open(path, 'w')

for chunk in read_in_chunks(infile):
 out.write(chunk)

Script: extract-video.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os.path

def read_in_chunks(infile, chunk_size=4):
 packet = False
 padding = False
 bloco_video = b""
 infile.seek(512)
 for chunk in iter(lambda: infile.read(chunk_size), ''):
  if packet == True and chunk == b"\x00\x00\x01\xb3":
   packet = False
   if bloco_video != b"":
    if bloco_video[-4608:] == (b"\x00" * 4608):
     yield bloco_video[:-9216]
    else:
     yield bloco_video
   bloco_video = b""
  if chunk == b"\x00\x00\x01\xb3":
   packet = True
   bloco_video += chunk
   continue
  if packet == True:
   bloco_video += chunk
   continue

infile = open(sys.argv[1], "rb")
path = os.path.dirname(sys.argv[1])+"/"+os.path.splitext(os.path.split(sys.argv[1])[1])[0]+"_video.ts"
out = open(path, 'w')

for chunk in read_in_chunks(infile):
 out.write(chunk)

(Não entrarei no aspecto de como rodar Python e FFMPEG em algum sistema pois devem ter instruções muito melhores e atualizadas internet afora.)

Após rodar estes scripts com "python extract-audio.py o-arquivo-danificado.mov" e "python extract-video.py o-arquivo-danificado.mov", e isso vai demorar bastante principalmente se o arquivo tiver vários gigabytes, você terá na mesma pasta do arquivo MOV arquivos com o mesmo tempo só que finais _audio.raw e _video.ts. Agora entra o FFMPEG para reorganizar eles a serem legíveis. E tudo dependerá do formato que o áudio e video pertencem.

Algumas correções necessárias para reprodução correta: video_track_timescale para corrigir a velocidade do arquivo (59,94 fps neste caso, pode ser diferente em outros arquivos) e vtag para assinalar a faixa de vídeo como a do formato escrito pela Tricaster e não o MPEG padrão. Também os parâmetros para definir para o programa player como deve ser lido o áudio PCM.

ffmpeg -i arquivo_video.ts -f s16le -ar 48000 -ac 2 -i arquivo_audio.raw -map 0:0 -map 1:0 \
-vcodec copy -video_track_timescale 60000 -vtag xd59 -acodec copy arquivo_video.mov

Isto feito temos um arquivo MOV com o vídeo e áudio que estava presente no arquivo danificado, agora legícvel em um novo arquivo MOV.

sábado, 19 de outubro de 2013

Usando o FFMPEG (FFPLAY) como player de streams HLS

HLS, ou HTTP Live Streaming, formato criado para a Apple para exibição de vídeo ao vivo no iOS e que vem sendo aos poucos sendo adaptada por outras plataformas (infelizmente ainda mal implementado no Android) exige um bocado de malabarismo para quem queira trabalhar com ele. Até mesmo para assistir os streams no computador enquanto trabalha.

Se você usa Mac, não é complicado. O QuickTime X tem suporte nativo ao HLS, basta abrir a URL com M3U8 nele. Nos outros sistemas, especialmente Windows, a coisa complica. O FFMPEG pode ser uma boa solução.

O FFMPEG, em alguns builds, vem com outras duas ferramentas, o FFPROBE e FFPLAY. A primeira serve de ferramenta de diagnóstico para arquivos. A segunda serve justamente para assistir conteúdo utilizando o engine do FFMPEG. E como nas últimas versões (atualmente estamos na 1.2.1) os suporte a HLS como formato de entrada evoluiu muito ele pode ser um player bem útil.

Basta chamar na linha de comando ffmpeg http://a.url.do/seu.stream/playlist.m3u8 Simples e prático.

domingo, 13 de outubro de 2013

Instalando o mais recente FFMPEG no Ubuntu 12.10

(Adaptado de: "Install FFMPEG on Ubuntu From Source" e "Making use of /usr/local/lib")

Tenho um VPS com Ubuntu 12.10 e precisava usá-lo para fazer remotamente conversões de formatos através do FFMPEG. O problema é que as distribuições oficiais via apt-get install ffmpeg não instalam realmente a última versão e sim uma versão modificada do 0.6 apenas para manter compatibilidade com outros programas. Como usar então as últimas versões do aplicativo nesse sistema, ou ainda, como utilizar outras bibliotecas não incluídas por padrão? Compilando do código-fonte. Para os não tão iniciados no mundo Linux (eu incluso), aqui vai um registro do caminho das pedras:

Comece fazendo a limpeza

Retire todas as dependências previamente instaladas via apt-get para evitar conflitos:

sudo apt-get remove ffmpeg x264 libav-tools libvpx-dev libx264-dev yasm

PS: Caso precise da biblioteca libfaac lembre-se de adicionar o repositório multiverse. Leia mais detalhes aqui

Instale as dependências

sudo apt-get update

sudo apt-get -y install autoconf build-essential checkinstall git libass-dev libfaac-dev libgpac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev librtmp-dev libtheora-dev libtool libvorbis-dev pkg-config texi2html zlib1g-dev

Instalando os pacotes

Yasm

cd

wget http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz

tar xzvf yasm-1.2.0.tar.gz

cd yasm-1.2.0

./configure

make

sudo checkinstall --pkgname=yasm --pkgversion="1.2.0" --backup=no --deldoc=yes --fstrans=no --default

make install

x264

cd

git clone --depth 1 git://git.videolan.org/x264

cd x264

./configure --enable-static

make

sudo checkinstall --pkgname=x264 --pkgversion="3:$(./version.sh | awk -F'[" ]' '/POINT/{print $4"+git"$5}')" --backup=no --deldoc=yes --fstrans=no --default

make install

fdk-aac

cd

git clone --depth 1 git://github.com/mstorsjo/fdk-aac.git

cd fdk-aac

autoreconf -fiv

./configure --disable-shared

make

sudo checkinstall --pkgname=fdk-aac --pkgversion="$(date +%Y%m%d%H%M)-git" --backup=no --deldoc=yes --fstrans=no --default

make install

libvpx

cd

git clone --depth 1 http://git.chromium.org/webm/libvpx.git

cd libvpx

./configure --disable-examples --disable-unit-tests

make

sudo checkinstall --pkgname=libvpx --pkgversion="1:$(date +%Y%m%d%H%M)-git" --backup=no --deldoc=yes --fstrans=no --default

make install

E finalmente, o FFMPEG em si

cd

git clone --depth 1 git://source.ffmpeg.org/ffmpeg

cd ffmpeg

./configure --enable-gpl --enable-libass --enable-libfaac --enable-libfdk-aac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-librtmp --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-nonfree --enable-version3

make

sudo checkinstall --pkgname=ffmpeg --pkgversion="7:$(date +%Y%m%d%H%M)-git" --backup=no --deldoc=yes --fstrans=no --default

make install

hash -r

Pronto!

Ué, e esse erro "undefined reference to `x264(...)"?"

É um problema que pode acontecer por referências erradas à biblioteca do x264. Tente:

Edite o arquivo /etc/ld.so.conf e adicione a linha "/usr/local/lib"

Execute "sudo ldconfig"

Continue a instalação do FFMPEG novamente a partir do 'make'"

ERROR: libvpx decoder version must be >=0.9.1

cd ~/libvpx

make clean

git pull

./configure

make

sudo checkinstall --pkgname=libvpx --pkgversion="$(date +%Y%m%d%H%M)-git" --backup=no --default --deldoc=yes

http://stackoverflow.com/questions/14899290/error-libvpx-decoder-version-must-be-0-9-1

sábado, 12 de outubro de 2013

Publicando um stream Flash no Original Livestream.com

Uma capacidade muito interessante do FFMPEG é de poder enviar o resultado final da codificação em forma de streaming para outro computador ou servidor, inclusive no formato RTMP, usado por servidores como o Flash Media Server ou Wowza Server. Sobre essas capacidades falarei mais a fundo numa próxima oportunidade.

O que me levou a fazer esse post é uma dor de cabeça que eu tive durante um bom tempo. Uso um serviço de streaming chamado Livestream, e no seu serviço original (não confundir com o novo Livestream, uma plataforma tecnológica bem diferente) é possível enviar o stream através de programas como Wirecast e Flash Live Encoder, que usam o protocolo RTMP. Ou seja, em tese deveria funcionar. Mas no meu computador não conseguia realizar conexão.

O curioso é que com outros servidores, como o Wowza, eu conseguia. Demorei um certo tempo para descobrir a questão. E acho que agora matei a charada.

Há um certo tempo o FFMPEG permite a publicação de streams através do comando -f rtmp://servidor/app/caminho, mas graças a uma implantação de parte da biblioteca do librtmp, vinda do projeto rtmpdump. Note bem: parte.

Ao tentar usar a URL do Livestream, que utiliza vários parâmetros para autenticação (rtmp://publish.livestream.com/mogulus/[canal]/username=[usuario]/password=[senha]/isAutoLive=true) o parser padrão dessa parte da biblioteca se confundia e acessava o caminho errado. E não é possível passar os parâmetros corretamente.

Tá, e como resolvo isso?

Ao compilar o FFMPEG para esse trabalho, exija as legítimas Havaianas certifique-se que o comando ./configure tenha também o parâmetro --enable-librtmp***, além dos demais parâmetros que você deseje para o FFMPEG. Assim você garante que o FFMPEG será compilado usando a biblioteca original inteira, não apenas a resumida dentro do programa. Aí é só utilizar "rtmp://publish.livestream.com/mogulus/[canal]/username=[usuario]/password=[senha]/isAutoLive=true/live app=mogulus/[canal]/username=[usuario]/password=[senha]/isAutoLive=true live=1" como endereço do servidor.

UPDATE: Caso sua transmissão também seja direcionada para dispositivos móveis (e isso obriga também que o vídeo seja em h264 e o áudio em AAC, nada de MP3) é importante que você defina também "playpath" no comando, indicando o intevalo de keyframes e o bitrate total da transmissão (audio+video). Neste exemplo: "rtmp://publish.livestream.com/mogulus/[canal]/username=[usuario]/password=[senha]/isAutoLive=true/live app=mogulus/[canal]/username=[usuario]/password=[senha]/isAutoLive=true playpath=livestream?videoKeyframeFrequency=5&totalDatarate=400 live=1"

*** Caso você use Mac com o Homebrew, o comando para instalar com o librtmp é brew install ffmpeg --with-rtmpdump

segunda-feira, 7 de maio de 2012

Duplicando o áudio de um vídeo

Na dica sobre nomalização de áudio de vídeos já embutimos recursos para duplicar o áudio de arquivos onde a trilha estéreo tem um dos lados mudos, só que agora retornamos ao assunto para tratar exclusivamente este problema e sem a utilização de programas externos.

ffmpeg -f lavfi -i "amovie=arquivo_original.flv,pan=stereo: c0=c1: c1=c1" -i arquivo_original.flv -map 0:0 -map 1:0 -vcodec copy -acodec libfaac arquivo_final.mp4

Para entender melhor a sintaxe:

A primeira parte do comando causa bastante estranheza, mas tem uma explicação. -f lavfi -i "amovie=arquivo_original.flv,pan=stereo: c0=c1: c1=c1" indica para o FFMPEG que o arquivo de entrada na verdade é um filtro do libav e logo em seguida passa as opções para o mesmo. Neste caso é a biblioteca que abre o arquivo e não o FFMPEG em si, por isso a sintaxe um pouco estranha. pan=stereo: c0=c1: c1=c1 indica como será o balanceamento do áudio, onde c0 é o canal esquerdo e c1 é o canal direito. Como queremos que o canal direito seja usado nos dois lados do áudio indicamos c0=c1 e c1=c1.

O resto é familiar. -i arquivo_original.flv abre o segundo arquivo que servirá como fonte de vídeo, -map 0:0 -map 1:0 aponta qual stream será o de vídeo e o de áudio, -vcodec copy -acodec libfaac os codecs utilizados e por fim o nome do arquivo final.

sábado, 5 de maio de 2012

De FLV para MP4 sem recompressão

Aprendemos no último post a diferença entre codec e wrapper. Agora vamos tirar proveito disso:

É uma situação bastante corriqueira querer salvar um vídeo do YouTube ou outro site de compartilhamento de vídeos para ver em outro dispositivo. Muitas vezes os aplicativos de download de vídeos não fazem a conversão de formatos ou o fazem piorando ainda mais a qualidade do arquivo que na maioria das vezes já não é bom.

O FFMPEG resolve esse problema. Se o arquivo FLV foi codificado em H264/AAC (você pode ver esta informação pelo VLC em "Informações da Mídia > Detalhes do codec") basta executar:

ffmpeg -i arquivo.flv -vcodec copy -acodec copy arquivo_final.mp4

Pronto, você já tem um arquivo MP4, compatível com uma grande variedade de dispositivos (iOS por exemplo) sem precisar recodificar o arquivo e sem perda nenhuma de qualidade nesse processo.

terça-feira, 24 de abril de 2012

Noções básicas: Codec e wrapper

Para dominar bem o uso do FFMPEG é preciso antes deixar claro alguns pontos que a maioria das pessoas fazem confusão. Um dos principais é a diferença entre wrapper e codec. É muito comum uma pessoa falar "preciso de um vídeo em formato AVI" e depois ficar confuso pelo vídeo não funcionar no player ou dispositivo utilizado. Vamos a explicação:

Um vídeo e um áudio carregam quantidades enormes de informação digital. Para fazerem parte do nosso dia a dia precisam ser comprimidos. Os processos e técnicas utilizadas para atingir esse objetivo determinam o codec usado. Codec = codificação. Aí entram o h264, DivX, MP3, Windows Media...

Já AVI, tal como FLV, MKV e muitos outros que geralmente emprestam o nome ao conhecimento popular são "wrappers", ou seja, o que a própria tradução diz: Empacotadores. Eles unem vários streams (fluxos) de áudio e vídeo, em diferentes codecs, em um arquivo baixável, um streaming, uma transmissão de TV digital ou TV a cabo, entre outros.

Fazendo uma analogia com o mundo analógico (rá!) o wrapper seria a diagramação do livro, a quantidade de palavras por página, a existência ou não de notas no rodapé das páginas, etc... e o codec a língua em que o livro está escrito.

Portanto, voltando ao exemplo inicial, dizer que um arquivo é AVI não indica muita coisa além da forma que ele é organizado entre stream de áudio e vídeo. É preciso saber os codecs que serão usados dependendo quais são suportados pelo dispositivo-alvo. DivX? h264? Indeo? DV? Tudo depende do objetivo buscado.

Conceito esclarecido? Então até o próximo post, onde baseado nesses conceitos vamos ver como é passar um vídeo Flash FLV baixado do YouTube ser tranformado em MP4 sem perda de qualidade numa recompressão.