Basic tutorial 2: GStreamer concepts

41895 ワード

Basic tutorial 2: GStreamer concepts
// basic-tutorial-2.c
#include <gst/gst.h>

int main(int argc, char* argv[])
{
    GstElement* pipeline, * source, * sink;
    GstBus* bus;
    GstMessage* msg;
    GstStateChangeReturn ret;

    /* Initialize GStreamer */
    gst_init(&argc, &argv);

    /* Create the elements */
    source = gst_element_factory_make("videotestsrc", "source");
    sink = gst_element_factory_make("autovideosink", "sink");

    /* Create the empty pipeline */
    pipeline = gst_pipeline_new("test-pipeline");

    if (!pipeline || !source || !sink) {
        g_printerr("Not all elements could be created.\n");
        return -1;
    }

    /* Build the pipeline */
    gst_bin_add_many(GST_BIN(pipeline), source, sink, NULL);
    if (gst_element_link(source, sink) != TRUE) {
        g_printerr("Elements could not be linked.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* Modify the source's properties */
    g_object_set(source, "pattern", 0, NULL);

    /* Start playing */
    ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* Wait until error or EOS */
    bus = gst_element_get_bus(pipeline);
    msg =
        gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
            (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));

    /* Parse message */
    if (msg != NULL) {
        GError* err;
        gchar* debug_info;

        switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_ERROR:
            gst_message_parse_error(msg, &err, &debug_info);
            g_printerr("Error received from element %s: %s\n",
                GST_OBJECT_NAME(msg->src), err->message);
            g_printerr("Debugging information: %s\n",
                debug_info ? debug_info : "none");
            g_clear_error(&err);
            g_free(debug_info);
            break;
        case GST_MESSAGE_EOS:
            g_print("End-Of-Stream reached.\n");
            break;
        default:
            /* We should not reach here because we only asked for ERRORs and EOS */
            g_printerr("Unexpected message received.\n");
            break;
        }
        gst_message_unref(msg);
    }

    /* Free resources */
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
    return 0;
}

Walkthrough



GStreamerのパイプは、ソースストリームからデータが集約され、フィルタを通過するブロックです.
/* Initialize GStreamer */
gst_init (&argc, &argv);
Basic tutorial 1と同様にGstreamerを初期化します.

Element creation

/* Create the elements */
source = gst_element_factory_make("videotestsrc", "source");
sink = gst_element_factory_make("autovideosink", "sink");
gst_element_factory_make()関数は、新しい要素を作成します.

パラメータ:
factoryname
作成する要素のタイプ
name ([ nullable ])
NULLを入力して、新しい要素の名前または一意の名前を自動的に作成します.
上記の例では、videotestsrcとautovideosinkの2つの要素を作成しますが、フィルタ要素はありません.

videotestsrcは、テストビデオモードを生成するソース要素(データ生成)である.
Autovideosinkはsink要素(データ消費)で、受信した画像がウィンドウに表示されます.異なるオペレーティングシステムには、異なるビデオ機能があります.Autovideosinkでは、最適なコンテンツを自動的に選択およびインスタンス化できるので、詳細を心配する必要はありません.コードはプラットフォームから独立しています.

Pipeline creation

/* Create the empty pipeline */
pipeline = gst_pipeline_new ("test-pipeline");
GStreamerのすべての要素は、通常、いくつかのクロックおよびメッセージ機能を処理するので、それらを使用する前にパイプラインの内部に含める必要があります.gst pipeline new()を使用してパイプラインを作成します.
/* Build the pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
if (gst_element_link (source, sink) != TRUE) {
    g_printerr ("Elements could not be linked.\n");
    gst_object_unref (pipeline);
    return -1;
}
pipelineは、他の要素を含む要素binの特定のタイプである.従ってbinに適用されるすべての方法はpipelineにも適用される.
例では、gst_bin_add_many()を呼び出して要素をパイプに追加し、NULLで終わる追加する要素のリストを受信する.gst_bin_add()を使用して、単一の要素を追加できます.
gst_bin_add_many()
NULLで終わる要素のリストをリポジトリに追加します.この関数は、リスト内の各メンバーにgst bin addを呼び出すのと同じです.各gst bin addの戻り値は無視されます.
gst_bin_add()
指定した要素を空に追加します.要素の親を設定して、要素の所有権を取得します.要素は1つのリポジトリにしか追加できません.
gst_element_link()関数を使用して、追加された要素を相互に関連付けます.

パラメータ:
src ([transfer: none])
ソースボードを含むGSTElement
dest ([transfer: none])
GustElementは宛先Padを含む
1番目のパラメータ・ソースと2番目のパラメータ・宛先は、データ・ストリーム(ソース->sink)に基づいてリンクを確立する必要があるため、順序が重要です.
同じリポジトリ内の要素間でのみ接続できるため、試行する前にパイプに追加することを忘れないでください(gst bin add multi()/gst bin add().

Properties


GStreamer要素は、属性機能を提供するエンティティGObjectの特定のタイプである.
ほとんどのGStreamer要素には、カスタマイズ可能なプロパティがあります.アクションのプロパティ(書き込みプロパティ)を変更し、内部ステータスを表示するプロパティ(読み込みプロパティ).
g_object_get():属性の読み込み
g_object_set():書き込みプロパティ
g object set()は、属性-名前と属性-値のペアリスト(NULLで終わる)を許可するので、複数の属性を一度に変更することができます.
/* Modify the source's properties */
g_object_set (source, "pattern", 0, NULL);
上記の例では、要素出力のテストビデオタイプを制御するvideotestsrcの「pattern」プロパティを変更します.

Error checking

/* Start playing */
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (pipeline);
    return -1;
}
ステータス変更は複雑なプロセスですので、gst element set state()を呼び出した後、戻り値にエラーがあることを確認してください.
/* 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);

/* Parse message */
if (msg != NULL) {
    GError *err;
    gchar *debug_info;

    switch (GST_MESSAGE_TYPE (msg)) {
      case GST_MESSAGE_ERROR:
        gst_message_parse_error (msg, &err, &debug_info);
        g_printerr ("Error received from element %s: %s\n",
            GST_OBJECT_NAME (msg->src), err->message);
        g_printerr ("Debugging information: %s\n",
            debug_info ? debug_info : "none");
        g_clear_error (&err);
        g_free (debug_info);
        break;
      case GST_MESSAGE_EOS:
        g_print ("End-Of-Stream reached.\n");
        break;
      default:
        /* We should not reach here because we only asked for ERRORs and EOS */
        g_printerr ("Unexpected message received.\n");
        break;
    }
    gst_message_unref (msg);
}
gst element get bus()は、実行の終了を待機し、GstreamerがエラーまたはEOSに遭遇したときにGstMessageに戻ります.
GstMessageは様々な構造であり、ほとんどのタイプの情報を伝えることができます.
GST MESSAGE TYPEにerrorが含まれていることが判明した場合、gst message parse error()を使用して、GErrorエラー構造とデバッグに使用できる文字列を返します.

The GStreamer bus


要素によって生成されたGSTメッセージをアプリケーションスレッドに順次渡すオブジェクト.GStreamerバスの役割は、メディアの実際のストリーム管理がアプリケーションではなく他のスレッドで行われるため、非常に重要です.
gst bus timed pop filter()同期または非同期(信号)を使用してバスからメッセージを抽出できます.アプリケーションは、エラーやその他の再生の問題に関する通知を受信するために、バスに常に注意してください.

Exercise


パイプラインのソースと穴の間にビデオフィルタ要素を追加します.
(プラットフォームや使用可能なプラグインによっては、シンクタンクがフィルタの作成を理解していないため、交渉エラーが発生する可能性があります.フィルタの後ろにビデオ変換要素を追加してください.)
#include <gst/gst.h>

int main(int argc, char* argv[])
{
    GstElement* pipeline, * source, * filter, * convert, * sink;
    GstBus* bus;
    GstMessage* msg;
    GstStateChangeReturn ret;

    /* Initialize GStreamer */
    gst_init(&argc, &argv);

    /* Create the elements */
    source = gst_element_factory_make("videotestsrc", "source");
    filter = gst_element_factory_make("vertigotv", "filter");
    convert = gst_element_factory_make("videoconvert", "convert");
    sink = gst_element_factory_make("autovideosink", "sink");

    /* Create the empty pipeline */
    pipeline = gst_pipeline_new("test-pipeline");

    if (!pipeline || !source || !filter || !sink) {
        g_printerr("Not all elements could be created.\n");
        return -1;
    }

    /* Build the pipeline */
    gst_bin_add_many(GST_BIN(pipeline), source, filter, convert, sink, NULL);
    if (gst_element_link(source, filter) != TRUE) {
        g_printerr("Elements could not be linked.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    if (gst_element_link(filter, convert) != TRUE) {
        g_printerr("Elements could not be linked.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    if (gst_element_link(convert, sink) != TRUE) {
        g_printerr("Elements could not be linked.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* Modify the source's properties */
    g_object_set(source, "pattern", 0, NULL);

    /* Start playing */
    ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* Wait until error or EOS */
    bus = gst_element_get_bus(pipeline);
    msg =
        gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
            (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));

    /* Parse message */
    if (msg != NULL) {
        GError* err;
        gchar* debug_info;

        switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_ERROR:
            gst_message_parse_error(msg, &err, &debug_info);
            g_printerr("Error received from element %s: %s\n",
                GST_OBJECT_NAME(msg->src), err->message);
            g_printerr("Debugging information: %s\n",
                debug_info ? debug_info : "none");
            g_clear_error(&err);
            g_free(debug_info);
            break;
        case GST_MESSAGE_EOS:
            g_print("End-Of-Stream reached.\n");
            break;
        default:
            /* We should not reach here because we only asked for ERRORs and EOS */
            g_printerr("Unexpected message received.\n");
            break;
        }
        gst_message_unref(msg);
    }

    /* Free resources */
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
    return 0;
}