QProcess 介绍
"QProcess" 是 Qt 框架中用于启动外部进程和与之进行交互的类。它提供了一个方便的接口,允许你执行外部命令并捕获其输出、错误信息以及监控其运行状态。通过使用 "QProcess" 类,你可以在你的 Qt 应用程序中调用其他的可执行文件,比如系统命令行工具或者其他应用程序,然后处理它们的输出结果或者与其进行交互。
使用流程
#include <QProcess>
QProcess *ffmpegProcess= new QProcess(this);
// 设置要执行的外部命令和参数
QString program = "ffmpeg"; // FFmpeg 命令(假设已将 FFmpeg 添加到系统环境变量)
//转码参数
QStringList arguments;
arguments << "-i" << "input.mp4" << "-c:v" << "h264" << "-c:a" << "aac" << "output.mp4"; // 设
// 启动外部进程
ffmpegProcess.start(program, arguments);
//如果需要获取外部进程的输出,可以连接“QProcess” 的信号和槽函数
connect(ffmpegProcess, &QProcess::readyReadStandardOutput, this, &YourClass::onReadyReadStandardOutput);
connect(ffmpegProcess, &QProcess::readyReadStandardError, this, &YourClass::onReadyReadStandardError);
//在相应的槽函数中处理外部进程的输出:
void YourClass::onReadyReadStandardOutput()
{
QByteArray output = ffmpegProcess->readAllStandardOutput();
// 处理标准输出数据
}
void YourClass::onReadyReadStandardError()
{
QByteArray error = ffmpegProcess->readAllStandardError();
// 处理标准错误输出数据
}
ffmpegProcess->waitForFinished(); // 阻塞当前线程,直到进程完成
注意事项
请注意,此示例中的代码是同步执行的,即在调用 waitForFinished 后,程序会等待 FFmpeg 进程完成转码操作。如果你希望异步执行转码,并在转码过程中继续运行其他任务,可以使用 QProcess::startDetached 方法。
即使用startDetached () 替换 start()方法。
关于startDetached ()介绍:
bool QProcess::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(), qint64 *pid = nullptr);
参数说明:
program: 一个QString类型的参数,表示要启动的外部应用程序的路径或可执行文件的名称。
arguments: 一个QStringList类型的参数,表示启动外部应用程序时传递给它的命令行参数列表。
workingDirectory: 一个可选的QString类型的参数,表示启动外部应用程序时使用的工作目录。如果不提供此参数,默认使用当前程序的工作目录。
pid: 一个可选的qint64类型的指针参数,用于获取启动的新进程的进程ID。如果不需要获取进程ID,可以将该参数设置为nullptr。
函数返回值:
如果成功启动了新进程,则返回true。
如果启动进程失败或遇到错误,则返回false。
使用QProcess::startDetached函数时,注意以下几点:
该函数启动的进程是独立于当前程序的,所以在当前程序退出后,新进程会继续在后台运行。
由于该函数是无阻塞的,因此在调用该函数后,程序会立即继续执行后续代码,不会等待新进程的执行完成。
如果要与启动的进程进行交互或获取其输出结果,可以考虑使用QProcess的其他相关方法,如QProcess::start和QProcess::waitForFinished。
需要注意的是,QProcess::startDetached函数在不同的操作系统上可能有一些行为上的差异,因此在使用时最好查阅官方文档,以及考虑处理潜在的错误和异常情况。
进一步的,使用ffmpeg 转码音视频流,并且获取音视频流:
可以使用 QProcess 的 setReadChannel() 方法来设置要读取的通道,然后使用 QProcess 的 readAllStandardOutput() 方法来获取输出。
例子:
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 创建一个 QProcess 对象
QProcess ffmpegProcess;
// 设置要执行的外部命令和参数
QString program = "ffmpeg"; // FFmpeg 命令(假设已将 FFmpeg 添加到系统环境变量)
QStringList arguments;
arguments << "-i" << "input.mp4" << "-c:v" << "h264" << "-c:a" << "aac" << "-f" << "matroska" << "-"; // 设置转码参数并将输出格式设置为 matroska
// 设置标准输出读取通道
ffmpegProcess.setReadChannel(QProcess::StandardOutput);
// 启动外部进程
ffmpegProcess.start(program, arguments);
// 等待进程完成
if (ffmpegProcess.waitForFinished(-1)) {
// 进程已完成
qDebug() << "转码完成!";
// 读取转码后的视频流
QByteArray outputData = ffmpegProcess.readAllStandardOutput();
// 在这里你可以对 outputData 进行处理,比如保存为文件或传递给其他模块进行处理
} else {
// 进程未能正常完成
qDebug() << "转码失败:" << ffmpegProcess.errorString();
}
return a.exec();
}
注意事项
在上面的示例中,我们将 FFmpeg 的输出格式设置为 matroska,并通过管道获取转码后的视频流。转码后的视频流将保存在 outputData 变量中。你可以根据需要对视频流进行处理,例如保存为文件或传递给其他模块进行进一步处理。
请注意,如果视频非常大,或者转码过程非常耗时,可能会导致 readAllStandardOutput() 方法阻塞程序。为了避免阻塞,你可以使用 readyReadStandardOutput() 信号来异步读取输出流的数据,或者使用其他方法逐块读取数据。
关于readAllStandardOutput() 和 readyReadStandardOutput()介绍
readAllStandardOutput() 方法:
QByteArray readAllStandardOutput(): 该方法会读取并返回子进程的标准输出(stdout)中的所有数据。
调用该方法会阻塞当前线程,直到子进程完成并关闭了标准输出通道,或者直到 QProcess 对象被销毁为止。
如果子进程的输出量较小,且处理速度较快,使用该方法可能是方便的。它将一次性返回所有输出数据,你可以直接对数据进行处理。
然而,如果子进程的输出较大,或者处理速度较慢,使用该方法可能会导致主线程阻塞,造成程序无响应的情况。因此,在处理大量输出数据或子进程输出速度较快时,推荐使用 readyReadStandardOutput() 方法。
readyReadStandardOutput() 信号:
信号声明:void readyReadStandardOutput()
该信号会在子进程的标准输出通道有新数据可读取时触发,表示可以安全地读取数据而不会阻塞主线程。
当你启动子进程后,并希望异步处理其输出数据时,可以连接该信号到槽函数来处理。每次该信号触发时,都可以调用 readAllStandardOutput() 或 readLineStandardOutput() 方法来读取新的输出数据。
注意:由于该信号在子进程输出可读取时会频繁触发,因此你应该在槽函数中高效地处理数据,并避免耗时操作,以免影响程序的响应性能。
例子:
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 创建一个 QProcess 对象
QProcess ffmpegProcess;
// 设置要执行的外部命令和参数...
// (与之前示例相同)
// 设置标准输出读取通道
ffmpegProcess.setReadChannel(QProcess::StandardOutput);
// 连接 readyReadStandardOutput() 信号到槽函数
QObject::connect(&ffmpegProcess, &QProcess::readyReadStandardOutput, [&ffmpegProcess](){
// 读取并处理输出数据
QByteArray outputData = ffmpegProcess.readAllStandardOutput();
// 在这里你可以对 outputData 进行处理,比如保存为文件或传递给其他模块进行处理
});
// 启动外部进程
ffmpegProcess.start(program, arguments);
// ...
return a.exec();
}
总结:readAllStandardOutput() 方法适合处理较小量的输出数据,或者在子进程完成后读取所有输出;而 readyReadStandardOutput() 信号适用于异步处理输出数据,特别是在输出数据量较大或输出速度较快的情况下,避免阻塞主线程。根据实际场景,你可以选择使用其中的一种或两种方法来处理子进程的标准输出。