[C#]自作クラスへのカスタムイベント追加メモ。

自作クラスへカスタムイベントを実装する方法のメモ。

自作クラスが保持するある変数の値の変更前・変更後の通知を行うカスタムイベントを実装してみる。

今回もインターネッツのサイト様を参考。
C# 入門 & 実践 / C sharp - 4-27. イベント – 1 – イベントの発生 / イベントの実装

1秒周期で値を変更するイベントの例。

マイイベントクラス(MyEventClass)

    /// <summary>
    /// マイイベントクラス
    /// </summary>
    class MyEventClass
    {
        /// <summary>
        /// 内部で値を保持する
        /// </summary>
        private int? _val = null;

        /// <summary>
        /// プライベート変数へのアクセッサ
        /// </summary>
        public int? VAL
        {
            get
            {
                return _val;
            }

            private set
            {
                bool change = _val != value;
                if (change) OnChangingHandler(new EventArgs());
                _val = value;
                if (change) OnChangedHandler(new EventArgs());
            }
        }

        /// <summary>
        /// 値変更前イベント
        /// </summary>
        public EventHandler OnChangingValue;


        /// <summary>
        /// 値変更後イベント
        /// </summary>
        public EventHandler OnChangedValue;

        /// <summary>
        /// 値変更前イベントハンドラ
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnChangingHandler(EventArgs e)
        {
            if (OnChangingValue != null)
            {
                OnChangingValue(this, e);
            }
        }

        /// <summary>
        /// 値変更後イベントハンドラ
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnChangedHandler(EventArgs e)
        {
            if (OnChangedValue != null)
            {
                OnChangedValue(this, e);
            }
        }

        /// <summary>
        /// 値変更
        /// </summary>
        /// <param name="i"></param>
        public void SetData(int? i)
        {
            VAL = i;
        }

        /// <summary>
        /// 定周期値変更イベント開始
        /// </summary>
        public void Start()
        {
            var task = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    System.Threading.Thread.Sleep(1000);

                    /// ここで値を変更する
                    if (VAL == null) SetData(0);
                    else SetData(VAL + 1);
                }
            });

        }
    }

テストForm

    public partial class Form1 : Form
    {
        private MyEventClass _evt = new MyEventClass();

        public Form1()
        {
            InitializeComponent();

            /// 値変更前通知イベント
            _evt.OnChangingValue += (s, e) =>
                {
                    this.Invoke(new Action(() => label1.Text = "OnChangingValue : " + _evt.VAL.ToString()));
                };

            /// 値変更後通知イベント
            _evt.OnChangedValue += (s, e) =>
            {
                this.Invoke(new Action(() => label2.Text = "OnChangedValue : " + _evt.VAL.ToString()));
            };
        }

        /// <summary>
        /// タイマー開始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            /// 定周期タイマー開始
            _evt.Start();
        }

        /// <summary>
        /// 値 = 0
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            _evt.SetData(0);
        }
    }

実行画面

今回作成したソースはこちら

[C#]Microsoft Expression Encoderを使用して簡易画面キャプチャソフトを作る、その3。

Microsoft Expression Encoderを使用したキャプチャソフト続き。

もうやめるといいつつ、改良を加えてみた。改良点は2つ。
・キャプチャ時の画面の大きさをエンコード後も維持させる。
・録音デバイスの自動選択設定。

キャプチャ時の画面の大きさを維持
これは、エンコード時に画面の大きさを指定してしないと出力サイズがキャプチャ時のサイズよりも小さくなるという問題。
このキャプチャソフトはテンポラリに作成されたファイルを連結して一つのファイルとしてWMVファイルをエンコードして生成するので、その時にパラメータを指定してあげれば良い。
具体的にはMediaItemインスタンスのOutputFormat.VideoProfile.Sizeプロパティにサイズを指定する。

エンコード箇所ソース(一部割愛)

//// 対象ファイルのパスを取得(ファイル名は昇順になる辞書順)
var files = System.IO.Directory.GetFiles(_dir);

//// MediaItemインスタンスを作成
MediaItem item = new MediaItem(files.First());

//// 後のファイルをAddする
foreach (var file in files.Skip(1))
{
   item.Sources.Add(new Source(file));
}

//// オリジナルのサイズを維持
item.OutputFormat.VideoProfile.Size = new System.Drawing.Size(item.CropRect.Width, item.CropRect.Height);

//// エンコードJOBの作成
var job = new Job();
job.MediaItems.Add(item);

//// エンコードの開始
job.Encode();
job.Dispose();

録音デバイスの自動選択設定
これは動画の録画開始時に音声デバイスを自動で選択する機能。普段は普通のスピーカーをデフォルトの音声デバイスとして使用しているのだけれど、一時的にHDMIモニタなどを使用し、キャプチャを実行した時に、録音を行う音声デバイスを自動的に選択(HDMIモニタがプライマリのときはHDMIから音声を録音)するよう改良するというもの。

WMI(Windows Management Instrumentation)を使用して取得できると思ったらデバイス情報しか見えてこなかったので、以前使用したCoreAudioAPIを使用することに。

Vista Core Audio API Master Volume Control
http://www.codeproject.com/Articles/18520/Vista-Core-Audio-API-Master-Volume-Control

CoreAudioAPIのページの最初に記述されているGetDefaultAudioEndpoint()を使用してデフォルトの音声デバイスを取得し、IDプロパティがデバイスパスになるようなので、これを利用し元からあるソースを改修。思ったよりも楽にできた。
音声デバイスを取得する関数

        /// <summary>
        /// オーディオデバイスを取得する
        /// </summary>
        /// <returns></returns>
        private void GetAuidoDevice()
        {
            if (_audioDevice == null)
            {
                /// デバイスの一覧を取得
                var devs = Microsoft.Expression.Encoder.Devices.EncoderDevices.FindDevices(Microsoft.Expression.Encoder.Devices.EncoderDeviceType.Audio);
                
                /// CoreAudioAPIを使用してデフォルトのデバイスを取得
                var devEnum = (new CoreAudioApi.MMDeviceEnumerator()).GetDefaultAudioEndpoint(CoreAudioApi.EDataFlow.eRender, CoreAudioApi.ERole.eMultimedia);

                /// デバイスパスを参照してデフォルトデバイスを取得
                var defDevice = devs.Where(p => p.DevicePath == devEnum.ID);

                if (defDevice.Any())
                {
                    _audioDevice = defDevice.First();
                }
            }
        }

GetAuidoDevice関数はキャプチャ開始時に呼ばれる関数なので音声デバイスは常に音がでるものが選ばれるようになる。

尚、設定画面から音声デバイスの設定項目を外した。
Img20130203183713

今回作成したソースはこちら