dongzu0742 2016-02-28 13:16
浏览 77
已采纳

为什么在将4096个字节写入以proc_open开头的进程后,PHP挂起?

For anyone wondering, after leaving it all for a couple hours it now works perfectly.

I'm trying to pass a video file to VLC using PHP as a proof of concept for an upcoming project proposal for someone.

I've managed to show it works by creating a file < 4KB (Gray for 10 seconds) and testing my script but I'm curious as to the reason why this is happening in the first place.

Here's an example script to see what I mean:

$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);

I'm on Windows 10 and using PHP 5.5.31. I've seen a few bug reports on the PHP site about this kind of thing but they suggest the latest version has fixed it. I don't quite understand the concepts of blocking a stream but I've already tried PHP v7.0.3 to no avail.

I'm running this script using the command line: php file.php

  • 写回答

1条回答 默认 最新

  • dtkp51520 2016-02-28 20:38
    关注

    I ran into the exact same issue trying to do WAV to MP3 conversion using LAME on Windows and was unable to find a workable solution.

    I tried dozens of things including blocking/non-blocking writes, writing small (< 1k) chunks of data, sleeping and trying to write but it never was able to write all data. About as much as I could ever write before it failing was around 40kb (failure being fwrite would always return 0 and never write more data to the stream, no matter how long I waited; regardless of the sizes of the chunks written before. I even tried waiting seconds between writes and they would always succeed to about 30-40kb and never write more).

    Ultimately I gave up and luckily LAME could read input from a file instead of STDIN, so I just opted to write the data to a temp file, call LAME, and remove the temp file.

    Here's the relevant code:

    // 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;
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用三极管设计一个单管共射放大电路
  • ¥20 fluent无法启动
  • ¥15 孟德尔随机化r语言运行问题
  • ¥15 pyinstaller编译的时候出现No module named 'imp'
  • ¥15 nirs_kit中打码怎么看(打码文件是csv格式)
  • ¥15 怎么把多于硬盘空间放到根目录下
  • ¥15 Matlab问题解答有两个问题
  • ¥15 LCD12864中文显示
  • ¥15 在使用CH341SER.EXE时不小心把所有驱动文件删除了怎么解决
  • ¥15 gsoap生成onvif框架