今日は Chapter 5. The chain funtion についてです。
※ Day13 の環境を前提にこれからお話しするので、まだDay13を見てない人は、まずはそちらで環境構築を!
やりたいことを書く _chain()
Chapter 5 にも書いているように _chain()
は「プラグインでやりたいこと」を実装する場所です。「プラグイン作りたいなー」と思ってまず弄っていくのはここということになります。
バケツリレーな GStreamer の処理
Element は好きな処理をした後pad_push()
するのが、 GStreamer のルールです。
上流の Element が pad_push()
すると、_chain()
の第3引数に GstBuffer
が入ってきます。そして、なんらかの「やりたいこと」を処理したあと、GstBuffer
を pad_push()
します。
pad_push()
されると下流の_chain()
が実行され、バケツリレーの要領で_chain()
が次々と実行されていきます。(まさにパイプラインです!)
パイプラインの実装は?
この動きは gstpad.c
に書かれています。
下流のElementの_chain()
を呼ぶのは gstpad.c のこの行なので、ここからどんどん遡っていくとgst_pad_push()
に巡りあえます :)
_chain を編集してみよう
さて、pad_push()
→ _chain()
の概念を知ったところで Boilerplate のコードに手を入れてみましょう。
※ GstBuffer についてはyashi さんの Day 12で解説されているのでここでは省きます。
ここから、ここまで を _chain()
に追加したらさっそくビルドしましょう。
/* chain function
* this function does the actual processing
*/
static GstFlowReturn
gst_plugin_template_chain(GstPad * pad, GstObject * parent, GstBuffer * buf)
{
GstPluginTemplate *filter;
filter = GST_PLUGIN_TEMPLATE(parent);
if (filter->silent == FALSE)
g_print("I'm plugged, therefore I'm in.\n");
// ここから
{
GstMapInfo info;
gst_buffer_map(buf, &info, GST_MAP_READ);
g_print("%s", info.data);
gst_buffer_unmap(buf, &info);
}
// ここまで
/* just push out the incoming buffer without touching it */
return gst_pad_push(filter->srcpad, buf);
}
早く動かしたい気持ちはぐっとこらえつつ、メモ帳や echo コマンドなどで、input
というファイルを作りましょう。
$ echo "hoge" > input
さあ、やっと実行です!
$ GST_PLUGIN_PATH=`pwd` gst-launch-1.0.exe filesrc location=input ! plugin silent=true ! fakesink
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
hoge
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 0:00:00.000122404
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...
filesrc から input を読み込み、plugin がそれをハンドルして、hoge
と表示してくれましたね!
plugin の開発というと敷居が高い感じがしますが、簡単なものはたったこれだけで作れるのです。ぜひ遊んでみてください :)