叠帧 · Imagens Numeradas → Vídeo de Capa
Visão Geral
Escaneie uma pasta, mantenha apenas os arquivos cujo nome seja puramente um número (01.jpg, 200.jpg), exiba-os em ordem numérica e codifique um MP4 H.264. Entre as imagens, você pode usar corte seco (--transition none) ou crossfade (--transition fade, o padrão). Imagens não numeradas (logo, discord, …) e vídeos existentes são ignorados.
Procedimento
- Inspecione a pasta primeiro. Liste os arquivos e verifique as dimensões de uma imagem com ffprobe. Anote quantas imagens numeradas existem e se há proporções misturadas.
- Faça backup da saída existente. Se
<pasta>/cover.mp4já existir, renomeie-o paracover.prev-YYYYMMDD.mp4antes de renderizar. Nunca sobrescreva silenciosamente a renderização anterior do usuário. - Renderize com o script incluído:
python "<dir-da-skill>/scripts/imgseq2mp4.py" --dir "<pasta>" --out cover.mp4
Padrões: 0,8 s por imagem com um crossfade fade de 0,2 s, 30 fps, 1920x1080, preenchimento letterbox, CRF 18, sem áudio, +faststart.
- Verifique, não suponha. Investigue a duração/quadros, confirme que não há quadros pretos e extraia o último quadro para comparar com a última imagem de origem:
ffprobe -v error -show_entries format=duration -show_entries stream=nb_frames -of default=nw=1 cover.mp4
ffmpeg -i cover.mp4 -vf blackdetect=d=0.05:pix_th=0.10 -an -f null -
ffmpeg -y -sseof -0.05 -i cover.mp4 -frames:v 1 frame_last.png
Quando as transições estiverem ativadas, capture também um quadro dentro da primeira janela de transição e verifique se é uma mescla (mais próximo da imagem 2 do que seria um corte seco, mas ainda mensuravelmente diferente de ambas as fontes).
- Relate a contagem de imagens, imagens ignoradas, duração total, caminho e tamanho da saída.
Ritmo
Comprimento total = n × segundos − (n−1) × segundos_de_transição. O tempo de exibição de cada imagem na tela é segundos − segundos_de_transição; esse passo, não --seconds, é o que o espectador percebe.
| Passo por imagem | Comando | 20 imagens | 44 imagens | 200 imagens |
|---|---|---|---|---|
| 0,35 s | --seconds 0.5 --transition-seconds 0.15 | ~8 s | ~18 s | ~75 s |
| 0,45 s | --seconds 0.65 --transition-seconds 0.2 | ~9 s | ~22 s | ~95 s |
| 0,60 s (padrão) | --seconds 0.8 --transition-seconds 0.2 | ~12 s | ~27 s | ~120 s |
| 0,80 s | --seconds 1.0 --transition-seconds 0.2 | ~16 s | ~34 s | ~150 s |
Cortes secos usam --transition none --seconds <passo>.
Avance uma linha por vez quando o usuário pedir mais rápido ou mais lento. Mantenha --transition-seconds em 0,15–0,2; valores maiores começam a parecer uma apresentação de slides em vez de um crossfade.
Regras
- Apenas crossfade. Não use transições de deslize, cortina ou outras transições push — elas foram rejeitadas como direção.
- Selecione com regex
^\d+\.(jpe?g|png|webp)$— o nome do arquivo deve conter apenas dígitos. Isso é o que excluilogo.jpg,discord.jpg,cover.jpg. - Ordene por valor inteiro, não lexicograficamente (
2.jpgantes de10.jpg,99.jpgantes de100.jpg). Lacunas na numeração são aceitáveis; números faltantes não são erros. - Use
--fit pad(padrão) para que todo o quadro permaneça visível. Use--fit fillapenas quando o usuário explicitamente quiser corte borda a borda. - A saída é silenciosa. Não adicione música a menos que o usuário forneça uma faixa.
- Mantenha as cores intactas. JPEGs são full-range; se você codificá-los como H.264 full-range não marcado, a maioria dos players decodifica como limited e o resultado fica mais claro e desbotado (+10 níveis). O script converte para limited-range bt709 e o marca — não "simplifique" essa cadeia.
- O script se recusa a sobrescrever
--outsem--force; resolva fazendo backup, não forçando cegamente.
Notas da máquina
- ffmpeg não está no PATH. O script prefere um
ffmpeg.exereal (~/.dsh/tools/ffmpeg/**/ffmpeg.exe, depois cópias sobC:/ouD:/ffmpeg) antes de qualquer shim.cmd, porque o shim roteia via cmd.exe e limita a linha de comando a ~8k caracteres. Substitua comFFMPEG=/caminho/para/ffmpeg. - Esta compilação não possui
-filter_complex_script; passe o gráfico xfade inline via-filter_complex(o script já faz isso). - As transições são renderizadas em grupos de
--chunk(padrão 6) e depois mescladas, para que no máximo 6 decodificadores estejam abertos ao mesmo tempo. Uma única passagem de xfade com 44 entradas esgotou a RAM em uma máquina de 16 GB (~2,4 GB livres) e falhou comCannot allocate memory; não aumente--chunkacima de ~8 aqui. O agrupamento é recursivo, então 200 imagens são mescladas em três estágios sem estouro de memória. - Os arquivos de estágio intermediário são codificados com CRF 14 / veryfast e descartados; apenas a passagem final usa
--crf/ medium. - Os quadros intermediários precisam de um diretório gravável. Os resultados de
tempfile.mkdtemp()podem ser inacessíveis em sandboxes restritas (observado no Windows + DSH: ffmpeg obtevePermission deniedeos.listdirgerouWinError 5). O script, portanto, cria um diretório simples, prova que é gravável e recorre a$IMGSEQ_WORKDIR→ temp do sistema →<dir-de-saida>/.imgseq-work.
Recursos
scripts/imgseq2mp4.py— seleção, ordenação numérica, renderização com corte seco ou crossfade, resumo amigável para verificação.