Есть ли способ получить миниатюру видео в FFmpeg?
Я хотел бы взять самый средний кадр в качестве видео и использовать его в качестве эскиза. Продолжительность видео неизвестна.
Возможность указать размеры миниатюры также будет полезна.
Есть ли способ получить миниатюру видео в FFmpeg?
Я хотел бы взять самый средний кадр в качестве видео и использовать его в качестве эскиза. Продолжительность видео неизвестна.
Возможность указать размеры миниатюры также будет полезна.
Однострочная команда:
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
Подкоманда получает общую продолжительность входного видео
ffmpeg -i input.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,
И направить его в awk, чтобы вычислить продолжительность /2 следующим образом
echo '00:01:30.000' | awk -F ':' '{print ($3+$2*60+$1*3600)/2}'
Так что дайте это среди секунд опции -ss, и все готово.
Если вы хотите указать размер, добавьте опцию -s, например WxH, где W и H - целочисленные значения (например, -s 800x600 или -s svga) или прочитайте справочную страницу ffmpeg, чтобы увидеть другие доступные опции или формат.
Прежде всего, всегда используйте последнюю версию FFmpeg.
Если у вас есть доступ к PHP, на ваш вопрос отлично ответят по переполнению стека: используйте FFMpeg, чтобы получить средний кадр видео?
$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}";
Он просто извлекает длительность из вывода FFmpeg и использует ее для определения временного кода среднего кадра.
Вы можете легко адаптировать его к другим оболочкам и просто вставить в следующую команду, где средний кадр примерно равен 534
секундам:
ffmpeg -y -i input.mp4 -f mjpeg -vframes 1 -ss 534 thumbnail.jpg
Вы всегда можете изменить размер с -s 480x320
или аналогичным, в зависимости от того, насколько он велик, вставленный где-то после опции -i input.mp4
.
Вышеупомянутое решение немного неточно. Это сразу даст вам результат, но вы не можете указать, какой кадр вы хотите. Если вы уже знаете точный кадр, который хотите извлечь, используйте фильтр select
, например, с номером кадра 12345
:
ffmpeg -i input.mp4 -filter:v select="eq(n\,12345)" -vframes 1 thumbnail.jpg
Обратите внимание, что эта команда может занять некоторое время, поскольку ей нужно перейти к указанному кадру, прежде чем она сможет извлечь его.
Вот метод, использующий:
ffprobe
чтобы получить длительностьbc
чтобы рассчитать половину продолжительностиffmpeg
чтобы сделать эскиз изображенияПример:
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
Вы можете заменить мое ленивое использование bc
вашей любимой альтернативой, такой как awk
или printf
, если хотите.
Вы можете масштабировать / изменять размер изображения, добавив фильтр масштабирования в качестве параметра вывода в вашей команде ffmpeg
, например -vf scale=320:-1
.
Продолжительность, предоставляемая ffprobe
не всегда может быть точной в зависимости от ввода. В маловероятном случае, если у вас возникнет такая проблема, вам придется полностью декодировать ввод, например, с помощью ffmpeg -i input -f null -
, и проанализировать вывод, чтобы получить правильное значение длительности.
Простое решение:
ffmpeg -i l1.mp4 -ss 00:00:14.435 -vframes 1 out.png
$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");
замените $ videopath на путь к вашему видео
Эта команда bash работает как шарм:
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