精华内容
下载资源
问答
  • 【懒人改变世界】我懒得出去购物——电商...矩阵加法——对应元素相加矩阵减法——对应元素相减那么,很自然,你以为矩阵乘法——对应元素相乘然而实际矩阵乘法:估计你看到这个的反应:更气人是,性质也奇葩——相...

    懒人改变世界】

    我懒得出去购物——

    电商来了!

    我懒得出去吃饭——

    外卖来了!

    我懒得现场招手打车——

    网约车来了!

    ......

    什么,你要跟我比懒???

    我懒得跟你比!

    9ce0d294a958feb8764e1cff7d7f8f97.png

    矩阵乘法绝对算是学习线性代数之路的一个噩梦,

    还记得当初遇到矩阵的情形吗?

    矩阵加法——

    对应元素相加

    矩阵减法——

    对应元素相减

    那么,

    很自然,

    你以为矩阵乘法——

    对应元素相乘

    然而实际的矩阵乘法:

    c8154584ec8a56c713d174929376fa0e.png

    估计你看到这个的反应:

    aedaad159a8f1440d92b68109fe89b50.png

    更气人的是,

    性质也奇葩——

    相乘的矩阵得满足特定条件,

    没有交换律,

    没有消去律,

    但有结合律

    ......

    2d16b05c5d9447b2617ffbe53e5c3b06.png

    当然,

    如果这玩意用处不多,

    那么爱咋地咋地也就随它去了,

    根本不用操心,

    问题是,

    这玩意无处不在啊

    逆矩阵,伴随矩阵,对角化...

    对于很多很多很多知识点,

    矩阵乘法都是必须的,

    根本就不可能避开。

    离开了矩阵乘法,

    线性代数这座大厦非得散架不可...

    折腾来折腾去,

    可不就成了噩梦了么

    d2a9403a9d2216f1a1546919a39526ab.png

    有没有感觉到万恶之源就是矩阵乘法呢?

    有没有觉得这个乘法的定义很奇葩呢?

    为啥要这么定义?

    为啥不定义成对应元素相乘?

    031f21861bb58fa1fedfcb9ce19dd9c6.png

    要回答这些问题,

    先来看看矩阵是怎么横空出世的:

    其实非常非常简单

    说白了,

    就是一个字——

    懒!

    从何说起呢,

    得从线性方程组说起:

    先请问——这两方程有本质区别吗?

    c5d1e0f9df8b8c7e7036afa175400e9c.png

    透过现象看本质的话,

    其实没有区别,

    运算起来步骤是一模一样的,

    只是未知数名字有区别罢了,

    其实名字这玩意,

    真没多大重要的,

    用阿猫阿狗其实也未尝不可:

    0f46dcefeb798133bdb2bdd3540c973c.png

    数学家就是认识到了这一点,

    于是迈出了第一步,

    把系数和变量分离:

    c30bee5a5e76bd5fbe002dd99785806e.png

    于是矩阵自然就应运而生了,

    把系数部分当成矩阵后,

    方便了很多,

    直接操作矩阵,

    就能得到方程的解,

    不用把什么"xyab阿猫阿狗..."来回抄写,

    节省了时间,

    提高了效率,

    于是第一次偷懒,

    产生了矩阵

    那么矩阵乘法呢?

    那就是第2次工业革...

    oh,no

    是第2次偷懒的成果了:

    830f4229cb590b272291e8aeda90d458.png

    这两方程,

    前面系数矩阵是一样的,

    只是方程右边不一样.

    如果分开解的话,

    得弄2次,

    但是其中对系数矩阵做初等变换的情形是一模一样的,

    分开弄的话,

    浪费时间精力啊,

    那咋办呢?

    既然分开浪费资源,

    那就合在一起写呗:

    9e511c6549f75a9631eb220e039b08d1.png

    是不是很省事了啊!

    系数矩阵只需要做一遍初等变换,

    就可以把2个方程都解出来了,

    多方便啊。

    然而有道是:

    名不正则言不顺,

    言不顺则事不成!

    这几坨东西这么放在一起算怎么回事?

    怎么地也得有个说法啊!

    dd664933aa140a81fed478afcf557a6d.png

    于是这种运算就需要被命名了。

    但请注意一点,

    这个运算是客观存在的,

    不是谁谁谁吃饱了闲得荒造出来的,

    也不是谁谁谁不喜欢就可以忽略的,

    是不以人的意志为转移的...

    我们能做的就是——

    给它取个名字,

    最终取了个名字叫——

    矩阵乘法

    26b678758249708cf10d340a6589fcb7.png

    然后就有人不服了:

    """

    这个**运算凭什么叫矩阵乘法啊,

    我不服!

    在我的世界里,

    只有两个矩阵对应元素相乘的才能叫做矩阵乘法,

    其他都是冒牌货,

    我不承认!!!

    """

    78d7dbb255e6ccea9c32179a9fb17612.png

    说的似乎很霸气,

    可惜,

    那个所谓的元素对应相乘的运算,

    不叫"矩阵乘法",

    公认的称呼是——"阿达马乘积"

    e8db77c35c2e6f47dc8671ec8584200e.png

    居然还真有这种运算...

    估计你没怎么听过吧,

    不但如此,

    还有一个更另类的"矩阵乘法":

    克罗内克乘积

    b367bad5c0151a1cd7f05b7e00742508.png

    举例:

    1b7ca0af0dabdc5b2a255c387a6eb86a.png

    当然你也可以自定义你心目中的某某运算,

    比如把它叫做"XKSX积",

    只不过不一定有人认同...

    a729ee615e5fc97c01eb9c245cab9a25.png

    到此,明白了吗?

    不是为啥把"矩阵乘法"定义得那么复杂,

    是该运算被我们取名"矩阵乘法",

    至于为啥是该运算获此称号,

    而不是什么

    "阿达马乘积",

    "克罗内克乘积"

    "XKSX积"...

    来获取这一称呼,

    那就更简单了:

    频繁使用者重要者居之罢了。

    对于不重要的运算,

    即使强行赋予"矩阵乘法"这一称号,

    因为实际原因也不会被人重视,

    最终也会逐渐没落,

    配不上这一称号,

    最终尸位素餐,

    浪费资源...

    而对于原本的"真龙天子",

    如果强行不给"矩阵乘法"的称号,

    只称呼为"某某某某乘积",

    那么人们在学习交流过程中,

    就不得不频繁地使用"某某某某乘积"这样的术语,

    真是降低沟通效率,

    再次浪费资源!

    所以,

    "矩阵乘法"这称号,

    该给谁,

    还有异议吗?

    141c35296fad077be239f28ed3bb749d.png

    最后简要总结一下:

    矩阵乘法,为啥定义得这么复杂?

    答:

    我们只是把一种客观存在且重要的运算,

    命名为"矩阵乘法"。

    其他的,

    真的几乎啥都没干,

    如此罢了......

    1a39b88accce66da4b75ab36757a798c.png

    往期精选】

    ●弧度制是必须的!

    ●柯西不等式,被彻底征服!

    ●整系数多项式,就别指望f(n)全是素数了!

    ●如何理解,描述无穷?

    轻松搞定级数敛散性——“2^n法”

    更多内容,欢迎关注微信公众号:

    笑看数学

    展开全文
  • 复杂事件处理描述就是系统如何持续地处理这些事件,即系统对变化持续反应。不论是个体还是系统,都需要从大量事件中过滤提取,按照既定处理反应规则做处理。复杂事件处理产品主要采用两种技术手段来完成事件...
    事件即事物的状态信息变化,事物之间的作用和动作。复杂事件处理描述的就是系统如何持续地处理这些事件,即系统对变化的持续反应。不论是个体还是系统,都需要从大量的事件中过滤提取,按照既定的处理反应规则做处理。复杂事件处理产品主要采用两种技术手段来完成事件的过滤,判断和处理,即规则语言和持续查询语言。
    规则语言定义事件处理的规则,即条件+动作。当某些条件满足时,执行一些处理,一些动作。规则语言定义的规则集合在运行时由规则引擎来执行,当有新的事件和对象产生,或者已有事件和对象变化时,匹配所有规则,满足条件的规则按优先级进入执行队列,按顺序执行规则中的动作。如果该动作的处理导致事件和对象的变化,可能会有新的规则加入执行队列,或者从执行队列中减去一些规则。这个过程会一直执行下去,模拟了一个实体对变化的持续反应。
    持续查询语言 CQL 使用类似 SQL 的语法来描述事件和事件反应处理规则。对于内存中大量的外部事件和内部对象, CQL 通过查询语句来做条件匹配,同时提供回调函数,当某些事件或者对象符合查询条件,就调用回调函数做相应的处理。 CQL 提供两种查询方式,快照方式和持续方式。 快照查询只做一次,持续查询类似规则引擎中的规则,只要事件和对象有变化,就执行查询做条件匹配,有匹配上的对象就调用相应的回调函数。这个过程一直会执行下去。同样可以描述对事件的持续反应处理。
    从几个方面来比较一下规则语言和持续查询语言。
    (1) 两种技术的实现手段。 规则引擎使用RETE网络,将规则集合中的所有条件的所有模式构造成一个匹配树,变化的对象通过这个树进行过滤匹配,判断有哪些条件被满足。匹配树的各个节点会存储在这个节点上满足模式的对象,这样可以在对象变化时不需要重新匹配所有对象,大大加快匹配的速度。持续查询语言使用的是数据库技术,事件和对象相当于表,不论是在内存里还是在文件里。持续查询相当于视图,只要对象有变化,视图里就有对应的体现。通过索引来加快查询匹配速度。抽象一点说这是过滤和查找的对比。打个比方不知道恰当与否,前一个好比是拿着所有的药对着一排药方配药,后一个相当于拿着一张张的药方对着所有的药抓药。
    (2) 两种技术的性能。对于这两种技术哪个性能更好,我不知道答案。规则引擎的RETE树通过单个模式节点的连接(joint)来做多个对象多个模式的条件判断,查询语言通过表之间的连接(joint)来做跨多表的查询。谁的性能更好,需要有精通理论的人来研究试验。对我们做应用的人来说感觉当事件和对象很多,但匹配上条件的对象占少数时,使用规则引擎更好些。只是感觉,大家做应用时自己做试验来判断。
    (3) 如何选择使用哪种技术。两种技术都能实现对事件对象的持续条件匹配和处理。从开发的角度,一个使用自定义的规则语言,一个使用类SQL的语言,差别也不大;运行时看,对内存的使用都不小。对于这个问题,我现阶段没有好的回答,之后了解得更深些,可能会给一个选择推荐。个人而言,更喜欢规则语言,觉得和现实中描述一个系统的变化反应比较相似。

    了解技术的本质,才能决定什么样的需求场景使用什么样的技术手段。不论是规则语言,还是持续查询语言,我们用复杂事件处理技术替代普通编程语言来实现一些应用,究竟能带来什么好处呢。
    (1) 开发时采用声明型语言替代过程式语言。规则语言和持续查询语言都是声明型编程语言,只声明事件的匹配条件和对应的处理动作,整个系统的运行由引擎来执行。这样开发的工作量要小一些,但需要非常准确地了解引擎的工作原理和细节。
    (2) 在对大量事件和对象的持续条件匹配和处理的过程中,复杂事件处理产品提供高效的条件匹配,对象查询。这个是应用开发者自己难以实现的部分。
    和其他技术一样,复杂事件处理技术不只是产品提供的这些内容。其实更多的是实施的方法论,事件如何分层,如何确定事件彼此的关系,如何来做判断推理,等等。总的来说就是如何把现实世界的一些实体和行为来做建模,用产品工具实现要做的模拟和处理,来得到我们需要的结果。而这部分恰好是没有标准答案的部分,是我们应用开发者在实践中不断思考积累的东西。
    展开全文
  • 本教程展示了使用GStreamer所需其他基本概念,这些概念允许在信息可用时“动态”构建管道,而不是在应用程序开头定义单片管道。 在本教程之后,您将拥有开始播放教程所必需知识。这里回顾要点是: 如何在...

    1. 目标

    本教程展示了使用GStreamer所需的其他基本概念,这些概念允许在信息可用时“动态”构建管道,而不是在应用程序的开头定义单片管道。

    在本教程之后,您将拥有开始播放教程所必需的知识。这里回顾的要点是:

    • 如何在链接元素时获得更好的控制。
    • 如何得到有趣事件的通知以便及时做出反应。

    元素可以处于的各种状态。

    2. 介绍

    正如您将要看到的,本教程中的管道在设置为播放状态之前并没有完全构建。这没关系。如果我们不采取进一步的措施,数据将到达管道的末端,管道将生成错误消息并停止。但我们会采取进一步的行动…

    在这个例子中,我们打开一个被多路复用(或多路复用)的文件,也就是说,音频和视频一起存储在一个容器文件中。负责打开此类容器的元素称为demuxers,容器格式的一些示例包括Matroska(MKV)、Quick Time(QT、MOV)、Ogg或Advanced Systems Format(ASF、WMV、WMA)。

    如果一个容器嵌入了多个流(例如,一个视频和两个音频轨),则解复用器会将它们分开,并通过不同的输出端口公开它们。这样,可以在管道中创建不同的分支,处理不同类型的数据。

    GStreamer元素相互通信的端口称为pad(GstPad)。存在数据进入元素的汇区和数据退出元素的源区。自然地,源元素只包含源pad,sink元素只包含sink pad,而filter元素包含这两者。

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    图1. GStreamer 中的元素和它们的 pads。


    在这里插入图片描述

    图2 具有两个 pad 的解码复用器(demuxer)
    ...

    为了完整起见,这里有一个简化的管道,其中包含一个解复用器和两个分支,一个用于音频,一个用于视频。这不是将在本例中构建的管道:

    在这里插入图片描述

    图3. 拥有两个分支的管道的例子
    ...

    处理demuxer时的主要复杂性是,它们在接收到一些数据并有机会查看容器以查看其中的内容之前,无法生成任何信息。也就是说,demuxer从没有其他元素可以链接到的源pad开始,因此管道必须在它们处终止。

    解决方案是构建从源到解复用器的管道,并将其设置为run(play)。当demuxer接收到足够的信息来了解容器中的流的数量和类型时,它将开始创建源pad。现在是我们完成管道建设并将其连接到新添加的解复用器垫的正确时间。

    为了简单起见,在本例中,我们将只链接到音频板而忽略视频。

    3. 动态 Hello World

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

    #include <gst/gst.h>
    
    /* Structure to contain all our information, so we can pass it to callbacks */
    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 */
      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);
      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 */
      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("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);
    }
    

    4. 从头分析代码

    /* Structure to contain all our information, so we can pass it to callbacks */
    typedef struct _CustomData {
      GstElement *pipeline;
      GstElement *source;
      GstElement *convert;
      GstElement *sink;
    } CustomData;
    

    到目前为止,我们已经将所需的所有信息(基本上是指向GstElements的指针)保留为局部变量。由于本教程(以及大多数实际应用程序)涉及回调,我们将把所有数据分组在一个结构中,以便于处理。

    /* Handler for the pad-added signal */
    static void pad_added_handler(GstElement *src, GstPad *pad, CustomData *data);
    

    这是一个远期参考,稍后使用。

    /* Create the elements */
    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");
    

    我们像往常一样创建元素。uridecodebin将在内部实例化所有必要的元素(源、解复用器和解码器),以将URI转换为原始音频和/或视频流。它完成了playbin一半的工作。由于它包含demuxer,它的源pad最初不可用,我们需要动态链接到它们。

    audioconvert对于在不同音频格式之间进行转换非常有用,请确保此示例适用于任何平台,因为音频解码器生成的格式可能与音频接收器预期的格式不同。

    音频重采样对于在不同的音频采样率之间进行转换非常有用,类似地,确保此示例在任何平台上都能工作,因为音频解码器生成的音频采样率可能不是音频接收器支持的采样率。

    对于音频,autoaudiosink相当于上一个教程中的autovideosink。它会将音频流呈现到声卡。

    if (!gst_element_link (data.convert, data.sink)) {
      g_printerr ("Elements could not be linked.\n");
      gst_object_unref (data.pipeline);
      return -1;
    }
    

    在这里,我们将转换器元素链接到接收器,但不将它们与源链接,因为此时它不包含源 pads。我们只是不链接这个分支(转换器+接收器),直到稍后。

    /* 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);
    

    我们将文件的URI设置为通过属性播放,就像在上一个教程中一样。

    (1) 信号

    /* Connect to the pad-added signal */
    g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data);
    

    GSignals是GStreamer中的一个关键点。它们允许在发生有趣的事情时(通过回调)通知您。信号由名称标识,每个GObject都有自己的信号。

    在这一行中,我们附加到源的“pad added”信号(uridecodebin元素)。为此,我们使用g_signal_connect()并提供要使用的回调函数(pad_added_handler)和数据指针。GStreamer对这个数据指针没有任何作用,它只是将它转发给回调,以便我们可以与它共享信息。在本例中,我们传递一个指向为此目的专门构建的CustomData结构的指针。

    GstElement生成的信号可以在其文档中找到,也可以使用gst-inspect-1.0工具,如基本教程10:GStreamer工具中所述。

    我们现在准备出发了!只需将管道设置为播放状态,并开始侦听总线以获取有趣的消息(如ERROREOS),就像在前面的教程中一样。

    (2) 回调

    当我们的源元素最终有足够的信息开始生成数据时,它将创建源pad,并触发“pad added”信号。此时,我们将调用回调:

    static void pad_added_handler(GstElement *src, GstPad *new_pad, CustomData *data) {
    

    src是触发信号的GstElement。在本例中,它只能是uridecodebin,因为它是我们附加到的唯一信号。信号处理程序的第一个参数始终是触发它的对象。

    new_pad是刚添加到src元素的GstPad。这通常是我们要链接到的pad

    数据是我们在附加到信号时提供的指针。在本例中,我们使用它传递CustomData指针。
    ·

    GstPad *sink_pad = gst_element_get_static_pad(data->convert, "sink");
    

    CustomData中提取转换器元素,然后使用gst_element_get_static_pad()检索其sink pad。这是我们要链接到的new_pad。在上一个教程中,我们将元素链接到元素,并让GStreamer选择适当的pad。现在我们要直接把垫子连接起来。

    /* 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;
    }
    

    uridecodebin可以创建尽可能多的pad,对于每个pad,都将调用这个回调。这些代码行将阻止我们尝试链接到一个新的pad一旦我们已经链接。

    /* Check the new pad's type */
    new_pad_caps = gst_pad_get_current_caps(new_pad, NULL);
    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;
    }
    

    现在我们将检查这个新的pad要输出的数据类型,因为我们只对pad产生音频感兴趣。我们之前已经创建了一个处理音频的管道(一个与音频重采样和自动音频接收器链接的音频转换器),例如,我们将无法将其链接到产生视频的pad。

    gst_pad_get_current_caps()检索封装在GstCaps结构中的pad的当前功能(即它当前输出的数据类型)。可以使用gst_pad_query_caps()查询一个焊盘可以支持的所有可能的上限。一个pad可以提供许多功能,因此gstcap可以包含许多GstStructure,每个GstStructure代表不同的功能。pad上的当前caps将始终具有单个GstStructure并表示单个媒体格式,或者如果没有当前caps,则返回NULL。

    因为,在本例中,我们知道我们想要的pad只有一个功能(音频),所以我们使用gst_caps_get_structure()检索第一个GstStructure

    最后,使用gst_structure_get_name()恢复结构的名称,它包含格式的主要描述(实际上是它的媒体类型)。

    如果名称不是audio/x-raw,这不是解码的音频板,我们对此不感兴趣。

    否则,尝试链接:

    /* 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);
    }
    

    gst_pad_link()尝试链接两个焊盘。与gst_element_link()的情况一样,必须从源到汇指定链接,并且两个焊盘都必须由位于同一个bin(或管道)中的元素拥有。

    我们完成了!当出现正确类型的pad时,它将链接到音频处理管道的其余部分,并继续执行,直到出现错误或EOS为止。但是,通过引入状态的概念,我们将从本教程中挤出更多的内容。

    (3) GStreamer 状态

    我们已经讨论了一些状态,当我们说回放不会开始,直到你把管道带到播放状态。我们将在这里介绍其他状态及其含义。GStreamer有4个状态:

    状态 描述
    NULL 元素的空状态或初始状态。
    READY 元素已准备好进入暂停状态。
    PAUSED 元素暂停,准备接受和处理数据。但是,接收器元素只接受一个缓冲区,然后阻塞。
    PLAYING 元素正在播放,时钟正在运行,数据正在流动。

    你只能在相邻的状态之间移动,这就是说,你不能从空到播放,你必须经历中间的就绪和暂停状态。不过,如果将管道设置为播放,GStreamer将为您进行中间转换。

    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;
    

    我们添加了这段代码,用于侦听有关状态更改的总线消息并将其打印到屏幕上,以帮助您理解转换。每个元素都会在总线上放置有关其当前状态的消息,因此我们将它们过滤掉,只监听来自管道的消息。

    大多数应用程序只需要去PLAYING开始播放,然后PAUSED执行暂停,然后在程序退出时返回NULL以释放所有资源。

    5. 练习

    动态pad链接一直是许多程序员的一个难题。通过实例化一个autovideosink(可能前面有一个videoconvert)并在右pad出现时将其链接到demuxer来证明您已经掌握了它。提示:您已经在屏幕上打印了视频板的类型。

    现在您应该看到(和听到)与基本教程1:Hello World!中相同的电影!。在那个教程中,您使用了playbin,它是一个方便的元素,可以自动为您处理所有的解组和pad链接。大多数回放教程都是专门介绍playbin的。

    6. 小结

    在本教程中,您了解到:

    • 如何使用GSignals通知事件
    • 如何直接连接gstpad而不是其父元素。
    • GStreamer元素的各种状态。
    • 您还可以组合这些项来构建一个动态管道,该管道不是在程序启动时定义的,而是在有关媒体的信息可用时创建的。

    现在,您可以继续学习基本教程,并了解如何在基本教程4:时间管理中执行查找和与时间相关的查询,或者转到回放教程,进一步了解playbin元素。

    请记住,附在本页上的是教程的完整源代码和构建教程所需的任何附件文件。很高兴你能来,很快就见到你了!

    展开全文
  • 在少数示例中,我们使用它来构造与体积共轭的边界变形,例如空的AdS,反向反应的标量冷凝物或无限时热场加倍。 我们为这种变形提出了一种可能的自然边界解释方法,并将其用于激发复杂度=体积猜想的具体版本,其中...
  • 1.的定义  RIA(Rich Internet Application,富互联网应用系统)技术允许我们在因特网上以一种象使用Web一样简单的方式来部署富客户端程序。这是一个用户接口,它比用 HTML能实现的接口更加健壮、反应更加...

    1.的定义

      RIA(Rich Internet Application,富互联网应用系统)技术允许我们在因特网上以一种象使用Web一样简单的方式来部署富客户端程序。这是一个用户接口,它比用 HTML能实现的接口更加健壮、反应更加灵敏和更具有令人感兴趣的可视化特性。无论将来RIA是否能够如人们所猜测的那样完全代替HTML应用系统,对于 那些采用胖客户端技术运行复杂应用系统的机构来说,RIA确实提供了一种廉价的选择。


      2. RIA的产生背景

      基于HTML的应用程序之所以变得流行是由于应用系统的部署成本低、结构简单,且HTML易于学习和使用。很多用户和开发人员都乐于放弃由桌面 计算机带来的用户界面改进,来实现对新数据和应用系统的快速访问。与丧失一些重要的UI功能相比,基于Web的方式所带来的好处要更大得多。

      然而,某些应用系统并不完全适合采用HTML技术。复杂的应用系统可能要求多次提取网页来完成一项事务处理,在某些领域中,如医药和财务领域, 这往往导致交互速度低得无法接受。让我考虑一个项目管理系统:我们可以将其实现为一个HTML应用系统,但是如果用户可以看到并且操作图表、进度表和各种 层次结构,那么显然会工作得更好。

      此外,虽然HTML开始走向简单,但是即使简单的交互活动也仍然需要用很多的脚本来完成。即使一个输入窗体经过仔细的布置和全面的脚本设计,它 从浏览器所能发送的也仅仅是简单的"名字/值"对。如果一个HTML窗体能够以XML文档形式发送和接收更复杂的数据结构,那就好多了。

      RIA利用相对健壮的客户端描述引擎,这个引擎能够提供内容密集、响应速度快和图形丰富的用户界面。除了提供一个具有各种控件(滑标、日期选择 器、窗口、选项卡、微调控制器和标尺等)的界面之外,RIA一般还允许使用SVG(Scalable Vector Graphics,可伸缩向量图)或其他技术来随时构建图形。一些RIA技术甚至能够提供全活动的动画来对数据变化作出响应。

      RIA的另一个好处在于,数据能够被缓存在客户端,从而可以实现一个比基于HTML的响应速度更快且数据往返于服务器的次数更少的用户界面。对 于无线设备和需要偶尔连接的设备来说,将来的趋势肯定是向富客户端的方向发展,并且会逐渐远离基于文本的Web客户端。那些运行在膝上设备上的应用系统, 可以被设计成以离线方式工作,或者至少当连接丢失的时候能基本上以离线的方式工作。

    展开全文
  • ace 反应式服务器例子

    千次阅读 2014-03-28 11:50:52
    因为系统结构和业务逻辑都不太复杂,所以开始就决定不使用类似ACE或Boost之类库,而是自己实现。结果在实现过程中,还是遇到了许多麻烦地方,例如: a) 跨平台。这一点相对比较容易,主要是针对类似多线程、...
  • 这些工具正越来越多地用于改善废水处理厂设计,因为概念设计复杂定义不明确。 在本文中,有三种选择:1)完全混合活性污泥不脱氮(CAS); 2)完全混合活性污泥具有脱氮功能(CAS-N),并且; 3)膜生物...
  • 问题提示: 问题一:go to XXX选项无法点击或者点击后没有反应也没有提示音。 ...出现这个问题话就比较复杂了。 可能导致问题原因: ①你正在编写这个文件路径当中包含中文或者特殊字符,如
  • 数据运营人员常常会需要查找活跃用户名单,而活跃用户很多情况下被定义为连续在线或发单n天及以上用户。一方面我们可以根据n值直接进行筛选;更具一般性地,就要求我们去求取每个用户某段时间内最大连续在线...
  • 来源:labuladong 作者:labuladong很多读者反应,就算看了前文 动态规划详解,了解了动态规划套路,也不会写状态转移方程,没有思路,怎么办?本文就借助「最长递增子序列」来讲一种设计动态规划通用技巧:数学...
  • 作用提供 需在后台长期运行服务,如:复杂计算、音乐播放、下载等3.特点无用户界面、在后台运行、生命周期长一个运行在后台执行长时间运行操作组件,它不提供任何用户界面,作为与Activity同级组件,它依旧是...
  • 说明 RxSwift到底是什么?这是一个很好的定义: RxSwift是一个库,用于通过使用可观察的序列和功能样式运算符来组成...让我们从一个简单的,易于理解的定义开始,并逐步发展成为更好,更具表现力的定义,当我们在本章
  • Unity渲染管线

    千次阅读 2018-09-26 11:01:51
    着色器定义了对象视觉效果(通过材质属性设置)以及对象如何与光线产生反应。因为光照计算必须内置到着色器中,而且光源与阴影种类可能有很多种,所以编写能够“干活”优质着色器是一项复杂的任务。为了使这一...
  • 游戏中DDA算法和Bresenham算法应用

    千次阅读 2014-12-09 15:46:13
    游戏场景地面情况复杂,而且场面大,若采用盲目式搜索,例如盲目穷举法,则几乎要遍历整个场景,效率非常低,造成角色反应速度过慢,实践证明是一种不适合网络游戏寻路方法。而启发式搜索算法在障碍较少情况下也显得...
  • 认识信息输入

    2019-10-13 17:25:41
    认知信息的输入感觉的基本概念感觉的定义感觉的重要性知觉的基本概念知觉概念知觉理论,特性 感觉的基本概念 感觉的定义 感觉 :人脑对直接作用于感觉器官刺激物的个别属性的反应(客观、直接、脑机能个别属性) ...
  • 定义一个指示地球强度极限因素有助于实现上述目的以及对潜水员科学中未解决问题的反应,例如:宇宙如何开始? 宇宙是如何工作? 光速变化不明显吗? 物理常数会改变吗? 地球强度极限通过其规格和定义的...
  • 通过引入简单非局部场重新定义,我们将描述真实,自相互作用标量场给定相对论转换为描述每次都编码原始场及其共轭动量的复杂标量场等效理论。 我们低能效理论将对动能相对论校正以及快速振荡项对场...
  • 程序属性

    2017-07-24 11:54:10
    为了全面方便描述一个程序,我们定义了以下属性。 1、功能完整性:程序满足合理需求的反应。 2、强壮型 : 程序面对不合理需求属性。 3、可读性 :编写复杂的程序并不难,难得是理解复杂的程序。 4、可...
  • 结果表明,单电极电流源激发电场形态简单,能够很好地反应地电结构,磁场形态复杂;采用电磁场定义的视电阻率,在二层模型上,曲线在高频、大收发距时,趋于第一层电阻率,在低频、大收发距时,趋于第二层电阻率。
  •  由于石化生产中使用装置和设备的复杂,如工业炉,反应塔和斧,换热器,压缩机,泵,压力罐,搅拌器等,加之生产危险性亦大,对安全生产和维修要求颇高。实践证明,生产装置在停车,检修施工和复工过程中最容易...
  • ACE中Reactor框架简介

    千次阅读 2009-08-23 13:06:00
    一、 概要目前用于事件多路分离OS抽象既复杂又难以使用,因而也容易出错。...特别地,反应器对基于定时器事件、信号事件、基于I/O端口监控事件和用户定义的通知进行统一地处理。 二、 使用a) 如
  • 界面编程总结(6)

    千次阅读 2010-05-30 13:28:00
    RIA技术l 定义RIA(Rich Internet Application,富互联网应用系统)技术允许我们在因特网上以一种象使用Web一样简单方式来部署富客户端程序。这是一个用户接口,它比用HTML能实现接口更加健壮、反应更加灵敏和...
  • 网上搜了一下各种编码格式的定义,对于大脑简单的我来说,这些定义太复杂。总结了一下,目前我们一般做开发时用UTF-8的格式,它属于unicode编码。要想不出现乱码现象,就必须注意一点,从前台到后台再到前台的格式...
  • 大规模网络中社区结构的近线性时间检测算法 (标签传播算法(LPA)) ...现在对于社区结构没有明确的定义,暂且理解为一个团体。 二、标签传播算法介绍 每个节点都初始化一个唯一的标签,在算法的每次迭代中,每个
  • 网上搜了一下各种编码格式的定义,对于大脑简单的我来说,这些定义太复杂。总结了一下,目前我们一般做开发时用UTF-8的格式,它属于unicode编码。要想不出现乱码现象,就必须注意一点,从前台到后台再到前台的格式...
  • transition与animation区别

    千次阅读 2018-03-10 21:22:41
    相同点:(1)指定要监听CSS属性变化(2)设置定时函数...循环方式,如何定义复杂的动画,跟JS搭配使用(1)触发方式transition只作为一种反应过渡到一个CSS属性已经改变了。一个常见场景是你使用:hover伪类来改...
  • 元胞自动机是定义在一个由离散、有限状态元胞组成元胞空间上,按照一定局部规则,在离散时间维度上演化动力学系统。 冯诺依曼提出模仿人脑行为,人脑包含自控制和自维护机理。考虑在完全离散框架下处理...
  • 外语学习真实方法与误区29

    千次阅读 2009-06-18 14:04:00
    尽管对复杂的英文理解有困难或还有些 听不懂部分,说英文大多是大白话,但如果听说的反应迅速,已经可以定义为流利英文了。第三阶段跨越是最具挑战,情况很复杂(第四阶段反而简单) 而且每个人成功跨越该...
  • 令人头疼编译原理之文法

    万次阅读 多人点赞 2012-09-15 19:09:21
    提到“编译原理”,大部分人首要反应就是苦恼。确实,编译原理这一部分内容在计算机学习中是比较难以理解一部分。首次接触编译原理,我也感觉很复杂,难以理解。但是当看过几次之后,对于一些简单知识点理解...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 128
精华内容 51
关键字:

复杂反应的定义