gstreamer playbin3的工作机制

 

playbin3的调用流程如图:

  最上层可以分为三个部分 ,playbin的任务负责创建下面三个bin, 然后进行连接,连接的机制依赖于gsingal。这三个bin分别为urisourcebin 、decodebin3、playsink。其中urisourcebin 的任务 负责从文件或者网络流中读取文件 并识别封装格式。decodebin3 则负责将urisourcebin读取的数据解码成raw video audio text。playsink 则负责将音视频进行同步 并输出到对应的设备上。

5.1 urisourcebin

    这里面创建两个element,根据url的情况创建相对应的source elemnt。 随后创建一个typefind element 去探测封装格式。playbin创建时候 会注册pad_added消息给urisourcebin, 当typefind 的element 探测到某一个格式后 会创建一个pad。创建pad后 发送消息给playbin,然后playbin就将urisourcebin和decodebin连接起来。

 

5.2 decodebin3

    decodecbin创建parsebin 和multiqueue 和 音频 视频 字幕的解码器。parsebin 的任务是 解封装和解析  multiqueue的任务是起线程,让读数据解析和解码分离开来。parsebin也包含多个element,parsebin会创建typefind 重新探测一遍封装格式, 探测到之后,创建对应的demux elemnet, demux element开始工作,当demux发现新的流的时候,会在element上创建一个srcpad, 创建srcpad 会通知到parsbin。parsebin根据srcpad的caps 创建对应的pasre element(如 h264parse, aac pase 等)。 这个时候parse的 任务也完成了。创建之后,在decodebin3中会去请求multiqueue的一个sink pad, 每请求一个sink pad,mutliqueue就会分配一个队列给这个pad。 然后将parse的src pad 和multiqueue 的sink pad 连在一起。 

    multiqueue 将上游(parse)的数据 缓冲到队列里面,然后起一个task负责将队列中的数据push到下游的decoder去。缓冲区的大小会综合考虑所有队列缓冲的时长和数据大小。decodebin会监听mutiqueue的src pad,当接收到cap event(表明解封装到一个新流),会根据cap的情况创建不同的解码器element。

 

5.2.1 parsebin(Autiopluging)

    gstreamer 中存在各种各样不同的插件,同时也有不同插件动态组装的pipeline如playbin, decodebin 等。pipeline 是 通过gst的autopluging来实现的, gst中自动化插件组装核心 是glib的 信号注册函数g_signal_connect。它会让你在你感兴趣的事情发生时收到通知。

以decodebin中的parsebin为例, 这个bin的任务是将src elment读上来的数据解封装 解析(假设现在播放一个ts格式的视频)

1、定义消息和回调函数

parsebin中定义了这几类消息和相对于的回调函数

  • autoplug-continue ------- autoplug_continue
  • autoplug-factories -------- autoplug_factories
  • have-type------------ type_found

 

其中前两个消息是在类结构体初始化的时候的定义

最后一个消息是在parsebin state从READY变成PAUSED的时候 定义的

autoplug_continue: 都是返回TRUE

autoplug_factories:根据传入的caps返回 gst factories 的名字,用于创建后续的element使用

 

2、跟autoplug有关的是两个plugin 

  • typefind
  • tsdumux

typefind

1、plugin init/element init

typefind: 识别封装格式,运行在pull 模式,在typefind的插件的初始化的时候即调用plugin_init的时候

多次调用了类似下面的函数来注册不同封装格式的type find

  TYPE_FIND_REGISTER_RIFF (plugin, "video/x-msvideo", GST_RANK_PRIMARY,

      "avi", "AVI ");

在gst_type_find_element_init 实例结构体初始化函数当中,将当前插件的运行模式设置为MODE_TYPEFIND。

2、type_find_element_loop

从后面可以知道typefind数据流动方式是pull mode。也即会起一个task 线程,在线程的loop里面

首先会判断是不是MODE_TYPEFIND,假设是这种模式的话,会调用之前init时候注册好的函数一个个进行判断,并对probability进行赋值。

最后返回probability最大的那个封装格式,并emit have_type 的消息给到parsebin 这边。

从1知道在parsebin中注册了 have_type信号的回调函数是type_found。 

type_found主要完成

analyze_new_pad:

1、判断typefind 返回的cap是不是fixed(固定的只有一个)

2、emit autoplug_continue(默认返回TURE)

3、emit autoplug-factories (返回factories)

connect_pad:

4、根据factories 创建element(这个例子中是tsdemux)并加入到parsebin 中,并对sinkpad进行link

5、获取element的source pad,如果获取不到的话,那么注册pad-added 的信息到回调函数pad_added_cb(这个例子会注册这个回调)

pad_added_cb:在tsdemux 解析到一个视频流,音频流或者字幕流的时候 会调用到这里。在这个回调中 调用analyze_new_pad,同样是完成创建element 和完成连接的过程。

总的一个运行的机制就是:通过g_signal_connect注册事件和回调,然后随着数据的读取,不同的插件会依据解析到的数据  发送的不同信号,接收到信号后,会调用之前注册好的回调函数进行处理。

5.2.2 multiqueue(probes)

decodebin 中parsebin的功能我们已经了解,那么什么时候decodebin会去请求一个multiqueue的队列呢?

这个需要用到gst的一个probe的机制,通过gst_pad_add_probe可以对pad设置回调。

1、在decodebin中对parsebin的pad-added设置回调

    input->pad_added_sigid =

        g_signal_connect (input->parsebin, "pad-added",

        (GCallback) parsebin_pad_added_cb, input);

从parasebin上面知道当demux 到视频流,音频流或者字幕流的时候,会emit pad-added信号,emit之后会调用parsebin_pad_added_cb。

2、对pad设置probe

parsebin_pad_added_cb中,注册了buffer和event的两个probe的事件。

  ppad->event_probe =

      gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,

      (GstPadProbeCallback) parsebin_pending_event_probe, ppad, NULL);

  ppad->buffer_probe =

      gst_pad_add_probe (pad,

      GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,

      (GstPadProbeCallback) parsebin_buffer_probe, input, NULL);

  1. GST_PAD_PROBE_TYPE_BUFFER

    如果有这个发生时,表示有buffer来了,probe注册的函数可以就这个buffer进行操作如检查,改变,丢弃等。

  1. GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM

    有事件通过pad传送时。

3、probe的回调

parsebin_buffer_probe:这里面根据pad的stream情况创建一个流,流创建好之后就从mutliqueue那边取到一个slot(这个就是相当于是一个pad),将流和slot link在一起。

      slot = get_slot_for_input (dbin, input_stream);

      link_input_to_slot (input_stream, slot);

其中get_slot_for_input (GstDecodebin3 * dbin, DecodebinInputStream * input)

会做一堆的判断, 判断之后创建一个slot

create_new_slot (dbin, input_type);

5.3 playsink

将解码出来的音视频 数据做同步,然后分别放到各自的队列里面,同时后处理也在这个element里面。

 

 

猜你喜欢

转载自blog.csdn.net/H2008066215019910120/article/details/112565704