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 chaquopy python 安卓
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 有没有帮写代码做实验仿真的
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥30 vmware exsi重置后登不上
  • ¥15 易盾点选的cb参数怎么解啊
  • ¥15 MATLAB运行显示错误,如何解决?
  • ¥15 c++头文件不能识别CDialog
  • ¥15 Excel发现不可读取的内容
  • ¥15 关于#stm32#的问题:CANOpen的PDO同步传输问题