三、动态构建GStreamer管道
1 代码
#include <gst/gst.h>/* Structure to contain all our information, so we can pass it to callbacks */
/* 这里存下了所有需要的局部变量,因为本教程中会有回调函数,使用struct比较方便 */
typedef struct _CustomData
{GstElement *pipeline;GstElement *source;GstElement *convert;GstElement *resample;GstElement *sink;
} CustomData;/* Handler for the pad-added signal */
static void pad_added_handler (GstElement * src, GstPad * pad,CustomData * data);int
main (int argc, char *argv[])
{CustomData data;GstBus *bus;GstMessage *msg;GstStateChangeReturn ret;gboolean terminate = FALSE;/* Initialize GStreamer */gst_init (&argc, &argv);/* Create the elements *//* 我的理解是:uridecodebin创建的时候,没有初始化内部source pad,是因为内部带有demuxer */data.source = gst_element_factory_make ("uridecodebin", "source");data.convert = gst_element_factory_make ("audioconvert", "convert");data.resample = gst_element_factory_make ("audioresample", "resample");data.sink = gst_element_factory_make ("autoaudiosink", "sink");/* Create the empty pipeline */data.pipeline = gst_pipeline_new ("test-pipeline");if (!data.pipeline || !data.source || !data.convert || !data.resample|| !data.sink) {g_printerr ("Not all elements could be created.\n");return -1;}/* Build the pipeline. Note that we are NOT linking the source at this* point. We will do it later. */gst_bin_add_many (GST_BIN (data.pipeline), data.source, data.convert,data.resample, data.sink, NULL);/* 这儿没有吧source连接上,因为这个时候还没有source pad */if (!gst_element_link_many (data.convert, data.resample, data.sink, NULL)) {g_printerr ("Elements could not be linked.\n");gst_object_unref (data.pipeline);return -1;}/* Set the URI to play */g_object_set (data.source, "uri","https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm",NULL);/* Connect to the pad-added signal *//* 在这里把回调函数的src data变量指定参数*/g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler),&data);/* Start playing */ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);if (ret == GST_STATE_CHANGE_FAILURE) {g_printerr ("Unable to set the pipeline to the playing state.\n");gst_object_unref (data.pipeline);return -1;}/* Listen to the bus */bus = gst_element_get_bus (data.pipeline);do {msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);/* 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;case GST_MESSAGE_STATE_CHANGED:/* We are only interested in state-changed messages from the pipeline */if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) {GstState old_state, new_state, pending_state;gst_message_parse_state_changed (msg, &old_state, &new_state,&pending_state);g_print ("Pipeline state changed from %s to %s:\n",gst_element_state_get_name (old_state),gst_element_state_get_name (new_state));}break;default:/* We should not reach here */g_printerr ("Unexpected message received.\n");break;}gst_message_unref (msg);}} while (!terminate);/* Free resources */gst_object_unref (bus);gst_element_set_state (data.pipeline, GST_STATE_NULL);gst_object_unref (data.pipeline);return 0;
}/* This function will be called by the pad-added signal */
static void
pad_added_handler (GstElement * src, GstPad * new_pad, CustomData * data)
{GstPad *sink_pad = gst_element_get_static_pad (data->convert, "sink");GstPadLinkReturn ret;GstCaps *new_pad_caps = NULL;GstStructure *new_pad_struct = NULL;const gchar *new_pad_type = NULL;g_print("1\n");g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad),GST_ELEMENT_NAME (src));/* If our converter is already linked, we have nothing to do here */if (gst_pad_is_linked (sink_pad)) {g_print ("We are already linked. Ignoring.\n");goto exit;}/* Check the new pad's type */new_pad_caps = gst_pad_get_current_caps (new_pad);new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);new_pad_type = gst_structure_get_name (new_pad_struct);if (!g_str_has_prefix (new_pad_type, "audio/x-raw")) {g_print ("It has type '%s' which is not raw audio. Ignoring.\n",new_pad_type);goto exit;}/* Attempt the link */ret = gst_pad_link (new_pad, sink_pad);if (GST_PAD_LINK_FAILED (ret)) {g_print ("Type is '%s' but link failed.\n", new_pad_type);} else {g_print ("Link succeeded (type '%s').\n", new_pad_type);}exit:/* Unreference the new pad's caps, if we got them */if (new_pad_caps != NULL)gst_caps_unref (new_pad_caps);/* Unreference the sink pad */gst_object_unref (sink_pad);
}
2 代码分析
主要分析一些官方手册这一节没有介绍到的函数。
2.1 通过element和pad名字检索到已存在的GstPad
GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name);
这是通过 gst-inspect-1.0 audioconvert
命令查看Pad,由图片信息可知道,pad的名字是sink和src。所以通过该函数可以得到Pad。只能查找Availability:Always的元素的Pad。name等于sink或者src。
2.2 查看Pad类型
/* 获得pad的Capabilities地址 */
GstCaps * gst_pad_get_current_caps (GstPad *pad);
/* 获得Capabilities中包含结构体信息 */
GstStructure * gst_caps_get_structure (const GstCaps *caps,guint index);
/* 读出type */
const gchar * gst_structure_get_name (const GstStructure *structure);struct _GstStructure {GType type;/*< private >*/GQuark name;
};
2.4 Message和Cap都继承于mini_object
struct _GstCaps {GstMiniObject mini_object;
};struct _GstMessage
{GstMiniObject mini_object;/*< public > *//* with COW */GstMessageType type;guint64 timestamp;GstObject *src;guint32 seqnum;/*< private >*//* with MESSAGE_LOCK */GMutex lock; /* lock and cond for async delivery */GCond cond;
};
释放资源函数
static inline void
gst_caps_unref (GstCaps * caps)
{gst_mini_object_unref (GST_MINI_OBJECT_CAST (caps));
}static inline void
gst_message_unref (GstMessage * msg)
{gst_mini_object_unref (GST_MINI_OBJECT_CAST (msg));
}
3 函数总结
/*1.查看Message信息是那个element发出*/
GST_MESSAGE_SRC(message) /*2.从message读取管道状态*/
void gst_message_parse_state_changed (GstMessage *message, GstState *oldstate,GstState *newstate, GstState *pending);
/*3.获得状态字符串*/
const gchar* gst_element_state_get_name (GstState state);/*4.*/
GstPad* gst_element_get_static_pad(GstElement *element, const gchar *name);
4. 继承关系
4.1 GstObject
GObject╰──GInitiallyUnowned╰──GstObject╰──GstAllocator╰──GstBufferPool╰──GstBus╰──GstClock╰──GstControlBinding╰──GstControlSource╰──GstDevice╰──GstDeviceMonitor╰──GstDeviceProvider╰──GstElement╰──GstPad╰──GstPadTemplate╰──GstPlugin╰──GstPluginFeature╰──GstRegistry╰──GstStream╰──GstStreamCollection╰──GstTask╰──GstTaskPool╰──GstTracer╰──GstTracerRecord
4.2 GstMiniObject
GstMiniObject是一个种简单的,能够实现可计数类型结构。查看该结构并没有继承GObject对象,所以,任何继承于GstMiniObject的类都不可以使用GObject类的功能。主要要区别GstObject和GstMiniObject。GstObject中有属性、信号,后者没有。
struct _GstMiniObject {GType type;/*< public >*/ /* with COW */gint refcount; gint lockstate;guint flags;GstMiniObjectCopyFunction copy;GstMiniObjectDisposeFunction dispose;GstMiniObjectFreeFunction free;/* < private > *//* Used to keep track of weak ref notifies and qdata */guint n_qdata;gpointer qdata;
};
GstMiniObject╰──GstBuffer /*缓冲*/╰──GstCaps /*Pad的相关信息*/╰──GstMessage /*管道的消息*/╰──GstEvent╰──GstQuery
5. 获得name宏和函数总结
#define GST_PAD_NAME(pad) (GST_OBJECT_NAME(pad))
#define GST_ELEMENT_NAME(elem) (GST_OBJECT_NAME(elem))#define gst_pad_get_name(pad) gst_object_get_name(GST_OBJECT_CAST (pad))
#define gst_element_get_name(elem) gst_object_get_name(GST_OBJECT_CAST(elem))
gchar* gst_object_get_name (GstObject *object);
从上面不难发现,无论Pad还是Element得到对象名称的时候,宏定义后面使用的函数都是相同的。
三、动态构建GStreamer管道相关推荐
- 07 Confluent_Kafka权威指南 第七章: 构建数据管道
文章目录 CHAPTER 7 Building Data Pipelines 构建数据管道 将数据集成到上下文 Considerations When Building Data Pipelines ...
- Android TV开发总结(三)构建一个TV app的焦点控制及遇到的坑
原文:Android TV开发总结(三)构建一个TV app的焦点控制及遇到的坑 版权声明:我已委托"维权骑士"(rightknights.com)为我的文章进行维权行动.转载务必 ...
- Vue动态构建混合数据Treeselect选择树及巨树问题的解决方法
今天在项目中需要通过行政区域选择,然后选择该行政区域下面的景区,也就是要构建行政区划.景区两表数据表的树. 全国的行政区域到县已经3500多了,再加上景区会有几万个点,这棵选择树不论是在后台还是在前台 ...
- VUE 动态构建混合数据Treeselect选择树,同时解决巨树问题
今天在项目中需要通过行政区域选择,然后选择该行政区域下面的景区,也就是要构建行政区划.景区两表数据表的树.全国的行政区域到县已经3500多了,再加上景区会有几万个点,这棵选择树不论是在后台还是在前台构 ...
- LINQ to SQL 运行时动态构建查询条件
原文地址:http://msdn.microsoft.com/zh-cn/dd567295.aspx 在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句 ...
- 多个客户端抢夺命名管道_使用Kafka构建数据管道
目标:使用Kafka和使用Redis的服务层编写数据管道. 先决条件 请根据您的操作系统安装以下组件: · Kafka · Zookeeper · Redis · Java 目标观众 本文针对的是正在 ...
- python 机器学习管道_构建机器学习管道-第1部分
python 机器学习管道 Below are the usual steps involved in building the ML pipeline: 以下是构建ML管道所涉及的通常步骤: Imp ...
- jenkins部署三种构建方式的详细步骤
部署背景: jenkins: CentOS 7.4C IP:172.16.3.74 gitlab-11.5.3: Cen ...
- devops 开源工具链_使用开源工具构建DevOps管道的初学者指南
devops 开源工具链 DevOps已成为修复缓慢,孤立或其他功能不正常的软件开发流程的默认答案. 但是,当您不熟悉DevOps并且不确定从哪里开始时,这并不意味着什么. 本文探讨了什么是DevOp ...
- h5select动态加载数据_HTML5+中动态构建列表并填充数据
部分代码参考demo----<历史上的今天>. 感谢作者的分享,愿好人一生平安,虽然只有两个页面,但是通过这个示例让我学会了5+中如何动态构建列表并填充数据,非常实用. html部分: 历 ...
最新文章
- SpringBoot整合Swagger测试api构建
- android 计算运动速度,android – 计算参考真北的加速度
- tomcat改项目的访问路径 ROOT
- 扩展SpringMVC WebMvcConfigurerAdapter ||全面接管SpringMVC @EnableWebMvc
- Spring boot其他框架日志
- XCTF_Web_新手练习区:command_execution
- C++(20)--类型自动转换
- Java环境的正确配置你会了吗?
- javascript编写_如何在JavaScript中使用解构来编写更简洁,功能更强大的代码
- Intel保护机制:特权级别:Protection Rings
- echarts 报错问题 is null 或者未定义等问题
- [Java][Android][Process] Process 创建+控制+分析 经验浅谈
- 防止各大网盘下载限速解决方案--idman
- yum源配置的三种方法
- 【PyTorch教程】P30 GPU加速
- 简单三招,设计复杂ERP报表
- win7 efi安装(个人心得)
- 使用fsck命令检查并修复linux文件系统
- 地方政府留言板文本数据
- text/plain
热门文章
- ruby + cucumber环境搭建
- 孤独星球android app,《孤独星球》终于出了全套免费的旅行指南APP !
- 02.Rocky8安装KVM
- CyanogenMod源码下载和编译
- android 闪屏图片,Android的闪屏图像尺寸,以适应所有设备Android的闪屏图像尺寸,以适应所有设备(Andro...
- html中颜色打字机效果,Css打字机效果
- 【Servlet入门】一篇文章让你从没听过到了熟于心
- marshmallow文档
- CSS生日快乐:CSS之父Håkon Wium Lie访谈录
- VUE提示Gradient has outdated direction syntax