11.2. イベント: シーク (およびその他のこと)

イベントは、問い合わせと非常によく似た方法で動作します。たとえば、ディスパッチはイベントでもまったく同様に動作します (同時にまったく同じ制約があります)。イベントもトップレベルのパイプラインに送ることができ、このパイプラインがプログラマに代わって必要な処理を行います。イベントを使ってアプリケーションとエレメントがやり取りする方法はほかにもたくさんありますが、ここではシークに的を絞って説明します。シークの場合、シークイベントを使います。シークイベントに含まれるものには、再生レート、シークオフセット形式 (これはオフセットの単位で、時間、音声サンプル、動画フレーム、バイトなど) があり、さらにオプションで一連のシーク関連フラグ (内部バッファをフラッシュする必要があるかどうかなど)、シークメソッド (オフセットが何に対する相対位置かを示すもの)、およびシークオフセットが含まれます。最初のオフセット (cur) は、シーク先の新しい位置です。2 番目のオフセット (stop) は省略可能で、ストリーミングの停止位置を示します。通常は、停止メソッドと停止オフセットに GST_SEEK_TYPE_NONE と -1 を指定しておきます。シークの動作は、gst_element_seek () でもラップされています。


static void
seek_to_time (GstElement *pipeline,
	      gint64      time_nanoseconds)
{
  if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
                         GST_SEEK_TYPE_SET, time_nanoseconds,
                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
    g_print ("Seek failed!\n");
  }
}
    

パイプラインが一時停止 (PAUSED) 状態または再生中 (PLAYING) 状態の場合には、GST_SEEK_FLAG_FLUSH を指定してシークする必要があります。パイプラインは、シーク後の新しいデータによってパイプラインが再びプリロール (PRFEROLL) 状態になるまで、自動的にプリロール (PREROLL) 状態になります。パイプラインがプリロールされると (前準備が済むと)、パイプラインは、シークが実行されたときの状態 (一時停止 (PAUSED) 状態または再生中 (PLAYING) 状態) に戻ります。gst_element_get_state() を使うか、ASYNC_DONE メッセージがバスに送られるまで待てば、シークが完了するまで待機する (動作をブロックする) ことができます。

GST_SEEK_FLAG_FLUSH を指定しないシークは、パイプラインが再生中 (PLAYING) 状態のとき以外は、行ってはいけません。一時停止 (PAUSED) 状態でフラッシュなしのシークを実行すると、パイプラインストリーミングスレッドがシンク内でブロックされることがあるため、デッドロックになる場合があります。

シークは瞬時に行われるわけではない点には十分注意しておく必要があります。これは、シークは関数 gst_element_seek () から戻ったときに完了するという意味です。関係するエレメントによっては、実際のシークは別のスレッド (ストリーミングスレッド) で行われることがあり、新しいシーク位置からのバッファが、シンクなどの下流エレメントに達するまでには、いくらか時間がかかる可能性があります (フラッシュなしのシークではさらに時間がかかる場合があります)。

スライダの動きに対するダイレクトな反応など、短い間隔で複数のシークを行うこともできます。シーク後のパイプラインは、内部的には一時停止し (再生中だった場合)、位置は内部的にリセットされ、デマルチプレクサとデコーダは新しい位置からデコードを開始し、すべてのシンクに再びデータが行き渡るまで、デコードが繰り返されます。パイプラインがシーク前に再生中 (PLAYING) 状態だった場合には、再び再生中 (PLAYING) 状態になります。動画出力では新しい位置はすぐに利用可能になるので、パイプラインが再生中 (PLAYING) 状態になっていなくても、新しいフレームが表示されます。