Miniaturas significativas para um vídeo usando o FFmpeg

71

O FFmpeg pode capturar imagens de vídeos que podem ser usados como miniaturas para representar o vídeo. As formas mais comuns de fazer isso são capturadas no Wiki do FFmpeg .

Mas não quero escolher quadros aleatórios em alguns intervalos. Eu encontrei algumas opções usando filtros no FFmpeg para capturar mudanças de cena:

O filtro thumbnail tenta encontrar os quadros mais representativos no vídeo:

ffmpeg -i input.mp4 -vf  "thumbnail,scale=640:360" -frames:v 1 thumb.png

e o comando a seguir seleciona apenas quadros que têm mais de 40% de alterações em comparação com as alterações anteriores (e provavelmente são mudanças de cena) e gera uma sequência de 5 PNGs.

ffmpeg -i input.mp4 -vf  "select=gt(scene\,0.4),scale=640:360" -frames:v 5 thumb%03d.png

Crédito da informação para os comandos acima para Fabio Sonnati . O segundo parecia melhor, pois eu conseguia imagens n e escolher o melhor. Eu tentei e gerou a mesma imagem 5 vezes.

Mais algumas investigações me levaram a:

ffmpeg -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr  out%02d.png

-vsync vfr garante que você obtenha imagens diferentes. Isso sempre escolhe o primeiro quadro do vídeo, na maioria dos casos, o primeiro quadro é créditos / logotipo e não é significativo, então adicionei um -ss 3 para descartar os primeiros 3 segundos do vídeo.

Meu comando final é assim:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.jpg

Isso foi o melhor que pude fazer. Tenho notado que desde que escolhi apenas 5 vídeos, todos são principalmente do início do vídeo e podem perder cenas importantes que ocorrem mais tarde no vídeo

Eu gostaria de escolher seu cérebro para quaisquer outras opções melhores.

    
por d33pika 18.01.2013 / 09:35

5 respostas

23

Que tal procurar, idealmente, o primeiro quadro de mudança de > 40% dentro de cada um dos 5 intervalos de tempo, onde os períodos de tempo são o 1º, 2º, 3º, 4º e 5º 20% do vídeo. p>

Você também pode dividi-lo em 6 intervalos de tempo e desconsiderar o primeiro para evitar créditos.

Na prática, isso significaria configurar o fps para um número baixo enquanto aplica a verificação de mudança de cena e o argumento para eliminar o primeiro bit do vídeo.

... algo como:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.4)" -frames:v 5 -vsync vfr -vf fps=fps=1/600 out%02d.jpg
    
por 15.06.2013 / 23:35
5

Definir significativo é difícil, mas se você quiser fazer com que as miniaturas N ocupem todo o arquivo de vídeo, é isso que uso para gerar miniaturas na produção com conteúdo enviado pelo usuário.

Pseudo-código

for X in 1..N
  T = integer( (X - 0.5) * D / N )  
  run 'ffmpeg -ss <T> -i <movie>
              -vf select="eq(pict_type\,I)" -vframes 1 image<X>.jpg'

Onde:

  • D - duração do vídeo lida de ffmpeg -i <movie> sozinho ou ffprobe que tem um bom escritor de saída JSON btw
  • N - número total de miniaturas que você deseja
  • X - número da miniatura, de 1 a N
  • T - ponto no tempo para a miniatura

Simplesmente, o texto acima anota o quadro-chave central de cada partição do filme. Por exemplo. se o filme tiver 300s de comprimento e você quiser 3 miniaturas, será necessário um quadro-chave após 50s, 150s e 250s. Para 5 miniaturas, seria 30s, 90s, 150s, 210s, 270s. Você pode ajustar N dependendo da duração do filme D, por exemplo Um filme de 5 minutos terá 3 miniaturas, mas mais de 1 hora terá 20 miniaturas.

Desempenho

Cada chamada do comando ffmpeg acima leva uma fração de segundo (!) para ~ 1GB H.264. Isso ocorre porque ele salta instantaneamente para <time> position (mente -ss before -i ) e obtém o primeiro quadro chave que é praticamente o JPEG completo. Não há tempo perdido para renderizar o filme para corresponder à posição exata do tempo.

Pós-processamento

Você pode misturar acima com scale ou qualquer outro método de redimensionamento. Você também pode remover quadros de cores sólidas ou tentar misturá-los com outros filtros, como thumbnail .

    
por 06.10.2014 / 22:21
2

Uma vez fiz algo parecido, mas exportei todos os frames do vídeo (em 1 fps) e os comparei com um utilitário perl que calculei a diferença entre as imagens. Eu comparei cada quadro com as miniaturas anteriores e, se era diferente de todas as miniaturas, adicionei-o à coleção de miniaturas. A vantagem aqui é que, se o seu vídeo passar da cena A para B e ele retornar para A, o ffmpeg exportará 2 quadros de A.

    
por 17.03.2013 / 15:36
2

Tente isso

 ffmpeg -i input.mp4 -vf fps= no_of_thumbs_req/total_video_time out%d.png

Usando esse comando, posso gerar o número necessário de miniaturas representativas de todo o vídeo.

    
por 31.07.2015 / 03:33
1

Aqui está o que eu faço para gerar uma miniatura periódica para que os streams m3u8 ao vivo sejam usados como poster. Eu encontrei executando uma tarefa ffmpeg contínua apenas para gerar miniaturas come toda a minha CPU, então, em vez disso, eu corro um cronjob a cada 60 segundos que gera todas as miniaturas para meus fluxos.

#!/usr/bin/env bash

## this is slow but gives better thumbnails (takes about 1+ minutes for 20 files)
#-vf thumbnail,scale=640:360 -frames:v 1 poster.png

## this is faster but thumbnails are random (takes about 8 seconds for 20 files)
#-vf scale=640:360 -frames:v 1 poster.png
cd ~/path/to/streams

find . -type f \
  -name "*.m3u8" \
  -execdir sh -c 'ffmpeg -y -i "$0" -vf scale=640:360 -frames:v 1 "poster.png"' \
  {} \;

Se você precisa fazer mais do que 60 segundos (limitação do cronjob), então você pode fazer um loop while no seu script e ele será executado para sempre. Basta adicionar um sleep 30 para alterar a frequência para 30 segundos. No entanto, não recomendo fazer isso com um grande número de vídeos, pois a execução anterior pode não ser concluída antes do início da próxima.

Idealmente, com o cronjob, executo-o a cada 5 minutos.

    
por 31.12.2015 / 08:03