当方Windows 10でVisual Studio Community 2019を使用しています。
参照の追加
C#のプロジェクトを右クリック→追加→COM参照を選択します。
[ActiveMovie control type library]にチェックを入れ、OKを押します。
もしActiveMovie control type libraryが存在しない場合などは次の方法でdllを追加してください。
[参照]→[参照]ボタン→C:\Windows\System32\quartz.dllを選択して、③が追加されたことを確認します。
必要なパッケージ
using QuartzTypeLib;
コード
C#でフォームアプリケーションでプロジェクトを作成します。
GUI
デザイナーで以下のコンポーネントを追加します。
・Panel (名前:panel1)
・Button (名前:button1)
ここでは、ボタンを押すとpanelに動画が再生されるようにコードを書きます。
C#のコード
private FilgraphManager objFilterGraph = null; private IBasicAudio objBasicAudio = null; private IVideoWindow objVideoWindow = null; private IMediaEvent objMediaEvent = null; private IMediaEventEx objMediaEventEx = null; private IMediaPosition objMediaPosition = null; private IMediaControl objMediaControl = null; private const int WM_APP = 0x8000; private const int WM_GRAPHNOTIFY = WM_APP + 1; private const int EC_COMPLETE = 0x01; private const int WS_CHILD = 0x40000000; private const int WS_CLIPCHILDREN = 0x2000000; enum MediaStatus { None, Stopped, Paused, Running }; private MediaStatus currentStatus = MediaStatus.None; private void button1_Click(object sender, EventArgs e) { objFilterGraph = new FilgraphManager(); // ここに固定で再生したい動画ファイルのフルパスを書く objFilterGraph.RenderFile(@"C:\temp\midori.avi"); objBasicAudio = objFilterGraph as IBasicAudio; objBasicAudio.Volume = -1000; // 音量を少し下げておく try { objVideoWindow = objFilterGraph as IVideoWindow; objVideoWindow.Owner = (int)panel1.Handle; objVideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN; objVideoWindow.SetWindowPosition(panel1.ClientRectangle.Left, panel1.ClientRectangle.Top, panel1.ClientRectangle.Width, panel1.ClientRectangle.Height); } catch (Exception ex) { objVideoWindow = null; } objMediaEvent = objFilterGraph as IMediaEvent; // メッセージの傍受 DirectShowを親ウィンドウに送信します objMediaEventEx = objFilterGraph as IMediaEventEx; objMediaEventEx.SetNotifyWindow((int)this.Handle, WM_GRAPHNOTIFY, 0); // ビデオまたはオーディオトラックを開始および停止する objMediaControl = objFilterGraph as IMediaControl; // 再生開始 objMediaControl.Run(); currentStatus = MediaStatus.Running; }
フォーム終了時などに実行する解放処理は以下の通りです。
if (objMediaControl != null) { objMediaControl.Stop(); } currentStatus = MediaStatus.Stopped; if (objMediaEventEx != null) { objMediaEventEx.SetNotifyWindow(0, 0, 0); } if (objVideoWindow != null) { objVideoWindow.Visible = 0; objVideoWindow.Owner = 0; } if (objMediaControl != null) objMediaControl = null; if (objMediaPosition != null) objMediaPosition = null; if (objMediaEventEx != null) objMediaEventEx = null; if (objMediaEvent != null) objMediaEvent = null; if (objVideoWindow != null) objVideoWindow = null; if (objBasicAudio != null) objBasicAudio = null; if (objFilterGraph != null) objFilterGraph = null;
一時停止する場合は以下のコードを実行します。
objMediaControl.Pause();
一時停止を再開する場合は以下のコードを実行します。
objMediaControl.Run();
動画を末尾まで再生したことを検知して止めるためのコードは以下の通りです。
メッセージプロシージャをオーバーライドして特定のメッセージだけ処理を追加する形にしています。
protected override void WndProc(ref Message m) { if (m.Msg == WM_GRAPHNOTIFY) { int lEventCode; int lParam1, lParam2; while (true) { try { objMediaEventEx.GetEvent(out lEventCode, out lParam1, out lParam2, 0); objMediaEventEx.FreeEventParams(lEventCode, lParam1, lParam2); if (lEventCode == EC_COMPLETE) { objMediaControl.Stop(); objMediaPosition.CurrentPosition = 0; currentStatus = MediaStatus.Stopped; } } catch (Exception) { break; } } } base.WndProc(ref m); }
トラックバー(シークバー)の設置
どうせなのでトラックバーも設置してしまいましょう。
トラックバー設置により、再生位置をクリックしたりドラッグしたりして、好きな位置に飛べるようにします。
GUIの設置
デザイナ画面でTrackbarを設置します。変数名はデフォルトのtrackBar1とします。
コード
button1_Click関数で再生を開始するときにトラックバーの設定コードを追加します。
まずトラックバーの取りうる値をMinimumとMaximumに設定します。
ここでは動画の秒数をMaximumに設定します。
private void button8_Click(object sender, EventArgs e) { : // 再生開始 objMediaControl.Run(); currentStatus = MediaStatus.Running; // トラックバーの設定 this.trackBar1.Minimum = 0; this.trackBar1.Maximum = (int)objMediaPosition.Duration; this.trackBar1.Value = 0; this.trackBar1.TickFrequency = 1;
再生中にトラックバーを更新する関数を作成します。
private void updateTrackBar() { if (this.currentStatus == MediaStatus.Running && this.objMediaPosition != null) { this.trackBar1.Value = (int)objMediaPosition.CurrentPosition; } else { this.trackBar1.Minimum = 0; this.trackBar1.Maximum = 0; this.trackBar1.Value = 0; } }
上述したトラックバー更新関数をコールするコードを追加します。
まずは動画の再生が完了したときにトラックバーを0に戻すため、WndProc関数にコードを追加します。
protected override void WndProc(ref Message m) { : if (lEventCode == EC_COMPLETE) { : updateTrackBar(); } }
次に、1秒に1度トラックバーを更新するためにタイマーを設定し、そこからupdateTrackBar関数を呼び出します。
private void Form1_Load(object sender, EventArgs e) { : // トラックバーの更新 Timer trackbar_timer = new Timer(); trackbar_timer.Interval = 1000; trackbar_timer.Enabled = true; trackbar_timer.Start(); trackbar_timer.Tick += (sender, e) => { if (this.currentStatus == MediaStatus.Running) { this.updateTrackBar(); } };
続いて、マウスクリックとマウスの移動でシークバーを更新するようにします。
MouseDownとMouseMoveイベントハンドラを作成してください。
MouseDownについては、クリックされた場所とトラックバーの幅から比率を計算して、その場所に再生位置を設定するだけです。
private void trackBar1_MouseDown(object sender, MouseEventArgs e) { if (this.currentStatus == MediaStatus.Running && this.objMediaPosition != null) { if (e.Button == MouseButtons.Left) { double pos = ((double)e.X / this.trackBar1.Width) * (this.trackBar1.Maximum - this.trackBar1.Minimum); // トラックバー this.trackBar1.Value = (int)(pos); // 動画再生位置 this.objMediaPosition.CurrentPosition = pos; } } }
MouseMoveについては、基本的にMouseDownと同じですが、範囲外にマウスをドラッグされた場合の対応コードを追加したものとなります。
private void trackBar1_MouseMove(object sender, MouseEventArgs e) { if (this.currentStatus == MediaStatus.Running && this.objMediaPosition != null) { if (e.Button == MouseButtons.Left) { double pos = ((double)e.X / this.trackBar1.Width) * (this.trackBar1.Maximum - this.trackBar1.Minimum); try { if ((int)(pos) >= this.trackBar1.Minimum && (int)pos <= this.trackBar1.Maximum) { // トラックバー this.trackBar1.Value = (int)(pos); // 動画再生位置 this.objMediaPosition.CurrentPosition = pos; } } catch(ArgumentException) { // 位置を超えて設定してしまった場合は例外が飛ぶが無視する } catch(Exception ex) { MessageBox.Show(ex.Message, "error"); } } } }