GStreamer —— 2.6、Windows下Qt加载GStreamer库后运行 - “教程6:媒体格式和Pad功能“(附:完整源码)
运行效果
简介
上一个教程演示了GUI 工具包集成(gtk)。本教程介绍媒体格式和Pad功能。Pad Capabilities 是 GStreamer 的一个基本元素,尽管大多数它们不可见,因为框架会处理它们 自然而然。这个有点理论性的教程展示了:
• 什么是 Pad 功能。
• 如何检索它们。
• 何时检索它们。
• 为什么你需要了解它们。
如前所述,Pads 允许信息进入和离开 一个元素。Pad 的功能(或简称 Caps),那么, 指定哪些类型的信息可以通过 Pad 传输。为 示例,“分辨率为 320x200 像素和 30 帧的 RGB 视频 per second“或”16 bits per sample audio, 5.1 channels at 44100 samples” 每秒“,甚至是 MP3 或 H264 等压缩格式。Pads 可以支持多种功能(例如,视频接收器可以 支持不同类型的 RGB 或 YUV 格式的视频)和功能可以是 指定为范围 (例如,音频接收器可以支持示例 速率为每秒 1 到 48000 个样本)。但是,实际的 从 Pad 到 Pad 传输的信息必须只有一个 Well Specify 类型。通过称为协商的过程,两个链接的 Pad 就 一个通用类型,因此 Pad 的 Capabilities 变得固定(它们只有一个类型并且不包含范围)。演练 下面的示例代码应该清楚地说明了这一切。为了将两个元素链接在一起,它们必须共享一个 common subset of Capabilities (否则它们不可能 相互理解)。这是 Capabilities 的主要目标。作为应用程序开发人员,您通常会通过链接 元素一起(如果使用 all-in-all 元素,则程度较小 喜欢 )。在这种情况下,您需要知道 Pad Caps(因为它们 都熟悉地引用了)的元素,或者至少知道什么 它们是 GStreamer 拒绝将两个元素与协商联系起来的时候 错误。
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
完整源码
#include <gst/gst.h>
/* Functions below print the Capabilities in a human-friendly format */
static gboolean print_field (GQuark field, const GValue * value, gpointer pfx)
{
gchar *str = gst_value_serialize (value);
g_print ("%s %15s: %s\n", (gchar *) pfx, g_quark_to_string (field), str);
g_free (str);
return TRUE;
}
static void print_caps (const GstCaps * caps, const gchar * pfx)
{
guint i;
g_return_if_fail (caps != NULL);
if (gst_caps_is_any (caps))
{
g_print ("%sANY\n", pfx);
return;
}
if (gst_caps_is_empty (caps))
{
g_print ("%sEMPTY\n", pfx);
return;
}
for (i = 0; i < gst_caps_get_size (caps); i++)
{
GstStructure *structure = gst_caps_get_structure (caps, i);
g_print ("%s%s\n", pfx, gst_structure_get_name (structure));
gst_structure_foreach (structure, print_field, (gpointer) pfx);
}
}
/* 打印有关pod模板的信息,包括其功能 */
static void print_pad_templates_information (GstElementFactory * factory)
{
g_print ("Pad Templates for %s:\n", gst_element_factory_get_longname (factory));
if (!gst_element_factory_get_num_pad_templates (factory)) { g_print (" none\n"); return; }
GstStaticPadTemplate *padtemplate;
const GList *pads = gst_element_factory_get_static_pad_templates (factory);
while (pads)
{
padtemplate = (GstStaticPadTemplate*)pads->data;
pads = g_list_next (pads);
if (padtemplate->direction == GST_PAD_SRC)
g_print (" SRC template: '%s'\n", padtemplate->name_template);
else if (padtemplate->direction == GST_PAD_SINK)
g_print (" SINK template: '%s'\n", padtemplate->name_template);
else
g_print (" UNKNOWN!!! template: '%s'\n", padtemplate->name_template);
if (padtemplate->presence == GST_PAD_ALWAYS)
g_print (" Availability: Always\n");
else if (padtemplate->presence == GST_PAD_SOMETIMES)
g_print (" Availability: Sometimes\n");
else if (padtemplate->presence == GST_PAD_REQUEST)
g_print (" Availability: On request\n");
else
g_print (" Availability: UNKNOWN!!!\n");
if (padtemplate->static_caps.string)
{
GstCaps *caps;
g_print (" Capabilities:\n");
caps = gst_static_caps_get (&padtemplate->static_caps);
print_caps (caps, " ");
gst_caps_unref (caps);
}
g_print ("\n");
}
}
/* 显示给定元素中请求pod的能力 */
static void print_pad_capabilities (GstElement *element, gchar *pad_name)
{
/* 取回pad */
GstPad *pad = gst_element_get_static_pad (element, pad_name);
if (!pad) { g_printerr ("Could not retrieve pad '%s'\n", pad_name); return; }
/* 获取当前在 pad 上配置的具有最后一个 GST_EVENT_CAPS 事件的功能。(如果协商尚未完成,则检索可接受的上限) */
GstCaps *caps = gst_pad_get_current_caps (pad);
if (!caps){caps = gst_pad_query_caps (pad, NULL);}
/* 打印后释放 */
g_print ("Caps for the %s pad:\n", pad_name);
print_caps (caps, " ");
gst_caps_unref (caps);
gst_object_unref (pad);
}
int main(int argc, char *argv[])
{
/* 初始化GStreamer */
gst_init (&argc, &argv);
/* 创建元素工厂 */
GstElementFactory *source_factory = gst_element_factory_find ("audiotestsrc");
GstElementFactory *sink_factory = gst_element_factory_find ("autoaudiosink");
if (!source_factory || !sink_factory) { g_printerr ("Not all element factories could be created.\n"); return -1; }
/* 打印这些工厂的pod模板信息 */
print_pad_templates_information (source_factory);
print_pad_templates_information (sink_factory);
/* 要求工厂实例化实际元素 */
GstElement *source = gst_element_factory_create (source_factory, "source");
GstElement *sink = gst_element_factory_create (sink_factory, "sink");
/* 创建空管道 */
GstElement *pipeline = gst_pipeline_new ("test-pipeline");
if (!pipeline || !source || !sink) { g_printerr ("Not all elements could be created.\n"); return -1; }
/* 构建管道 */
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
if (gst_element_link (source, sink) != TRUE) { g_printerr ("Elements could not be linked.\n"); gst_object_unref (pipeline); return -1; }
/* 打印初始能力(处于NULL状态) */
g_print ("In NULL state:\n");
print_pad_capabilities (sink, (gchar *)"sink");
/* 开始播放 */
GstStateChangeReturn ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) { g_printerr ("Unable to set the pipeline to the playing state (check the bus for error messages).\n"); }
gboolean terminate = FALSE;
GstMessage *msg;
/* 等待错误、EOS或状态更改 */
GstBus *bus = gst_element_get_bus (pipeline);
do
{
// 等待获取符合条件的消息
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_STATE_CHANGED));
/* 解析消息 */
if (msg != NULL)
{
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE (msg))
{
case GST_MESSAGE_ERROR:
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
terminate = TRUE; break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream reached.\n");
terminate = TRUE; break;
case GST_MESSAGE_STATE_CHANGED:
/* 我们只对来自管道的状态更改消息感兴趣 */
if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline))
{
GstState old_state, new_state, pending_state;
gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
g_print ("\nPipeline state changed from %s to %s:\n", gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
/* 打印sink元素的当前功能 */
print_pad_capabilities (sink, (gchar *)("sink"));
}
break;
default:
/* 通常不会运行到这里 */
g_printerr ("Unexpected message received.\n"); break;
}
gst_message_unref (msg);
}
} while (!terminate);
/* 释放资源 */
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
gst_object_unref (source_factory);
gst_object_unref (sink_factory);
return 0;
}
关注
笔者 - jxd