Debian GNU/Linux (amd64, stretch)にて確認。
この文書では、以下のGStreamerエレメントを作る
- guint32をインクリメントして出力し続けるnumbersrc
- numbersrcを受けて数字を2倍して出力するtwicefilter
- 結果を出力するnumbersink
チュートリアル等を参照しながら手探りで実行した結果なので間違いあるかも。
前準備
パッケージインストール
$ sudo apt install build-essential libgstreamer1.0-dev indent
エレメント雛形作成スクリプト(gst-element-maker)がGNUindentを使用するため一緒にインストールしている。
ツールのコピー
Debianだと残念ながらgst-plugins-badに入っているはずのgst-element-maker
が無いため、リポジトリからコピーする。
$ git clone https://anongit.freedesktop.org/git/gstreamer/gst-plugins-bad.git
$ cd gst-plugsins-bad/tools
$ cp -r gst-element-maker element-templates <パスが通ったディレクトリ>
あとgst-element-maker
から呼ばれるgst-indent
もコピーする。
$ git clone https://anongit.freedesktop.org/git/gstreamer/gstreamer.git
$ cd gstreamer/tools
$ cp gst-indent <パスが通ったディレクトリ>
エレメント作成
ソースとシンクを作る
basesrcを継承してnumbersrc, basesinkを継承してnumbersinkを作成する。
$ gst-element-maker numbersrc basesrc
$ gst-element-maker numbersink basesink
gstnumbersrc.c, gstnumbersrc.h, gstnumbersink.c, gstnumbersink.hの4ファイルが作成され、ビルドまでしてgstnumbersrc.so, gstnumbersink.soが作成される。
Makefileを追加しビルド出来るようにしたものが以下
https://github.com/maueki/learning-gstreamer/tree/tag_add_makefile
だが実行してみるとエラーがでてしまう。
$ GST_PLUGIN_PATH=. gst-launch-1.0 numbersrc ! numbersink
(gst-launch-1.0:36307): GStreamer-CRITICAL **: gst_mini_object_ref: assertion 'mini_object != NULL' failed
(以下エラーいろいろ)
WARNING: erroneous pipeline: numbersrc0 を numbersink0 へリンクできません
原因はgst-element-maker
で作成されたファイルではGstBaseSrcやGstBaseSinkのvmethodをオーバーライドしているが、NULLを返してしまったりとあまりよろしくない実装をしてしまっているためである。
ソース側はfill()
、シンク側はrender()
がオーバーライドされていれば最低限動作するため、それ以外のオーバーロードを無効にしたものが以下
https://github.com/maueki/learning-gstreamer/tree/tag_1st_run
ビルドして実行してみると
$ GST_PLUGIN_PATH=. gst-launch-1.0 numbersrc ! numbersink
パイプラインを一時停止 (PAUSED) にしています...
Pipeline is PREROLLING ...
Pipeline is PREROLLED ...
パイプラインを再生中 (PLAYING) にしています...
New clock: GstSystemClock
無事動作した。
ソースからシンクへデータを受け渡す
ソースのgst_numbersrc_fill()
を修正しデータを送ってみる
static GstFlowReturn
gst_numbersrc_fill (GstBaseSrc * src, guint64 offset, guint size,
GstBuffer * buf)
{
static guint32 i = 0;
GstNumbersrc *numbersrc = GST_NUMBERSRC (src);
GstMapInfo info;
GST_DEBUG_OBJECT (numbersrc, "fill");
if (size < sizeof(i)) {
GST_ERROR_OBJECT(numbersrc, "gst_numbersrc_fill: size too short");
return GST_FLOW_ERROR;
}
if (!gst_buffer_map (buf, &info, GST_MAP_WRITE))
return GST_FLOW_ERROR;
guint8 *data = info.data;
memcpy(data, &i, sizeof(i));
i++;
gst_buffer_unmap (buf, &info);
gst_buffer_resize(buf, 0, sizeof(i));
return GST_FLOW_OK;
}
gst_numbersrc_fill()
が呼び出されるたびにインクリメントされる変数のメモリ内容を送るだけのものだ。
シンク側は送られてきたバッファをgst_util_dump_mem()
でダンプする。
static GstFlowReturn
gst_numbersink_render (GstBaseSink * sink, GstBuffer * buffer)
{
GstNumbersink *numbersink = GST_NUMBERSINK (sink);
GST_DEBUG_OBJECT (numbersink, "render");
GstMapInfo info;
if (gst_buffer_map (buffer, &info, GST_MAP_READ)) {
gst_util_dump_mem (info.data, info.size);
gst_buffer_unmap (buffer, &info);
}
return GST_FLOW_OK;
}
実行してみる
$ GST_PLUGIN_PATH=. gst-launch-1.0 numbersrc ! numbersink
(snip)
00000000 (0x7ff294004490): 14 35 05 00 .5..
00000000 (0x7ff294007090): 15 35 05 00 .5..
00000000 (0x7ff294004490): 16 35 05 00 .5..
00000000 (0x7ff294007090): 17 35 05 00 .5..
00000000 (0x7ff294004490): 18 35 05 00 .5..
00000000 (0x7ff294007090): 19 35 05 00 .5..
インクリメントされたメモリ内容がダンプされているのが見て取れる。
トランスフォームエレメントの作成
numbersrcを受けて2倍にして出力するtwicefilterを作ってみる
$ gst-element-maker twicefilter basetransform
ここではベースクラスとしてソース、シンクが1対1で対応するbasetransformを使用した。
例によって自動生成された実装はあまりよろしくないため、base_transform_class.transformへの登録以外はコメントアウトし、gst_twicefilter_transform()
を以下のように実装した
/* transform */
static GstFlowReturn
gst_twicefilter_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstTwicefilter *twicefilter = GST_TWICEFILTER (trans);
GST_DEBUG_OBJECT (twicefilter, "transform");
GstMapInfo iinfo;
if (!gst_buffer_map (inbuf, &iinfo ,GST_MAP_READ))
return GST_FLOW_ERROR;
guint32 i=0;
memcpy(&i, iinfo.data, sizeof(i));
gst_buffer_unmap(inbuf, &iinfo);
i*=2;
GstMapInfo oinfo;
if (!gst_buffer_map(outbuf, &oinfo, GST_MAP_WRITE))
return GST_FLOW_ERROR;
memcpy(oinfo.data, &i, sizeof(i));
gst_buffer_unmap(outbuf, &oinfo);
gst_buffer_resize(outbuf, 0, sizeof(i));
return GST_FLOW_OK;
}
かなりテキトウな実装だけどご勘弁。inbuf
から数字を取り出し2倍してoutbuf
へ格納しているだけ。
ビルドしたらgst-launch-1.0
で動作を確認してみる
$ GST_PLUGIN_PATH=. gst-launch-1.0 numbersrc ! twicefilter ! numbersink
(snip)
00000000 (0x55870716e6f0): 90 a7 01 00 ....
00000000 (0x55870716e790): 92 a7 01 00 ....
00000000 (0x7fd3140060a0): 94 a7 01 00 ....
00000000 (0x7fd314006140): 96 a7 01 00 ....
00000000 (0x7fd3140061e0): 98 a7 01 00 ....
00000000 (0x7fd314006280): 9a a7 01 00 ....
数字が2つ飛びになっており、たしかに2倍されていることがわかる。