もし本当に GStreamer の pipeline に入っているエレメントの名前が分らなかったら?
pipeline は自分が持っているエレメントを知っています。なので、pipeline に問い合わせて、持っているエレメントをイテレーターで貰うことができます。これ、pipeline の親クラスである GstBin
の機能なんです。
Ruby のように Internal Iterator (内部イテレータ)かつ、Dynamic Typing (動的型付け) であれば
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pipeline.each do |elem| | |
puts elem.name | |
end |
と書けるのですが、C で実装されている GStreamer では、ちょっと面倒ですね。
- Pipelineから外部イテレータを貰い (
gst_bin_iterate_elements()
) - 次のエレメントをイテレーターから貰います。(
gst_iterator_next()
) - 貰ったエレメントは、実は GValue という「なんでも内包できる構造体」なので、これから実際のエレメントを取り出します。 (
g_value_get_object()
)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <gst/gst.h> | |
gboolean on_message(GstBus *bus, GstMessage *message, gpointer p) | |
{ | |
GMainLoop *mainloop = p; | |
(void)bus; | |
if ((GST_MESSAGE_TYPE(message) & GST_MESSAGE_EOS)) | |
g_main_loop_quit(mainloop); | |
return TRUE; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
GMainLoop *mainloop; | |
GstElement *pipeline; | |
GError *error = NULL; | |
GstBus *bus; | |
GstIterator *itr; | |
GstElement *elem; | |
GValue val = G_VALUE_INIT; | |
gboolean done = FALSE; | |
gst_init(&argc, &argv); | |
mainloop = g_main_loop_new(NULL, FALSE); | |
pipeline = gst_parse_launch("filesrc location=a.txt ! fdsink", &error); | |
bus = gst_element_get_bus(pipeline); | |
gst_bus_add_watch(bus, on_message, mainloop); | |
itr = gst_bin_iterate_elements(GST_BIN(pipeline)); | |
while (!done) { | |
switch (gst_iterator_next(itr, &val)) { | |
case GST_ITERATOR_OK: | |
elem = g_value_get_object(&val); | |
g_print("name: %s\n", gst_element_get_name(elem)); | |
g_value_unset(&val); | |
break; | |
default: | |
done = TRUE; | |
break; | |
} | |
} | |
gst_element_set_state(pipeline, GST_STATE_PLAYING); | |
g_main_loop_run(mainloop); | |
return 0; | |
} |
gst_iterator_foreach()
もあるのですが Lambda が使えない C では、関数を指定する必要があります。
GValue は、なんでも入れることができるという点で、「void*」のようなものですが、型情報を持っている点が異なります。型が必須なので必ず使う前に G_VALUE_INIT
または g_value_init()
で初期化してください。
GValue や GstElement は、Dynamic Typing を持っていない C のために実装された Glib Dynamic Type System を使っています。 GObject が基本クラスです。Ruby C API で言うところの、 VALUE
ですね。
他のエレメントを内包できるエレメントは、イテレーターが使えることが多いので、一度やり方を覚えると便利です。お試しあれ。
No comments:
Post a Comment