Как настроить proc_open "каналы" для ffmpeg stdin / stderr в Windows? - PullRequest
0 голосов
/ 07 сентября 2018

Во-первых, я потратил неделю на поиски и отбор вариантов десятков и десятков ответов для Unix, но это полный провал, мне нужен ответ для Windows , так что это не дубликат вопроса об эквивалентах Unix.

Мы пытаемся создать запланированное задание, которое будет обрабатывать очередь заданий в PHP и поддерживать массив до 10 экземпляров ffmpeg за раз. Я пробовал exec, shell_exec и proc_open, в сочетании с / без start /B без "полной" удачи. Я также совершенно уверен, что это связано с настройкой descriptorspec и каналов (с которыми я совершенно не знаком), и вот почему:

За https://trac.ffmpeg.org/wiki/PHP,

Часть, которая говорит "> / dev / null", будет перенаправлять стандартный OUTPUT (stdout) экземпляра ffmpeg в / dev / null (фактически игнорируя output) и «2> / dev / null» перенаправят стандартную ОШИБКУ (stderr) на / dev / null (эффективно игнорирует любые сообщения журнала ошибок). Эти двое могут быть объединены в более короткое представление: "> / dev / null 2> & 1". если ты Например, вы можете? Узнайте больше о перенаправлении ввода / вывода.

Важное примечание следует упомянуть здесь. Командная строка ffmpeg инструмент использует stderr для вывода сообщений журнала ошибок, а stdout - зарезервировано для возможного использования каналов (для перенаправления носителя вывода поток, сгенерированный из ffmpeg в другой инструмент командной строки). Тот как говорится, если вы запустите свой ffmpeg в фоновом режиме, вы будете наиболее вероятно, хотите перенаправить stderr в файл журнала, чтобы иметь возможность проверьте это позже.

Еще одна вещь, о которой нужно позаботиться, это стандартный INPUT (stdin). Средство командной строки ffmpeg разработано как интерактивная утилита, которая принимает ввод пользователя (обычно с клавиатуры) и сообщает журнал ошибок на текущем экране / терминале пользователя. Когда мы запускаем ffmpeg в фон, мы хотим сказать ffmpeg, что вход не должен быть принят (и не ждал) от стандартного ввода. Мы можем сказать это ffmpeg, используя ввод / вывод перенаправление снова

echo "Starting ffmpeg...\n\n";
echo shell_exec("ffmpeg -y -i input.avi output.avi </dev/null >/dev/null 2>/var/log/ffmpeg.log &");
echo "Done.\n";

В этом примере фактически используется shell_exec, хотя мы хотим использовать proc_open, чтобы мы могли использовать цикл для проверки, завершен ли процесс или нет.

Вот базовый пример цикла из того, что я пробовал. Проблема в выполнении этого состоит в том, что фактическая обработка ffmpeg завершается, но процесс зависает, ожидая чего-то. Когда я использую отладку, выхожу из цикла и завершаю процесс через несколько минут, вывод ffmpeg записывается и сценарий продолжается. (Из командной строки ffmpeg занимает меньше минуты)

$descriptorspec = array(
    array('pipe', 'r'),
    array('pipe', 'w'),
    array('pipe', 'w'),
);
$pipes = null;
$cwd = null;
$env = null;
$process = proc_open('start /B ffmpeg.exe -i input.mov output.mp4 -nostdin', $descriptorspec, $pipes, $cwd, $env);
$status = proc_get_status($process);
while($status['running']) {
    sleep (60);
    $status = proc_get_status($process);
}
proc_terminate($process);

Кроме того, как указано в ffmpeg Main-options :

Включить взаимодействие на стандартном вводе. По умолчанию, если не стандарт вход используется как вход. Чтобы явно отключить взаимодействие, вам нужно указать -nostdin.

Опция -nostdin, кажется, указывает на то, что она решает мою проблему, но она не оказывает видимого влияния. Во всех решениях для Unix, которые я обнаружил, по-прежнему требуется некоторая форма этого добавленного Unix: </dev/null или 2>&1.

Итак, с помощью этого несколько исчерпывающего пролога кто-то может объяснить, как правильно настроить функцию proc_open, чтобы удовлетворить взаимодействие ffmpeg.exe с вводом / выводом? Если есть лучший или более подходящий подход, я с удовольствием это сделаю, но важно иметь возможность циклически проходить через массив процессов, чтобы проверить, завершены ли они, чтобы другие более быстрые процессы могли завершиться в То время.

UPDATE Похоже, что после исчерпывающих НИОКР ввод-вывод не является проблемой для реализации этого (опция - nostdin, кажется, работает так, как объявлено). Исходная посылка моего проекта состояла в том, чтобы использовать proc_get_status(), чтобы определить, когда ffmpeg был закончен. Недостаток этого подхода заключается в том, что очевидно, что он НЕ возвращает фактический PID процесса ffmpeg ... он возвращает parent PID. Итак, когда proc_get_status() вернуло, что преобразование видео было завершено, оно фактически продолжало работать, а не зависало. Это было еще сложнее при тестировании больших видеофайлов. Чем больше видео, тем дольше оставалось «остаточное» время, которое потребовалось для фактического завершения - не было проблемы с вводом / выводом - проблема была в том, что просмотр родительского PID вместо дочернего PID. Таким образом, без углубления во внутренние системы более низкого уровня с Windows это не представляется возможным напрямую с PHP. Я решил отказаться от этого подхода, но, надеюсь, это открытие сэкономит кому-то еще время и проблемы.

...