参考:
- GStreamer基础教程之媒体格式和pad功能link
- GStreamer基础教程06——媒体格式和pad的Capabilitieslink
本文中(gstreamer-1.0, version 1.14.5;glib-2.0, version 2.56.4)修改了两篇中旧版本不能run的地方,并添加了详细的注释。
//script name --> basic_pad-6.c
#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);
// 检测是否caps代表所有的媒体格式
if (gst_caps_is_any (caps)) {
g_print ("%sANY\n", pfx);
return;
}
//检测是否caps代表没有媒体格式
if (gst_caps_is_empty (caps)) {
g_print ("%sEMPTY\n", pfx);
return;
}
//gst_caps_get_size caps包含的结构的数量
for (i = 0; i < gst_caps_get_size (caps); i++) {
// struct _GstStructure {
// GType type;
//
// /*< private >*/
// GQuark name;
// };
GstStructure *structure = gst_caps_get_structure (caps, i);
g_print ("%s%s\n", pfx, gst_structure_get_name (structure));
//为GstStructure的每个字段都执行print_field函数
gst_structure_foreach (structure, print_field, (gpointer) pfx);
}
}
/* Prints information about a Pad Template, including its Capabilities */
/*
Pad Templates for Audio test source:
SRC template: 'src'
Availability: Always
Capabilities:
audio/x-raw
format: { (string)S16LE, (string)S16BE, (string)U16LE, (string)U16BE, (string)S24_32LE, (string)S24_32BE, (string)U24_32LE, (string)U24_32BE, (string)S32LE, (string)S32BE, (string)U32LE, (string)U32BE, (string)S24LE, (string)S24BE, (string)U24LE, (string)U24BE, (string)S20LE, (string)S20BE, (string)U20LE, (string)U20BE, (string)S18LE, (string)S18BE, (string)U18LE, (string)U18BE, (string)F32LE, (string)F32BE, (string)F64LE, (string)F64BE, (string)S8, (string)U8 }
layout: interleaved
rate: [ 1, 2147483647 ]
channels: [ 1, 2147483647 ]
print_pad_templates_information (source_factory);
print_pad_templates_information (sink_factory);
*/
static void print_pad_templates_information (GstElementFactory * factory) {
const GList *pads;
GstStaticPadTemplate *padtemplate;
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;
}
//pads = factory->staticpadtemplates; pads -->_GList
/*
* struct _GList
{
gpointer data;
GList *next;
GList *prev;
};
*/
pads = gst_element_factory_get_static_pad_templates (factory);
while (pads) {
padtemplate = (GstStaticPadTemplate *) (pads->data);
//#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
pads = g_list_next (pads);
/*
* /**
* GstStaticPadTemplate:
* @name_template: the name of the template
* @direction: the direction of the template
* @presence: the presence of the template
* @static_caps: the caps of the template.
*
* Structure describing the #GstStaticPadTemplate.
padtemplate -->_GstStaticPadTemplate
struct _GstStaticPadTemplate {
const gchar *name_template;
GstPadDirection direction;
GstPadPresence presence;
GstStaticCaps static_caps;
};
*/
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) {
g_print (" Capabilities:\n");
print_caps (gst_static_caps_get (&padtemplate->static_caps), " ");
}
g_print ("\n");
}
}
/* Shows the CURRENT capabilities of the requested pad in the given element */
static void print_pad_capabilities (GstElement *element, gchar *pad_name) {
GstPad *pad = NULL;
GstCaps *caps = NULL;
/* Retrieve pad */
/*
gst_element_get_static_pad()方法会从给定的element里面取得Pad的名字。
这个Pad是静态的,因为它会一直存在。
*/
pad = gst_element_get_static_pad (element, pad_name);
if (!pad) {
g_printerr ("Could not retrieve pad '%s'\n", pad_name);
return;
}
/* Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet) */
/*
调用gst_pad_get_current_caps(pad)(gst_pad_get_negotiated_caps() oldversion)方法来获得Pad当前的Capabilities,无论是否已经固定下来,都会依赖协商过程的状态。
这时Capabilities可能是不存在的,如果遇到这种情况,我们就调用gst_pad_query_caps(pad,NULL)(gst_pad_get_caps_reffed() old version)方法来建立一个当前可以接受的Pad Capabilities。
这个所谓的当前可接受的Caps时Pad Template的在NULL状态下的Caps,但后面这个可能会改变,因为还会查询实际的硬件*/
//caps = gst_pad_get_negotiated_caps (pad);
caps = gst_pad_get_current_caps(pad);
if (!caps)
//caps = gst_pad_get_caps_reffed (pad);
caps = gst_pad_query_caps(pad,NULL);
/* Print and free */
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[]) {
GstElement *pipeline, *source, *sink;
GstElementFactory *source_factory, *sink_factory;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
gboolean terminate = FALSE;
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Create the element factories */
/*
直接使用gst_element_factory_make()方法来创建element,而忽略了工厂本身。
一个GstElementFactory是负责通过一个工厂名来实例化一个element的
可以使用gst_element_factory_find()来创建一个“videotestsrc”工厂,
然后通过gst_element_factory_create()来实例化多个“videotestsrc” element。
gst_element_factory_make()实际上只是这个过程的一个封装。
*/
source_factory = gst_element_factory_find ("audiotestsrc");
sink_factory = gst_element_factory_find ("autoaudiosink");
if (!source_factory || !sink_factory) {
g_printerr ("Not all element factories could be created.\n");
return -1;
}
/* Print information about the pad templates of these factories */
/*通过工厂,Pad模板实际上已经可以访问了,所以工厂一建立我们立刻打印这些信息。*/
/* Ask the factories to instantiate actual elements */
source = gst_element_factory_create (source_factory, "source");
sink = gst_element_factory_create (sink_factory, "sink");
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("test-pipeline");
if (!pipeline || !source || !sink) {
g_printerr ("Not all elements could be created.\n");
return -1;
}
/* Build the pipeline */
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;
}
/* Print initial negotiated caps (in NULL state) */
g_print ("In NULL state:\n");
print_pad_capabilities (sink, "sink");
/* Start playing */
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");
}
/* Wait until error, EOS or State Change */
bus = gst_element_get_bus (pipeline);
do {
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS |
GST_MESSAGE_STATE_CHANGED);
/* Parse message */
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;
/* 每次pipeline状态切换的时候简单地打印当前的Pad Caps。
你可以看到,在输出信息里面,初始的Caps(Pad模板的Caps)是如何逐步变化直到确定下来的(仅包含一个类型而且数值固定)。*/
case GST_MESSAGE_STATE_CHANGED:
/* We are only interested in state-changed messages from the pipeline */
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));
/* Print the current capabilities of the sink element */
print_pad_capabilities (sink, "sink");
}
break;
default:
/* We should not reach here because we only asked for ERRORs, EOS and STATE_CHANGED */
g_printerr ("Unexpected message received.\n");
break;
}
gst_message_unref (msg);
}
} while (!terminate);
/* Free resources */
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;
}