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

簡易キャプチャソフト改良。
Formクラスの枠を使ってキャプチャ範囲を指定するという手抜きソフトですが、意外と使いやすいというwww
Img20130228204806

改良点
◇動画録画中途中キャンセル可
 これは、録画中に録画停止ボタン(右上)を右クリック、左クリック同時押しでその録画をキャンセルできるというもの。
◇録画範囲のエラーチェック
 キャプチャ対象エリアをディスプレイ外に指定された場合に強制終了する不具合をエラーを表示させるように修正。
◇キャプチャサイズ保持
 最後に使用した時のキャプチャサイズを設定ファイルに保持できるように修正。
◇簡易エンコーダー(EasyEncoder)同梱
 このキャプチャソフトは録画ファイルを00.xesc~99.xescまで作成するが、簡易エンコーダー(EasyEncoder)はこのファイルをWMVエンコードするソフト。通常は録画停止時にエンコードするが、されなかった場合用。
xescファイルと同ディレクトリ内で実行するか、xescファイルのディレクトリをコマンドライン引数で指定することでwmvへエンコードすることができる。
◇操作パネル小さくした
◇動画録画時、音声の録画とマウスカーソルのキャプチャありなしをコントロールに表示させるようにした。

既知のバグ
◇動画録画時の一時停止について
 試用版のExpression Encoderは録画開始時から10分経つと一時停止中でも構わず停止する。そのため、一時停止中に10分経ってしまい自動停止された後に新規JOBが開始され録画が始まってしまうという現象。そこまでして一時停止にこだわらないので今回はメッセージを表示して録画を停止してしまうようにした。
◇キャプチャフォームの大きさ変更不可問題
 これはキャプチャフォームの大きさを変更しているとあるところから変更できなくなる(Formの境界線に変更矢印が表示されなくなる)という致命的な問題。キャプチャフォームは録画中はWndProc()で移動不可、大きさ変更不可にしているのだが、この現象はわかんない状態。
◇設定ファイルバッティング問題
 このソフトは複数起動が可能なのだが、アプリケーション終了時に設定ファイルに設定データを保存している。なので、どっかでファイルIOがバッティングするとエラーになる。まぁ、しょうがない。

今後の改良
◇全画面キャプチャ
 全画面を対象としたキャプチャ。Expression EncoderはHD画質での録画も可能なのでWXGAのモニタ全画面もおk。
◇Expression Encoderのプリセット選択
 Expression Encoderには豊富なプリセットが用意されていてプログラム的に指定が可能だったりする。

プリセットの種類
Expression Bumper
Silverlight トレーラー
VC-1 256k DSL CBR
VC-1 256k DSL VBR
VC-1 512k DSL CBR
VC-1 512k DSL VBR
VC-1 HD 1080p VBR
VC-1 HD 720p VBR
VC-1 IIS スムーズ ストリーミング – 720p CBR
VC-1 IIS スムーズ ストリーミング – HD 1080p VBR
VC-1 IIS スムーズ ストリーミング – HD 420p VBR
VC-1 IIS スムーズ ストリーミング – SD 480p VBR
VC-1 IIS スムーズ ストリーミング – 画面エンコード VBR
VC-1 Windows Mobile
VC-1 Xbox 360 HD 1080p
VC-1 Xbox 360 HD 720p
VC-1 Zune 1
VC-1 Zune 2
VC-1 Zune 2 (AV ドック再生)
VC-1 Zune HD
VC-1 Zune HD (AV ドック再生)
VC-1 ブロードバンド CBR
VC-1 ブロードバンド VBR
VC-1 モーション サムネイル VBR
VC-1 画面エンコード VBR
VC-1 高速ブロードバンド CBR
VC-1 高速ブロードバンド VBR
WMA Lossless 5.1 オーディオ
WMA 音声オーディオ
WMA 高品質オーディオ
WMA 最良 VBR
WMA 低品質オーディオ
WMA 良質オーディオ
サンプルのオーバーレイ
ソース エンコード設定の適用
バランス
最速
最良

エンコード実施時のプリセットの指定

var job = new Job();
job.MediaItems.Add(item);

// プリセットの設定
job.ApplyPreset(Presets.AACGoodQualityAudio);

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

プリセットを指定することで出力されるファイルがそれぞれに応じた音声コーデック、画面の大きさに変更されるようになる。

Expression Encoder4自体のソフトを見ているとかなりカスタマイズが可能なようなので、プログラムレベルでこれらが指定できるのは非常にありがたい。うーん、本当に開発が終わってしまうのが惜しい。
Img20130228205755

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

[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

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

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

以前作成したMicrosoft Expression Encoder4を使用したキャプチャソフトにGIFアニメーション作成機能を追加してみた。

GIFエンコーダーにはNGifというエンコーダーを使用。フレームレートが高いとgifのエンコードにかなり時間がかかる。

あと、いろいろバグ修正。エンコード中画面を邪魔にならないようにしたり、複数同時起動時に画面番号をつけたりした。
Expression Encoderを使ってWebカメラを使ったストリーミングとか試してみたいけど、色々機能つけすぎてソースが汚くなったので、もういじりたくない。

ソースはこちら
別途、Microsoft Expression Encoder4が必要。
参照に、JSON.NETNGifが必要。

複数起動時の画面番号
Img20121225214309

GIFアニメーション作成機能の追加

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

画面キャプチャいろいろ調べていたらMicrosoft Expression Encoderが面白そうだったので、いろいろいじってみた。
動画の画面キャプチャについて、かなり簡単にできるようだったので、ちょっと作りこんでみた。無償版なら10分まで動画のキャプチャが可能。音声も録音できるので便利。

Expression Encoder 4
http://www.microsoft.com/japan/products/expression/products/encoder_overview.aspx

なお、こちらの方のエントリーを参照した。
http://code-life.net/?s=Expression+Encoder


実行画面

画面キャプチャのAPIがはじめから用意されていて、範囲を指定すると緑の枠が表示され、その範囲がキャプチャされる。キャプチャされたファイルは Expression Encoder 画面キャプチャ ファイル (.xesc) というファイル形式で保存される。このままではWindowsMediaPlayerでしか再生できないので、Expression Encoderの機能を使用して、wmv(VC-1コーデック)に変換して終了。これで他の動画プレイヤーやYoutubeにアップできる形式になる。
詳細はSDKをインストールした時にできるSDKフォルダの中のサンプルを参照すると良い。

動画キャプチャソース

                _scrJob = new Microsoft.Expression.Encoder.ScreenCapture.ScreenCaptureJob();
                _scrJob.CaptureRectangle = GetLocation();
                _scrJob.ScreenCaptureVideoProfile.FrameRate = 25;
                _scrJob.OutputScreenCaptureFileName = @"C:\Movie\aaa.xesc";
                var devs = Microsoft.Expression.Encoder.Devices.EncoderDevices.FindDevices(Microsoft.Expression.Encoder.Devices.EncoderDeviceType.Audio);
                _scrJob.AddAudioDeviceSource(devs[3]);  /// ここはデフォルトに設定されているデバイスがくるようにする
                _scrJob.Start();

キャプチャ対象位置の指定
キャプチャ画面の幅と高さかは偶数値を指定しないとだめなので、プロパティCaptureRectangle に渡す数値を決めるGetLocation関数は次のようになる。
※Formに貼り付けているPanelControlのサイズをキャプチャ対象とする場合。

        /// <summary>
        /// キャプチャ対象画面の位置を取得
        /// </summary>
        /// <returns></returns>
        public Rectangle GetLocation()
        {
            var rc = new Rectangle(panel1.PointToScreen(panel1.ClientRectangle.Location), panel1.Size);

            rc.Width = (rc.Width % 2 == 0) ? rc.Width : rc.Width + 1;
            rc.Height = (rc.Height % 2 == 0) ? rc.Height : rc.Height + 1;

            return rc;
        }

録音デバイスの指定
録音デバイスの指定で音声も録音できるようになる。複数の音声デバイスがある場合、デフォルトの音声デバイスが指定されるようにする。
さて、デフォルトの音声デバイスはどうやってわかるのやら。。。

var devs = Microsoft.Expression.Encoder.Devices.EncoderDevices.FindDevices(Microsoft.Expression.Encoder.Devices.EncoderDeviceType.Audio);
_scrJob.AddAudioDeviceSource(devs[3]);  /// ここはデフォルトに設定されているデバイスがくるようにする

wmv(VC-1)へのエンコード

MediaItem mItem;
mItem = new MediaItem(@"C:\Movie\aaa.xesc");
Job job = new Job();
job.MediaItems.Add(mItem);
job.Encode();

動画を連結する場合
複数の動画を連結させてからエンコードをかける事ができる。MediaItem()には引数なしのコンストラクタが無いので、初めのファイルをコンストラクタに指定し、後のファイルはMediaItemのSourcesに追加する。

var files = System.IO.Directory.GetFiles(_dir).ToList();
/// MediaItemのコンストラクタに1つめのファイルを指定
MediaItem item = new MediaItem(files.First());

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

動画を連続してキャプチャする
無償版は10分までキャプチャが可能であるが、10分を超えた場合自動でキャプチャが停止する。キャプチャが自動で終了した時に発生してくれるイベントがある。これを利用することで、次のキャプチャを開始すれば良い。
後はキャプチャ動画を連結してエンコードをかけることで、10分を超える動画の作成が可能。

イベントを利用して継続してキャプる例
キャプチャ動作を手動で停止した際にもイベントが発生してしまうので、状態管理を施しておく。Microsoft.Expression.Encoder.ScreenCapture.ScreenCaptureJob型のインスタンスを2つ(0,1)持っておき、交互に動作を切り替える。

            /// 動画キャプチャが自動停止した場合、新規JOBを自動的に開始
            job.ScreenCaptureFinished += (s, e) =>
                {
                    /// 状態がRECODEのみ新規JOB開始
                    if (_stat == MediaStatus.RECODE)
                    {
                        /// カレントのJOB番号を入れ替える
                        _currentJob = _currentJob == 0 ? 1 : 0;
                        StartNewJob();
                    }
                };
            
            /// 動画キャプチャ開始
            job.Start();

今回作成したソースはこちら※ExpressionEncoderとNewtonsoft.Jsonの参照が必要。