GStreamer——教程——基础教程7:Multithreading and Pad Availability

news2024/11/23 16:17:20

基础教程7:多线程和Pad可用性

目标

GStreamer自动处理多线程,但是在某些情况下,用户可能需要手动解耦线程。这篇教程将展示如何解耦线程以及完善关于Pad Availability的描述。更准确来说,这篇文档解释了:

  • 如何为pipeline的某些部分创建新的线程。

  • 什么是Pad Availability。

  • 如何复制流。

介绍

Multithreading(多线程)

GStreamer是一个多线程的框架,这意味着在内部,它根据需要创建和销毁线程,例如,将流的处理从应用程序线程解耦。此外,插件也可以自由创建线程来处理它们的任务,例如视频解码器可以创建四个线程以充分利用CPU的四个核。

最重要的是,应用程序在创建pipeline的时候可以明确的指定它的一个分支(pipeline的一部分)运行在不同的线程上(例如同时进行音频和视频的解码)。

这使用queue插件完成,它的sink pad只负责将数据入队,并且在另一个线程中src pad将数据出队并传递给其余插件。这个插件同样可以用来做缓冲机制,这点在后面讲述流的教程中可以看到,queue内部队列的长度可以通过属性来设置。

pipeline示例

此示例构建以下管道:

程序的源是合成音频信号(连续的音调),它被tee分离(tee将从sink pad中接收到的所有东西通过src pad发送出去)。一个分支将信号传递给声卡,并外一个分支将波形渲染成视频并发送给显示屏。

如上图所示,queue创建了一个新的线程,所以整条pipeline有三个线程。含有多个sink element的pipeline通常是多线程的,因为为了同步多个sink元素通常会互相阻塞直到所有的sink准备好,假如是单线程运行那么它们将被第一个sink阻塞住。

请求pads

在基础教程3:动态管道我们了解到uridecodebin这个插件在最开始是没有src pad的,直到数据开始传递并且uridecodebin知道媒体类型才出现,这类pad被称为Sometimes Pads,而通常一直可用的pad被称作Always Pads

还有一类pad是Request Pad,这类pad是按需创建的。最典型的例子就是tee,它只有sink pad而没有初始化的src pads:它们需要被申请然后tee才会添加它们。在这种情况下,一个输入的流可以被复制任意次数。缺点是Request Pad和其他element的连接和sometimes pads一样,需要手动完成。

另外,在PLAYING或PAUSED状态下去申请(或释放)pad需要注意(Pad阻塞,本教程没有讲到这点),在NULL和READY状态去获得pad是安全的。

没有进一步的延迟,让我们看看代码。

简单多线程示例

将此代码复制到名为basic-tutorial-7.c文本文件中(或找到它在您的GStreamer安装中)。

basic-tutorial-7.c

#include <gst/gst.h>

int main(int argc, char *argv[]) {
  GstElement *pipeline, *audio_source, *tee, *audio_queue, *audio_convert, *audio_resample, *audio_sink;
  GstElement *video_queue, *visual, *video_convert, *video_sink;
  GstBus *bus;
  GstMessage *msg;
  GstPad *tee_audio_pad, *tee_video_pad;
  GstPad *queue_audio_pad, *queue_video_pad;

  /* Initialize GStreamer */
  gst_init (&argc, &argv);

  /* Create the elements */
  audio_source = gst_element_factory_make ("audiotestsrc", "audio_source");
  tee = gst_element_factory_make ("tee", "tee");
  audio_queue = gst_element_factory_make ("queue", "audio_queue");
  audio_convert = gst_element_factory_make ("audioconvert", "audio_convert");
  audio_resample = gst_element_factory_make ("audioresample", "audio_resample");
  audio_sink = gst_element_factory_make ("autoaudiosink", "audio_sink");
  video_queue = gst_element_factory_make ("queue", "video_queue");
  visual = gst_element_factory_make ("wavescope", "visual");
  video_convert = gst_element_factory_make ("videoconvert", "csp");
  video_sink = gst_element_factory_make ("autovideosink", "video_sink");

  /* Create the empty pipeline */
  pipeline = gst_pipeline_new ("test-pipeline");

  if (!pipeline || !audio_source || !tee || !audio_queue || !audio_convert || !audio_resample || !audio_sink ||
      !video_queue || !visual || !video_convert || !video_sink) {
    g_printerr ("Not all elements could be created.\n");
    return -1;
  }

  /* Configure elements */
  g_object_set (audio_source, "freq", 215.0f, NULL);
  g_object_set (visual, "shader", 0, "style", 1, NULL);

  /* Link all elements that can be automatically linked because they have "Always" pads */
  gst_bin_add_many (GST_BIN (pipeline), audio_source, tee, audio_queue, audio_convert, audio_resample, audio_sink,
      video_queue, visual, video_convert, video_sink, NULL);
  if (gst_element_link_many (audio_source, tee, NULL) != TRUE ||
      gst_element_link_many (audio_queue, audio_convert, audio_resample, audio_sink, NULL) != TRUE ||
      gst_element_link_many (video_queue, visual, video_convert, video_sink, NULL) != TRUE) {
    g_printerr ("Elements could not be linked.\n");
    gst_object_unref (pipeline);
    return -1;
  }

  /* Manually link the Tee, which has "Request" pads */
  tee_audio_pad = gst_element_request_pad_simple (tee, "src_%u");
  g_print ("Obtained request pad %s for audio branch.\n", gst_pad_get_name (tee_audio_pad));
  queue_audio_pad = gst_element_get_static_pad (audio_queue, "sink");
  tee_video_pad = gst_element_request_pad_simple (tee, "src_%u");
  g_print ("Obtained request pad %s for video branch.\n", gst_pad_get_name (tee_video_pad));
  queue_video_pad = gst_element_get_static_pad (video_queue, "sink");
  if (gst_pad_link (tee_audio_pad, queue_audio_pad) != GST_PAD_LINK_OK ||
      gst_pad_link (tee_video_pad, queue_video_pad) != GST_PAD_LINK_OK) {
    g_printerr ("Tee could not be linked.\n");
    gst_object_unref (pipeline);
    return -1;
  }
  gst_object_unref (queue_audio_pad);
  gst_object_unref (queue_video_pad);

  /* Start playing the pipeline */
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  /* Wait until error or EOS */
  bus = gst_element_get_bus (pipeline);
  msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);

  /* Release the request pads from the Tee, and unref them */
  gst_element_release_request_pad (tee, tee_audio_pad);
  gst_element_release_request_pad (tee, tee_video_pad);
  gst_object_unref (tee_audio_pad);
  gst_object_unref (tee_video_pad);

  /* Free resources */
  if (msg != NULL)
    gst_message_unref (msg);
  gst_object_unref (bus);
  gst_element_set_state (pipeline, GST_STATE_NULL);

  gst_object_unref (pipeline);
  return 0;
}

需要帮忙吗?

如果您需要帮助来编译此代码,请参阅为您的平台构建教程部分:Linux、Mac OS X或Windows,或在Linux上使用此特定命令:

gcc basic-tutorial-7.c -o basic-tutorial-7 `pkg-config --cflags --libs gstreamer-1.0`

如果您需要帮助来运行此代码,请参阅为您的平台运行教程部分:Linux、Mac OS X或Windows。

本教程通过声卡播放可听音调,并打开一个带有音调波形表示的窗口。波形应该是正弦曲线,但由于窗口的刷新可能不会出现。

所需库:gstreamer-1.0

工作流

/* Create the elements */
audio_source = gst_element_factory_make ("audiotestsrc", "audio_source");
tee = gst_element_factory_make ("tee", "tee");
audio_queue = gst_element_factory_make ("queue", "audio_queue");
audio_convert = gst_element_factory_make ("audioconvert", "audio_convert");
audio_resample = gst_element_factory_make ("audioresample", "audio_resample");
audio_sink = gst_element_factory_make ("autoaudiosink", "audio_sink");
video_queue = gst_element_factory_make ("queue", "video_queue");
visual = gst_element_factory_make ("wavescope", "visual");
video_convert = gst_element_factory_make ("videoconvert", "video_convert");
video_sink = gst_element_factory_make ("autovideosink", "video_sink");

上述pipeline示例图中的所有elements都在这完成实例化。

audiotestsrc生成连续的音调。wavescope消费一个音频信号并且将它渲染成音波(可以将它看作一个简易的示波器)。autoaudiosinkautovideosink在前文介绍过了。

转换element(audioconvertaudioresamplevideoconvert)也是必须的,它们可以保证pipeline可以正确地连接。事实上,音频和视频的sink的Caps是由硬件确定的,所以你在设计时是不知道audiotestsrcwavescope是否可以匹配上。如果Caps能够匹配,这些element的行为就类似于直通——对信号不做任何修改,这对于性能的影响基本可以忽略不计。

/* Configure elements */
g_object_set (audio_source, "freq", 215.0f, NULL);
g_object_set (visual, "shader", 0, "style", 1, NULL);

为了更好的演示做了小小的调整:audiotestsrc的“freq”属性设置成215Hz,wavescope设置“shader”和“style”,让波形连续。使用gst-inspect-1.0工具 在基本教程10中描述:GStreamer工具学习这几个element的属性。

/* Link all elements that can be automatically linked because they have "Always" pads */
gst_bin_add_many (GST_BIN (pipeline), audio_source, tee, audio_queue, audio_convert, audio_sink,
    video_queue, visual, video_convert, video_sink, NULL);
if (gst_element_link_many (audio_source, tee, NULL) != TRUE ||
    gst_element_link_many (audio_queue, audio_convert, audio_sink, NULL) != TRUE ||
    gst_element_link_many (video_queue, visual, video_convert, video_sink, NULL) != TRUE) {
  g_printerr ("Elements could not be linked.\n");
  gst_object_unref (pipeline);
  return -1;
}

这块代码在pipeline里加入了所有的element并且把可以自动连接的element都连接了起来(就是Always Pad)。

事实上可以直接使用gst_element_link_many()连接Request Pads,它会在内部申请Pads所以用户不需要担心连接的elment具有Always PadsRequest Pads,但这并不方便,因为最终总是要释放申请的Pad而使用get_element_link_many()会很容易忽略这点。因此建议的做法是始终手动请求Request Pads,避免麻烦。

/* Manually link the Tee, which has "Request" pads */
tee_audio_pad = gst_element_request_pad_simple (tee, "src_%u");
g_print ("Obtained request pad %s for audio branch.\n", gst_pad_get_name (tee_audio_pad));
queue_audio_pad = gst_element_get_static_pad (audio_queue, "sink");
tee_video_pad = gst_element_request_pad_simple (tee, "src_%u");
g_print ("Obtained request pad %s for video branch.\n", gst_pad_get_name (tee_video_pad));
queue_video_pad = gst_element_get_static_pad (video_queue, "sink");
if (gst_pad_link (tee_audio_pad, queue_audio_pad) != GST_PAD_LINK_OK ||
    gst_pad_link (tee_video_pad, queue_video_pad) != GST_PAD_LINK_OK) {
  g_printerr ("Tee could not be linked.\n");
  gst_object_unref (pipeline);
  return -1;
}
gst_object_unref (queue_audio_pad);
gst_object_unref (queue_video_pad);

为了连接Request Pad,需要获得对element的申请一个pad。一个element可能可以创建不同种类的Request Pad,所以,当请求Pad生成时,必须提供想要的Pad模板。Pad模板可以gst_element_class_get_pad_template()方法来获得,而且用它们的名字来区分开。在tee element的文档里面我们可以看到两个pad模板,分别被称为sink(sink pad)和src%_u(Request Pad)。我们使用gst_element_request_pad()方法向tee请求两个Pad——分别给音频分支和视频分支。

然后我们去获得需要连接Request Pad的下游element(queue)的sink Pad,这些通常都是Always Pad,所以我们用get_element_get_static_pad()方法去获得。

最后,我们用gst_pad_link()方法把pad连接起来。在gst_element_link()gst_element_link_many()方法里面也是调用这个函数来连接的。

我们请求的queuesink pad需要通过gst_object_unref()来释放。Request Pad是在我们不需要的时候释放,也就是在程序的最后。

就像平常一样,我们设置pipeline到PLAYING状态,等待一个错误消息或者EOS消息到达。剩下的所有事情就是释放请求的Pads:

/* Release the request pads from the Tee, and unref them */
gst_element_release_request_pad (tee, tee_audio_pad);
gst_element_release_request_pad (tee, tee_video_pad);
gst_object_unref (tee_audio_pad);
gst_object_unref (tee_video_pad);

gst_element_release_request_pad()可以释放tee的pad,但还需要调用gst_object_unref()减少pad的引用计数(释放)才行。

结论

本教程显示:

  • 如何使用 queue 在不同线程上运行 pipeline 的一部分。

  • 什么是 Request Pad 以及如何使用 gst_element_request_pad_simple()gst_pad_link() 和 gst_element_release_request_pad()将 elements 和 Request Pads 连接。

  • 如何使用tee元素在不同的分支中提供相同的stream。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1830922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不会策划营销活动?教你一步步成为策划高手

要想让活动大获成功&#xff0c;不仅需要创意十足&#xff0c;更要有严谨的策划和执行&#xff0c;确实新人会有点感觉不知所措。 但其实也不用怕&#xff0c;只要按照以下五个关键步骤&#xff0c;一步步来&#xff0c;也可以轻松策划及格的好活动。 步骤一&#xff1a;锁定目…

AIGC绘画设计基础——十分钟读懂Stable Diffusion

写在最前面&#xff1a; 由于Stable Diffusion里面有关扩散过程的描述&#xff0c;描述方法有很多版本&#xff0c;比如前向过程也可以叫加噪过程&#xff0c;为了便于理解&#xff0c;这里把各种描述统一说明一下。 Diffusion扩散模型&#xff1a;文章里面所有出现Diffusion…

志全重庆官网下载

baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? 现在越来越多的人抱怨说搜索引擎收录很难做,站群程序似乎不在是那么重要, 花费高价购买域名成为了做出高收录站群的越来越重要的建站前提。实上…

Python文本处理:初探《三国演义》

Python文本处理&#xff1a;初探《三国演义》 三国演义获取文本文本预处理分词与词频统计引入停用词后进行词频统计分析人物出场次数结果可视化完整代码 三国演义 《三国演义》是中国古代四大名著之一&#xff0c;它以东汉末年到晋朝统一之间的历史为背景&#xff0c;讲述了魏…

2024下《软件设计师》50个高频考点汇总,背就有效!

宝子们&#xff01;上半年软考已经结束一段时间了&#xff0c;准备考下半年软考中级-软件设计师的小伙伴们可以开始准备了&#xff0c;这里给大家整理了50个高频考点&#xff0c;涵盖全书90%以上重点&#xff0c;先把这个存下&#xff01;再慢慢看书&#xff0c;边看书边背这个…

CNN和Transformer创新结合,模型性能炸裂!

CNN结合Transformer 【CNNTransformer】这个研究方向通过结合卷积神经网络&#xff08;CNN&#xff09;的局部特征提取能力和Transformer的全局上下文建模优势&#xff0c;旨在提升模型对数据的理解力。这一方向在图像处理、自然语言处理等多个领域展现出强大的应用潜力&#…

告诉你提升UI质感的两个秘密,谁用谁知道。

秘密一&#xff1a;善用头部装饰 秘密二&#xff1a;设计好瓷片区

老电脑焕发第二春,玩转 Stable Diffusion 3

几年前&#xff0c;我头脑一热&#xff0c;配置了一台顶配级消费 PC&#xff08;RTX 2080 Ti GPU i9 CPU&#xff09;&#xff0c;打算用来学习 AI。然而&#xff0c;起初我并没有找到合适的切入点。深度学习早期阶段&#xff0c;消费级显卡根本无法承担训练大模型、微调大模型…

优思学院|精益管理是什么?3大问题帮你彻底搞懂

有一位朋友他喜欢投资&#xff0c;他偶然看中了一家公司&#xff0c;从公司的一些新闻稿中表示他们因为实施了“精益管理”&#xff08;Lean Management&#xff09;&#xff0c;因此每股盈余&#xff08;EPS&#xff09;长期稳定增长&#xff0c;甚至在行业内的重要指标——库…

微信小游戏备案 之 游戏内容介绍编写实例

微信小游戏备案 之 游戏内容介绍编写实例 前言一,编写规范二,内容填写2.1 本游戏不涉及2.2 游戏场景2.3 游戏玩法2.4 功能系统2.5 主要特点三,小结前言 对于游戏开发者来说,微信小游戏备案是让游戏合法上线的重要步骤,而其中游戏内容介绍的编写尤为关键。下面为大家提供一…

Python实现管线建模 - 3.同心变径管

往期回顾 Python实现管线建模 || 1.圆直管、方管https://blog.csdn.net/Xxy9426/article/details/138836778?spm1001.2014.3001.5501 对依赖库的补充 随着后续内容的深入&#xff0c;我发现单纯靠trimesh库已经无法完成后续的建模&#xff08;涉及到多个几何体拼接或者是创建…

Prometheus+Grafana监控MySQL

一、准备 grafana服务器&#xff1a;192.168.48.136Prometheus服务器&#xff1a;192.168.48.136被监控服务器&#xff1a;192.168.48.134、192.168.48.135查看时间是否同步 二、安装prometheus server 【2.1】安装 # 解压安装包 tar -zxvf prometheus-2.52.0.linux-amd64.t…

安卓删除文件恢复,3个技巧轻松解决,让你的数据失而复得

如今&#xff0c;手机数据的重要性不言而喻。无论是工作文档、个人照片还是其他珍贵的资料&#xff0c;一旦丢失&#xff0c;都可能带来不小的困扰。而当我们不小心删除了手机中的文件时&#xff0c;焦虑和无助感更加强烈。但幸运的是&#xff0c;随着技术的不断进步&#xff0…

Unity接入PS5手柄和Xbox手柄以及Android平台的(以及不同平台分析)

Unity接入PS5手柄和Xbox手柄以及Android平台的&#xff08;以及不同平台分析&#xff09; 介绍Unity手柄小知识PC端和编辑器上的摇杆事件和滑动事件PS5手柄Xbox手柄北通手柄 安卓环境下&#xff08;安卓手机或者安卓模拟器&#xff09;PS5手柄Xbox手柄北通手柄 总结 介绍 最近…

高中数学:数列-等比数列

一、概念 二、通项公式 1、与函数的关系 类似一个指数函数 2、重要性质 三、求和公式 错位相减法 四、练习 例题1 例题2

基于机器学习的变频器故障诊断方法(MATLAB,Python)

变频器故障数据由MATLAB Simulink生成。 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.neighbors import KNeighborsClassifier from sklearn.svm import SVC from sklearn.ensemble import RandomForestClass…

折叠手机鼻祖倒下了,折叠屏手机或完蛋,苹果早有先见之明

柔宇即将倒下&#xff0c;这家率先开发出折叠屏技术的企业未能挽救它自己&#xff0c;而对于折叠手机行业来说&#xff0c;这么多年过去&#xff0c;折叠手机也仍然是绝对的少数派&#xff0c;或许折叠手机也快要寿终正寝了。 柔宇开发的折叠手机为外折叠&#xff0c;弯曲部分无…

【UIDynamic-动力学-UICollisionBehavior-碰撞行为-与引用View碰撞-与另一个item发生碰撞 Objective-C语言】

一、接下来,我们来说这个碰撞啊, 1.把之前的代码备份一份,改个名字,叫做“02-碰撞-与引用View碰撞” 首先呢,把重力的这些属性,先删了, 让它先有重力,先command + R, 当我们点击屏幕的时候,它有重力,所以自然会往下落, 但是呢,好像感觉,超出了控制器的View了以后…

React+TS前台项目实战(九)-- 全局常用组件弹窗Dialog封装

文章目录 前言Dialog公共弹窗组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天这篇主要讲全局公共弹窗Dialog组件封装&#xff0c;将用到上篇封装的模态框Modal组件。有时在前台项目中&#xff0c;偶尔要用到一两个常用的组件&#xff0c;如 弹窗&#x…

建筑工程软件Revit中复杂大模型如何实现Web端轻量化?| HOOPS技术应用

建筑信息模型&#xff08; BIM&#xff09;技术在建筑工程中扮演着越来越重要的角色&#xff0c;而Autodesk Revit作为主流的BIM软件&#xff0c;被广泛应用于设计、施工和管理。然而&#xff0c;Revit生成的复杂大模型常常由于数据量庞大而难以直接在Web端展示和操作。这时&am…