.NETからGStreamerを使ってみる
GStreamerとは
クロスプラットフォームのマルチメディアライブラリ。映像や音声の入力(デバイスでもファイルでもよい)をエンコードしたり、RTMPでストリーミングしたりとか、そういったものを簡単に作ることができる。
なお、.NETからGStreamerをつかう実例としてはBansheeというOSSなiTunesみたいなものが存在している。
.NET/Windows用のGStreamerバイナリの入手
2013年7月の時点では、.NET/Windows向けのバイナリはhttp://code.google.com/p/ossbuild-vs2010/で配布されているいるものを使うのがよさそう。GStreamer本家が配布しているものと比較すると最新ではないものの、比較的新しいものが利用できる。
.NET/WindowsからGStreamerを使うための初期設定
サンプルコード(http://code.google.com/p/ossbuild-vs2010/source/browse/#git%2FExamples%2Fcsharp-helloworld)を参考にしながら。
参照設定
gstreamer-sharp.dllを参照に追加する。gstreamer-sharp-net4.dllも存在するのだが、こちらを使った場合はうまく動かなかった。
ビルド設定
gstreamerが32bitバイナリのため、ビルドターゲットをx86に設定する。
セットアップコード
GStreamerを使う場合、いくつか環境変数が設定されている必要がある。システム設定の方で環境変数を設定してあっても良いのだが、実際にアプリを配布する際に邪魔くさくなるので、アプリの初期化中(WPFの場合はApp.xaml.csのコンストラクタ内など)に環境変数を設定するコードを埋め込む。
var path = @"C:\gstreamer"; Environment.SetEnvironmentVariable("GST_PLUGIN_PATH", ""); Environment.SetEnvironmentVariable("GST_PLUGIN_SYSTEM_PATH", String.Format(@"{0}\bin\plugins", path)); Environment.SetEnvironmentVariable("PATH", String.Format(@"C:\Windows;{0}\lib;{0}\bin", path)); // デバッグログ出力設定 Environment.SetEnvironmentVariable("GST_DEBUG", "*:3"); Environment.SetEnvironmentVariable("GST_DEBUG_FILE", "GstreamerLog.txt"); Environment.SetEnvironmentVariable("GST_DEBUG_DUMP_DOT_DIR", path); Gst.Application.Init(); //GStreamerの初期化
ひとまずここまでやれば.NETからGStreamerのAPIをたたくことができる。
動作確認
ちゃんとGStreamerが初期化できていれば、以下のようなコードでGStreamerのバージョンが出力できる。
String.Format("{0}.{1}.{2}", Gst.Version.Major, Gst.Version.Minor, Gst.Version.Micro)
GStreamerを使ってマイクからの入力をOgg/Speexで録音してみる
とりあえず音声といえばSpeexだろうということで、マイクからの入力をリアルタイムにOgg/Speexにエンコードしてファイル出力してみる。先ほどと同じくサンプルコード(/ - ossbuild-vs2010 - Visual Studio 2010 fork of ossbuild - Google Project Hosting)を参考にしながらコードを書いてみた。終了処理とかかなり適当なので、本格的にアプリを作る場合は要注意。
public partial class MainWindow : Window { private Gst.GLib.MainLoop glibMainLoop; private System.Threading.Thread glibThread; private Gst.Pipeline pipeline; public MainWindow() { InitializeComponent(); glibMainLoop = new Gst.GLib.MainLoop(); glibThread = new System.Threading.Thread(glibMainLoop.Run); glibThread.Name = "GLibMainLoop"; glibThread.Start(); pipeline = CreatePipeline(); } private Gst.Pipeline CreatePipeline() { // 録音デバイス(OSの規定のデバイス), 16KHz MONO 16bit var src = Gst.ElementFactory.Make("autoaudiosrc"); var srcFilter = Gst.Caps.FromString("audio/x-raw-int, width=16, depth=16, rate=16000, channels=1"); // ノイズ除去 var conv = Gst.ElementFactory.Make("audioconvert"); // Speexエンコーダ ABR, quality=8, complexity=8 // 帯域設定は未指定だが入力サンプリングレートによって自動設定される(ソースを読んだ) // 8KHz -> 狭帯域, 16KHz -> 広帯域, 32KHz -> 超広帯域 var enc = Gst.ElementFactory.Make("speexenc"); enc["abr"] = 1; enc["quality"] = 8.0f; enc["complexity"] = 8; // Ogg Multiplexer var mux = Gst.ElementFactory.Make("oggmux"); // Sink(出力先) var sink = Gst.ElementFactory.Make("filesink"); sink["location"] = "test.ogg"; // パイプラインの構築 var pipeline = new Gst.Pipeline(); pipeline.Add(src, conv, enc, mux, sink); src.LinkFiltered(conv, srcFilter); conv.Link(enc); enc.Link(mux); mux.Link(sink); return pipeline; } private void ToggleButton_Click(object sender, RoutedEventArgs e) { var button = (ToggleButton)sender; if (button.IsChecked == true) { pipeline.SetState(Gst.State.Playing); } else { pipeline.SetState(Gst.State.Ready); } } private void Window_Closed(object sender, EventArgs e) { pipeline.SetState(Gst.State.Ready); pipeline.Dispose(); glibMainLoop.Quit(); } }
C#でGStreamerプログインを書いてみる
これもサンプル(http://code.google.com/p/ossbuild-vs2010/source/browse/#git%2FExamples%2Fcsharp-plugin-example)を参考に書いてみる。
自プログラム内のみで使うプラグインは、ベースクラスを継承して、PadTemplate(このプラグインでどんな入出力を受け付けるかを指定)する程度でできてしまう。具体的な実装例はGStreamer自体のコードを参考にする。
public class SampleSink : Gst.Base.BaseSink { public SampleSink() : base() { } public SampleSink(IntPtr raw) : base(raw) { } static SampleSink() { var gtype = (Gst.GLib.GType)typeof(SampleSink); AddPadTemplate(gtype, new Gst.PadTemplate( "sink", Gst.PadDirection.Sink, Gst.PadPresence.Always, Gst.Caps.NewAny())); } protected override bool OnStart() { System.Diagnostics.Debug.WriteLine("OnStart"); return true; } protected override bool OnStop() { System.Diagnostics.Debug.WriteLine("OnStop"); return true; } protected override Gst.FlowReturn OnRender(Gst.Buffer buffer) { var bytes = buffer.ToByteArray(); var time = DateTime.Now.ToString("mm:ss.fff"); System.Diagnostics.Debug.WriteLine(String.Format("OnRender {0} {1}", time, bytes.Length)); return base.OnRender(buffer); } protected override bool OnEvent(Gst.Event evnt) { System.Diagnostics.Debug.WriteLine("OnEvent"); return base.OnEvent(evnt); } }
プラグインをインスタンス化する際は、Gst.ElementFactory.Make("filesink")みたいに指定する必要はなく、普通にnewすればよい。
また、外部プログラム(GStreamerのコマンドラインツール等)からC#製のプラグインを認識させたい場合は、サンプル(http://code.google.com/p/ossbuild-vs2010/source/browse/#git%2FExamples%2Fcsharp-plugin-example)に付属しているPluginWrapperを使えばよいらしい。詳細はサンプルコードおよびReadMe.txtを参照。