gstreamer のエレメントを作る
Jetson Orin でgstreamerのエレメントを作ってみます。
準備
参考にしたページ
gst-plugins-bad/tools
にあるgst-element-maker
を使いたいのでその準備をします。
Jetson Orinのgstreamerは1.16.2なので、それに合わせます。
$ cd ~/work/src/gst/
$ git clone https://github.com/GStreamer/gst-plugins-bad.git
$ cd gst-plugins-bad
$ git checkout -b w1.16.2 1.16.2
$ sudo apt install autopoint automake
$ NOCONFIGURE=1 ./autogen.sh
$ sudo cp common/gst-indent /usr/local/bin/
$ sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-bad1.0-dev indent
gst-indent
はgstreamerの流儀でのソースコードの整形をおこなってくれます。
$ gst-indent --help
usage: indent file [-o outfile ] [ options ]
indent file1 file2 ... fileN [ options ]
myfakesink の作成
filesink
の構成を調べると、これはGstBaseSinkを継承していることがわかりました。これを真似します。
$ gst-inspect-1.0 filesink
...
GObject
+----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstBaseSink
+----GstFileSink
basesinkを雛形にしてエレメントのソースコードを生成します。
$ mkdir myfakesink
$ cd myfakesink/
$ ~/work/src/gst/gst-plugins-bad/tools/gst-element-maker myfakesink basesink
自動で、gstmyfakesink.h, gstmyfakesink.cを生成して、そこから共有ライブラリをビルドするところまでやってくれました。
ビルドしたときにどのようなオプションを使ったのかを知るために、もう一度ログをとりながら実行します。
$ sh -x ~/work/src/gst/gst-plugins-bad/tools/gst-element-maker myfakesink basesink > log 2>&1
これをもとに以下のようなMakefileを作成しました。
TARGET = libgstmyfakesink.so
OBJS = gstmyfakesink.o
CC = gcc
PACKAGES = gstreamer-1.0 gstreamer-base-1.0
CFLAGS = -Wall -Werror -fPIC $(shell pkg-config --cflags $(PACKAGES))
LDLIBS = $(shell pkg-config --libs $(PACKAGES))
$(TARGET): $(OBJS)
$(CC) -shared -o $@ $< $(LDLIBS)
clean:
rm -f $(TARGET) $(OBJS)
install: $(TARGET)
cp $(TARGET) ${HOME}/.local/share/gstreamer-1.0/plugins/
%.o: %.c
gst-indent $<
$(CC) $(CFLAGS) -c -o $@ $<
$ make install
gst-indent gstmyfakesink.c
gcc -Wall -Werror -fPIC -pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include -c -o gstmyfakesink.o gstmyfakesink.c
gcc -shared -o libgstmyfakesink.so gstmyfakesink.o -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0
cp libgstmyfakesink.so /home/koba/.local/share/gstreamer-1.0/plugins/
以下のスクリプトで動かしてみます。
#!/bin/sh -eux
WIDTH=1280
HEIGHT=720
FRAMERATE=30
GST_DEBUG_NO_COLOR=1 GST_DEBUG=myfakesink:6 gst-launch-1.0 -v v4l2src device="/dev/video0" ! \
"image/jpeg, width=$WIDTH, height=$HEIGHT, framerate=$FRAMERATE/1" ! \
nvv4l2decoder mjpeg=1 ! 'video/x-raw(memory:NVMM)' ! \
nvvidconv ! 'video/x-raw, format=(string)I420' ! \
myfakesink
gstfilesink.c
をまねして以下のように修正したらストリームが流れるようになりました。
@@ -90,8 +90,7 @@ static GstStaticPadTemplate gst_myfakesink_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/unknown")
- );
+ GST_STATIC_CAPS_ANY);
/* class initialization */
@@ -317,11 +316,20 @@ gst_myfakesink_unlock_stop (GstBaseSink * sink)
static gboolean
gst_myfakesink_query (GstBaseSink * sink, GstQuery * query)
{
+ gboolean res;
GstMyfakesink *myfakesink = GST_MYFAKESINK (sink);
- GST_DEBUG_OBJECT (myfakesink, "query");
+ GST_DEBUG_OBJECT (myfakesink, "query: GST_QUERY_TYPE (query)=%d",
+ GST_QUERY_TYPE (query));
- return TRUE;
+ switch (GST_QUERY_TYPE (query)) {
+ default:
+ res =
+ GST_BASE_SINK_CLASS (gst_myfakesink_parent_class)->query (sink,
+ query);
+ break;
+ }
+ return res;
}
/* notify subclass of event */
これで動作を確認しつつ、実装を増やしていきます。
余談
自作したエレメントをどこに置いたら認識してもらえるのか? 実験途中のものをいきなり /lib/aarch64-linux-gnu/gstreamer-1.0/
に置くのは気が引けますね。間違って余計なものを消してしまう恐れもあるし。
結果として ${HOME}/.local/share/gstreamer-1.0/plugins/
に置けばよいということがわかったのですが、それは strace -f -o st.log gst-inspect-1.0 myfakesink
とやって、そのログでオープンしているディレクトリから見当をつけました。
そこから検索して、公式ドキュメントの記載を見つけました。
余談2
makeの中でgst-indent
を実行するのはあまりよくないかなと思って、いったんそれを削除。
そうすると、 .c
から .o
を作るとところはデフォルトのままでよいのでレシピを削除。
Makefileはこうなりました。
TARGET = libgstmyfakesink.so
OBJS = gstmyfakesink.o
CC = gcc
PACKAGES = gstreamer-1.0 gstreamer-base-1.0
CFLAGS = -Wall -fPIC $(shell pkg-config --cflags $(PACKAGES))
LDLIBS = $(shell pkg-config --libs $(PACKAGES))
$(TARGET): $(OBJS)
$(CC) -shared -o $@ $< $(LDLIBS)
clean:
rm -f $(TARGET) $(OBJS)
install: $(TARGET)
cp $(TARGET) ${HOME}/.local/share/gstreamer-1.0/plugins/
make
のデフォルトのレシピは以下のようにすることで確認できます。
$ make -p |less
デフォルトは以下のようになっていることがわかります。
...
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
...
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
余談3
Makefileにヘッダファイルに依存関係を書いていませんでした。こちらの記事で追加しました。
参考
Discussion