Запустите процесс ffmpeg в фоновом режиме

Я хочу использовать ffmpeg для преобразования видео в .flv в php. В настоящее время у меня это работает, но браузер зависает до тех пор, пока файл не будет загружен и не завершен. Я просматривал документы php о том, как запустить процесс exec() в фоновом режиме, обновляя процесс с использованием возвращенного PID. Вот что я нашел:

//Run linux command in background and return the PID created by the OS
function run_in_background($Command, $Priority = 0)
{
    if($Priority)
        $PID = shell_exec("nohup nice -n $Priority $Command > /dev/null & echo $!");
    else
        $PID = shell_exec("nohup $Command > /dev/null & echo $!");
    return($PID);
}

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

//Verifies if a process is running in linux
function is_process_running($PID)
{
    exec("ps $PID", $ProcessState);
    return(count($ProcessState) >= 2);
}

Должен ли я создать отдельный файл .php, который затем запускается из php cli для выполнения одной из этих функций? Мне просто нужен небольшой толчок, чтобы заставить это работать, и тогда я смогу взять его оттуда.

Спасибо!


person Nic Hubbard    schedule 29.07.2009    source источник


Ответы (2)


Должен ли я создать отдельный файл .php, который затем запускается из php cli для выполнения одной из этих функций?

Вероятно, я бы сделал так:

  • the PHP webpage adds a record in database to indicate "this file has to be processed"
    • and displays a message to the user ; something like "your file will be processed soon"
  • In CLI, have a batch process the new inserted files
    • first, mark a record as "processing"
    • сделать вещь ffmpeg
    • пометить файл как "обработанный"
  • And, on the webpage, you can show to the user in which state his file is :
    • if it has not been processed yet
    • если он обрабатывается
    • или если он был обработан - вы можете дать ему ссылку на новый видеофайл.

Вот еще пара мыслей:

  • The day your application becomes bigger, you can have :
    • one "web server"
    • много «серверов обработки»; в вашем приложении это ffmpeg, который потребует много ресурсов ЦП, а не обслуживания веб-страниц; поэтому возможность масштабировать эту часть хороша (это еще одно, чтобы «блокировать» файлы, указывая их как «обрабатываемые» в БД: таким образом, у вас не будет нескольких серверов обработки, пытающихся обработать один и тот же файл)
  • You only use PHP from the web server to generate web pages, which is je job of a web server
    • Heavy / long processing is not the job of a web server !
    • В тот день, когда вы захотите переключиться на что-то другое, кроме PHP, для части «обработки», это будет проще.

Ваш «скрипт обработки» должен запускаться каждые пару минут; вы можете использовать для этого cron, если вы работаете на Linux-подобной машине.


Изменить: немного больше информации после просмотра комментария

Поскольку часть обработки выполняется из CLI, а не из Apache, вам не нужны какие-либо «фоновые» манипуляции: вы можете просто использовать shell_exec, который вернет весь вывод команды в ваш PHP-скрипт, когда он завершит свою работу.

Для пользователя, просматривающего веб-страницу с надписью «обработка», это будет выглядеть как фоновая обработка; и, в некотором смысле, так и будет, так как обработка будет производиться другим процессором (возможно, даже на другой машине).

Но для вас это будет намного проще:

  • одна веб-страница (ничего "фонового")
  • один скрипт CLI, без каких-либо фоновых вещей.

Я полагаю, ваш сценарий обработки может выглядеть примерно так:

// Fetch informations from DB about one file to process
// and mark it as "processing"

// Those would be fetched / determined from the data you just fetched from DB
$in_file = 'in-file.avi';
$out_file = 'out-file.avi';

// Launch the ffmpeg processing command (will probably require more options ^^ )
// The PHP script will wait until it's finished : 
//   No background work
//   No need for any kind of polling
$output = shell_exec('ffmpeg ' . escapeshellarg($in_file) . ' ' . escapeshellarg($out_file));

// File has been processed
// Store the "output name" to DB
// Mark the record in DB as "processed"

На самом деле проще, чем вы сначала подумали, не так ли? ;-)
Просто больше не беспокойтесь о фоновых вещах: важно только то, что скрипт обработки запускается регулярно, из crontab.


Надеюсь, это поможет :-)

person Pascal MARTIN    schedule 29.07.2009
comment
Я понимаю процесс того, как это сделать, и как это будет логически работать. Мне просто нужна помощь в совершенствовании php для этого. Сценарии, которые я предоставил, сбили меня с толку относительно того, как их правильно использовать. - person Nic Hubbard; 29.07.2009

Вам не нужно писать отдельный php-скрипт для этого (хотя вы можете захотеть это сделать позже, если вы реализуете какую-то систему очередей).

Ты почти там. Единственная проблема заключается в том, что вызов shell_exec() блокирует ожидание возврата оболочки. Этого можно избежать, если вы перенаправите весь вывод команды в оболочке, чтобы удалить файл или /dev/null и выполнить задачу в фоновом режиме (с оператором &). Таким образом, ваш код станет:

//Run linux command in background and return the PID created by the OS
function run_in_background($Command, $Priority = 0)
{
    if($Priority) {
        shell_exec("nohup nice -n $Priority $Command 2> /dev/null > /dev/null &");
    } else {
        shell_exec("nohup $Command 2> /dev/null > /dev/null &");
    }
}

К сожалению, я не думаю, что есть какой-либо способ получить PID.

person Brenton Alker    schedule 29.07.2009
comment
Да, вы можете получить PID, я использовал: $pid = shell_exec(nohup $process_ffmpeg › /dev/null 2›&1 & echo $!); - person Nic Hubbard; 30.07.2009