当前位置: 首页 > article >正文

GStreamer —— 2.9、Windows下Qt加载GStreamer库后运行 - “教程9:媒体信息收集“(附:完整源码)

简介

     上一个教程演示了多线程和 Pad 可用性。本教程介绍媒体信息收集。有时,您可能希望快速找出文件的媒体类型 (或 URI)包含媒体,或者您是否能够播放媒体。你 可以构建一个管道,将其设置为 Run,并监视总线消息,但 GStreamer 有一个实用程序可以为您执行此作。本教程 显示:

          • 如何恢复有关 URI 的信息

          • 如何确定 URI 是否可播放


     GstDiscoverer是在库中找到的实用程序对象 (插件基础实用程序),它接受 URI 或 URI 列表,并返回 关于他们的信息。它可以在同步或异步模式下工作 模式。在同步模式下,只有一个函数可以调用,该函数会阻塞,直到信息为 准备。由于这种阻塞,它通常不太有趣 使用基于 GUI 的应用程序和异步模式,如前所述 在本教程中。gst_discoverer_discover_uri()恢复的信息包括编解码器描述、流拓扑 (流和子流的数量)和可用的元数据(如 audio language) 的 Interface。例如,这是结果发现 https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm

在这里插入图片描述

GStreamer相关运行库
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/gstreamer-1.0/gst
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/gstreamer-1.0
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/glib-2.0
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/lib/glib-2.0/include

LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gstreamer-1.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/glib-2.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gobject-2.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gstaudio-1.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gstpbutils-1.0.lib

完整源码
#include <string.h>
#include <gst/gst.h>
#include <gst/pbutils/pbutils.h>

typedef struct _CustomData
{
    GstDiscoverer *discoverer;
    GMainLoop *loop;
} CustomData;

/* 以人类可读的格式打印标签(名称:值) */
static void print_tag_foreach (const GstTagList *tags, const gchar *tag, gpointer user_data)
{
    GValue val = { 0, };
    gst_tag_list_copy_value (&val, tags, tag);  /* 将给定标签的内容复制到值 如果多个值关联,则将多个值合并为一个值 替换为标签。 使用后必须g_value_unset该值。 */

    gchar *str;
    if (G_VALUE_HOLDS_STRING (&val))
        str = g_value_dup_string (&val);
    else
        str = gst_value_serialize (&val);

    gint depth = GPOINTER_TO_INT (user_data);
    g_print ("%*s%s: %s\n", 2 * depth, " ", gst_tag_get_nick (tag), str);
    g_free (str);

    g_value_unset (&val);
}

/* 打印有关流的信息 */
static void print_stream_info (GstDiscovererStreamInfo *info, gint depth)
{
    gchar *desc = NULL;
    GstCaps *caps = gst_discoverer_stream_info_get_caps (info);
    if (caps)
    {
        /*
         * 修复 GstCap 只描述一种格式,也就是说,它们恰好具有 一个结构,结构中的每个字段都描述一个固定类型。 非固定类型的示例包括 GST_TYPE_INT_RANGE 和 GST_TYPE_LIST。
            如果上限固定,则为 TRUE
        */
        if (gst_caps_is_fixed (caps))
        {
            /* 返回一个本地化的(尽可能可能的)字符串,描述 以大写字母指定的媒体格式,用于错误对话框或其他消息 以便用户看到。除非 caps 无效,否则不应返回 NULL。 */
            desc = gst_pb_utils_get_codec_description (caps);
        }
        else
        {
            /* 将 Cap 转换为 String 表示形式。此字符串表示 可以通过 gst_caps_from_string 转换回 GstCap。 */
            desc = gst_caps_to_string (caps);
        }
        gst_caps_unref (caps);
    }

    g_print ("%*s%s: %s\n", 2 * depth, " ", gst_discoverer_stream_info_get_stream_type_nick (info), (desc ? desc : ""));

    if (desc)
    {
        g_free (desc);
        desc = NULL;
    }

    const GstTagList *tags = gst_discoverer_stream_info_get_tags (info);
    if (tags)
    {
        g_print ("%*sTags:\n", 2 * (depth + 1), " ");
        gst_tag_list_foreach (tags, print_tag_foreach, GINT_TO_POINTER (depth + 2));
    }
}

/* 打印有关流及其子流的信息(如果有的话) */
static void print_topology (GstDiscovererStreamInfo *info, gint depth)
{
    if (!info){ return; }

    print_stream_info (info, depth);

    GstDiscovererStreamInfo *next = gst_discoverer_stream_info_get_next (info);
    if (next)
    {
        print_topology (next, depth + 1);
        gst_discoverer_stream_info_unref (next);
    }
    else if (GST_IS_DISCOVERER_CONTAINER_INFO (info))
    {
        GList *streams = gst_discoverer_container_info_get_streams (GST_DISCOVERER_CONTAINER_INFO (info));
        for (GList *tmp = streams; tmp; tmp = tmp->next)
        {
            GstDiscovererStreamInfo *tmpinf = (GstDiscovererStreamInfo *) tmp->data;
            print_topology (tmpinf, depth + 1);
        }
        gst_discoverer_stream_info_list_free (streams);
    }
}

/* 每当发现者有关于我们提供的URI之一的信息时,就会调用此函数。 */
static void on_discovered_cb (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, CustomData *data)
{
    GstDiscovererResult result;
    const gchar *uri;
    const GstTagList *tags;
    GstDiscovererStreamInfo *sinfo;

    uri = gst_discoverer_info_get_uri (info);
    result = gst_discoverer_info_get_result (info);
    switch (result)
    {
    case GST_DISCOVERER_URI_INVALID:
        g_print ("Invalid URI '%s'\n", uri);
        break;
    case GST_DISCOVERER_ERROR:
        g_print ("Discoverer error: %s\n", err->message);
        break;
    case GST_DISCOVERER_TIMEOUT:
        g_print ("Timeout\n");
        break;
    case GST_DISCOVERER_BUSY:
        g_print ("Busy\n");
        break;
    case GST_DISCOVERER_MISSING_PLUGINS:
    {
        const GstStructure *s;
        gchar *str;

        s = gst_discoverer_info_get_misc (info);
        str = gst_structure_to_string (s);

        g_print ("Missing plugins: %s\n", str);
        g_free (str);
        break;
    }
    case GST_DISCOVERER_OK:
        g_print ("Discovered '%s'\n", uri);
        break;
    }

    if (result != GST_DISCOVERER_OK) { g_printerr ("This URI cannot be played\n"); return; }

    /* 如果没有错误,显示检索到的信息 */
    g_print ("\nDuration: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (gst_discoverer_info_get_duration (info)));

    tags = gst_discoverer_info_get_tags (info);
    if (tags)
    {
        g_print ("Tags:\n");

        /* 为标签列表中的每个标签调用给定的函数。请注意,如果存在 没有标签,则根本不会调用该函数。 */
        gst_tag_list_foreach (tags, print_tag_foreach, GINT_TO_POINTER (1));
    }

    g_print ("Seekable: %s\n", (gst_discoverer_info_get_seekable (info) ? "yes" : "no"));
    g_print ("\n");

    sinfo = gst_discoverer_info_get_stream_info (info);
    if (!sinfo){ return; }

    g_print ("Stream information:\n");

    print_topology (sinfo, 1);

    gst_discoverer_stream_info_unref (sinfo);

    g_print ("\n");
}

/* 当发现者检查完我们提供的所有URI后,将调用此函数。.*/
static void on_finished_cb (GstDiscoverer *discoverer, CustomData *data)
{
    g_print ("Finished discovering\n");

    g_main_loop_quit (data->loop);
}

int main (int argc, char **argv)
{
    gchar *uri = (gchar *)("https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm");
    if (argc > 1) { uri = argv[1]; }

    CustomData data;
    memset (&data, 0, sizeof (data));

    /* 初始化GStreamer */
    gst_init (&argc, &argv);
    g_print ("Discovering '%s'\n", uri);

    /* 实例化发现者 */
    GError *err = NULL;
    data.discoverer = gst_discoverer_new (5 * GST_SECOND, &err);
    if (!data.discoverer)
    {
        g_print ("Error creating discoverer instance: %s\n", err->message);
        g_clear_error (&err); return -1;
    }

    /* 连接到有趣的信号 */
    g_signal_connect (data.discoverer, "discovered", G_CALLBACK (on_discovered_cb), &data);
    g_signal_connect (data.discoverer, "finished", G_CALLBACK (on_finished_cb), &data);

    /* 启动发现者进程(目前还没什么可做的) */
    gst_discoverer_start (data.discoverer);

    /* 添加请求以异步处理通过命令行传递的URI */
    if (!gst_discoverer_discover_uri_async (data.discoverer, uri))
    {
        g_print ("Failed to start discovering URI '%s'\n", uri);
        g_object_unref (data.discoverer); return -1;
    }

    /* 创建一个GLib主循环并将其设置为运行,这样我们就可以等待信号了 */
    data.loop = g_main_loop_new (NULL, FALSE);
    g_main_loop_run (data.loop);

    /* 停止发现者进程 */
    gst_discoverer_stop (data.discoverer);

    /* 释放资源 */
    g_object_unref (data.discoverer);
    g_main_loop_unref (data.loop);

    return 0;
}

关注

笔者 - jxd


http://www.kler.cn/a/580586.html

相关文章:

  • 年末网络安全检查的清单
  • 力扣hot100二刷——哈希、双指针、滑动窗口
  • Python第十六课:深度学习入门 | 神经网络解密
  • PyTorch 中的混合精度训练方法,从 autocast 到 GradScalar
  • 力扣hot100_二叉树(4)_python版本
  • FastAPI 表单参数与文件上传完全指南:从基础到高级实战 [特殊字符]
  • 如何实现创意的角落切割效果:使用 CSS 和 SVG 创建时尚的网页元素
  • NLP常见任务专题介绍(1)-关系抽取(Relation Extraction, RE)任务训练模板
  • TypeError: Cannot convert object to primitive value
  • JavaScript(最后一个元素的索引就是数组的长度减 1)array.length - 1
  • Java 大视界 -- 基于 Java 的大数据实时数据处理框架性能评测与选型建议(121)
  • 请谈谈 TypeScript 中的接口(interface)和类型别名(type alias),它们的区别是什么?
  • Python | 机器学习中最常用的超参数及使用示例
  • Qt常用控件之树形QTreeWidget
  • 如何使用postman来测试接口
  • Synology 部署的 WordPress 無法升級至最新版本時,可以透過以下改良版指南進行排查和解決。
  • 雪藏HsFreezer(游戏冻结工具) v2.21
  • jsonRPC实现前后端分离
  • delphi 正则提取html中的内容
  • listen EACCES: permission denied 0.0.0.0:811