在后台运行一个ffmpeg进程

Posted

技术标签:

【中文标题】在后台运行一个ffmpeg进程【英文标题】:Run a ffmpeg process in the background 【发布时间】:2010-11-14 22:41:13 【问题描述】:

我想在 php 中使用 ffmpeg 将视频转换为 .flv。目前我有这个工作,但它会挂起浏览器,直到文件上传并完成。我一直在查看有关如何在后台运行 exec() 进程的 php 文档,同时使用返回的 PID 更新进程。这是我发现的:

//Run linux command in background and return the PID created by the OS
function run_in_background($Command, $Priority = 0)

    if($Priority)
        $PID = shell_exec("nohup nice -n $Priority $Command > /dev/null & echo $!");
    else
        $PID = shell_exec("nohup $Command > /dev/null & echo $!");
    return($PID);

还有一个技巧可以用来跟踪后台任务是否正在使用返回的 PID 运行:

//Verifies if a process is running in linux
function is_process_running($PID)

    exec("ps $PID", $ProcessState);
    return(count($ProcessState) >= 2);

我想创建一个单独的 .php 文件,然后从 php cli 运行以执行这些功能之一吗?我只需要稍微推动一下就可以让它工作,然后我就可以从那里开始了。

谢谢!

【问题讨论】:

【参考方案1】:

我想创建一个单独的 .php 然后从 php cli 运行的文件 执行这些功能之一?

这可能是我会做的方式:

PHP 网页在数据库中添加一条记录以指示“此文件必须处理” 并向用户显示一条消息;诸如“您的文件将很快得到处理”之类的内容 在 CLI 中,对新插入的文件进行批处理 首先,将记录标记为“处理中” 做 ffmpeg 的事情 将文件标记为“已处理” 并且,在网页上,您可以向用户显示他的文件处于哪个状态: 如果尚未处理 如果它正在处理中 或者如果它已被处理 - 然后你可以给他新视频文件的链接。

还有一些其他的想法:

您的应用程序变得更大的那一天,您可以拥有: 一个“网络服务器” 许多“处理服务器”;在您的应用程序中,ffmpeg 需要大量 CPU,而不是提供网页;因此,能够扩展该部分是很好的(这是另一个“锁定”文件,将它们指示为 DB 中的“处理”:这样,您将不会有多个处理服务器尝试处理同一个文件) 您只使用来自 Web 服务器的 PHP 来生成网页,这是 Web 服务器的工作 繁重/长时间的处理不是 Web 服务器的工作! 如果“处理”部分想要切换到 PHP 以外的其他东西,那会更容易。

您的“处理脚本”必须每隔几分钟启动一次;如果你在类似 Linux 的机器上,你可以使用cron。


编辑:更多信息,在看到评论后

由于处理部分是从 CLI 而非 Apache 完成的,因此您不需要任何类型的“后台”操作:您只需使用 shell_exec,它将命令的整个输出返回到您的 PHP 脚本当它完成它的工作时。

对于观看网页的用户说“正在处理”,它看起来像是在后台处理;而且,在某种程度上,它会是,因为处理将由另一个进程完成(甚至可能在另一台机器上)。

但是,对你来说,它会简单得多:

一个网页(没有“背景”) 一个 CLI 脚本,也没有背景内容。

我想您的处理脚本可能看起来像这样:

// Fetch informations from DB about one file to process
// and mark it as "processing"

// Those would be fetched / determined from the data you just fetched from DB
$in_file = 'in-file.avi';
$out_file = 'out-file.avi';

// Launch the ffmpeg processing command (will probably require more options ^^ )
// The PHP script will wait until it's finished : 
//   No background work
//   No need for any kind of polling
$output = shell_exec('ffmpeg ' . escapeshellarg($in_file) . ' ' . escapeshellarg($out_file));

// File has been processed
// Store the "output name" to DB
// Mark the record in DB as "processed"

真的比你最初想象的要容易,不是吗? ;-) 不要再担心后台的东西了:唯一重要的是处理脚本会定期从 crontab 启动。

希望这会有所帮助:-)

【讨论】:

我了解如何做的“过程”,以及它在逻辑上的工作方式。我只需要帮助完善 php 即可。我提供的脚本让我不知道如何正确使用它们。【参考方案2】:

您不需要编写单独的 php 脚本来执行此操作(但如果您实现某种排队系统,您可能希望稍后再编写)。

你快到了。唯一的问题是,shell_exec() 调用阻塞等待 shell 的返回。如果将 shell 中命令的所有输出重定向到枯萎文件或 /dev/null 并将任务置于后台(使用 & 运算符),则可以避免这种情况。 所以你的代码会变成:

//Run linux command in background and return the PID created by the OS
function run_in_background($Command, $Priority = 0)

    if($Priority) 
        shell_exec("nohup nice -n $Priority $Command 2> /dev/null > /dev/null &");
     else 
        shell_exec("nohup $Command 2> /dev/null > /dev/null &");
    

不幸的是,我认为没有任何方法可以检索 PID。

【讨论】:

是的,你可以得到PID,我用的是:$pid = shell_exec("nohup $process_ffmpeg > /dev/null 2>&1 & echo $!");

以上是关于在后台运行一个ffmpeg进程的主要内容,如果未能解决你的问题,请参考以下文章

Elixir 长时间运行的后台任务未完成,有时会崩溃

linux中如何把一个进程放在后台运行

Linux 进程后台运行

怎么让 Linux 进程在后台运行?

我想让一个app始终在后台运行,不被杀掉进程,怎么设置?

让进程在后台运行