在博主之前的博文《FFmpeg解封装(解复用)并获取本地媒体文件的信息》中,介绍了使用FFmpeg的API获取媒体文件信息的方法。但FFmpeg的API是比较复杂的,如果不是专门从事音视频开发的工程师,可能无法很好地使用里面的API。本文以获取媒体文件的信息为例子,介绍另外一种使用FFmpeg的方法---------通过调用外部程序(ffmpeg.exe)的方式使用FFmpeg。使用该方法程序员不需要了解FFmpeg的api,只需要懂得一些FFmpeg的命令即可对媒体文件进行处理。下面介绍这种方法:
一、原理:
在下图所示文件夹中,存在ffmpeg.exe和video1.mp4。
通过命令提示符进入上图所示目录中,执行命令:
ffmpeg -hide_banner -i video1.mp4
可以得到如下图所示的媒体文件video1.mp4的信息
所以程序员在程序中只要通过调用外部程序的方式执行命令“ffmpeg -hide_banner -i video1.mp4”(比如在Qt中可以通过QProcess的start函数执行命令),将在命令提示符中输出的信息保存到程序的变量中,即可在程序中得到媒体文件的信息
二、代码
开发环境为windows7 64位,Qt5.9.0 + vs2015
部分代码如下:
QtGuiApplication2.h
#pragma once
#include <QtWidgets/QMainWindow>
#include <QProcess>
#include "ui_QtGuiApplication2.h"
class QtGuiApplication2 : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication2(QWidget *parent = Q_NULLPTR);
public slots:
void ReadMediaFileInformation();
void ProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
private:
Ui::QtGuiApplication2Class ui;
QProcess *m_proc;
std::string m_FFmpegBuf; //保存FFmpeg的输出信息
QString m_MediaFileName; //要获取信息的媒体文件的名称
};
QtGuiApplication2.cpp
#include "QtGuiApplication2.h"
using namespace std;
QtGuiApplication2::QtGuiApplication2(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
m_proc = new QProcess(this);
m_proc->setProcessChannelMode(QProcess::MergedChannels);
connect(m_proc, SIGNAL(readyReadStandardOutput()), this, SLOT(ReadMediaFileInformation()));
connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(ProcessFinished(int, QProcess::ExitStatus)));
m_MediaFileName = "video1.mp4";
QString cmd = "ffmpeg -hide_banner -i " + m_MediaFileName;
if (m_proc->state() != m_proc->NotRunning)
{
m_proc->waitForFinished(20000);
}
m_proc->start(cmd); //启动外部进程(执行命令ffmpeg -hide_banner -i video1.mp4)
}
//当外部进程产生的新的数据时该函数会被调用
void QtGuiApplication2::ReadMediaFileInformation()
{
QString buf(QString::fromLocal8Bit(m_proc->read(10000)));
string s = buf.toStdString();
if (0 == s.length())
{
return;
}
m_FFmpegBuf += s;
}
//当外部进程结束时,该函数会被调用
void QtGuiApplication2::ProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug("m_FFmpegBuf:%s", m_FFmpegBuf.c_str());
int pos1,pos2;
string bitrate;
string duration;
pos1 = m_FFmpegBuf.find("bitrate: ");
pos2 = m_FFmpegBuf.find(" kb/s");
if (pos1>=0 && pos2>=0)
{
bitrate = m_FFmpegBuf.substr(pos1+strlen("bitrate: "), (pos2+strlen(" kb/s")) - (pos1+strlen("bitrate: "))); //该媒体文件的平均码率
}
pos1 = m_FFmpegBuf.find("Duration: ");
pos2 = m_FFmpegBuf.find(", start:");
if (pos1 >= 0 && pos2 >= 0)
{
duration = m_FFmpegBuf.substr(pos1 + strlen("Duration: "), pos2 - (pos1 + strlen("Duration: "))); //该媒体文件总时长
}
ui.LabelMediaFileName->setText(m_MediaFileName);
ui.Labelbitrate->setText(QString::fromStdString(bitrate));
ui.LabelDuration->setText(QString::fromStdString(duration));
}
执行上述程序的效果如下:
可以看到可以得到媒体文件video1.mp4的信息(码率,时长)
三、两种使用FFmpeg方式的比较:
1、通过外部进程调用ffmpeg.exe的方式:
优点:操作简单,只需要了解FFmpeg的命令即可对媒体文件进行处理。主要使用在对音视频处理执行时间要求不高的场合,比如市面上的一些视频编辑器的转换封装格式,合并视频音频,音视频分离等操作就是通过这种方式实现的。
缺点:执行效率低,时间开销大。有些音视频操作是只能用FFmpeg的API完成而无法通过调用ffmpeg.exe代替的,比如实现一个播放器。
2、通过调用FFmpeg的API的方式:
优点:灵活,速度快,效率高。能通过外部进程调用ffmpeg.exe的方式实现的操作就必然可以通过调用FFmpeg的API的方式实现。
缺点:使用比较复杂,对程序员的要求较高。
四、资源文件下载
上面演示的所有源码,完整的工程可以在https://download.csdn.net/download/u014552102/11859971下载,欢迎各位下载