WindowsFormsでGstSharpを使った

せしまるです。

仕事でGStreamerのC#版を使ったので備忘録として。

#開発環境
・VisualStudio 2017
・.NET Framework 4.7.2
・Gstreamer 1.16.0

#環境構築

まずは、Gstreamerの[公式ページ](https://gstreamer.freedesktop.org/download/)に書かれているとおりにGstreamerのダウンロード&インストールを行います。

Windows項目にある「1.16.0 runtime installer」をダウンロードしてインストール。
自分はインストールするときのオプションでcompleteを選択しました。

後でまた書きますが、Gstreamerのbinフォルダへのパスを環境変数に追加しておきます。
自分はCドライブ直下に配置したので以下のようにパスを追加しました

```console
C:\gstreamer\1.0\x86_64\bin
```

バージョン確認などは、以下のコマンドで確認できます

```console:console
C:\Users\seshimaru> gst-inspect-1.0.exe --version
gst-inspect-1.0 version 1.16.0
GStreamer 1.16.0
Unknown package origin
```

次にVisualStudioを起動してWindowsFormsアプリケーションプロジェクトを作成します。
その後NuGetパッケージマネージャーで「GstSharp」をインストールします。

Gstreamerは64bitのため、プロジェクトのプロパティから、ビルドの設定を変更します。
・プラットフォーム　ターゲット：Any CPU
・32ビットを優先のチェックを外す

これで準備完了。

#こーでぃんぐ
初期化

```c#:Programs.cs
[STAthread]
static void Main()
{
    ~~~
    Gst.Application.Init();
    GtkSharp.GstreamerSharp.ObjectManager.Initialize();
    ~~~
}
```

自分はユーザコントロール作って、ユーザコントロール側でパイプラインなどを作成したので、そのコードを記載

```c#:UserControl.cs
using System;
using Gst;
using Gst.Video;

namespace MyApp.Controlls.UserControlls
{
    public partial class VideoPanel : USerControll
    {
        // パイプライン作成のための文字列.
        public string PipelineSource;
        // 文字列から生成したパイプライン格納変数.
        private Element _pipeline { get; set; }
        // コントロールのハンドル.
        private IntPtr _handle;

        public VideoPanel()
        {
            InitializeComponent();
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            // 開放処理を追加しておく.
            this.Dispose += ( sender, args ) =>
            {
                if( _pipeline == null )
                    return;

                _pipeline.Bus.SyncMessage -= Bus_SyncMessage;
                _pipeline.Bus.Message -= Bus_Message;
                _pipeline.SetState( State.Null );
                _pipeline.Dispose();
                _pipeline = null;
            };
        }

        // 実行.
        public void Execute()
        {
            if( string.IsNullOrEmpty( PipelineSource ) )
                return;
            if( InitGstreamerPipeline() )
                HandleRealized();
        }

        // パイプライン作成.
        private bool InitGstreamerPipeline()
        {
            if( _pipeline != null )
                _pipeline.SetState( State.Null );
            // パイプライン生成
            _pipeline = Parse.Launch( PipelineSource );

            if( _pipeline == null )
                return false;

            _pipeline.Bus.EnableSyncMessageEmission();
            _pipeline.Bus.AddSignalWatch();
            _pipeline.Bus.SyncMessage += Bus_SyncMessage;
            _pipeline.Bus.Message += Bus_Message;
            _pipeline.SetState( State.Playing );
            return true;
        }

        private void Bus_SyncMessage( object o, SyncMessageArgs args )
        {
            string msg;
            switch( args.Message.Type )
            {
                case MessageType.Error:
                    GLib.GException err;
                    args.Message.ParseError( out err, out msg );
                    // エラー処理.
                    break;
                case MessageType.Eos:
                    // ストリーム終了.
                    break;
                case MessageType.NewClock:
                    // 再生開始.
                    break;
                default:
                    break;
            }
        }

        private void Bus_Message( object o, MessageArgs args )
        {
            Console.WriteLine( args );
        }

        // コントロールに映像を埋め込むためハンドルを渡す.
        private void HandleRealized()
        {
            _handle = this.Handle();
            Element overlay = ( ( Gst.Bin ) _pipeline ).GetByInterface( VideoOerlayAdapter.GType );
            var adapter = new VideoOverlayAdapter( overlay.Handle );
            adapter.WindowHandle = _handle;
            adapter.HandleEvent( true );
        }

        // 停止.
        public void Stop()
        {
            if( _pipeline == null )
                return;

            _pipeline.Bus.SyncMessage -= Bus_SyncMessage;
            _pipeline.Bus.Message -= Bus_Message;
            _pipeline.SetState( State.Null );
            _pipeline.Dispose();
            _pipeline = null;
        }
        ~~~~
    }
}
```

使う側はデザイナーで作成したユーザコントロールを配置しておく。

```c#:MainForm.cs
public partial class MainForm : Forms
{
    public MainForm()
    {
        InitializeComponent();
    }

    private void MainForm_Load( object sender, EventArgs e )
    {
        // Gstreamerのパイプライン生成文字列を入れる.
        videoPanel.PipelieSource = "/*再生したい内容*/";
        videoPanel.Execute();
    }
}
```

これでMainFormに配置したVideoPanelに映像が再生されるはず。

#環境変数
後で書くって行ったやつです。
実は環境変数を通さなくてもGstreamerを動かす方法があります。
アプリケーション実行時だけパスを通すのです。(・∀・)

```c#:Programs.cs
static void Main()
{
    ~~~
    var gstreamerPath= "C:\gstreamer\1.0\x86_64";
    var path = Environment.GetEnvironmentVariable( "PATH" ).Split( ';', path) );
    path.Add( Path.Combine( gstreamerPath, "bin" ) );
    Environment.SetEnvironmentVariable( "PATH", string.Join( ";", path ) );
    ~~~
}
```

上記を書くことで一時的にパスを追加できます。
ベタ書きはどうかと思いますが…(^^;)

#感想
書籍やサイトがあんまり無くて困りました。
最終的に行き着いたサンプルをみつつできたのでよかったなぁ…

あと、ユーザーコントロールを複数置いて、それぞれでLaunchすれば、複数の映像を表示することも可能です！
よきストリームライフを！