17.2. メディアストリームの種類の認識

通常、メディアストリームをロードするときは、ストリームの種類はまだ不明です。これは、ストリームをデコードするためのパイプラインを選択できるためには、その前にストリームの種類を識別する必要があることを意味します。GStreamer は、そのために型情報の取得処理 (typefinding) というコンセプトを利用します。型情報の取得処理はパイプラインの通常の一部で、ストリームの種類を識別できるまで、データを読み込みます。この間、データは typefinder を実装しているすべてのプラグインに渡されます。typefinder のいずれか 1 つがストリームを識別すると、その typefind エレメントはシグナルを送信し、その時点からパススルーモジュールとして機能するようになります。一方、該当する種類が 1 つも見つからなかった場合には、エラーが送信され、それ以上のメディア処理はストップします。

typefind エレメントが種類を見つけると、アプリケーションではこのことを利用して、メディアストリームをデコードするためのパイプラインをつなぎ合わせることができます。この点については、次の項で説明します。

すでに述べたように、GStreamer のプラグインは、typefinder の機能を実装できます。typefinder の機能を実装したプラグインは、MIME 型を提供するほか、場合によっては、そのメディアの種類に対して一般的に使われる一連のファイル拡張子、および、typefind 関数を提供します。プラグインの中でこの typefind 関数が呼び出されると、プラグインはメディアストリーム内のデータが特定のパターンに一致するかどうかを調べます。特定のパターンとは、該当する MIME 型によって識別されるメディアの種類を表すものです。もしこの特定のパターンに一致した場合には、プラグインはこのことを typefind エレメントに通知し、どのメディアの種類が認識されたのか、そのストリームが実際にそのメディアの種類である確度はどれくらいかを知らせます。typefind 機能を実装しているすべてのプラグインでこの処理が完了すると、typefind エレメントはアプリケーションに対し、自身が認識した考えるメディアストリームの種類を知らせます。

次に示すコードは、typefind エレメントの使い方を示したものです。プログラムは、認識されたメディアの種類を出力するか、またはメディアの種類が見つからなかったことを報告します。次の項では、デコードを行うパイプラインのプラッギングなど、さらに便利な処理について説明します。


#include <gst/gst.h>

[.. my_bus_callback をここに記述 ..]


static gboolean
idle_exit_loop (gpointer data)
{
  g_main_loop_quit ((GMainLoop *) data);

  /* once */
  return FALSE;
}

static void
cb_typefound (GstElement *typefind,
	      guint       probability,
	      GstCaps    *caps,
	      gpointer    data)
{
  GMainLoop *loop = data;
  gchar *type;

  type = gst_caps_to_string (caps);
  g_print ("Media type %s found, probability %d%%\n", type, probability);
  g_free (type);

  /* since we connect to a signal in the pipeline thread context, we need
   * to set an idle handler to exit the main loop in the mainloop context.
   * Normally, your app should not need to worry about such things. */
  g_idle_add (idle_exit_loop, loop);
}

gint 
main (gint   argc,
      gchar *argv[])
{
  GMainLoop *loop;
  GstElement *pipeline, *filesrc, *typefind, *fakesink;
  GstBus *bus;

  /* init GStreamer */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* check args */
  if (argc != 2) {
    g_print ("Usage: %s <filename>\n", argv[0]);
    return -1;
  }

  /* create a new pipeline to hold the elements */
  pipeline = gst_pipeline_new ("pipe");

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_watch (bus, my_bus_callback, NULL);
  gst_object_unref (bus);

  /* create file source and typefind element */
  filesrc = gst_element_factory_make ("filesrc", "source");
  g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
  typefind = gst_element_factory_make ("typefind", "typefinder");
  g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), loop);
  fakesink = gst_element_factory_make ("fakesink", "sink");

  /* setup */
  gst_bin_add_many (GST_BIN (pipeline), filesrc, typefind, fakesink, NULL);
  gst_element_link_many (filesrc, typefind, fakesink, NULL);
  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
  g_main_loop_run (loop);

  /* unset */
  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (pipeline));

  return 0;
}
    

メディアの種類が認識されたら、typefind エレメントのソースパッドにエレメント (デマルチプレクサやデコーダなど) をつなげることができ、その直後からメディアストリームのデコードが始まります。