Como criar uma miniatura a partir do meio de um vídeo com o FFmpeg

6

Existe uma maneira de capturar uma miniatura de vídeo no FFmpeg?

Gostaria de pegar o quadro do meio como o vídeo e usá-lo como miniatura. A duração do vídeo é desconhecida.

A capacidade de especificar as dimensões da miniatura também seria útil.

    
por StackOverflowNewbie 20.09.2012 / 08:08

6 respostas

9

Comando de uma linha:

ffmpeg -i input.mp4 -vcodec mjpeg -vframes 1 -an -f rawvideo -ss 'ffmpeg -i input.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d , | awk -F ':' '{print ($3+$2*60+$1*3600)/2}'' output.jpg

O subcomando obtém a duração total do vídeo de entrada

ffmpeg -i input.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,

E canalizar para awk para calcular a duração / 2 como este

echo '00:01:30.000' | awk -F ':' '{print ($3+$2*60+$1*3600)/2}'

Então, dê isso em segundos para a opção -ss e pronto.

Se você gostaria de especificar o tamanho, adicione a opção -s como essa WxH whet W e H são valores inteiros (ex: -s 800x600 ou -s svga) ou leia a página man do ffmpeg para ver outras opções disponíveis ou formatar .

    
por 03.06.2014 / 20:32
5

Primeiro de tudo, use sempre a versão mais recente do FFmpeg.

Se você tiver acesso ao PHP, sua pergunta será respondida com perfeição no Stack Overflow: Use o FFMpeg para obter o quadro intermediário de um vídeo?

$output = shell_exec("/usr/local/bin/ffmpeg -i {$path}");
preg_match('/Duration: ([0-9]{2}):([0-9]{2}):([^ ,])+/', $output, $matches);
$time = str_replace("Duration: ", "", $matches[0]);
$time_breakdown = explode(":", $time);
$total_seconds = round(($time_breakdown[0]*60*60) + ($time_breakdown[1]*60) + $time_breakdown[2]);
shell_exec("/usr/local/bin/ffmpeg -y  -i {$path} -f mjpeg -vframes 1 -ss " . ($total_seconds / 2) . " -s {$w}x{$h} {$output_filename}"; 

O que ele fará é apenas extrair a duração da saída do FFmpeg e usá-la para determinar o timecode do quadro intermediário.

Você pode facilmente adaptar isso a outros shells e simplesmente inserir no seguinte comando, onde o quadro do meio está aproximadamente em 534 segundos:

ffmpeg -y  -i input.mp4 -f mjpeg -vframes 1 -ss 534 thumbnail.jpg

Você sempre pode alterar o tamanho com -s 480x320 ou similar, dependendo do tamanho desejado, inserido em algum lugar após a opção -i input.mp4 .

A solução acima é um pouco imprecisa. Ele lhe dará imediatamente um resultado, mas você não pode especificar qual quadro deseja. Se você já conhece o quadro exato que deseja extrair, use o filtro select , por exemplo, com o número de quadros 12345 :

ffmpeg -i input.mp4 -filter:v select="eq(n\,12345)" -vframes 1 thumbnail.jpg

Observe que esse comando pode demorar um pouco, já que ele precisa pular para o quadro especificado antes de extraí-lo.

    
por 20.09.2012 / 08:36
1

Aqui está um método usando:

  • ffprobe para obter a duração
  • bc para calcular metade da duração
  • ffmpeg para criar a imagem em miniatura

Exemplo:

input=video.mp4
duration=$(ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 "$input")
ffmpeg -ss "$(echo "$duration"/2 | bc)" -i "$input" -q:v 2 -vframes 1 output.jpg
  • Você pode substituir meu uso preguiçoso de bc por sua alternativa favorita, como awk ou printf , se preferir.

  • Você pode redimensionar / redimensionar a imagem adicionando o filtro de escala como uma opção de saída em sua Comando ffmpeg , como -vf scale=320:-1 .

  • A duração fornecida por ffprobe pode nem sempre ser precisa, dependendo da entrada. No caso improvável de você ter um problema como esse, será necessário decodificar totalmente a entrada, como com ffmpeg -i input -f null - , e analisar a saída para obter o valor de duração correto.

por 15.05.2015 / 21:42
0
$currentVideoDuration =  shell_exec("$ffmpeg -i $videoPath 2>&1 | grep Duration");
  $actualDuration = substr($currentVideoDuration, 11, 12);
  $arrayWithHoursMinsAndSecs = explode(":", $actualDuration);
  $thisVideoDurationInSeconds = $arrayWithHoursMinsAndSecs[2] + $arrayWithHoursMinsAndSecs[1]*60 + $arrayWithHoursMinsAndSecs[0]*3600;
  $halfVideoDuration = $thisVideoDurationInSeconds/2;
  echo 'midpoint of this video: '. $halfVideoDuration;
  echo shell_exec("$ffmpeg -i $videoPath -y -ss 00:00:$halfVideoDuration -vframes 1 thumbnail.png 2>&1");

substitua $ videopath pelo caminho para o seu vídeo

    
por 03.05.2017 / 21:17
0

A solução simples é:

 ffmpeg -i l1.mp4 -ss 00:00:14.435 -vframes 1 out.png
    
por 28.09.2018 / 08:52
-1

Este comando bash funciona como um encanto:

avconv -i 'in.mpg' -vcodec mjpeg -vframes 1 -an -f rawvideo \
-s 420x300 -ss 'avconv -i in.mpg 2>&1 | grep Duration \
| awk '{print $2}' | tr -d , \ 
| awk -F ':' '{print ($3+$2*60+$1*3600)/2}'' out.jpg
    
por 09.11.2014 / 18:14