2017年11月30日 星期四

[轉] (assertion)敘述

維護(assertion)敘述

        當自己寫的函式庫要提供他人使用時,適當的利用維護敘述,可以建立安全的使用
        介面,避免他人因為使用不當,而造成不可預期的後果。
        C 語言有自己的維護函式- assert() ,使用方法如下:

           assert(iTotalNumber < 1000);

        當程式執行到該行時,若 iTotalNumber < 1000 則程式可以繼續執行;若
        iTotalNumber >= 1000 ,則會秀出維護錯誤訊息的字串,並結束程式。
        維護字串包含有:判斷式子、程式檔名及該行的行號。

        // Test.CPP -- test assert message
        #include 
        main()
        {
           int iTotalNumber=10000;
           assert(iTotalNumber<1000);
        }

        C:LCPPBIN>tt
        Assertion failed: iTotalNumber<1000, file test.cpp, line 6
        Abnormal program termination

2017年11月14日 星期二

[轉] 編譯中的-shared和-fPIC

接著昨天的工作,絕大部分問題已經解決,現在拖到最後解決,擺在眼前的問題是:
1makefileLDFLAGS有參數-shared,導致報錯
/usr/bin/ld: md5c.o: relocation R_ARM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC
md5c.o: could not read symbols: Bad value
collect2: ld returned 1 exit status
make: *** [object] Error 1
2、去掉在LDFLAGS中添加-fPIC同樣報錯,去掉-shared,有沒有-fPIC都沒有這個報錯了,但是會有另一個報錯
//usr/lib/crt1.o: In function `_start':
(.text+0x34): undefined reference to `main'
collect2: ld returned 1 exit status
make: *** [object] Error 1
這表明沒有-shared選項,編譯器預設編譯的是一個可執行程式,但是又找不到main函數(-start是內核程式的主函數,應用程式主函數為main,是供-start調用的),看來,-shared不能去掉

那麼為什麼報錯提示會說recompile with -fPIC呢?
原來,人家說的是“recompilewith -fPIC,而不是用-fPIC連結,所以-fPIC應該添加到CPPFLAGS += -fPIC中,而非LDFLAGS。將mainservicemakefile添上這一行命令,在他用到的所有連結化物件(包括libtinyxml.a)的makefile中都添上,再編譯,就ok了。


2017年11月4日 星期六

[轉] Linux Gstreamer and GST-OMX插件

Linux Gstreamer and GST-OMX插件
http://blog.sina.com.cn/s/blog_80ce3a550100xo8p.html

1. Gstreamer基本介紹
Gstreamer是linux上的多媒體框架。如下所示:
      Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

 從上面這個圖中可以看到,底層是以plugin插件形式存在包括codec標準,parser,audio, protocol等,
 也包括用戶自己開發的plugin和第三方開發的plugin。
 core framework提供了plugin之間的交互機制和管理,通過將一些plugin連接起來形成一個系統,並且對上
 提供訪問的接口。APP是構建在framework上的。

 通過這個框架,底層開發者可以專注於開發plugin,APP開發者通過調用這個plugin來組成完成某種功能的
 APP,plugin之間的通信都是由gstreamer framework提供的。

 目前已經有一些成熟的plugin已經開發,並且作為library提供給了用戶:
     gst-plugins-base: an essential exemplary set of elements
     gst-plugins-good: a set of good-quality plug-ins under LGPL
     gst-plugins-ugly: a set of good-quality plug-ins that might pose distribution problems
     gst-plugins-bad:  a set of plug-ins that need more quality

plugin中的element實際上就是實現該element支持的API,供上層來調用.

Gstreamer中的幾個術語:
   Elements: plugin的實例,在一個APP中可能需要創建多個elements並且把這些elements連接在一起形成系統
       elements可以分為:
          source element: 沒有輸入,只有輸出pad,用來產生數據。
          sink element:    只有輸入pad,沒有輸出pad,是數據的目的地。如disk,soundcard
          filter element: 包含輸入pad和輸出pad,接收輸入的數據並且產生輸出數據
                           輸入輸出Pad的數目可以是N個(N >= 1)
                          
                         Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件
                 queue element: 是一個特殊的element,作為thread的邊界存在。Gstreamer是可以
                                支持多線程的,線程的邊界通過queue來隔開。
                            Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

  element state:
      element有4個狀態:
           Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件
   
Pads:element的輸入輸出端口。elements之間就是通過Pad來進行連接的。數據通過Pads在elements之間
         進行傳遞。
         輸入pad稱為 sink pad
         輸出pad稱為 source pad
 
       element並不禁止自己的source pad和sink pad連接在一起形成一個loop。
       pad的capability 定義了該pad上能夠處理的data的類型和一些參數(Gstcaps數據結構):
                Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

           

   bin: 是一些elements的集合。對這個bin進行的操作會影響到該bin包含的所有的elements。
   pipeline: pipeline也是一個bin,不過它是一個top level bin。

   Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件


 Bus: Bus是pipeline傳輸message給APP時的通路,從下面的圖中可以看到,從pipeline中發給APP的message
      需要通過BUS(events/Queries 不需要通過BUS)。在創建pipeline時缺省會創建bus,因此用戶不需要
      去單獨創建bus。APP需要做的就是為message設置message handler(APP提供callback函數給
      pipeline調用),當pipeline需要發信息給APP時,調用這些APP提供的callback函數。
             gst_bus_add_watch () or gst_bus_add_signal_watch ()
      例子:
             Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

        如果使用的是GLIB,那麼還可以有另外一種方式來聲明callback,見文檔。
        Gstreamer定義了一些特殊的message包括error/EOS/State-change/element message,plugin也可以自
        定義一些message。

 通信 communication:
    從框架來看,APP需要和pipeline進行數據和控制信息的通信包括進行play、pause等的控制以及數據的傳輸
    pipeline中的elements之間也需要進行數據和信息的傳輸:
       Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件
 buffers: 在pad上傳輸的data是通過buffer傳輸的。 elements <-> elements
       buffer的創建有2種方式,一種是由當前的element自己創建,然後把這個buffer傳遞給下一個element。
另外一種方式就是dwonstream-allocated buffers,就是由下一個element來創建要求大小的buffer,並提供buffer操作函數,當前element通過調用buffer操作函數將數據寫入這個buffer中完成buffer數據傳遞。
區別在於buffer的創建是在數據傳輸的源端element創建還是在數據接收端element來創建。

 events: APP向elements發出的或者elements之間的傳輸都可以通過events。 APP -> elements, elements<->
 messages: elements向APP傳輸的信息。 elements -> APP
 queries:  APP向elements請求信息,或者elements之間的信息請求。APP->Elements, elements<->
 注意方向,APP和elements之間的傳輸是有方向的。

 
 Gstreamer的數據驅動(schedule):
   Gstreamer是一個多thread的框架。但是為了performance的原因,不會對每一個element都創建一個thread,
   而是根據應用的特點和element的工作特點來進行thread的劃分,thread的邊界必須是queue element。
    Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件
Gstreamer中pad支持兩種schedule方式:docs/design/part-activation.txt
   push-based scheduling: 這種scheduling方法中,downstream elements的sink pad上需要定義chain函數
                          (gst_pad_set_chain_function ),upstream elements調用這個chain函數來完成
                          將buffer從upstream(source pad)到downstream elements(sink pad)的傳遞。
                          這種scheduling方式中source elements遞歸調用downstream elements的chain函
                          數,最後一直調用到目的elements的才能函數。
                          (由於chain函數是定義在sink pad上,而source element是沒有sink pad的,因此
                           source element是不提供chain函數的).
                           調用的順序是從sink element到source element。(遞歸調用).
                            sink-to-source elements order。

          Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件
                       B_chain_function(C_chain_function(buffer2),buffer1)

       在這種模式下,upstream elements通過調用downstream elements sink pad上定義的chain函數
       主動的將數據傳輸給downstream elements,因此數據驅動是由upstream element發起的。

     Pull-based scheduling:  
         在這種模式下,upstream elements 的source pad上提供了數據訪問函數,downstream elements通過
         sink pad主動的去調用upstream elements的函數來要數據,
         因此數據驅動是由downstream elements發起的(在sink pad上調用source pad 上的
         gst_pad_pull_range())。
      
 
   具體到某一個element上的PAD可以有下面幾種情況:
         (1) 該element的所有PAD全部使用push-based mode
         (2) 該element的所有pad都採用pull-based mode。
         (3) 該element的sinkpad採用pull-based mode,而該element的sourcepad採用push-based
             mode.  這種elements只能是queue element。在queue element的sink pad和source pad
             上各有一個thread,每一個thread只能有一種數據驅動mode。(GstTask)
        
  
核心代碼:

push-based mode://source pad主動調用chain函數
#define GST_PAD_CHAINFUNC(pad)        (GST_PAD_CAST(pad)->chainfunc)
GstFlowReturn  gst_pad_push (GstPad * pad, GstBuffer * buffer)
{
    g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
    g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR); //source pad調用chain函數
    cache = pad_take_cache (pad, cache_ptr);
    peer = cache->peer;//得到連接在這個sourcePad上的sink pad的list
    ret = GST_PAD_CHAINFUNC (peer) (peer, buffer);//調用sink pad上的chain函數
}

//給sink Pad設置chain函數
void  gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain)
{
   g_return_if_fail (GST_IS_PAD (pad));
   g_return_if_fail (GST_PAD_IS_SINK (pad));
   GST_PAD_CHAINFUNC (pad) = chain;
}


pull-based mode:sinkpad主動調用get_range()函數

GstFlowReturn gst_pad_pull_range (GstPad * pad, guint64 offset, guint size, GstBuffer ** buffer)
{
  g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
  g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);//由sinkpad來調用
  if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL)) //通過該sinkpad找到和它連接的sourcepad
    goto not_connected;
  ret = gst_pad_get_range_unchecked (peer, offset, size, buffer);//調用定義在source pad上的
                                                                   get_range函數
}


GstFlowReturn gst_pad_get_range (GstPad * pad, guint64 offset, guint size, GstBuffer ** buffer)
{
  return gst_pad_get_range_unchecked (pad, offset, size, buffer);
}

#define GST_PAD_GETRANGEFUNC(pad)    (GST_PAD_CAST(pad)->getrangefunc)
static GstFlowReturn gst_pad_get_range_unchecked (GstPad * pad, guint64 offset, guint size,
    GstBuffer ** buffer)
{
    if (G_UNLIKELY ((getrangefunc = GST_PAD_GETRANGEFUNC (pad)) == NULL))
            goto no_function;
    ret = getrangefunc (pad, offset, size, buffer);
}
  
那麼如何設置當前element的pad上採用哪一種scheduling mode,這就是pad-activation stage:
   (1) 首先gstreamer需要去查詢當前pad支持幾種scheduling mode。
   (2) Gstreamer來設置當前pad採用的scheduling mode方式,並通知當前pad知道。
        PAD上需要實現notice函數供gstreamer來調用:
               gst_pad_set_activatepull_function ()
               gst_pad_set_activatepush_function ()

#define GST_PAD_ACTIVATEPUSHFUNC(pad)    (GST_PAD_CAST(pad)->activatepushfunc)
      void  gst_pad_set_activatepush_function (GstPad * pad, GstPadActivateModeFunction activatepush)
{
  g_return_if_fail (GST_IS_PAD (pad));
  GST_PAD_ACTIVATEPUSHFUNC (pad) = activatepush; //函數指針
}

 在activatepush()中調用下面的函數來設置mode。
 gboolean gst_pad_activate_push/pull (GstPad * pad, gboolean active)
 
     ......
 }


2 . 基於Gstreamer構建應用APP
    Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

第2部分:如何註冊一個plugin
     一個plugin中可以包含多個element。每一個element作為plugin的一個feature。
     gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,GType type)
     ->gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name);

      首先從APP的角度來看,如何調用一個plugin(使用plugin feature name來調用如fakesink):
             sink = gst_element_factory_make ("fakesink", "swallow_audio");
    
             GstElement * gst_element_factory_make (const gchar * factoryname, const gchar * name)
             {
                  factory = gst_element_factory_find (factoryname);//根據factorName找到
                                                                    GstPluginFeature *feature;
                  element = gst_element_factory_create (factory, name);//通過factory得到plugin並
                                                                         創建element(name)
             }

             GstElementFactory * gst_element_factory_find (const gchar * name)
             {
                     feature = gst_registry_find_feature (gst_registry_get_default (), name,
                               GST_TYPE_ELEMENT_FACTORY);
              }


         GstElement * gst_element_factory_create (GstElementFactory * factory, const gchar * name)
         {
             //gst_plugin_feature_load調用plugin = gst_plugin_load_by_name (feature->plugin_name);
             newfactory = GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
                                              (factory)));
             factory = newfactory;
            
           if (name) //創建的instance的name
              element =
                   GST_ELEMENT_CAST (g_object_new (factory->type, "name", name, NULL));
           else
              element = GST_ELEMENT_CAST (g_object_newv (factory->type, 0, NULL));
          }


   gst_element_factory_create->gst_plugin_feature_load()
                         ->plugin = gst_plugin_load_by_name (feature->plugin_name);
                         -> plugin = gst_registry_find_plugin (gst_registry_get_default (), name);
                            newplugin = gst_plugin_load_file (plugin->filename, &error);
                         -> gst_plugin_register_func (plugin, plugin->orig_desc, NULL)
                         -> (desc->plugin_init) (plugin)

    總結下來就是:先通過factoryname找到該plugin的factory數據結構(GstPluginFeature factor->feature),再找到對應的plugin,並調用該plugin提供的plugin_init()函數。
                     Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件



   (1) gst_init()
      Initializes the GStreamer library, setting up internal path lists,
      registering built-in elements, and loading standard plugins.
      gst_init_check()
      {
         group = gst_init_get_option_group ();
       }
 

在plugin編寫中:有2種註冊plugin的方式:
    如下面的例子中的macro  GST_PLUGIN_DEFINE:
    GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "avi",
    "AVI stream handling",
    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)




* This macro needs to be used to define the entry point and meta data of a
 * plugin. One would use this macro to export a plugin, so that it can be used
 * by other applications.
 *
 * The macro uses a define named PACKAGE for the #GstPluginDesc,source field.
 When using autoconf, this is usually set automatically via the AC_INIT
 * macro, and set in config.h. If you are not using autoconf, you will need to
 * define PACKAGE yourself and set it to a short mnemonic string identifying
 * your application/package, e.g. 'someapp' or 'my-plugins-foo.
 *
 * If defined, the GST_PACKAGE_RELEASE_DATETIME will also be used for the
 * #GstPluginDesc,release_datetime field.
   #define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin)    \
G_BEGIN_DECLS \
GST_PLUGIN_EXPORT GstPluginDesc gst_plugin_desc = {    \
  major,                        \
  minor,                        \
  name,                            \
  (gchar *) description,                \
  init,                            \
  version,                        \
  license,                        \
  PACKAGE,                        \
  package,                        \
  origin,                        \
  __GST_PACKAGE_RELEASE_DATETIME,                       \
  GST_PADDING_INIT                        \
}; \
G_END_DECLS


    類似的有一個對應的靜態註冊函數:
   #define GST_PLUGIN_DEFINE_STATIC(major,minor,name,description,init,version,license,package,origin)  \
static void GST_GNUC_CONSTRUCTOR            \
_gst_plugin_static_init__ ##init (void)            \
                           \
  static GstPluginDesc plugin_desc_ = {            \
    major,                        \
    minor,                        \
    name,                        \
    (gchar *) description,                \
    init,                        \
    version,                        \
    license,                        \
    PACKAGE,                        \
    package,                        \
    origin,                        \
    NULL,                        \
    GST_PADDING_INIT                        \
  };                            \
  _gst_plugin_register_static (&plugin_desc_);        \ //調用了靜態註冊函數
}


編譯自己的plugin插件:http://blog.csdn.net/dyzhu/article/details/4357037
   
1. 從模板生成gstreamer插件

gst-template是gstreamer插件的開發模板,在gst-plugin/tools目錄下有 一個make_element,在gst-plugin/src目錄下,運行../tools/make_element myfilter,就可以生成一個myfilter插件。

    在gst-plugin目錄下的autogen.sh可以自動生成congifure和makefile.in文件,如果這個腳本運行不成功。可以用下面的方法:

編譯:
#libtool --mode=compile cc `pkg-config --cflags gstreamer-0.10` -DPACKAGE="Gstreamer" -DHAVE_USER_MTU -Wall -Wimplicit -g -o gstmyfilter.o -c gstmyfilter.c

鏈接:
#libtool --mode=link cc -module -avoid-version -rpath /usr/local/lib/gstreamer-0.10/ -export-symbols-regex gst_plugin_desc -o gstmyfilter.la gstmyfilter.lo `pkg-config --libs gstreamer-0.10`

安裝:
#libtool --mode=install install gstmyfilter.la /usr/local/lib/gstreamer-0.10/

之後,就可以在自己的應用程序中創建myfilter的element。
轉載兩篇相關的文章:http://blog.csdn.net/dyzhu/article/details/4362865
http://blog.csdn.net/dyzhu/article/details/4362865
由於在嵌入式系統中運行gstreamer,受到資源的限制,所以打算只安裝gstreamer核心庫和一些必須的element,其它的element用到的時候再添加。我的想法是,把base,good,。。。插件包中的需要用到的elment編譯成插件。
    拿good插件包中的id3demux做試驗(先在pc上試驗,可惜pc上已經裝了base插件包),把good插件包中的gst/id3demux目錄下的5個文件copy到gst-template/gst-plugin/src目錄下,用上一篇文章《編譯自己的gstreamer插件》中提到的方法編譯,鬱悶,沒通過,有空再研究一下(linux基本知識還很欠缺啊。。。)。
    後來我想,既然gstreamer的插件是動態鏈接庫,那麼只是把這些源文件編譯成動態鏈接庫是否可以呢?試一下:
    gcc -Wall $(pkg-config --cflags --libs gstreamer-0.10) -DPACKAGE='"GStreamer"' -Wimplicit -fpic -shared -g -o gstid3demux.so gstid3demux.c id3tags.c id3v2frames.c
     把編譯出來的gstid3demux.so拷貝到gstreamer庫目錄下,寫個應用程序調用一下,OK,沒問題。再用gst-template的工具生成一個myfilter,用同樣的方法:
     gcc -Wall $(pkg-config --cflags --libs gstreamer-0.10) -DPACKAGE='"GStreamer"' -DVERSION='"0.10.23"' -Wimplicit -fpic -shared -g -o gstmyfilter.so gstmyfilter.c
      把編譯出來的gstmyfilter.so拷貝到gstreamer庫目錄下,調用成功。

      原來,只需要把你element編譯成動態連接庫就可以了。





    看一個例子:
        Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

  上面這個例子中,這個plugin中註冊了幾個element。在plugin_init()中就是做element的註冊
 

 Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

struct _GstPluginDesc {
  gint major_version;
  gint minor_version;
  const gchar *name;
  const gchar *description;
  GstPluginInitFunc plugin_init; //初始化函數
  const gchar *version;
  const gchar *license;
  const gchar *source;
  const gchar *package;
  const gchar *origin;
  const gchar *release_datetime;
 
  gpointer _gst_reserved[GST_PADDING - 1];
};

 如下圖,一個plugin中註冊了多個components(elements)

 Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件


第3部分:GST-OMX
    GST-omx是Gstreamer的一個plugin,用來和OMX IL封裝的codec進行互連。從OMX IL的角度來說,GST-OMX
    其實就是一個OMX IL Client,通過GetHandle得到component的handle來操作component。
    由於是一個plugin,因此需要符合plugin的要求:

    GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "omx",
    "OpenMAX IL",
    plugin_init,
    PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

    static gboolean plugin_init (GstPlugin * plugin)
    {
        fetch_element_table (plugin);->path = get_config_path ();通過一個config文件來定義

     }
     缺省的config文件Gstomx_config.c 中default_config如下:
 "omx_mpeg4dec,\
"
 type=GstOmxMpeg4Dec,\
"
 library-name=libomxil-bellagio.so.0,\
"
 component-name=OMX.st.video_decoder.mpeg4,\
"
 rank=256;\
          
通過解析這個config可以得到library name(.so),component name等信息。config文件的路徑可以由環境變量OMX_CONFIG設置,沒有設置就使用default config(Gstomx.config)。

GST-OMX中的element做了一些抽象:
      Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

  一些API和OMX IL的對應關係:
               Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

  以H264dec為例:
在例化時會調用type_instance_init,由於基類是base filter,因此會先調用基類的type_instance_init函數

//Gstomx_h264dec.c
static void
type_instance_init (GTypeInstance * instance, gpointer g_class)
{
  GstOmxBaseVideoDec *omx_base;

  omx_base = GST_OMX_BASE_VIDEODEC (instance);//base videoDEC類型

  omx_base->compression_format = OMX_VIDEO_CodingAVC;
}

//GstOmxBaseVideoDec 構造函數
static void
type_instance_init (GTypeInstance * instance, gpointer g_class)
{
  GstOmxBaseFilter *omx_base;

  omx_base = GST_OMX_BASE_FILTER (instance);

  omx_base->omx_setup = omx_setup;

  omx_base->gomx->settings_changed_cb = settings_changed_cb;

  gst_pad_set_setcaps_function (omx_base->sinkpad, sink_setcaps);
}

基類basefilter的該函數:
static void
type_instance_init (GTypeInstance * instance, gpointer g_class)
{
  GstOmxBaseFilter *self;
  GstElementClass *element_class;

  element_class = GST_ELEMENT_CLASS (g_class);

  self = GST_OMX_BASE_FILTER (instance);

  GST_LOG_OBJECT (self, "begin");

  self->use_timestamps = TRUE;
 
  self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class)); //omx core生成,會調用
                                                                      g_omx_core_init->request_imp
                                                                      ->imp_new->dlopen()
  self->in_port = g_omx_core_new_port (self->gomx, 0);
  self->out_port = g_omx_core_new_port (self->gomx, 1);

  self->ready_lock = g_mutex_new ();

  self->sinkpad =
      gst_pad_new_from_template (gst_element_class_get_pad_template
      (element_class, "sink"), "sink");

  gst_pad_set_chain_function (self->sinkpad, pad_chain);
  gst_pad_set_event_function (self->sinkpad, pad_event);

  self->srcpad =
      gst_pad_new_from_template (gst_element_class_get_pad_template
      (element_class, "src"), "src");

  gst_pad_set_activatepush_function (self->srcpad, activate_push);

  gst_pad_use_fixed_caps (self->srcpad);

  gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);

  GST_LOG_OBJECT (self, "end");
}

void *
gstomx_core_new (void *object, GType type)
{
  GOmxCore *core = g_omx_core_new (object);
  gstomx_get_component_info (core, type);
  g_omx_core_init (core);
  return core;
}


//對core進行初始化
gboolean
gstomx_get_component_info (void *core, GType type)
{
  GOmxCore *rcore = core;
  const gchar *element_name;
  GstStructure *element;
  const gchar *str;

  element_name = g_type_get_qdata (type, element_name_quark);
  element = get_element_entry (element_name);

  if (!element)
    return FALSE;

  str = gst_structure_get_string (element, "library-name");
  rcore->library_name = g_strdup (str);

  str = gst_structure_get_string (element, "component-name");
  rcore->component_name = g_strdup (str);

  str = gst_structure_get_string (element, "component-role");
  rcore->component_role = g_strdup (str);

  return TRUE;
}


void
g_omx_core_init (GOmxCore * core)
{
  core->imp = request_imp (core->library_name);//core的library_name如何得到的?config文件中讀取

  if (!core->imp)
    return;

  //調用了get_handle
  core->omx_error = core->imp->sym_table.get_handle (&core->omx_handle,
      (char *) core->component_name, core, &callbacks);

  if (!core->omx_error) {
    core->omx_state = OMX_StateLoaded;

    if (core->component_role) {
      OMX_PARAM_COMPONENTROLETYPE param;

      GST_DEBUG_OBJECT (core->object, "setting component role: %s",
          core->component_role);

      G_OMX_INIT_PARAM (param);

      strncpy ((char *) param.cRole, core->component_role,
          OMX_MAX_STRINGNAME_SIZE);

      OMX_SetParameter (core->omx_handle, OMX_IndexParamStandardComponentRole,
          &param);
    }
  }
}

通過這些函數的調用,完成了element的例化。其中的關鍵函數:
core->imp = request_imp (core->library_name);//這裡的library_name就是config文件中的library name

如何得到config文件?
在GST-OMX中plugin_init()->fetch_element_table()->get_config_path()中去查找config文件:
尋找的優先級如下:
   1. OMX_CONFIG環境變量設置的文件
   2. 系統目錄下的gst-openmax.conf
   3. 用戶目錄下的gst-openmax.conf
  static gchar * get_config_path (void)
{
  gchar *path;
  const gchar *const *dirs;
  int i;

  path = g_strdup (g_getenv ("OMX_CONFIG")); //讀取環境變量中設置的config文件的位置和文件名

  if (path)
    return path;

  dirs = g_get_system_config_dirs (); //如果沒有設置環境變量,則去系統目錄下看是否這個文件存在
                                       system_dir/gstreamer-0.10/gst-openmax.conf文件
  for (i = 0; dirs[i]; i++) {
    path =
        g_build_filename (dirs[i], "gstreamer-0.10", "gst-openmax.conf", NULL);
    if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
      return path;
    g_free (path);
  }
  //如果上面兩個都沒有找到,那麼返回usr目錄下的gst-openmax.conf文件
  //其中g_get_user_config_dir ()的返回值通常為home/user_name/.config
  //在其它的代碼中會去測試是否這個文件存在
  return g_build_filename (g_get_user_config_dir (), "gst-openmax.conf", NULL);
}

config的內容:
   Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件
上面的config中還可以設置一個component_role,在gst-omx.c的plugin_init()函數中有下面的代碼:
    Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

在很多的omx component中需要這個component_role的設置:
  在TI OMX_CORE.c 中就包含有下面的role表,前面一個是component name後面一個是該component支持的role:
    char *tComponentName[MAXCOMP][2] = {
       {"OMX.TI.Video.Decoder", "video_decoder.avc"},
    {"OMX.TI.Video.Decoder", "video_decoder.vc1"},
    {"OMX.TI.Video.Decoder", "video_decoder.mpeg2"},
    {"OMX.TI.Video.Decoder", "video_decoder.mpeg4"},
    {"OMX.TI.Video.Decoder", "video_decoder.div3"},
    {"OMX.TI.Video.Decoder", "video_decoder.rv"},
    {"OMX.TI.MP3.decode", "audio_decoder.mp3"},
    {"OMX.TI.AAC.encode", "audio_encoder.aac"},
    {"OMX.TI.AAC.decode", "audio_decoder.aac"},
    {"OMX.TI.WMA.decode", "audio_decoder.wma"},
    {"OMX.TI.WBAMR.decode", "audio_decoder.amrwb"},
    {"OMX.TI.AMR.decode", "audio_decoder.amrnb"},
    {"OMX.TI.AMR.encode", "audio_encoder.amrnb"},
    {"OMX.TI.WBAMR.encode", "audio_encoder.amrwb"},
}



//初始化

static inline GOmxImp *
request_imp (const gchar * name)
{
  GOmxImp *imp = NULL;

  g_mutex_lock (imp_mutex);
  imp = g_hash_table_lookup (implementations, name);
  if (!imp) {
    imp = imp_new (name); //打開動態鏈接庫得到函數指針
    if (imp)
      g_hash_table_insert (implementations, g_strdup (name), imp);
  }
  g_mutex_unlock (imp_mutex);

  if (!imp)
    return NULL;

  g_mutex_lock (imp->mutex);
  if (imp->client_count == 0) {
    OMX_ERRORTYPE omx_error;
    omx_error = imp->sym_table.init (); //調用omx_init
    if (omx_error) {
      g_mutex_unlock (imp->mutex);
      return NULL;
    }
  }
  imp->client_count++;
  g_mutex_unlock (imp->mutex);

  return imp;
}


static GOmxImp *
imp_new (const gchar * name)
{
  GOmxImp *imp;

  imp = g_new0 (GOmxImp, 1);

 
  {
    void *handle;

    GST_DEBUG ("loading: %s", name);

    imp->dl_handle = handle = dlopen (name, RTLD_LAZY); //打開omxcore的動態鏈接庫,在GST-OMX
                                                         中只是提供了OMX_CORE.h,沒有提供
                                                         OMX_CORE.c,這部分是由OMX提供,
                                                         在stagefright中這個庫位libOMXCORE.so
                                                         在GST-OMX中由config中的library name指定
                                                         如下面的libomxil-bellagio.so.0
                   component_name是在getHandle時被調用(打開lib+component_name.SO):
   (core->omx_error = core->imp->sym_table.get_handle (&core->omx_handle,
      (char *) core->component_name, core, &callbacks);)
                  Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件



    GST_DEBUG ("dlopen(%s) -> %p", name, handle);

    if (!handle) {
      g_warning ("%s\n", dlerror ());
      g_free (imp);
      return NULL;
    }

    imp->mutex = g_mutex_new ();
    imp->sym_table.init = dlsym (handle, "OMX_Init"); //得到OMX 函數。
    imp->sym_table.deinit = dlsym (handle, "OMX_Deinit");
    imp->sym_table.get_handle = dlsym (handle, "OMX_GetHandle");
    imp->sym_table.free_handle = dlsym (handle, "OMX_FreeHandle");
  }




struct GstOmxBaseVideoDec
{
  GstOmxBaseFilter omx_base; //繼承baseFilter類

  OMX_VIDEO_CODINGTYPE compression_format;
  gint framerate_num;
  gint framerate_denom;
};



//GstOmxBaseFilter 構造函數
static void
type_class_init (gpointer g_class, gpointer class_data)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  gobject_class = G_OBJECT_CLASS (g_class);
  gstelement_class = GST_ELEMENT_CLASS (g_class);

  gobject_class->finalize = finalize;
  gstelement_class->change_state = change_state;

 
  {
    gobject_class->set_property = set_property;
    gobject_class->get_property = get_property;

    gstomx_install_property_helper (gobject_class);
 
    //設置property
    g_object_class_install_property (gobject_class, ARG_USE_TIMESTAMPS,
        g_param_spec_boolean ("use-timestamps", "Use timestamps",
            "Whether or not to use timestamps",
            TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

    g_object_class_install_property (gobject_class, ARG_NUM_INPUT_BUFFERS,
        g_param_spec_uint ("input-buffers", "Input buffers",
            "The number of OMX input buffers",
            1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
    g_object_class_install_property (gobject_class, ARG_NUM_OUTPUT_BUFFERS,
        g_param_spec_uint ("output-buffers", "Output buffers",
            "The number of OMX output buffers",
            1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }
 



在base filter中定義了這些property設置函數:
static void
set_property (GObject * obj,
    guint prop_id, const GValue * value, GParamSpec * pspec)
{
  GstOmxBaseFilter *self;

  self = GST_OMX_BASE_FILTER (obj);

  switch (prop_id) {
    case ARG_USE_TIMESTAMPS:
      self->use_timestamps = g_value_get_boolean (value);
      break;
    case ARG_NUM_INPUT_BUFFERS:
    case ARG_NUM_OUTPUT_BUFFERS:
    {
      OMX_PARAM_PORTDEFINITIONTYPE param;
      OMX_HANDLETYPE omx_handle = self->gomx->omx_handle;
      OMX_U32 nBufferCountActual;
      GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
          self->in_port : self->out_port;

      if (G_UNLIKELY (!omx_handle)) {
        GST_WARNING_OBJECT (self, "no component");
        break;
      }

      nBufferCountActual = g_value_get_uint (value);

      G_OMX_INIT_PARAM (param);

      param.nPortIndex = port->port_index;
      OMX_GetParameter (omx_handle, OMX_IndexParamPortDefinition, &param); //調用OMX IL API

      if (nBufferCountActual < param.nBufferCountMin) {
        GST_ERROR_OBJECT (self, "buffer count %lu is less than minimum %lu",
            nBufferCountActual, param.nBufferCountMin);
        return;
      }

      param.nBufferCountActual = nBufferCountActual;

      OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
    }
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
      break;
  }
}

數據結構中:
struct GstOmxBaseFilter
{
  GstElement element;

  GstPad *sinkpad;
  GstPad *srcpad;

  GOmxCore *gomx; //OMXCORE
  GOmxPort *in_port;
  GOmxPort *out_port;

  gboolean use_timestamps;  
  gboolean ready;
  GMutex *ready_lock;

  GstOmxBaseFilterCb omx_setup;
  GstFlowReturn last_pad_push_return;
  GstBuffer *codec_data;

   
  gboolean share_input_buffer;
  gboolean share_output_buffer;
};

struct GOmxCore
{
  gpointer object;  

  OMX_HANDLETYPE omx_handle; //OMX HANDLE
  OMX_ERRORTYPE omx_error;

  OMX_STATETYPE omx_state;
  GCond *omx_state_condition;
  GMutex *omx_state_mutex;

  GPtrArray *ports;

  GSem *done_sem;
  GSem *flush_sem;
  GSem *port_sem;

  GOmxCb settings_changed_cb;
  GOmxImp *imp;

  gboolean done;

  gchar *library_name;
  gchar *component_name;
  gchar *component_role;
};

struct GOmxPort
{
  GOmxCore *core;
  GOmxPortType type;

  guint num_buffers;
  gulong buffer_size;
  guint port_index;
  OMX_BUFFERHEADERTYPE **buffers;

  GMutex *mutex;
  gboolean enabled;
  gboolean omx_allocate;  
  AsyncQueue *queue;
};

Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

在stagefright中是libomxCore.SO,在GST-OMX中通過config文件中的library_name來指定使用的core的so文件
這是因為在omx_core.c中的一些API的實現是同實現相關的,因此需要開發這個core.so由開發者來實現,在
Gst-omx中可以通過config來定義使用的core.so文件
     Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件
比如stagefright中的TI的實現中:
      OMX_ERRORTYPE TIOMX_Init()
     {
          eError = TIOMX_BuildComponentTable(); //component table的定義就是同實現相關的
     }
     //component name : role
     char *tComponentName[MAXCOMP][2] = {
   
    //{"OMX.TI.JPEG.decoder", "image_decoder.jpeg" },
    {"OMX.TI.JPEG.Encoder", "image_encoder.jpeg"},
    //{"OMX.TI.Video.Decoder", "video_decoder.h263"},
    {"OMX.TI.Video.Decoder", "video_decoder.avc"},
    //{"OMX.TI.Video.Decoder", "video_decoder.mpeg2"},
    {"OMX.TI.Video.Decoder", "video_decoder.mpeg4"},
    {"OMX.TI.Video.Decoder", "video_decoder.wmv"},
    {"OMX.TI.Video.encoder", "video_encoder.mpeg4"},
    {"OMX.TI.Video.encoder", "video_encoder.h263"},
    {"OMX.TI.Video.encoder", "video_encoder.avc"},


從上面這個圖中可以看到,GSTREMAER的GST-OMX確實只是通過GOMXCORE(omxcore)來調用GetHandler得到component 的handle後來操作omx component。因此可以認為GST-OMX只是一個OMX IL Client而已。

GST-OMX和OMX IL 工作機制
  通過playbin2來調用omx中實現的decoder,由於decodebin是一個filter類型,因此在filter類型初始化中:
   type_instance_init()會創建一個gomx_core對象來調用OMX IL API;
  {
     self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class)); //打開config中的
                                     omxcore.so,並調用get_handler得到component的IL handler。
     self->in_port = g_omx_core_new_port (self->gomx, 0);
     self->out_port = g_omx_core_new_port (self->gomx, 1);

    //gstreamer這邊對應的sinkpad和srcpad,並且為pad上設置chain函數和event
    self->sinkpad =
      gst_pad_new_from_template (gst_element_class_get_pad_template
      (element_class, "sink"), "sink");
  //push-based schedule機制
   gst_pad_set_chain_function (self->sinkpad, pad_chain);
   gst_pad_set_event_function (self->sinkpad, pad_event);

   self->srcpad =
      gst_pad_new_from_template (gst_element_class_get_pad_template
      (element_class, "src"), "src");

   gst_pad_set_activatepush_function (self->srcpad, activate_push);

   gst_pad_use_fixed_caps (self->srcpad);

   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
  }
 另外,由於decodebin是一個filter,包含input/output port,因此同樣為OMX生成2個port。在Gstreamer這邊
 port對應的就是pad(src_pad,sink_pad)。
       Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

在pad_chain()函數中:完成OMX從loaded->idle的跳轉和port上資源的分配工作
static GstFlowReturn pad_chain (GstPad * pad, GstBuffer * buf)
{
  if (self->omx_setup) {
      self->omx_setup (self);
    }

    setup_ports (self); //調用get_parameter()得到port上的參數nBufferCountActual/nBufferSize來初始
                          化port(in,out),並將gstreamer的pad和Omx port連接起來(需要注意的是這裡要
                          確定是allocate_buffer()還是use_buffer()的方式)

    g_omx_core_prepare (self->gomx);//調用omx的sendCommand(),驅動omx狀態機從loaded->idle,分配port
                                      buffer

}

//PORT相關的函數 
static void
setup_ports (GstOmxBaseFilter * self)
{
 
  g_omx_port_setup (self->in_port);
  gst_pad_set_element_private (self->sinkpad, self->in_port);

 
  g_omx_port_setup (self->out_port);
  gst_pad_set_element_private (self->srcpad, self->out_port);

 
  if (g_getenv ("OMX_ALLOCATE_ON")) {
    GST_DEBUG_OBJECT (self, "OMX_ALLOCATE_ON");
    self->in_port->omx_allocate = TRUE;  //True:使用OMX的allocate_buffer方式;false:use_buffer
    self->out_port->omx_allocate = TRUE;
    self->share_input_buffer = FALSE;
    self->share_output_buffer = FALSE;
  } else if (g_getenv ("OMX_SHARE_HACK_ON")) {
    GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_ON");
    self->share_input_buffer = TRUE;
    self->share_output_buffer = TRUE;
  } else if (g_getenv ("OMX_SHARE_HACK_OFF")) {
    GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_OFF");
    self->share_input_buffer = FALSE;
    self->share_output_buffer = FALSE;
  } else {
    GST_DEBUG_OBJECT (self, "default sharing and allocation");
  }

  GST_DEBUG_OBJECT (self, "omx_allocate: in: %d, out: %d",
      self->in_port->omx_allocate, self->out_port->omx_allocate);
  GST_DEBUG_OBJECT (self, "share_buffer: in: %d, out: %d",
      self->share_input_buffer, self->share_output_buffer);
}


void
g_omx_core_prepare (GOmxCore * core)
{
  change_state (core, OMX_StateIdle); //OMX狀態機 從 loaded->idle

 
  core_for_each_port (core, port_allocate_buffers); //調用allocate_buffers來為port分配buffer。

  wait_for_state (core, OMX_StateIdle);
}

static void
port_allocate_buffers (GOmxPort * port)
{
  guint i;
  gsize size;

  size = port->buffer_size;

  for (i = 0; i < port->num_buffers; i++) {
    if (port->omx_allocate) {
      GST_DEBUG_OBJECT (port->core->object,
          "%d: OMX_AllocateBuffer(), size=%" G_GSIZE_FORMAT, i, size);
      OMX_AllocateBuffer (port->core->omx_handle, &port->buffers[i],
          port->port_index, NULL, size);
    } else {
      gpointer buffer_data;
      buffer_data = g_malloc (size);
      GST_DEBUG_OBJECT (port->core->object,
          "%d: OMX_UseBuffer(), size=%" G_GSIZE_FORMAT, i, size);
      OMX_UseBuffer (port->core->omx_handle, &port->buffers[i],
          port->port_index, NULL, size, buffer_data);
    }
  }
}

然而,對於很多情況來說,上面port上的參數很多都是default值,比如buffer的大小和數目,在實際中這個
設置可能不是正確的,因此如果實際buffer的需求超過了現在使用default參數初始化的port上的設置,底層
會發出"portSettingChange"來通知gst-omx,要求gst-omx重新根據實際的需求來分配port上的buffer.
Gst-omx需要提供幾個callback函數:
   static OMX_CALLBACKTYPE callbacks =
    { EventHandler, EmptyBufferDone, FillBufferDone };
在get_handler()是註冊給component來使用。其中EventHandler()中就是需要來處理component發給client(gst-omx)的event,其中就包括OMX_EventPortSettingsChanged


buffer數據驅動:
 在OMX中的數據驅動方式如下:
       Linux <wbr>Gstreamer <wbr>and <wbr>GST-OMX插件

在OMX狀態機狀態從loaded->idle後,資源分配完成。下面開始進入

static GstFlowReturn pad_chain (GstPad * pad, GstBuffer * buf)
{
  if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded)) {
   if (self->omx_setup) {
      self->omx_setup (self);
    }

    setup_ports (self);

    g_omx_core_prepare (self->gomx);

    if (gomx->omx_state == OMX_StateIdle) {
      self->ready = TRUE;
      gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
    }
  }

}
 
static void output_loop (gpointer data)
{
   if (G_LIKELY (out_port->enabled)) { //初始化為enable
      OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
      omx_buffer = g_omx_port_request_buffer (out_port); //從port buffer queue中得到一個空的buffer
     
      //對輸入buffer,填充數據
      //調用
      g_omx_port_release_buffer (out_port, omx_buffer);

  }
}

//調用fillthisbuffer和emptythisbuffer,開始傳遞buffer和數據
void g_omx_port_release_buffer (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
{
  switch (port->type) {
    case GOMX_PORT_INPUT:
      OMX_EmptyThisBuffer (port->core->omx_handle, omx_buffer);
      break;
    case GOMX_PORT_OUTPUT:
      OMX_FillThisBuffer (port->core->omx_handle, omx_buffer);
      break;
    default:
      break;
  }
}