简介
上一个教程演示了多线程和 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_18">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/includeLIBS += 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);elsestr = 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