Для всех, кто интересуется, оставив все на пару часов, теперь он работает отлично.
Я пытаюсь передать видеофайл в VLC, используя PHP в качестве доказательства концепции предстоящего предложения проекта для кого-то.
Мне удалось показать, что это работает, создав файл < 4 КБ (Серый в течение 10 секунд) и тестирование моего сценария, но мне любопытно, почему это происходит в первую очередь.
Вот пример сценария, чтобы понять, что я имею в виду:
$filepath = 'Path/to/your/video';
$vlcpath = 'Path/to/your/VLC executable';
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$vlc = proc_open($vlcpath . ' -', $descriptorspec, $pipes, null, null, ['bypass_shell' => true]);
$file = fopen($filepath, 'r');
stream_copy_to_stream($file, $pipes[0]);
fclose($file);
proc_close($vlc);
Я на Windows 10 и использую PHP 5.5.31. Я видел несколько сообщений об ошибках на сайте PHP об этом, но они предполагают, что в последней версии это исправлено. Я не совсем понимаю концепции блокировки потока, но я уже пробовал PHP v7.0.3 безрезультатно.
Я запускаю этот скрипт с помощью командной строки: php file.php
Я столкнулся с той же самой проблемой, пытаясь сделать преобразование WAV в MP3, используя LAME на Windows, и не смог найти работоспособное решение.
Я перепробовал десятки вещей, включая блокирующие / неблокирующие записи, небольшие записи (< 1k) куски данных, спящие и пытающиеся записать, но так и не смогли записать все данные. Примерно столько, сколько я мог написать до того, как произошел сбой, было около 40 КБ (если fwrite потерпит неудачу, он всегда вернет 0 и никогда не записывает больше данных в поток, независимо от того, как долго я ждал; независимо от размеров записанных ранее кусков. Я даже попробовал подождать секунды между записями, и они всегда преуспели бы приблизительно в 30-40kb и никогда больше не писали).
В конце концов я сдался, и, к счастью, LAME смог прочитать входные данные из файла вместо STDIN, поэтому я просто решил записать данные во временный файл, вызвать LAME и удалить временный файл.
Вот соответствующий код:
// file descriptors for reading and writing to the Lame process
$descriptors = array(
0 => array('pipe', 'r'), // stdin
1 => array('pipe', 'w'), // stdout
2 => array('pipe', 'a'), // stderr
);
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
// workaround for Windows conversion
// writing to STDIN seems to hang indefinitely after writing approximately 0xC400 bytes
$wavinput = tempnam(sys_get_temp_dir(), 'wav');
if (!$wavinput) {
throw new Exception('Failed to create temporary file for WAV to MP3 conversion');
}
file_put_contents($wavinput, $data);
$size = 0;
} else {
$wavinput = '-'; // stdin
}
// Mono, variable bit rate, 32 kHz sampling rate, read WAV from stdin, write MP3 to stdout
$cmd = sprintf("%s -m m -v -b 32 %s -", self::$lame_binary_path, $wavinput);
$proc = proc_open($cmd, $descriptors, $pipes);
if (!is_resource($proc)) {
throw new Exception('Failed to open process for MP3 encoding');
}
stream_set_blocking($pipes[0], 0); // set stdin to be non-blocking
for ($written = 0; $written < $size; $written += $len) {
// write to stdin until all WAV data is written
$len = fwrite($pipes[0], substr($data, $written, 0x20000));
if ($len === 0) {
// fwrite wrote no data, make sure process is still alive, otherwise wait for it to process
$status = proc_get_status($proc);
if ($status['running'] === false) break;
usleep(25000);
} else if ($written < $size) {
// couldn't write all data, small pause and try again
usleep(10000);
} else if ($len === false) {
// fwrite failed, should not happen
break;
}
}
fclose($pipes[0]);
$data = stream_get_contents($pipes[1]);
$err = trim(stream_get_contents($pipes[2]));
fclose($pipes[1]);
fclose($pipes[2]);
$return = proc_close($proc);
if ($wavinput != '-') unlink($wavinput); // delete temp file on Windows
if ($return !== 0) {
throw new Exception("Failed to convert WAV to MP3. Shell returned ({$return}): {$err}");
} else if ($written < $size) {
throw new Exception('Failed to convert WAV to MP3. Failed to write all data to encoder');
}
return $data;
Других решений пока нет …