Vídeo é código: composição com tempo e render determinístico
No motion por código, o vídeo é uma página que sabe desenhar qualquer instante. Um navegador sem tela pede o quadro 0, o 1, o 2, e o FFmpeg junta tudo num MP4. Se a mesma entrada der sempre os mesmos quadros, você pode refazer, corrigir e versionar o vídeo como código. Nesta aula você prova isso na sua máquina.
1As quatro peças: composição, relógio, navegador sem tela e codificador
2Comparar dois renders quadro a quadro com um comando
3Por que Math.random e Date.now quebram o vídeo
4Sorteio com semente: variedade sem perder a repetição
Objetivo: provar na sua máquina que a mesma composição dá os mesmos quadros e achar o que quebra isso.
01 · Do código ao MP4
Clique em cada peça. HyperFrames (HTML) e Remotion (React) seguem o mesmo desenho.
mesma entrada → mesmos quadros
Entre máquinas diferentes, GPU e fontes podem mudar alguns pixels; para repetir em outra máquina, o render do 0.8.176 tem --docker ("deterministic render") e --no-browser-gpu.
Determinístico = rodar duas vezes no mesmo ambiente e ter os mesmos quadros. É o que permite corrigir um detalhe sem refazer o resto.
02 · O que quebra a repetição
Três fontes de acaso que o lint do HyperFrames procura.
1. Sorteio
Cada render sorteia de novo: os mesmos 12 pontos nascem em lugares diferentes.
A troca é um sorteio com semente (mulberry32): a mesma semente dá os mesmos números, sempre.
Trocaconst sorteio = mulberry32(42); depois sorteio() no lugar de Math.random().
2. Relógio da máquina
A hora de agora muda a cada render e a cada quadro.
Tudo o que anima tem de vir do tempo que o motor manda, nunca do relógio do computador.
3. Rede na hora
Buscar dado na internet durante o render pode trazer outra resposta ou falhar no meio.
Busque antes, grave num arquivo da pasta e leia de lá (a aula 7 faz isso com as legendas).
03 · O ensaio: dois renders, comparados quadro a quadro
Duas composições quase iguais: uma usa Math.random, a outra um sorteio com semente. Cada uma é renderizada duas vezes e comparada pelo hash de cada quadro.
São 90 quadros (3 s a 30 fps). Com Math.random só o primeiro coincide; com a semente, os 90. O primeiro render baixa o hyperframes@0.8.176 e o navegador, por isso demora mais.
Comparar o MP4 com md5sum pode dar diferente mesmo com quadros iguais (metadados do arquivo). O comparar-quadros.sh decodifica e compara a imagem de cada quadro com ffmpeg -f framemd5.
04 · O lint acha o acaso antes do render
O mesmo par de composições passado pelo lint do HyperFrames. Ele aponta a linha e sugere a semente.
Terminal · lint das duas composições
K=~/projetos/formacao-cinema-ia-motion-v72/kit
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
for ex in a1-sorteio a1-semente; do
cd "$K/exemplos/$ex"
npx -y hyperframes@0.8.176 lint; echo "saída: $?"
done
Exemplo do repositório
◆ Linting a1-sorteio/index.html
✗ [~/projetos/formacao-cinema-ia-motion-v72/kit/exemplos/a1-sorteio/index.html:24:24] non_deterministic_code: Script contains `Math.random()` which produces non-deterministic output. Renders may differ between frames or runs.
Fix: Use a seeded PRNG (e.g. a simple mulberry32) so renders are deterministic across frames.
◇ 1 error(s), 0 warning(s)
saída: 1
◆ Linting a1-semente/index.html
◇ 0 errors, 0 warnings
saída: 0
O lint sai com código 1 quando acha erro: dá para usar como portão antes de qualquer render.
05 · Prática
Ensaio, lint e a sua semente.
E1 · Ver o acaso e a semente
10 min
Clone o curso em ~/projetos e rode o bloco "dois renders de cada e a comparação".
Pronto quando: a1-sorteio termina em DIFEREM: 89 de 90 quadros e saída: 1; a1-semente em IGUAIS: 90/90 quadros e saída: 0. (No seu computador o número de quadros diferentes pode variar; o que não pode é a semente dar diferente.)
E2 · O lint como portão
5 min
Rode o bloco do lint.
Pronto quando: a1-sorteio mostra non_deterministic_code e saída: 1; a1-semente mostra 0 errors, 0 warnings e saída: 0.
E3 · Outra semente, mesma garantia
10 min
Em /tmp/ensaio-motion/a1/a1-semente, troque mulberry32(42) por mulberry32(7), renderize duas vezes (render-3.mp4 e render-4.mp4, com o mesmo comando do bloco) e compare: 3 com 4, depois 1 com 3.
Pronto quando:bash ~/projetos/formacao-cinema-ia-motion-v72/kit/comparar-quadros.sh render-3.mp4 render-4.mp4 → IGUAIS: 90/90 quadros; o mesmo com render-1.mp4 render-3.mp4 → começa com DIFEREM:.
06 · Teste da aula
A explicação aparece depois da sua resposta.
Pergunta 1 de 4
Quem decide qual instante a composição desenha?
Correto
O motor pede o instante (2,5 s, quadro 75) e a composição desenha aquele instante. Por isso a velocidade não muda o resultado: no mesmo ambiente, uma máquina lenta demora mais, mas dá os mesmos quadros.
Não é essa
O motor pede o instante (2,5 s, quadro 75) e a composição desenha aquele instante. Por isso a velocidade não muda o resultado: no mesmo ambiente, uma máquina lenta demora mais, mas dá os mesmos quadros.Rever: Do código ao MP4
Pergunta 2 de 4
Dois renders da mesma composição deram 89 de 90 quadros diferentes. O que procurar primeiro?
Correto
Acaso dentro da composição é a causa mais comum, e o lint aponta Math.random pela linha. Os dois renders usaram o mesmo hyperframes@0.8.176 e o mesmo FFmpeg: o que mudou foi a entrada.
Não é essa
Acaso dentro da composição é a causa mais comum, e o lint aponta Math.random pela linha. Os dois renders usaram o mesmo hyperframes@0.8.176 e o mesmo FFmpeg: o que mudou foi a entrada.Rever: O que quebra a repetição
Pergunta 3 de 4
Para que serve o sorteio com semente?
Correto
A semente fixa a sequência de números: os pontos continuam espalhados, mas sempre nos mesmos lugares. Trocar a semente troca o desenho de propósito, e de novo de forma repetível.
Não é essa
A semente fixa a sequência de números: os pontos continuam espalhados, mas sempre nos mesmos lugares. Trocar a semente troca o desenho de propósito, e de novo de forma repetível.Rever: O ensaio: dois renders, comparados quadro a quadro
Pergunta 4 de 4
Por que comparar quadro a quadro e não o MP4 inteiro?
Correto
O que interessa é a imagem. O framemd5 decodifica cada quadro e compara os pixels; o hash do arquivo inteiro também muda com metadados que não aparecem na tela.