2017年12月22日 星期五

GCC: the --start-group and --end-group command line options

https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options

https://linux.die.net/man/1/ld

-( archives -) or --start-group archives --end-group
The archives should be a list of archive files. They may be either explicit file names, or -l options.
The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched only once in the order that it is specified on the command line. If a symbol in that archive is needed to resolve an undefined symbol referred to by an object in an archive that appears later on the command line, the linker would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all possible references are resolved.
Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular references between two or more archives.

2017年12月11日 星期一

[轉] [C/C++] 靜態函式 (static function) 2011

static function is a function whose scope is limited to the current source file.  Scope refers to the visibility of a function or variable. If the function or variable is visible outside of the current source file, it is said to have global, or externalscope. If the function or variable is not visible outside of the current source file, it is said to have local, or static scope.
意思是說靜態函式只能被該檔案所看見,其它檔案無法得知該檔案是否有其靜態函式。
有一些 C 的語法,在 C++ 的程序員相對少用。但就是因為這個原因,有時就會忽略了。
假設我們有一個Header檔 Foo.h
static void f1(){
cout << “f1()" << endl;
}
void f2(){
cout << “f2()" << endl;
}
f1 和 f2 的差別在於 static 這個 keyword 。在這裡的 f1 被宣告和定義為 static ,是指它只在這個 Compilation Unit 中生效。而 f2 沒有被定義為 static ,亦即是它可以被其他 Compilation Unit 訪問。
但到底什麼是 Compilation Unit 呢?首先,一個程式編譯過程如下:
compliation_process這裡的 a.cpp , b.cpp 和 c.cpp 也 引入了 Foo.h 這個檔案,經過前處理器後,Foo.h 的內容會被加入到 a.cpp, b.cpp 和 c.cpp 中,再經過編譯器,變成為 a.o , b.o 和 c.o 這些目的碼,最後經過連結器,變成執行檔
要留意的地方是,每個經過前處理器處理後的.cpp 檔,和它的目的檔是一一對應的,而Compilation Unit,就是這些被處理後的.cpp 檔了。
若以Foo.h 的 f1 為例子,雖然在每個 .cpp 檔也被定義了,但經過編譯後,所有的f1 也會被隱藏在自己的目的檔中,連結器在找尋symbol的過程中,是會忽略的。
但f2 就不同了,所有的f2 在目的檔中,也是不會被隱藏,所以在連結器找尋symbol,會找到多份的f2,那連結就會有錯誤了。
所以在大部份的情況下,在Header檔中定義函數,也是需要 static 這個 keyword 的。就算加上了 inline,情況也是一樣的。
static inline void f3(){
cout << “f3()" << endl;
}

2017年12月6日 星期三

link unused library as needed

https://lists.ubuntu.com/archives/ubuntu-devel/2010-November/031991.html

There is a second change to the linking in natty; as announced in [1], 
--no-add-needed/--no-copy-dt-needed-entries is passed by default, with the 
current gcc in natty, --as-needed is passed as well.  Please see [2] for 
implications (runtime failures) and a list of packages which might be affected.

To revert this change on a per package basis, pass --no-as-needed to the linker 
(-Wl,--no-as-needed in LDFLAGS).  To add an explicit dependency on a library use 
--no-as-needed -lfoo --as-needed.
-Wl,--no-as-needed -lfoo -Wl,--as-needed
Please tag bug reports with `as-needed' if you see runtime failures caused by 
this change (mostly unresolvable symbols referenced by plugins and ldopened 
objects).

2017年12月5日 星期二

h.265 (hevc)

alignment=au means that each output buffer contains the NALs for a whole 
picture. alignment=nal just means that each output buffer contains 
complete NALs, but those do not need to represent a whole frame

https://www.kancloud.cn/digest/hevc-fred/181914

https://mp.weixin.qq.com/s/r5_gO-I0WM-1sv3_vyVBeg



2017年12月4日 星期一

[轉] gstreamer學習筆記(3):message,event,signal區別


  • message
    在gstreamer中,message或者說Bus message(因為message都是在GSTBus上傳遞的),是用於gstreamer和application之間交互用的,比如當一個文件播放結束的時候,gstreamer會發一個EOS的message到GstBus上,如果app有去偵聽(函數gst_bus_add_watch),那麼在處理消息的callback函數中就可以收到這個消息。
  • event
Most of the event API is used inside plugins. Applications usually only construct and use seek events. To do that gst_event_new_seek() is used to create a seek event. It takes the needed parameters to specify seeking time and mode.
以上是關於GstEvent描述的一部分內容,也就是說,一般來說event是用於gstreamer內部element與element之間(或者說pad與pad之間)傳遞事件的,比如source element的數據已經結束了,那麼他就會發出一個EOS event,然後順著pipeline依次向down stream的方向傳遞, 這些elements可以得到通知,從而做一些cleanup的工作,當最終所有的sink element都收到並處理了這個EOS event之後,gstreamer內部就是產生一條GSTMessage,並post至GstBus,如果APP有監聽,那麼它就能知道當前播放已經結束了。 
而對於APP能用的就只有一個seek event。
  • signal
    signal不是gstreamer特有的東西,它是來自於GObject體系,是用於app和GObject之間進行交互的一種機制。在gstreamer中,element本身也是gobject,所以,通過signal,就可以將app和element聯繫起來。 
    當element發生了一些事情相讓app知道時,就可以用signal的方式來通知app比如動態創建了一個Pad。當然也可以在element與element之間使用, 比如在Gstplaybin當中就會偵聽uridecoderbin發出來的autoplug-factories,autoplug-select等信號。
signal和Bus message不同,bus message是pipeline上的,一般是app和pipeline交互的一種方法。signal則具體到了每個element。
整體框圖如(此圖來自網絡): 
這裡寫圖片描述

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