gstreamermmでGStreamerのチュートリアル1
卒研で使うThe Imaging Source社の産業用カメラをLinuxで制御する1ためにマルチメディアフレームワークのGStreamerを使うことになりそうなので、その練習をしている。
卒研ではOpenCVと組み合わせる予定なので、C++で書けると扱いやすい。GStreamerはC言語で書かれたライブラリだが、C++ラッパーのgstreamermmが用意されているので、これを使うことにした。
GStreamer公式の説明ページにはチュートリアルがいくつか用意されている。今回は最初のチュートリアル1を、gstreamermmを使って書いてみた。
開発環境
ライブラリのインストール
Homebrewを使って必要なライブラリをインストールした。
サンプル動画を再生するために、libvpxおよびlibvorbisとのリンクが必要。また brew link --force gettext
が必要になる。これを行わないと、書いたプログラムのリンクの際に「libintlが見つからない」というエラーが出た。後に問題が発生したら brew unlink gettext
を行う必要があるかもしれない。
brew install pkg-config gstreamer gst-plugins-good gettext brew install gst-plugins-base --with-libogg --with-libvorbis brew install gst-plugins-bad --with-libpng --with-libvpx brew link --force gettext
ソースコード
CMakeLists.txt
「CMake 簡易まとめ」を参考にした。
cmake_minimum_required(VERSION 3.0) project(tutorial CXX) find_package(PkgConfig) pkg_check_modules(GSTREAMERMM REQUIRED gstreamermm-1.0) set(CMAKE_CXX_FLAGS "-std=c++11 -Wall") set(CMAKE_CXX_FLAGS_DEBUG "-g3 -O0 -pg") set(CMAKE_CXX_FLAGS_RELEASE "-O2 -s -DNDEBUG -march=native") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g3 -Og -pg") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -s DNDEBUG -march=native") add_executable(tutorial01 tutorial01.cpp) target_include_directories(tutorial01 PUBLIC ${GSTREAMERMM_INCLUDE_DIRS}) target_link_libraries(tutorial01 ${GSTREAMERMM_LIBRARIES}) target_compile_options(tutorial01 PUBLIC ${GSTREAMERMM_CFLAGS_OTHER})
tutorial01.cpp
チュートリアルのコードをgstreamermmを使って書き直した。
#include <gstreamermm-1.0/gstreamermm.h> int main(int argc, char* argv[]) { // GStreamerを初期化する Gst::init(argc, argv); // パイプラインを構築する Glib::RefPtr<Gst::Element> pipeline = Gst::Parse::launch( "playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm" ); // 再生を開始する pipeline->set_state(Gst::STATE_PLAYING); { // エラーまたはEOSまで待つ Glib::RefPtr<Gst::Bus> bus = pipeline->get_bus(); Glib::RefPtr<Gst::Message> msg = bus->pop( Gst::CLOCK_TIME_NONE, Gst::MESSAGE_ERROR | Gst::MESSAGE_EOS ); } // リソースを解放する pipeline->set_state(Gst::STATE_NULL); return 0; }
C言語で書かれたチュートリアルのコードは以下のとおり。
#include <gst/gst.h> int main(int argc, char *argv[]) { GstElement *pipeline; GstBus *bus; GstMessage *msg; /* Initialize GStreamer */ gst_init (&argc, &argv); /* Build the pipeline */ pipeline = gst_parse_launch ("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL); /* Start playing */ gst_element_set_state (pipeline, GST_STATE_PLAYING); /* Wait until error or EOS */ bus = gst_element_get_bus (pipeline); msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); /* Free resources */ if (msg != NULL) gst_message_unref (msg); gst_object_unref (bus); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); return 0; }
ビルド
CMakeの慣習に従い、buildディレクトリを作ってその中でビルドする。
cd /path/to/tutorial01 mkdir build cd build cmake .. make
実行
ビルドしたら以下のコマンドで実行することができる。
./tutorial01
実行するとウィンドウが表示され、https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm の再生が始まる。最後まで再生されると終了する。
C言語で書かれたものとの違い
生ポインタの代わりにGlib::RefPtrを使う
例えば GstElement *
型が返る関数のgstreamermm版では Glib::RefPtr<Gst::Element>
が返る。
Glib::RefPtr(リファレンス)はglibmmが提供する参照カウンタ式のスマートポインタクラスで、C++11のstd::shared_ptrに似ている。デストラクタでカウントが1減り、0になったときにリソースが解放される。このスマートポインタのおかげで、gst_object_unref()
に相当する ->unreference()
を呼び出さなくてもよくなる。
上のコードではポインタを使用する範囲をブロックにした。ブロックを抜ける際にデストラクタが呼ばれ、C言語版とほぼ同じ場所で ->unreference()
が呼ばれることになる。
一部の関数のインターフェースが異なる
多くの関数のgstreamermm版はC言語版からの規則的な変換で書けるが、一部インターフェースが異なるものがある。上の例だと、gst_bus_timed_pop_filtered()
に対応する関数は Gst::Bus::pop(Gst::ClockTime timeout, Gst::MessageType message_type)
と、オーバーロードを利用したものになっている。
一つ一つドキュメントから探していけば良いのだが、インターネットでは現在の最新版1.8.0のドキュメントのページが空になっているため、少し不便になっている。gstreamermmをHomebrewでインストールした場合は /usr/local/opt/gstreamermm/share/doc/gstreamermm-1.0/reference/html/index.html からDoxygenで生成されたドキュメントを見ることができた。未確認だが、Linuxではlibgstreamermm-1.0-docのようなパッケージをインストールすれば閲覧できそうだ。
感想
常にリソース管理に注意しなければならないC++なので、スマートポインタでリソースの解放し忘れが減ることが嬉しい。慣れていないのでまだドキュメントを何度も見ているが、もともとGStreamerがオブジェクト指向で書かれているので、対応するgstreamermmの関数を見つけるのは難しくなかった。個人的にはC++11以降の書き方が気に入っていて、できるだけC++で書きたいと思うので、今後も積極的にgstreamermmを使っていきたい。
-
制御するためのLinux用ライブラリがGitHubで公開されている:
https://github.com/TheImagingSource/tiscamera↩