Генерация случайных эскизов с помощью PHP + FFMPEG

Я пытаюсь создать эскизы из случайных точек в фильме, используя расширение FFMPEG и FFMPEG-PHP.

Мой скрипт работает нормально .. однако требуется 20 минут, чтобы сгенерировать 5-10 миниатюр!

Сценарий работает путем генерации случайных чисел, которые позже используются в качестве номеров кадров. Все сгенерированные числа находятся в пределах количества кадров в фильмах.

Можете ли вы понять, почему этот сценарий занимает 20 минут? Если нет, лучшее решение?

<?php //Dont' timeout set_time_limit(0); //Load the file (This can be any file - still takes ages) $mov = new ffmpeg_movie('1486460.mp4'); //Get the total frames within the movie $total_frames = $mov->getFrameCount(); //Loop 5-10 times to generate random frames 5-10 times for ($i = 1; $i <= 5; ) { // Generate a number within 200 and the total number of frames. $frame = mt_rand(200,$total_frames); $getframe = $mov->getFrame($frame); // Check if the frame exists within the movie // If it does, place the frame number inside an array and break the current loop if($getframe){ $frames[$frame] = $getframe ; $i++; } } //For each frame found generate a thumbnail foreach ($frames as $key => $getframe) { $gd_image = $getframe->toGDImage(); imagejpeg($gd_image, "images/shot_".$key.'.jpeg'); imagedestroy($gd_image); echo $key.'<br/>'; } ?> 

Сценарий СЛЕДУЕТ генерировать числа кадров, которые действительны? Все, что в пределах START-END должно быть действительным числом кадров? Но петля занимает много времени!

Вы можете вызвать ffmpeg из командной строки, используя ключ -ss чтобы найти подходящую стартовую точку (во времени, а не в числе кадров) и -vframes 1 чтобы сказать, что он извлекает ровно один кадр, например:

 ffmpeg -i 1486460.mp4 -ss 10 -vframes 1 images/shot_10.jpg 

images/shot_10.jpg кадр с 10 секунд и вызовет его images/shot_10.jpg

Проблема здесь в том, что слово random . Я успешно получил продолжительность видео, а затем попытаюсь получить один кадр с такой случайной продолжительностью. Легко модифицируется для большего количества фреймов:

  $cmd = "ffmpeg -i {$src} 2>&1 |grep Duration"; $output = array (); exec($cmd, $output); if(count($output)) { $duration = explode(':', trim(str_replace('Duration:', NULL, current(explode(',', current($output)))))); list($hour, $min, $sec) = $duration; $sec = sprintf("%02d:%02d:%02d", rand(0, $hour), rand(0, $min), rand(0, $sec)); } else { $sec = "00:00:12"; //12sec it's ok :) } $cmd = "ffmpeg -ss {$sec} -i {$src} -s {$w}x{$h} -f image2 -vframes 1 {$destination}"; $output = array (); exec($cmd, $output); 

Я не очень много знаю о форматах фильмов, но поскольку сжатие, вероятно, зависит от однопроходного дельта-сжатия с опорными кадрами, если положение опорных кадров не определено, это означает, что система должна воспроизводить полный фильм чтобы получить конкретное смещение. Было бы легко проверить это, всегда загружая, скажем, поиск кадра между смещением 20 и количеством кадров, деленное на какое-то значение.

Предполагая, что это так, у вас есть еще одна проблема в том, как вы разработали свой алгоритм, вам нужно перемотать в начало и поиск вперед для каждого из 5 кадров – если вы заранее создали свои смещения, а затем отсортировали list, ffmpeg может получать фреймы за один проход.

НТН

C.

Вы написали ошибку в своем цикле.

 if($getframe) { $frames[$frame] = $getframe; $i++; } 

Допустим, цикл for работает бесконечно, пока не сломается. Если оператор if является ложным в первый раз, поэтому $i++ не может быть достигнуто, и цикл тогда бесконечен.

Вам нужно разместить $i++ в нижней части цикла for, тогда выполнение будет составлять 2 секунды вместо 20 минут.