Gstreamer(2)

Gstreamer でプログラムを書いてみます。

 omxh264enc はビットレートを指定すると妙なノイズが入ります。デフォルトの設定では画質に満足できないので、プログラムにしたときに変化があるか試してみます。

videotestsrc を表示する

 コマンドラインから、gst-launch-1.0 testvideosrc num-buffers=30 ! autovideosink を実行した場合をプログラムします。

 次の内容にファイル view.c を作ります。

/* * example view.c * gst-launch-1.0 videotestsrc num-buffers=30 ! autovideosink */ #include <gst/gst.h> #include <glib.h> static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) { GMainLoop *loop = (GMainLoop *)data; switch( GST_MESSAGE_TYPE (msg) ) { case GST_MESSAGE_EOS: g_print("End of stream\n"); g_main_loop_quit(loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(msg, &error, &debug); g_free(debug); g_printerr("Error: %s\n", error->message); g_error_free(error); g_main_loop_quit(loop); break; } default: break; } return TRUE; } int main(int argc, char *argv[]) { GMainLoop *loop; GstElement *pipeline, *source, *sink; GstBus *bus; /* 初期化 */ gst_init(&argc, &argv); loop = g_main_loop_new(NULL, FALSE); /* エレメントの作成 */ pipeline = gst_pipeline_new("audio-player"); source = gst_element_factory_make("videotestsrc", "Test-Video-source"); sink = gst_element_factory_make("autovideosink", "video-output"); if( !pipeline || !source || !sink ) { g_printerr("One element could not be created. Exiting.\n"); return -1; } /* パラメータの設定 */ g_object_set(G_OBJECT(source), "num-buffers", 30, NULL); /* メッセージハンドラを設定 */ bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline)); gst_bus_add_watch(bus, bus_call, loop); gst_object_unref(bus); /* エレメントをパイプラインに追加 */ gst_bin_add_many(GST_BIN (pipeline), source, sink, NULL); /* エレメントのリンク */ gst_element_link (source, sink); /* パイプラインの再生 */ gst_element_set_state (pipeline, GST_STATE_PLAYING); /* 再生中 */ g_print ("Running...\n"); g_main_loop_run (loop); /* 終了処理 */ g_print ("Returned, stopping playback\n"); gst_element_set_state (pipeline, GST_STATE_NULL); g_print ("Deleting pipeline\n"); gst_object_unref (GST_OBJECT (pipeline)); return 0; }

 次の内容の Makefile を作ります。

TARGET=view LIBS:=$(shell pkg-config --libs gstreamer-app-1.0) CFLAGS:=$(shell pkg-config --cflags gstreamer-app-1.0) all : $(TARGET) view : view.o gcc -o $@ $< $(LIBS) .c.o : gcc $(CFLAGS) -c $< clean : rm -f *.o $(TARGET)

make で view が粉パイルできます。実行すれば、30 frame だけテスト映像が表示されます。

HDMI から取り込み表示する

 以下のコマンド相当のプログラムです。

gst-launch-1.0 -v v4l2src device=/dev/video0 ! \ videorate ! \ image/jpeg,width=1280,height=720,framerate=30/1 ! \ jpegdec ! videoconvert ! videoscale ! \ video/x-raw,width=640 ! ximagesink

 HDMIview.c を作詞します。内容は次のとおりです。

/* * example HDMIview.c * gst-launch-1.0 gst-launch-1.0 -v v4l2src device=/dev/video0 ! \ * videorate ! image/jpeg,width=1280,height=720,framerate=30/1 ! \ * jpegdec ! videoconvert ! videoscale ! video/x-raw,width=640 ! \ * ximagesink */ #include <gst/gst.h> #include <glib.h> static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) { GMainLoop *loop = (GMainLoop *)data; switch( GST_MESSAGE_TYPE (msg) ) { case GST_MESSAGE_EOS: g_print("End of stream\n"); g_main_loop_quit(loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(msg, &error, &debug); g_free(debug); g_printerr("Error: %s\n", error->message); g_error_free(error); g_main_loop_quit(loop); break; } default: break; } return TRUE; } int main(int argc, char *argv[]) { GMainLoop *loop; GstElement *pipeline, *source, *rate, *filter1, *decode, *convert, *scale, *filter2, *sink; GstCaps *filtercaps; GstBus *bus; /* 初期化 */ gst_init(&argc, &argv); loop = g_main_loop_new(NULL, FALSE); /* エレメントの作成 */ pipeline = gst_pipeline_new("video-player"); source = gst_element_factory_make("v4l2src", NULL); rate = gst_element_factory_make("videorate", NULL); filter1 = gst_element_factory_make("capsfilter", NULL); decode = gst_element_factory_make("jpegdec", NULL); convert = gst_element_factory_make("videoconvert", NULL); scale = gst_element_factory_make("videoscale", NULL); filter2 = gst_element_factory_make("capsfilter", NULL); sink = gst_element_factory_make("ximagesink", NULL); if( !pipeline || !source || !rate || !filter1 || !decode || !convert || !scale || !filter2 || !sink ) { g_printerr("One element could not be created. Exiting.\n"); return -1; } /* パラメータの設定 */ g_object_set(G_OBJECT(source), "device", "/dev/video0", NULL); /* フィルタ作成 */ filtercaps = gst_caps_new_simple("image/jpeg", "width", G_TYPE_INT, 1280, "height", G_TYPE_INT, 720, "framerate", GST_TYPE_FRACTION, 30, 1, NULL); g_object_set(G_OBJECT(filter1), "caps", filtercaps, NULL); gst_caps_unref(filtercaps); filtercaps = gst_caps_new_simple("video/x-raw", "width", G_TYPE_INT, 640, NULL); g_object_set(G_OBJECT(filter2), "caps", filtercaps, NULL); gst_caps_unref(filtercaps); /* メッセージハンドラの設定 */ bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); gst_bus_add_watch(bus, bus_call, loop); gst_object_unref(bus); /* エレメントをパイプラインに追加 */ gst_bin_add_many(GST_BIN(pipeline), source, rate, filter1, decode, convert, scale, filter2, sink, NULL); /* エレメントのリンク */ gst_element_link_many(source, rate, filter1, decode, convert, scale, filter2, sink, NULL); /* パイプライン再生 */ gst_element_set_state (pipeline, GST_STATE_PLAYING); /* 再生中 */ g_print ("Running...\n"); g_main_loop_run (loop); /* 終了処理 */ g_print ("Returned, stopping playback\n"); gst_element_set_state (pipeline, GST_STATE_NULL); g_print ("Deleting pipeline\n"); gst_object_unref (GST_OBJECT (pipeline)); return 0; }

 Makefile は次のようにします。

TARGET=view HDMIview LIBS:=$(shell pkg-config --libs gstreamer-app-1.0) CFLAGS:=$(shell pkg-config --cflags gstreamer-app-1.0) all : $(TARGET) .c.o : gcc $(CFLAGS) -c $< HDMIview : HDMIview.o gcc -o $@ $< $(LIBS) view : view.o gcc -o $@ $< $(LIBS) clean : rm -f *.o $(TARGET)

 HDMI から取り込んだ映像が表示されました。

omxh264enc を使ってエンコードしてみる

gst-launch-1.0 v4l2src device=/dev/video0 ! \ videorate ! \ image/jpeg,width=1280,height=720,framerate=30/1 ! \ jpegdec ! tee name=v \ v. ! queue ! videoconvert ! videoscale ! \ video/x-raw,width=640 ! ximagesink \ v. ! queue ! omxh264enc ! video/x-h264,profile=high ! \ h264parse config-interval=4 ! \ mpegtsmux ! filesink location=test.ts

 上記相当のプログラムです。HDMIrec.c を作成します。

/* * example HDMIrec.c * gst-launch-1.0 gst-launch-1.0 -v v4l2src device=/dev/video0 ! \ * videorate ! image/jpeg,width=1280,height=720,framerate=30/1 ! \ * jpegdec ! tee name=v \ * v. ! queue ! videoconvert ! videoscale ! * video/x-raw,width=640 ! ximagesink \ * v. ! queue ! omxh264enc ! video/x-h264,profile=high ! \ * h264parse config-interval=4 ! \ * mpegtsmux ! filesink location=test.ts */ #include <gst/gst.h> #include <glib.h> static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) { GMainLoop *loop = (GMainLoop *)data; switch( GST_MESSAGE_TYPE (msg) ) { case GST_MESSAGE_EOS: g_print("End of stream\n"); g_main_loop_quit(loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(msg, &error, &debug); g_free(debug); g_printerr("Error: %s\n", error->message); g_error_free(error); g_main_loop_quit(loop); break; } default: break; } return TRUE; } int main(int argc, char *argv[]) { GMainLoop *loop; GstElement *pipeline, *source, *rate, *filter1, *decode, *convert, *scale, *filter2, *tee, *queue_d, *sink; GstElement *queue_f, *encode, *filter3, *parse, *mux, *filesink; GstCaps *filtercaps; GstBus *bus; /* 初期化 */ gst_init(&argc, &argv); loop = g_main_loop_new(NULL, FALSE); /* エレメント作成 */ pipeline = gst_pipeline_new("video-player"); source = gst_element_factory_make("v4l2src", NULL); rate = gst_element_factory_make("videorate", NULL); filter1 = gst_element_factory_make("capsfilter", NULL); decode = gst_element_factory_make("jpegdec", NULL); convert = gst_element_factory_make("videoconvert", NULL); scale = gst_element_factory_make("videoscale", NULL); filter2 = gst_element_factory_make("capsfilter", NULL); sink = gst_element_factory_make("ximagesink", NULL); tee = gst_element_factory_make("tee", NULL); queue_d = gst_element_factory_make("queue", NULL); queue_f = gst_element_factory_make("queue", NULL); encode = gst_element_factory_make("omxh264enc", NULL); filter3 = gst_element_factory_make("capsfilter", NULL); parse = gst_element_factory_make("h264parse", NULL); mux = gst_element_factory_make("mpegtsmux", NULL); filesink = gst_element_factory_make("filesink", NULL); if( !pipeline || !source || !rate || !filter1 || !decode || !convert || !scale || !filter2 || !sink || !tee || !queue_d || !queue_f || !encode || ! filter3 || !parse || !mux || !filesink ) { g_printerr("One element could not be created. Exiting.\n"); return -1; } /* パラメータの設定 */ g_object_set(G_OBJECT(source), "device", "/dev/video0", NULL); g_object_set(G_OBJECT(parser), "config-interval", 4, NULL); g_object_set(G_OBJECT(filesink), "location", "test.ts", NULL); /* g_object_set(G_OBJECT(encoder), "target-bitrate", 1000000, NULL); g_object_set(G_OBJECT(encoder), "control-rate", 1, NULL);*/ /* フィルタ作成 */ filtercaps = gst_caps_new_simple("image/jpeg", "width", G_TYPE_INT, 1280, "height", G_TYPE_INT, 720, "framerate", GST_TYPE_FRACTION, 30, 1, NULL); g_object_set(G_OBJECT(filter1), "caps", filtercaps, NULL); gst_caps_unref(filtercaps); filtercaps = gst_caps_new_simple("video/x-raw", "width", G_TYPE_INT, 640, NULL); g_object_set(G_OBJECT(filter2), "caps", filtercaps, NULL); gst_caps_unref(filtercaps); filtercaps = gst_caps_new_simple("video/x-h264", "profile", G_TYPE_STRING, "high", NULL); g_object_set(G_OBJECT(filter3), "caps", filtercaps, NULL); gst_caps_unref(filtercaps); /* メッセージハンドラの設定 */ bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); gst_bus_add_watch(bus, bus_call, loop); gst_object_unref(bus); /* エレメントをパイプラインに追加 */ gst_bin_add_many(GST_BIN(pipeline), source, rate, filter1, decode, convert, scale, filter2, sink, tee, queue_d, queue_f, encode, filter3, parse, mux, filesink, NULL); /* エレメントのリンク */ gst_element_link_many(source, rate, filter1, decode, tee, NULL); gst_element_link_many(tee, queue_d, convert, scale, filter2, sink, NULL); gst_element_link_many(tee, queue_f, encode, filter3, parse, mux, filesink, NULL); /* パイプラインの再生 */ gst_element_set_state (pipeline, GST_STATE_PLAYING); /* 再生中 */ g_print ("Running...\n"); g_main_loop_run (loop); /* 終了処置 */ g_print ("Returned, stopping playback\n"); gst_element_set_state (pipeline, GST_STATE_NULL); g_print ("Deleting pipeline\n"); gst_object_unref (GST_OBJECT (pipeline)); return 0; }

 コメントアウトしていますが、ビットレートを指定するとやはり妙なノイズが入りました。プログラムにしても変化はありませんでした。

Gstreamer

Posted by sirius