Может ли ffmpeg показать индикатор выполнения?

Я конвертирую файл .avi в .flv-файл, используя ffmpeg. Поскольку для преобразования файла требуется много времени, я бы хотел отобразить индикатор выполнения. Может кто-нибудь, пожалуйста, назовите меня, как идти примерно так же.

Я знаю, что ffmpeg каким-то образом должен выводить прогресс в текстовом файле, и я должен прочитать его с помощью вызовов ajax. Но как мне получить ffmpeg для вывода прогресса в текстовый файл?

Большое спасибо.

Я играю с этим несколько дней. Эта вещь «ffmpegprogress» помогла, но было очень сложно наладить работу с моей настройкой и трудно читать код.

Чтобы показать прогресс ffmpeg, вам необходимо сделать следующее:

  1. запустите команду ffmpeg с php, не ожидая ответа (для меня это была самая сложная часть)
  2. скажите ffmpeg, чтобы отправить его вывод в файл
  3. с передней стороны (AJAX, Flash, независимо) попадает либо в этот файл напрямую, либо в файл php, который может вывести прогресс из вывода ffmpeg.

Вот как я решил каждую часть:

1. Я получил следующую идею от «ffmpegprogress». Это он и сделал: один PHP-файл вызывает другого через http-сокет. Второй на самом деле запускает «exec», и первый файл просто зависает на нем. Для меня его реализация была слишком сложной. Он использовал «fsockopen». Мне нравится CURL. Итак, вот что я сделал:

$url = "http://".$_SERVER["HTTP_HOST"]."/path/to/exec/exec.php"; curl_setopt($curlH, CURLOPT_URL, $url); $postData = "&cmd=".urlencode($cmd); $postData .= "&outFile=".urlencode("path/to/output.txt"); curl_setopt($curlH, CURLOPT_POST, TRUE); curl_setopt($curlH, CURLOPT_POSTFIELDS, $postData); curl_setopt($curlH, CURLOPT_RETURNTRANSFER, TRUE); // # this is the key! curl_setopt($curlH, CURLOPT_TIMEOUT, 1); $result = curl_exec($curlH); 

Установка CURLOPT_TIMEOUT в 1 означает, что для ответа будет ждать 1 секунда. Предпочтительно, чтобы это было ниже. Существует также CURLOPT_TIMEOUT_MS, который занимает миллисекунды, но для меня это не сработало.

Через 1 секунду CURL зависает, но команда exec все еще работает. Часть 1 решена.

BTW – Несколько человек предлагали использовать команду nohup для этого. Но для меня это, похоже, не работало.

*ТАКЖЕ! Наличие php-файла на вашем сервере, который может выполнять код непосредственно в командной строке, является очевидным угрозой безопасности. У вас должен быть пароль или каким-то образом закодировать почтовые данные.

2. Сценарий «exec.php» выше также должен указывать ffmpeg для вывода в файл. Вот код для этого:

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1> path/to/output.txt 2>&1"); 

Обратите внимание на «1> путь / to / output.txt 2> & 1». Я не эксперт в командной строке, но из того, что я могу сказать, эта строка говорит «отправить нормальный вывод в этот файл и отправить ошибки в одно и то же место». Проверьте этот url для получения дополнительной информации: http://tldp.org/LDP/abs/html/io-redirection.html

3. От внешнего вызова вызовите php-скрипт, указав ему местоположение файла output.txt. Затем этот файл php вытащит прогресс из текстового файла. Вот как я это сделал:

 // # get duration of source preg_match("/Duration: (.*?), start:/", $content, $matches); $rawDuration = $matches[1]; // # rawDuration is in 00:00:00.00 format. This converts it to seconds. $ar = array_reverse(explode(":", $rawDuration)); $duration = floatval($ar[0]); if (!empty($ar[1])) $duration += intval($ar[1]) * 60; if (!empty($ar[2])) $duration += intval($ar[2]) * 60 * 60; // # get the current time preg_match_all("/time=(.*?) bitrate/", $content, $matches); $last = array_pop($matches); // # this is needed if there is more than one match if (is_array($last)) { $last = array_pop($last); } $curTime = floatval($last); // # finally, progress is easy $progress = $curTime/$duration; 

Надеюсь, это поможет кому-то.

На русском языке есть статья, которая описывает, как решить вашу проблему.

Дело в том, чтобы уловить значение Duration перед кодированием и уловить time=... значения во время кодирования.

 --skipped-- Duration: 00:00:24.9, start: 0.000000, bitrate: 331 kb/s --skipped-- frame= 41 q=7.0 size= 116kB time=1.6 bitrate= 579.7kbits/s frame= 78 q=12.0 size= 189kB time=3.1 bitrate= 497.2kbits/s frame= 115 q=13.0 size= 254kB time=4.6 bitrate= 452.3kbits/s --skipped-- 

FFmpeg использует stdout для вывода медиаданных и stderr для ведения журнала / информации о ходе работы. Вам просто нужно перенаправить stderr в файл или на stdin процесса, способного обрабатывать его.

С оболочкой unix это что-то вроде:

 ffmpeg {ffmpeg arguments} 2> logFile 

или

 ffmpeg {ffmpeg arguments} 2| processFFmpegLog 

В любом случае, вам нужно запустить ffmpeg как отдельный stream или процесс.

Это очень просто, если вы используете команду pipeview. Чтобы сделать это, преобразуйте

 ffmpeg -i input.avi {arguments} 

в

 pv input.avi | ffmpeg -i pipe:0 -v warning {arguments} 

Не нужно вдаваться в кодирование!

Вы можете сделать это с помощью аргумента -progress и nc

 WATCHER_PORT=9998 DURATION= $(ffprobe -select_streams v:0 -show_entries "stream=duration" \ -of compact $INPUT_FILE | sed 's!.*=\(.*\)!\1!g') nc -l $WATCHER_PORT | while read; do sed -n 's/out_time=\(.*\)/\1 of $DURATION/p') done & ffmpeg -y -i $INPUT_FILE -progress localhost:$WATCHER_PORT $OUTPUT_ARGS 

Вызов системной функции php блокирует этот stream, поэтому вам нужно будет развернуть 1 HTTP-запрос для выполнения преобразования и другой опрос для чтения txt-файла, который создается.

Или, еще лучше, клиенты отправляют видео для преобразования, а затем другой процесс отвечает за выполнение преобразования. Таким образом, соединение клиента не будет тайм-аутом в ожидании завершения системного вызова. Опрос выполняется так же, как указано выше.

Были проблемы со второй частью php. Поэтому я использую это вместо этого:

  $log = @file_get_contents($txt); preg_match("/Duration:([^,]+)/", $log, $matches); list($hours,$minutes,$seconds,$mili) = split(":",$matches[1]); $seconds = (($hours * 3600) + ($minutes * 60) + $seconds); $seconds = round($seconds); $page = join("",file("$txt")); $kw = explode("time=", $page); $last = array_pop($kw); $values = explode(' ', $last); $curTime = round($values[0]); $percent_extracted = round((($curTime * 100)/($seconds))); 

Выходы отлично.

Хотелось бы увидеть что-то для нескольких загрузок для другого индикатора выполнения. Это передача текущего файла за один процент. Затем общий индикатор выполнения. Почти готово.

Кроме того, если люди с трудом получают:

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1> path/to/output.txt 2>&1"); 

Работать.

Пытаться:

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1"); 

1> путь ” до ” 1> путь ” ИЛИ ” 2> путь ” до ” 2> путь

Принял меня немного, чтобы понять это. FFMPEG не работает. Работал, когда меня не коснулось.

javascript должен сказать php, чтобы начать преобразование [1], а затем сделать [2] …


[1] php: начать преобразование и записать статус в файл (см. Выше):

 exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1"); 

Для второй части нам нужен только javascript для чтения файла. Следующий пример использует dojo.request для AJAX, но вы можете использовать jQuery или ваниль или что-то еще:

[2] js: захватить прогресс из файла:

 var _progress = function(i){ i++; // THIS MUST BE THE PATH OF THE .txt FILE SPECIFIED IN [1] : var logfile = 'path/to/output.txt'; /* (example requires dojo) */ request.post(logfile).then( function(content){ // AJAX success var duration = 0, time = 0, progress = 0; var resArr = []; // get duration of source var matches = (content) ? content.match(/Duration: (.*?), start:/) : []; if( matches.length>0 ){ var rawDuration = matches[1]; // convert rawDuration from 00:00:00.00 to seconds. var ar = rawDuration.split(":").reverse(); duration = parseFloat(ar[0]); if (ar[1]) duration += parseInt(ar[1]) * 60; if (ar[2]) duration += parseInt(ar[2]) * 60 * 60; // get the time matches = content.match(/time=(.*?) bitrate/g); console.log( matches ); if( matches.length>0 ){ var rawTime = matches.pop(); // needed if there is more than one match if (lang.isArray(rawTime)){ rawTime = rawTime.pop().replace('time=','').replace(' bitrate',''); } else { rawTime = rawTime.replace('time=','').replace(' bitrate',''); } // convert rawTime from 00:00:00.00 to seconds. ar = rawTime.split(":").reverse(); time = parseFloat(ar[0]); if (ar[1]) time += parseInt(ar[1]) * 60; if (ar[2]) time += parseInt(ar[2]) * 60 * 60; //calculate the progress progress = Math.round((time/duration) * 100); } resArr['status'] = 200; resArr['duration'] = duration; resArr['current'] = time; resArr['progress'] = progress; console.log(resArr); /* UPDATE YOUR PROGRESSBAR HERE with above values ... */ if(progress==0 && i>20){ // TODO err - giving up after 8 sec. no progress - handle progress errors here console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }'); return; } else if(progress<100){ setTimeout(function(){ _progress(i); }, 400); } } else if( content.indexOf('Permission denied') > -1) { // TODO - err - ffmpeg is not executable ... console.log('{"status":-400, "error":"ffmpeg : Permission denied, either for ffmpeg or upload location ..." }'); } }, function(err){ // AJAX error if(i<20){ // retry setTimeout(function(){ _progress(0); }, 400); } else { console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }'); console.log( err ); } return; }); } setTimeout(function(){ _progress(0); }, 800); 

К сожалению, сам ffmpeg по-прежнему не может отображать индикатор выполнения. Многие из вышеупомянутых решений, основанных на bash или python, были устаревшими и нефункциональными.

Таким образом, я рекомендую дать новый ffmpeg-progressbar-cli попробовать:

ffmpeg-progressbar-cli screencast

Это shell для исполняемого файла ffmpeg , показывающая цветной, ориентированный по центру индикатор и оставшееся время.

Кроме того, он работает с открытым исходным кодом, основанный на Node.js, и активно развивается, обрабатывая большинство упомянутых причуд (полное раскрытие: я его ведущий разработчик).

Interesting Posts

Как отправить почту из приложения iPhone

Размеры значков кадров, используемых в Swing

Языковые книги / Учебники для популярных языков

Как я могу избежать случайного изменения размеров окон в Windows? (Путем уменьшения размера «края»)

Зачем нам нужно новое ключевое слово и почему поведение по умолчанию скрывается и не отменяется?

Как узнать размер файла перед его загрузкой?

Как использовать jQuery для вызова веб-службы ASP.NET?

Как понять термин «тензор» в TensorFlow?

Переключить вкладки с помощью Selenium WebDriver с Java

Реализация расстояния Левенштейна для mysql / нечеткого поиска?

Разница между UnxUtils и GnuWin32?

Почему отлаженная программа так сильно замедляется при использовании отладки ввода метода?

Вывести на передний план все окна для определенного приложения в Windows 7

Есть ли способ использовать условное форматирование в строке на основе значений в одном столбце?

Зафиксировать верхнюю строку и несколько столбцов в Excel

Давайте будем гением компьютера.