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;
}
コメントアウトしていますが、ビットレートを指定するとやはり妙なノイズが入りました。プログラムにしても変化はありませんでした。
ディスカッション
コメント一覧
まだ、コメントがありません