bash 如何以编程方式启动/停止 FFMPEG 流转码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21529348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to programmatically start/stop FFMPEG stream transcoding
提问by Paul Wieland
I have an ip webcam which provides an MJPEG stream. I can successfully transcode and save that stream with ffmpeg under OSX. The following gives me pretty much what I want:
我有一个提供 MJPEG 流的 ip 网络摄像头。我可以在 OSX 下使用 ffmpeg 成功转码并保存该流。以下给了我几乎我想要的:
ffmpeg -f mjpeg -i "http://user:[email protected]/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4
That will start an FFMPEG session and begin saving the live stream to my test.mp4 file. pressing q will quit ffmpeg and save the file.
这将启动一个 FFMPEG 会话并开始将实时流保存到我的 test.mp4 文件中。按 q 将退出 ffmpeg 并保存文件。
I would like to programmatically start & stop the recording using a PHP or Bash shell script. I have tried the following:
我想使用 PHP 或 Bash shell 脚本以编程方式开始和停止录制。我尝试了以下方法:
<?php
$pid = pcntl_fork();
if($pid == -1){
die("could not fork");
}elseif($pid){
// we are the parent...
print $pid.' started recording. waiting 10 seconds...';
sleep(10); // Wait 10 seconds
print_r(shell_exec("kill ".$pid)); // Kill the child recording process
echo 'done';
exit();
}else{
// we are the child process. call ffmpeg.
exec('../lib/ffmpeg -f mjpeg -i "http://user:[email protected]/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4');
}
But there are two problems:
但是有两个问题:
- The ffmpeg process does not end/die (probably because its forked again)
- When I manually kill the ffmpeg process, the video file is not readable
- ffmpeg 进程没有结束/死亡(可能是因为它再次分叉)
- 当我手动杀死ffmpeg进程时,视频文件不可读
采纳答案by Paul Wieland
So I was doing a combination of things wrong.
所以我做错了事情。
For starters, I needed to push the output form ffmpeg to a log file and also tell it to overwrite my temp file without prompting using the -y argument.
对于初学者,我需要将输出表单 ffmpeg 推送到日志文件,并告诉它覆盖我的临时文件而不提示使用 -y 参数。
So instead of
所以代替
ffmpeg -f mjpeg -i "http://user:[email protected]/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4
I am now using
我现在正在使用
ffmpeg -y -f mjpeg -i "http://user:[email protected]/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4 </dev/null >/dev/null 2>/tmp/ffmpeg.log &
The second problem was that I wasn't waiting long enough before sending the kill command to ffmpeg, and so a corrupt file was being created.
第二个问题是我在向 ffmpeg 发送 kill 命令之前等待的时间不够长,因此创建了一个损坏的文件。
By adding the -t (for time limit) argument with 1 second, I determined that it takes an average of 15 seconds for ffmpeg to record 1 second of video. Increasing the time limit to 10 seconds made the average increase to 25 seconds, so it seems that on my server at least, theres 14 seconds of overhead. By increasing my sleep command in my php script to 30 seconds, I was able to get a useable video file.
通过添加 1 秒的 -t(时间限制)参数,我确定 ffmpeg 平均需要 15 秒来记录 1 秒的视频。将时间限制增加到 10 秒使平均增加到 25 秒,所以看起来至少在我的服务器上,有 14 秒的开销。通过将我的 php 脚本中的 sleep 命令增加到 30 秒,我能够获得一个可用的视频文件。
So having PHP kill the ffmpeg process results in an unknown (or approximate at best) recording time length which is completely dependent on CPU power, network bandwidth, etc.
因此,让 PHP 终止 ffmpeg 进程会导致未知(或最多近似)的记录时间长度,这完全取决于 CPU 功率、网络带宽等。
Thats a bit of a bummer because I had hoped to be able to increase the recording length depending on some external variables (I have insteon motion sensors feeding a database, i would like to record until the motion stops).
这有点令人沮丧,因为我曾希望能够根据一些外部变量来增加记录长度(我有 insteon 运动传感器提供数据库,我想记录直到运动停止)。
In any event, here is a working PHP script in case it helps someone in the future:
无论如何,这是一个有效的 PHP 脚本,以防将来对某人有所帮助:
<?php
print date('H:i:s')."\nStarted recording. waiting 60 seconds...\n";
exec('../lib/ffmpeg -y -f mjpeg -i "http://user:[email protected]/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4 </dev/null >/dev/null 2>/tmp/ffmpeg.log &');
sleep(60); // Wait long enough before killing, otherwise the video will be corrupt!
shell_exec('pkill ffmpeg'); // find and kill
echo "done\n\n";
exit();
?>
回答by Eric Feillant
Send a SIGQUIT
signal to the background process to terminate the ffmpeg command normally.
SIGQUIT
向后台进程发送信号以正常终止ffmpeg命令。
Just use
只需使用
kill -s QUIT $PID
and the process will finish with a non-corrupted MP4 video file.
并且该过程将以未损坏的 MP4 视频文件结束。
回答by Wsj
Send the "q" key:
发送“q”键:
process.StandardInput.WriteLine("q");
回答by Mark Setchell
I am not sure why you are forking at all. Why don't you just background ffmpeg?
我不知道你为什么要分叉。你为什么不只是背景ffmpeg?
#!/bin/bash
ffmpeg -f mjpeg -i "http://user:[email protected]/nphMotionJp..../tmp/test.mp4 &
Then to stop it, do something like this:
然后停止它,做这样的事情:
#!/bin/bash
osascript -e 'tell application "ffmpeg" to quit'
I don't have ffmpeg, but maybe you need to use
我没有 ffmpeg,但也许你需要使用
osascript -e 'tell application "ffmpeg" to stop document /tmp/test.mp4"'
or
或者
osascript -e 'tell application "System Events" to keystroke "q"'