GStreamer基础教程07——多线程和Pad的有效性

 7449人阅读 评论(1) 收藏 举报
文章標籤

丘猴子 發表在 痞客邦 留言(0) 人氣()

GStreamer建议的学习步骤和网页链接汇总

 

学习步骤:

丘猴子 發表在 痞客邦 留言(0) 人氣()

4)精灵 Pads (Ghost pads)

Bins有属于它自己的Pads,这就是”精灵Pads”的由来。

丘猴子 發表在 痞客邦 留言(0) 人氣()

GstPad setcaps,getcaps,set_setcaps_function...caps协商解说

 
这里需要描述一下gst_pad_get_caps/gst_pad_set_getcaps_function, gst_pad_set_caps/gst_pad_set_setcaps_function这四个函数。 

gst_pad_get_caps函数用来返回该pad能接受的caps。这个函数的逻辑是:首先检查getcaps函数指针是否为NULL,如果不是则调用getcaps函数,这是一个函数指针,我们可以通过gst_pad_set_getcaps_function来给这个函数指针赋值,从而实现自定义的get_caps函数的逻辑。完成后函数返回;如果getcaps函数指针为NULL,则gst_pad_get_caps函数从该pad的pad template中列出所有的caps,返回;如果该pad没有pad template,则gst_pad_get_caps函数检查该GstPad的caps成员是否为NULL,如果不为NULL,则返回这个member;最后,如果前面的都不成立,则gst_pad_get_caps创建一个empty的GstCaps并返回,表示该pad目前没有caps。 

get_pad_set_caps函数用来设置指定pad的caps。该函数首先检查参数中给出的caps是否已经和目前该pad中的caps相同,如果是,则直接返回。如果不相同,则检查setcaps函数指针是否为NULL,如果不为NULL则调用setcaps函数。我们可以通过gst_pad_set_setcaps_function函数来给setcaps这个函数指针赋值,这样就在gst_pad_set_caps函数中实现了自定义的逻辑。注意,gst_pad_set_caps函数会判断setcaps函数的返回值,如果是FALSE,则会直接报错return FALSE,这样的结果就是gst_pad_set_caps函数执行失败,caps negotiation失败。OK,当setcaps函数执行完毕后,gst_pad_set_caps函数执行gst_caps_replace,将保存在该pad中的caps member替换成参数中指定的caps,然后函数结束。 

请参考gst_pad_get_caps, gst_pad_set_caps的源码,如果还有不清楚的地方的话。 

OK,说清楚了这四个函数的逻辑很有必要,因为这四个函数长相差不多,容易混淆,而且互相之间的连系也需要搞清楚。现在进一步,我们需要知道,什么时候gst_pad_get_caps/get_pad_set_caps会需要用到。这部分内容可以参考Part-negotiation.txt中的描述,说的很清楚,因为这两个函数就是用于caps negotiation的。简单概括一下: 

caps negotiation在PUSH MODE和PULL MODE下逻辑不相同。PUSH MODE下,总是由src pad发起negotiation,为了整出一个src pad和peer sink pad都能接受的caps来,src pad会将自己的caps和peer sink pad的caps做intersect,这时就会调用函数gst_pad_get_caps,参数就是peer sink pad(一般直接使用gst_pad_peer_get_caps函数一步完成)。回顾一下上面gst_pad_get_caps函数的逻辑,如果peer sink pad没有设置getcaps函数指针的话,那就会直接返回peer sink pad template中的所有caps。接下去就是src pad调用gst_pad_set_caps,把自己的caps确定下来,再然后就是申请并分配buffer...... 

在PULL MODE下,由于是sink element的sink pad来drive pipeline,所以,caps negotiation要在pull thread启动之前就完成。首先,sink pad将自己的caps和peer src pad的caps做intersect(当然需要调用src pad上的gst_pad_get_caps),然后调用gst_pad_set_caps将caps确定下来。然后我们需要设置setcaps函数指针,然后在setcaps函数中,调用gst_pad_set_caps,参数是peer src pad,如果成功,那么表示src pad和自己一样,都具备了相同的caps,这样negotiation就OK了。最后,我们就可以使用gst_pad_pull_range来获取数据了,这个函数会为我们检查buffer中的caps和当前sink pad中的caps是否一致,如果不一致,就会return GST_FLOW_NOT_NEGOTIATED。 

最后再说一下gst_pad_set_caps函数被调用的时机。当在_chain函数中收到一个buffer之后,一般需要检查该buffer中的caps是否和当前pad中的caps相同,以防止数据在运行过程中改变caps。如果这两个caps不相同,那么,_chain函数应该返回GST_FLOW_NOT_NEGOTIATED,这样,gstreamer core就会用buffer中这个新的caps,去调用gst_pad_set_caps,这样做的目的是gstreamer要知道pad能否接受这个caps,如果函数返回TRUE,表示接受该caps,而且pad已经更新了自己的caps为目前这个,如果函数返回FALSE,表示caps negotiation failed,pipeline就无法正常运行了。 

到这里,可以看到,在PUSH模式下,_chain函数返回GST_FLOW_NOT_NEGOTIATED,gstreamer core就会自动为我们调用gst_pad_set_caps;但是在PULL模式下,虽然gst_pad_pull_range也会返回GST_FLOW_NOT_NEGOTIATED,但是gst_pad_set_caps并不会自动被调用,这是因为出于latency的考虑,gstramer不支持在pull thread中做set caps的动作。所以,在PULL模式下,我们需要自己handle这种GST_FLOW_NOT_NEGOTIATED的情况。回想pull thread没有启动之前,为什么我们需要设置setcaps函数呢?这是因为我们需要在这个函数中,使用gst_pad_set_caps来给peer src pad设置caps来完成caps negotiation,而这个动作在PUSH模式下,只要peer element的_chain函数返回GST_FLOW_NOT_NEGOTIATED,gstreamer core就会自动为我们调用peer src pad上的gst_pad_set_caps,所以,PUSH模式下,我们不需要去设置setcaps函数指针。 

有不明白的,参考Part-negotiation.txt,有详细的说明

丘猴子 發表在 痞客邦 留言(0) 人氣()

GStreamer Pad and Capabilities Negotiation

丘猴子 發表在 痞客邦 留言(0) 人氣()

3. init函數和class_init函數的講解 趣讀 2016-10-30 23:21:49 頻道: IT 如何去使用GObject去構建一個所謂的“物件”呢?GObject中每個類要定義兩個結構體,假設你要定義的類型為People,那麼你要定義兩個結構分別名為People和PeopleClass,估計剛接觸的人會有些暈,一般的C++啊,JAVA什麼的都是直接一個class了事兒了。但記住C本身並沒有面向物件的機制,這里這樣做也僅僅是為了模擬。 名為PeopleClass的結構是表示類的結構,而名為People的結構則是這個類的實例,可能這麼說一般人還會有點摸不著頭腦,切記,這是一種模擬。   下面這段話摘自《快速上手Gobject 》︰ 在GObject世界里,類是兩個結構體的組合,一個是實例結構體,另一個是類結構體。有點繞。類、物件、實例有什麼區別?可以這麼理解,類-物件-實例,無非就是類型,該類型所聲明的變數,變數所存儲的內容。後面可以知道,類結構體初始化函數一般被調用一次,而實例結構體的初始化函數的調用次數等於物件實例化的次數。所有實例共享的資料,可儲存在類結構體中,而所有物件私有的資料,則儲存在實例結構體中。   在GObject中一個物件的產生遵循如下原則,如果產生的是該類的第一個實例,那麼先分配Class結構,再分配針對該實例的結構。否則直接分配針對該實例的結構。也就是說在Class結構中所有的內容,是通過該類生成的實例所公有的。而實例獲每個物件時,為其單獨分配專門的實例用結構。 同時需要注意的是,每個結構中的第一項描述的是其父類相關的結構,這是為了模擬繼承的機制,比如,在gstimxv4l2src.h檔案中︰ struct _GstImxV4l2Src { GstPushSrc videosrc; gchar *device; guint frame_plus; GstBufferPool *pool; GstAllocator *allocator; gpointer v4l2handle; GstCaps *probed_caps; GstCaps *old_caps; GList * gstbuffer_in_v4l2; guint w, h, fps_n, fps_d; guint v4l2fmt; guint actual_buf_cnt; GstVideoAlignment video_align; GstClockTime duration; GstClockTime base_time_org; gboolean stream_on; gboolean use_my_allocator; gboolean use_v4l2_memory; }; struct _GstImxV4l2SrcClass { GstPushSrcClass parent_class; }; 這兩個結構體中的第一個元素都是與其父類相關的結構。這一點一定要注意。   有關這方面的理解,查看《使用C語言進行面向物件的開發--GObject入門系列》中的《使用C語言進行面向物件的開發--GObject入門〔3〕.pdf》和《借助 C++ 來理解 GObject 的基本編程框架.pdf》這兩個文檔,網頁連結為︰ http://www.cnblogs.com/pingf/archive/2009/11/20/1606742.html https://segmentfault.com/a/1190000003861212 或者查看《快速上手Gobject.pdf》中有關這一部分的講解,連結如下︰ http://blog.csdn.net/acs713/article/details/7778051   在上一篇文章中講到了使用G_DEFINE_TYPE 宏來定義了幾個函數,其中有type_name##_init 函數和type_name##_class_init函數,這兩個函數分別對應實例初始化和類的初始化。   下面以gstimxv4l2src.c檔案為例來分析,先來看看gst_imx_v4l2src_init函數︰ static void gst_imx_v4l2src_init (GstImxV4l2Src * v4l2src) { v4l2src->device = g_strdup (DEFAULT_DEVICE); v4l2src->frame_plus = DEFAULT_FRAME_PLUS; v4l2src->v4l2handle = NULL; v4l2src->probed_caps = NULL; v4l2src->old_caps = NULL; v4l2src->pool = NULL; v4l2src->allocator = NULL; v4l2src->gstbuffer_in_v4l2 = NULL; v4l2src->actual_buf_cnt = 0; v4l2src->duration = 0; v4l2src->stream_on = FALSE; v4l2src->use_my_allocator = FALSE; v4l2src->use_v4l2_memory = DEFAULT_USE_V4L2SRC_MEMORY; v4l2src->base_time_org = GST_CLOCK_TIME_NONE; gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME); gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE); g_print("====== IMXV4L2SRC: %s build on %s %s. ======\n", (VERSION),__DATE__,__TIME__); } 先來看這個函數,這個函數完成的是實例的初始化,對比對應的.h頭檔案,可以發現這個函數只是將GstImxV4l2Src這個結構體中的各個元素賦初值。     再來看看gst_imx_v4l2src_class_init函數︰ static void gst_imx_v4l2src_class_init (GstImxV4l2SrcClass * klass) { GObjectClass *gobject_class; GstElementClass *element_class; GstBaseSrcClass *basesrc_class; GstPushSrcClass *pushsrc_class; gobject_class = G_OBJECT_CLASS (klass); element_class = GST_ELEMENT_CLASS (klass); basesrc_class = GST_BASE_SRC_CLASS (klass); pushsrc_class = GST_PUSH_SRC_CLASS (klass); gobject_class->finalize = (GObjectFinalizeFunc) gst_imx_v4l2src_finalize; gobject_class->set_property = gst_imx_v4l2src_set_property; gobject_class->get_property = gst_imx_v4l2src_get_property; gst_imx_v4l2src_install_properties (gobject_class); gst_element_class_add_pad_template (element_class, \ gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, \ gst_imx_v4l2src_get_all_caps ())); basesrc_class->start = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_start); basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_stop); basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_get_caps); basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_fixate); basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_set_caps); basesrc_class->query = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_query); basesrc_class->decide_allocation = \ GST_DEBUG_FUNCPTR (gst_imx_v4l2src_decide_allocation); pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_create); gst_element_class_set_static_metadata (element_class, \ "IMX Video (video4linux2) Source", "Src/Video", \ "Capture frames from IMX SoC video4linux2 device", IMX_GST_PLUGIN_AUTHOR); GST_DEBUG_CATEGORY_INIT (imxv4l2src_debug, "imxv4l2src", 0, "Freescale IMX V4L2 source element"); } 這個函數類似于C++里面的構造函數,該初始化過程只進行一次。 對于這個函數的理解,首先需要理解物件的分層結構圖︰ 可以看出GstPushSrcClass是按照GstObject--->GstElement--->GstBaseSrc--->GstPushSrc這樣繼承下來的,所以使用︰   gobject_class =G_OBJECT_CLASS (klass);   element_class =GST_ELEMENT_CLASS (klass);   basesrc_class =GST_BASE_SRC_CLASS (klass);   pushsrc_class =GST_PUSH_SRC_CLASS (klass); 的方法,分別獲取它們對應的父類。然後分別實現這些類中的虛函數,也就是這些結構體里面的那些函數指針。 這里之所以使用 klass 而不是 class,是因為class 是 c++ 語言的關鍵字,如果使用 class,那麼類如是被 C++ 程式調用,那麼程式編譯時就杯具了。   對于structGObjectClass︰ struct GObjectClass { GTypeClass g_type_class; /* seldom overidden */ GObject* (*constructor) (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties); /* overridable methods */ void (*set_property) (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); void (*get_property) (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); void (*dispose) (GObject *object); void (*finalize) (GObject *object); /* seldom overidden */ void (*dispatch_properties_changed) (GObject *object, guint n_pspecs, GParamSpec **pspecs); /* signals */ void (*notify) (GObject *object, GParamSpec *pspec); /* called when done constructing */ void (*constructed) (GObject *object); }; 上面標紅的就是在這個函數中實現的函數指針。需要注意的是,這個是基礎的物件,如果設定好這幾個函數指針以後,就需要設定這個物件的屬性,需要使用g_object_class_install_property函數,這個函數封裝在gst_imx_v4l2src_install_properties函數里面。來看看g_object_class_install_property函數的解釋︰ 至此,structGObjectClass的初始化就算完成。     對于structGstElementClass︰ struct GstElementClass { GstObjectClass parent_class; /* the element metadata */ gpointer metadata; /* factory that the element was created from */ GstElementFactory *elementfactory; /* templates for our pads */ GList *padtemplates; gint numpadtemplates; guint32 pad_templ_cookie; /* virtual methods for subclasses */ /* request/release pads */ /* FIXME 2.0 harmonize naming with gst_element_request_pad */ GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ, const gchar* name, const GstCaps *caps); void (*release_pad) (GstElement *element, GstPad *pad); /* state changes */ GstStateChangeReturn (*get_state) (GstElement * element, GstState * state, GstState * pending, GstClockTime timeout); GstStateChangeReturn (*set_state) (GstElement *element, GstState state); GstStateChangeReturn (*change_state) (GstElement *element, GstStateChange transition); void (*state_changed) (GstElement *element, GstState oldstate, GstState newstate, GstState pending); /* bus */ void (*set_bus) (GstElement * element, GstBus * bus); /* set/get clocks */ GstClock* (*provide_clock) (GstElement *element); gboolean (*set_clock) (GstElement *element, GstClock *clock); /* query functions */ gboolean (*send_event) (GstElement *element, GstEvent *event); gboolean (*query) (GstElement *element, GstQuery *query); gboolean (*post_message) (GstElement *element, GstMessage *message); void (*set_context) (GstElement *element, GstContext *context); }; 而對于struct GstElementClass來說,這個結構體可以看作一個pipeline中每一個元件所對應的結構體,所以,對于這個結構體主要是設定它的Pad等,需要使用gst_element_class_add_pad_template函數,函數解釋如下︰ 關于這兩個函數以後再具體分析。設定完Pad後,就需要設定metadata,使用gst_element_class_set_static_metadata函數來完成︰ 這個函數也是需要在class_init函數中完成的,具體的分析查看《外掛程式編寫指南》。     對于struct GstBaseSrcClass︰ struct GstBaseSrcClass { GstElementClass parent_class; /* virtual methods for subclasses */ /* get caps from subclass */ GstCaps* (*get_caps) (GstBaseSrc *src, GstCaps *filter); /* decide on caps */ gboolean (*negotiate) (GstBaseSrc *src); /* called if, in negotiation, caps need fixating */ GstCaps * (*fixate) (GstBaseSrc *src, GstCaps *caps); /* notify the subclass of new caps */ gboolean (*set_caps) (GstBaseSrc *src, GstCaps *caps); /* setup allocation query */ gboolean (*decide_allocation) (GstBaseSrc *src, GstQuery *query); /* start and stop processing, ideal for opening/closing the resource */ gboolean (*start) (GstBaseSrc *src); gboolean (*stop) (GstBaseSrc *src); /* given a buffer, return start and stop time when it should be pushed * out. The base class will sync on the clock using these times. */ void (*get_times) (GstBaseSrc *src, GstBuffer *buffer, GstClockTime *start, GstClockTime *end); /* get the total size of the resource in the format set by * gst_base_src_set_format() */ gboolean (*get_size) (GstBaseSrc *src, guint64 *size); /* check if the resource is seekable */ gboolean (*is_seekable) (GstBaseSrc *src); /* Prepare the segment on which to perform do_seek(), converting to the * current basesrc format. */ gboolean (*prepare_seek_segment) (GstBaseSrc *src, GstEvent *seek, GstSegment *segment); /* notify subclasses of a seek */ gboolean (*do_seek) (GstBaseSrc *src, GstSegment *segment); /* unlock any pending access to the resource. subclasses should unlock * any function ASAP. */ gboolean (*unlock) (GstBaseSrc *src); /* Clear any pending unlock request, as we succeeded in unlocking */ gboolean (*unlock_stop) (GstBaseSrc *src); /* notify subclasses of a query */ gboolean (*query) (GstBaseSrc *src, GstQuery *query); /* notify subclasses of an event */ gboolean (*event) (GstBaseSrc *src, GstEvent *event); /* ask the subclass to create a buffer with offset and size, the default * implementation will call alloc and fill. */ GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size, GstBuffer **buf); /* ask the subclass to allocate an output buffer. The default implementation * will use the negotiated allocator. */ GstFlowReturn (*alloc) (GstBaseSrc *src, guint64 offset, guint size, GstBuffer **buf); /* ask the subclass to fill the buffer with data from offset and size */ GstFlowReturn (*fill) (GstBaseSrc *src, guint64 offset, guint size, GstBuffer *buf); }; 上面標紅的就是在這個函數中實現的函數指針。   對于struct GstPushSrcClass︰ struct GstPushSrcClass { GstBaseSrcClass parent_class; /* ask the subclass to create a buffer, the default implementation * uses alloc and fill */ GstFlowReturn (*create) (GstPushSrc *src, GstBuffer **buf); /* allocate memory for a buffer */ GstFlowReturn (*alloc) (GstPushSrc *src, GstBuffer **buf); /* ask the subclass to fill a buffer */ GstFlowReturn (*fill) (GstPushSrc *src, GstBuffer *buf); }; 上面標紅的就是在這個函數中實現的函數指針。   至此,就簡單分析完class_init函數,整個.c檔案就是圍繞這個class_init函數來構建的,或者說,整個.c檔案就是來實現這些函數指針的具體內容。 Tags︰GObject   GStreamer   arm   glib   imx6   GStreamer   原文網址:https://ifun01.com/BNLBF2I.html


丘猴子 發表在 痞客邦 留言(0) 人氣()

Gstreamer 中的playback插件

 

1. PLAYBACK插件基本介绍
在早期的版本中同时存在playbin和playbin2,但是在最新的版本中,playbin2已经稳定,取代了playbin,
playbin不再进行维护。下面是官网上的一些描述: 

丘猴子 發表在 痞客邦 留言(0) 人氣()

Gstreamer 中的playback插件

标签:    

 

Playbin2 provides a stand-alone everything-in-one abstraction for an audio and/or video player.

丘猴子 發表在 痞客邦 留言(0) 人氣()

丘猴子 發表在 痞客邦 留言(0) 人氣()

H.265/HEVC 新世代的影像編碼格式

文/大林慈院教學部教學研發組程式設計師 劉普昇

 
 

 

丘猴子 發表在 痞客邦 留言(0) 人氣()