实时 ffmpeg shell 输出 PHP


Realtime ffmpeg shell output PHP

好吧,我已经与这个问题斗争了几天。在我的本地Windows机器上工作正常,但似乎无法让它在我的CentOS服务器上工作。我的脚本抓取正在转换的视频的持续时间,并抓取它在 ffmpeg 中处理的当前秒数。但是,它只是抓取 ffmpeg 输出的"输入文件"并停在那里。由于某种原因,我尝试使用两个管道(STDOUT [1]和STDERR [2](,出于某种原因,ffmpeg喜欢在STDERR管道上输出。奇怪。

$filename = "somefilename.tmp";
$descriptor = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w"),
    2 => array("pipe", "w")
);
$ffmpeg = "ffmpeg -i /var/www/spotloader/videos/flipped/tmp/".$file."_comb.ts -vcodec mpeg2video -acodec pcm_s16le -pix_fmt yuv422p -vtag xdvb -b:v 13000k -r 30000/1001 /var/www/spotloader/videos/flipped/tmp/".$file.".mov";
//open the process
$process = proc_open($ffmpeg, $descriptor, $pipes, NULL, $_ENV);
//if the process opened
if ( is_resource( $process ) == true )
{
    //get process status
    $procStatus = proc_get_status( $process );
    //if its running, let node know
    if ( $procStatus['running'] )
    {
        //nodejs socket, nothing wrong here
        $this->_sendSocket('converting', array('filename' => str_replace('.tmp', '', $file)));
    }
    //while the process is running
    while( $procStatus['running'] === true )
    {
        //there is output in the pipe
        if ( !feof( $pipes[1] ) )
        {
            //get the output
            $data = fgets($pipes[1], 128);
            //match the outputs duration and save it.
            if(preg_match('/Duration:'s([0-9]{2}:[0-9]{2}:[0-9]{2})/', $data, $matches)) 
            {
                static $duration;
                $duration = $this->_convertToSeconds($matches[1]);
            }
            //match the outputs current encoding time
            if(preg_match('/time=([0-9]{2}:[0-9]{2}:[0-9]{2})/', $data, $matches)) 
            {
                //convert to seconds works fine, so it is not included.
                $curTime = $this->_convertToSeconds($matches[1]);
                //nodejs socket, nothing wrong here
                $this->_sendSocket('update', array('percent' => round( ($curTime / $duration) * 100), 'filename' => str_replace('.tmp', '', $file)));
            }
        }
        //update process status
        $procStatus = proc_get_status( $process );
    }
    //nodejs socket, nothing wrong here
    $this->_sendSocket('converted', array('percent' => 100, 'filename' => str_replace('.tmp', '', $file)));
}

我使用上面的 PHP 代码接收的 FFMPEG 输出

ffmpeg version 1.2.1 Copyright (c) 2000-2013 the FFmpeg developers
built on May 10 2013 15:14:14 with gcc 4.4.6 (GCC) 20120305 (Red Hat 4.4.6-4)
configuration: --prefix=/usr --libdir=/usr/lib64 --shlibdir=/usr/lib64 
--mandir=/usr/share/man --enable-shared --enable-runtime-cpudetect --enable-gpl 
--enable-version3 --enable-postproc --enable-avfilter --enable-pthreads 
--enable-x11grab --enable-vdpau --disable-avisynth --enable-frei0r --enable-libopencv 
--enable-libdc1394 --enable-libgsm --enable-libmp3lame --enable-libnut 
--enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg 
--enable-librtmp --enable-libspeex --enable-libtheora --enable-libvorbis 
--enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid 
--extra-cflags='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions 
-fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -fPIC' 
--disable-stripping
libavutil      52. 18.100 / 52. 18.100
libavcodec     54. 92.100 / 54. 92.100
libavformat    54. 63.104 / 54. 63.104
libavdevice    54.  3.103 / 54.  3.103
libavfilter     3. 42.103 /  3. 42.103
libswscale      2.  2.100 /  2.  2.100
libswresample   0. 17.102 /  0. 17.102
libpostproc    52.  2.100 / 52.  2.100
[mpegts @ 0x243c620] max_analyze_duration 5000000 reached at 5016000 microseconds
Input #0, mpegts, from '/var/www/spotloader/videos/flipped/tmp/Wildlife10.tmp_comb.ts':
Duration: 00:00:02.02, start: 1.389978, bitrate: 227018 kb/s
Program 1
Metadata:
  service_name    : Service01
  service_provider: FFmpeg
Stream #0:0[0x100]: Video: mpeg2video (4:2:2) ([2][0][0][0] / 0x0002), yuv422p, 1920x1080 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
Stream #0:1[0x101](eng): Audio: mp2 ([3][0][0][0] / 0x0003), 48000 Hz, 1 channels (FL+FR), s16p, 128 kb/s

FFMPEG 输出 我期待最后的"时间=00:00:00"是我需要实时捕获的。这是通过在外壳中直接运行 FFMPEG 命令来实现的。

ffmpeg version 1.2.1 Copyright (c) 2000-2013 the FFmpeg developers
built on May 10 2013 15:14:14 with gcc 4.4.6 (GCC) 20120305 (Red Hat 4.4.6-4)
configuration: --prefix=/usr --libdir=/usr/lib64 --shlibdir=/usr/lib64 
--mandir=/usr/share/man --enable-shared --enable-runtime-cpudetect --enable-gpl 
--enable-version3 --enable-postproc --enable-avfilter --enable-pthreads 
--enable-x11grab --enable-vdpau --disable-avisynth --enable-frei0r --enable-libopencv 
--enable-libdc1394 --enable-libgsm --enable-libmp3lame --enable-libnut 
--enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg 
--enable-librtmp --enable-libspeex --enable-libtheora --enable-libvorbis 
--enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid 
--extra-cflags='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions 
-fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -fPIC' 
--disable-stripping
  libavutil      52. 18.100 / 52. 18.100
  libavcodec     54. 92.100 / 54. 92.100
  libavformat    54. 63.104 / 54. 63.104
  libavdevice    54.  3.103 / 54.  3.103
  libavfilter     3. 42.103 /  3. 42.103
  libswscale      2.  2.100 /  2.  2.100
  libswresample   0. 17.102 /  0. 17.102
  libpostproc    52.  2.100 / 52.  2.100
[mpegts @ 0x10c9620] max_analyze_duration 5000000 reached at 5016000 microseconds
Input #0, mpegts, from '/var/www/spotloader/videos/flipped/tmp/Wildlife10.tmp_comb.ts':
  Duration: 00:00:02.02, start: 1.389978, bitrate: 227018 kb/s
  Program 1
    Metadata:
      service_name    : Service01
      service_provider: FFmpeg
    Stream #0:0[0x100]: Video: mpeg2video (4:2:2) ([2][0][0][0] / 0x0002), yuv422p, 1920x1080 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Stream #0:1[0x101](eng): Audio: mp2 ([3][0][0][0] / 0x0003), 48000 Hz, 1 channels (FL+FR), s16p, 128 kb/s
Channel layout 'stereo' with 2 channels does not match specified number of channels 1: ignoring specified channel layout
Output #0, mov, to '/var/www/spotloader/videos/flipped/tmp/Wildlife10.tmp.mov':
  Metadata:
    encoder         : Lavf54.63.104
    Stream #0:0: Video: mpeg2video (xdvb / 0x62766478), yuv422p, 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 13000 kb/s, 30k tbn, 29.97 tbc
    Stream #0:1(eng): Audio: pcm_s16le (sowt / 0x74776F73), 48000 Hz, stereo, s16, 1536 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (mpeg2video -> mpeg2video)
  Stream #0:1 -> #0:1 (mp2 -> pcm_s16le)
Press [q] to stop, [?] for help
Input stream #0:1 frame changed from rate:48000 fmt:s16p ch:1 chl:1 channels (FL+FR) to rate:48000 fmt:s16p ch:2 chl:stereo
Input stream #0:1 frame changed from rate:48000 fmt:s16p ch:2 chl:stereo to rate:48000 fmt:s16p ch:1 chl:mono
Input stream #0:1 frame changed from rate:48000 fmt:s16p ch:1 chl:mono to rate:48000 fmt:s16p ch:2 chl:stereo
Input stream #0:0 frame changed from size:1920x1080 fmt:yuv422p to size:1280x720 fmt:yuv422p0
Input stream #0:1 frame changed from rate:48000 fmt:s16p ch:2 chl:stereo to rate:44100 fmt:s16p ch:2 chl:stereo
frame=  741 fps= 52 q=2.6 size=   43866kB time=00:00:24.65 bitrate=14573.5kbits/s dup=5 drop=0

有什么想法吗?从 Windows 切换到 CentOS 需要改变什么?

编辑:我用 popen 代替它工作。它还减少了我的代码。如果其他人确实有解决方案,请继续发布它。谢谢!

这里有一些东西

这是我不久前正在做的一个项目。我认为它非常接近你想要的。请注意,它有点错误,不是很安全

ffmpe测试.php

<html>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<h2>Video Uploader</h2>
<form method="post" enctype="multipart/form-data">
  <input type="file" required id="upload"  name="file"/>
  <input type="submit" value="Upload video" id="upload" name="upload"/> 
</form>
<?
ini_set('memory_limit', '1000M');
ini_set('post_max_size', '1000M');
ini_set('upload_max_filesize', '1000M');

if(isset($_POST['upload'])){
$ffmpeg = '/usr/local/Cellar/ffmpeg/1.2.1/bin/ffmpeg';//path to ffmpeg    
$origVideo =  $_FILES['file']['tmp_name'];
$newVideo = "videos/".$_FILES['file']['name'];
move_uploaded_file($origVideo, $newVideo);
$time = time();
  
$command1 = $ffmpeg.' -i "'.$newVideo.'" videos/'.$time.'.flv ';
shell_exec(sprintf('%s > videos/block.txt 2>&1 &', $command1));   
}
?>
<div id="load"></div>
<script>  
$('#thumb').load(function(){
setInterval(function() {
          $('#load').load('http://localhost/Playground/ffmpeLoader.php                           ffmpeLoader.php');
}, 600);
});
</script>
</body>
</html>

ffmpeloader.php

<?
$content = @file_get_contents('videos/block.txt');
if($content){
    //get duration of source
    preg_match("/Duration: (.*?), start:/", $content, $matches);
    $rawDuration = $matches[1];
    //rawDuration is in 00:00:00.00 format. This converts it to seconds.
    $ar = array_reverse(explode(":", $rawDuration));
    $duration = floatval($ar[0]);
    if (!empty($ar[1])) $duration += intval($ar[1]) * 60;
    if (!empty($ar[2])) $duration += intval($ar[2]) * 60 * 60;
    //get the time in the file that is already encoded
    preg_match_all("/time=(.*?) bitrate/", $content, $matches);
    $rawTime = array_pop($matches);
    //this is needed if there is more than one match
    if (is_array($rawTime)){$rawTime = array_pop($rawTime);}
    //rawTime is in 00:00:00.00 format. This converts it to seconds.
    $ar = array_reverse(explode(":", $rawTime));
    $time = floatval($ar[0]);
    if (!empty($ar[1])) $time += intval($ar[1]) * 60;
    if (!empty($ar[2])) $time += intval($ar[2]) * 60 * 60;
    //calculate the progress
    $progress = round(($time/$duration) * 100);
    echo "<progress id='p' max='100' value='" . $progress . "'></progress><span> ".$progress."%</span>";
    
}
if($progress == 100){
    
        echo '<p> Done!</p>';
    }
?>