获取metadata耗时对比(libtag/ffmpeg/gstreamer)
前言
有个需求是获取metadata,我想试试几种框架的性能对比情况,
结论
-
libtag获取metadata确实比ffmpeg和gstreamer快
-
但是libtag支持的格式不如后两者:
- gstreamer支持的格式和ffmpeg相同,但是速度慢了不少
QT测试程序源码
pro文件:
SOURCES += \
main.cpp
LIBS += -ltag
# ffmpeg*************************************
LIBS += \
# -lSDL2 \
-lavcodec \
# -lavdevice \
# -lavfilter \
-lavformat \
-lavutil \
-lswresample \
-lswscale
# gstreamer**********************************
CONFIG += link_pkgconfig
PKGCONFIG += gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-pbutils-1.0#gtk+-3.0
LIBS += -lX11
LIBS +=-lglib-2.0
LIBS +=-lgobject-2.0
LIBS +=-lgstreamer-1.0 # <gst/gst.h>
LIBS +=-lgstvideo-1.0 # <gst/video/videooverlay.h>
LIBS +=-L/usr/lib/x86_64-linux-gnu/gstreamer-1.0
LIBS +=-lgstautodetect
LIBS +=-lgstaudio-1.0
LIBS +=-lgstapp-1.0
INCLUDEPATH += \
/usr/include/glib-2.0 \
/usr/lib/x86_64-linux-gnu/glib-2.0/include \
/usr/include/gstreamer-1.0 \
/usr/lib/x86_64-linux-gnu/gstreamer-1.0/include
main.cpp
#include <QCoreApplication>
#include <QDebug>
#include <QElapsedTimer>
#include <QUrl>
#include <taglib/fileref.h>
#include <taglib/tag.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/dict.h>
}
#include <gst/gst.h>
#include <gst/tag/tag.h>
#include <gst/pbutils/pbutils.h>
void testTaglib(QString filePath){
// 使用 TagLib 读取文件
TagLib::FileRef file(filePath.toStdString().c_str());
if (!file.isNull() && file.tag()) {
// 获取元数据
TagLib::Tag *tag = file.tag();
QString title = QString::fromStdString(tag->title().to8Bit(true));
QString artist = QString::fromStdString(tag->artist().to8Bit(true));
QString album = QString::fromStdString(tag->album().to8Bit(true));
uint year = tag->year();
uint track = tag->track();
// 打印元数据
qDebug() << "Title:" << title;
qDebug() << "Artist:" << artist;
qDebug() << "Album:" << album;
qDebug() << "Year:" << year;
qDebug() << "Track:" << track;
// 获取音频时长
if (file.audioProperties()) {
int length = file.audioProperties()->lengthInSeconds();
qDebug() << "Duration:" << length << "seconds";
}
} else {
qDebug() << "Failed to read file or metadata.";
}
}
void testFFmpeg(QString filePath){
// 打开文件
AVFormatContext *formatContext = avformat_alloc_context();
if (avformat_open_input(&formatContext, filePath.toStdString().c_str(), nullptr, nullptr) != 0) {
qDebug() << "Could not open file";
return ;
}
// 获取流信息
if (avformat_find_stream_info(formatContext, nullptr) < 0) {
qDebug() << "Could not find stream information";
avformat_close_input(&formatContext);
return ;
}
// 打印元数据
AVDictionaryEntry *tag = nullptr;
while ((tag = av_dict_get(formatContext->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
qDebug() << tag->key << ":" << tag->value;
}
// 获取时长(以秒为单位)
if (formatContext->duration != AV_NOPTS_VALUE) {
int64_t duration = formatContext->duration / AV_TIME_BASE;
qDebug() << "Duration:" << duration << "seconds";
}
// 释放资源
avformat_close_input(&formatContext);
}
void print_metadata(const GstDiscovererInfo *info)
{
if (!info) {
qDebug() << "No metadata found.";
return;
}
// 获取标签列表
const GstTagList *tags = gst_discoverer_info_get_tags(info);
if (tags) {
// 定义一个辅助函数来获取标签值
auto get_tag_string = [](const GstTagList *tags, const char *tag_name) -> QString {
gchar *value = nullptr;
gst_tag_list_get_string(tags, tag_name, &value);
QString result = value ? QString::fromUtf8(value) : "N/A";
g_free(value);
return result;
};
// 提取并打印元数据
qDebug() << "Title:" << get_tag_string(tags, GST_TAG_TITLE);
qDebug() << "Artist:" << get_tag_string(tags, GST_TAG_ARTIST);
qDebug() << "Album:" << get_tag_string(tags, GST_TAG_ALBUM);
// 获取持续时间
guint64 duration = gst_discoverer_info_get_duration(info);
if (duration != GST_CLOCK_TIME_NONE) {
qDebug() << "Duration:" << duration / GST_SECOND << "seconds";
} else {
qDebug() << "Duration: N/A";
}
} else {
qDebug() << "No tags found.";
}
}
void testGst(QString filePath)
{
// 创建 GstDiscoverer 实例,设置超时时间为 5 秒
GstDiscoverer *discoverer = gst_discoverer_new(5 * GST_SECOND, nullptr);
if (!discoverer) {
qDebug() << "Failed to create GstDiscoverer instance";
return ;
}
// 同步获取元数据
GError *error = nullptr;
GstDiscovererInfo *info = gst_discoverer_discover_uri(discoverer, qPrintable(QUrl::fromLocalFile(filePath).toString()), &error);
if (error) {
qDebug() << "Error discovering media file:" << error->message;
g_error_free(error);
} else {
// 打印元数据
print_metadata(info);
}
// 清理资源
if (info) {
gst_discoverer_info_unref(info);
}
g_object_unref(discoverer);
}
int main(int argc, char *argv[])
{
//QCoreApplication a(argc, argv);
// 初始化 FFmpeg
av_register_all();
// 初始化 GStreamer
gst_init(&argc, &argv);
// 音频文件路径
QString filePath = "/home/enpht/Music/test1.mp3";
//QString filePath = "/home/enpht/Videos/9sub.mkv";
// test Taglib:
qDebug()<<"taglib:";
QElapsedTimer timer1;
qint64 elapsed1 = 0;
timer1.start();
testTaglib(filePath);
elapsed1 = timer1.elapsed();
qDebug()<<"tablib cost time: "<<elapsed1<<" milliseconds";
// test ffmpeg
qDebug()<<"\nffmpeg:";
filePath = "/home/enpht/Music/test1.mp3";
//filePath = "/home/enpht/Videos/9sub.mkv";
QElapsedTimer timer2;
qint64 elapsed2 = 0;
timer2.start();
testFFmpeg(filePath);
elapsed2 = timer2.elapsed();
qDebug()<<"ffmpeg cost time: "<<elapsed2<<" milliseconds";
// test gst
qDebug()<<"\ngst:";
QElapsedTimer timer3;
qint64 elapsed3 = 0;
timer3.start();
testGst(filePath);
elapsed3 = timer3.elapsed();
qDebug()<<"gst cost time: "<<elapsed3<<" milliseconds";
//return a.exec();
return 0;
}