获取metadata耗时对比(libtag/ffmpeg/gstreamer)

前言

有个需求是获取metadata,我想试试几种框架的性能对比情况,

结论

  • libtag获取metadata确实比ffmpeg和gstreamer快

  • 但是libtag支持的格式不如后两者:

  • gstreamer支持的格式和ffmpeg相同,但是速度慢了不少

QT测试程序源码

pro文件:

cpp 复制代码
  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

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;
}
相关推荐
wjs20242 小时前
状态模式(State Pattern)
开发语言
我命由我123452 小时前
Kotlin 数据容器 - List(List 概述、创建 List、List 核心特性、List 元素访问、List 遍历)
java·开发语言·jvm·windows·java-ee·kotlin·list
liulilittle2 小时前
C++ TAP(基于任务的异步编程模式)
服务器·开发语言·网络·c++·分布式·任务·tap
励志要当大牛的小白菜4 小时前
ART配对软件使用
开发语言·c++·qt·算法
爱装代码的小瓶子6 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
Maybe_ch7 小时前
.NET-键控服务依赖注入
开发语言·c#·.net
超浪的晨7 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
终焉暴龙王7 小时前
CTFHub web进阶 php Bypass disable_function通关攻略
开发语言·安全·web安全·php
Edingbrugh.南空8 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
CodeCraft Studio9 小时前
借助Aspose.HTML控件,在 Python 中将 HTML 转换为 Markdown
开发语言·python·html·markdown·aspose·html转markdown·asposel.html