+++ /dev/null
-using System;\r
-using System.Collections.Generic;\r
-using System.Diagnostics;\r
-using System.Runtime.InteropServices;\r
-using System.IO;\r
-using System.Drawing;\r
-using System.Drawing.Imaging;\r
-using System.Threading;\r
-using SharpDX;\r
-using SharpDX.Direct3D9;\r
-using SharpDX.Multimedia;\r
-using DirectShowLib;\r
-\r
-namespace FDK\r
-{\r
- /// <summary>\r
- /// <para>DirectShowを用いたクリップ(動画+音声)を扱う。</para>\r
- /// <para>1つのクリップにつき1つの CDirectShow インスタンスを生成する。</para>\r
- /// <para>再生の開始や停止などの操作の他、任意の時点でスナップイメージを取得することができる。</para>\r
- /// </summary>\r
- public class CDirectShow : IDisposable\r
- {\r
- // プロパティ\r
-\r
- public const uint WM_DSGRAPHNOTIFY = CWin32.WM_APP + 1;\r
-\r
- public enum Eグラフの状態 { 完全停止中, 再生のみ停止中, 再生中, 完全停止へ遷移中, 再生のみ停止へ遷移中, 再生へ遷移中, 未定 }\r
- public Eグラフの状態 eグラフの状態\r
- {\r
- get\r
- {\r
- var status = Eグラフの状態.未定;\r
-\r
- if( this.MediaCtrl != null )\r
- {\r
- FilterState fs;\r
- int hr = this.MediaCtrl.GetState( 0, out fs ); // それなりに重たいので注意。\r
-\r
- if( hr == CWin32.E_FAIL )\r
- {\r
- #region [ 失敗。]\r
- //-----------------\r
- status = Eグラフの状態.未定;\r
- //-----------------\r
- #endregion\r
- }\r
- else if( hr == CWin32.VFW_S_STATE_INTERMEDIATE )\r
- {\r
- #region [ 遷移中。]\r
- //-----------------\r
- switch( fs )\r
- {\r
- case FilterState.Running:\r
- status = Eグラフの状態.再生へ遷移中;\r
- break;\r
-\r
- case FilterState.Paused:\r
- status = Eグラフの状態.再生のみ停止へ遷移中;\r
- break;\r
-\r
- case FilterState.Stopped:\r
- status = Eグラフの状態.完全停止へ遷移中;\r
- break;\r
-\r
- default:\r
- status = Eグラフの状態.未定;\r
- break;\r
- }\r
- //-----------------\r
- #endregion\r
- }\r
- else\r
- {\r
- #region [ 安定状態。]\r
- //-----------------\r
- switch( fs )\r
- {\r
- case FilterState.Running:\r
- status = Eグラフの状態.再生中;\r
- break;\r
-\r
- case FilterState.Paused:\r
- status = Eグラフの状態.再生のみ停止中;\r
- break;\r
-\r
- case FilterState.Stopped:\r
- status = Eグラフの状態.完全停止中;\r
- break;\r
-\r
- default:\r
- status = Eグラフの状態.未定;\r
- break;\r
- }\r
- //-----------------\r
- #endregion\r
- }\r
- }\r
- return status;\r
- }\r
- }\r
- public bool b再生中;\r
- public bool bループ再生;\r
-\r
- public int n幅px\r
- {\r
- get;\r
- protected set;\r
- }\r
- public int n高さpx\r
- {\r
- get;\r
- protected set;\r
- }\r
- public int nスキャンライン幅byte\r
- {\r
- get;\r
- protected set;\r
- }\r
- public int nデータサイズbyte\r
- {\r
- get;\r
- protected set;\r
- }\r
- public bool b上下反転\r
- {\r
- get;\r
- protected set;\r
- }\r
-\r
- public bool b音声のみ\r
- {\r
- get;\r
- protected set;\r
- }\r
- \r
- public long n現在のグラフの再生位置ms\r
- {\r
- get\r
- {\r
- if( this.MediaSeeking == null )\r
- return 0;\r
-\r
- long current;\r
- int hr = this.MediaSeeking.GetCurrentPosition( out current );\r
- DsError.ThrowExceptionForHR( hr );\r
- return (long) ( current / ( 1000.0 * 10.0 ) );\r
- }\r
- }\r
- /// <summary>\r
- /// <para>無音:0~100:原音。set のみ。</para>\r
- /// </summary>\r
- public int n音量\r
- {\r
- get\r
- {\r
- return this._n音量;\r
- }\r
- set\r
- {\r
- if( this.BasicAudio == null )\r
- return;\r
-\r
-\r
- // 値を保存。\r
-\r
- this._n音量 = value;\r
-\r
-\r
- // リニア音量をデシベル音量に変換。\r
-\r
- int n音量db = 0;\r
-\r
- if( value == 0 )\r
- {\r
- n音量db = -10000; // 完全無音\r
- }\r
- else\r
- {\r
- n音量db = (int) ( ( 20.0 * Math.Log10( ( (double) value ) / 100.0 ) ) * 100.0 );\r
- }\r
-\r
-\r
- // デシベル音量でグラフの音量を変更。\r
-\r
- this.BasicAudio.put_Volume( n音量db );\r
- }\r
- }\r
- /// <summary>\r
- /// <para>左:-100~中央:0~100:右。set のみ。</para>\r
- /// </summary>\r
- public int n位置\r
- {\r
- set\r
- {\r
- if( this.BasicAudio == null )\r
- return;\r
-\r
- // リニア位置をデシベル位置に変換。\r
-\r
- int n位置 = Math.Min( Math.Max( value, -100 ), +100 );\r
- int n位置db = 0;\r
-\r
- if( n位置 == 0 )\r
- {\r
- n位置db = 0;\r
- }\r
- else if( n位置 == -100 )\r
- {\r
- n位置db = -10000;\r
- }\r
- else if( n位置 == 100 )\r
- {\r
- n位置db = +10000;\r
- }\r
- else if( n位置 < 0 )\r
- {\r
- n位置db = (int) ( ( 20.0 * Math.Log10( ( (double) ( n位置 + 100 ) ) / 100.0 ) ) * 100.0 );\r
- }\r
- else\r
- {\r
- n位置db = (int) ( ( -20.0 * Math.Log10( ( (double) ( 100 - n位置 ) ) / 100.0 ) ) * 100.0 );\r
- }\r
-\r
- // デシベル位置でグラフの位置を変更。\r
-\r
- this.BasicAudio.put_Balance( n位置db );\r
- }\r
- }\r
- public IMediaControl MediaCtrl;\r
- public IMediaEventEx MediaEventEx;\r
- public IMediaSeeking MediaSeeking;\r
- public IBasicAudio BasicAudio;\r
- public IGraphBuilder graphBuilder;\r
-\r
- /// <summary>\r
- /// <para>CDirectShowインスタンスに固有のID。</para>\r
- /// <para>DirectShow イベントをウィンドウに発信する際、MessageID として "WM_APP+インスタンスID" を発信する。</para>\r
- /// <para>これにより、受け側でイベント発信インスタンスを特定することが可能になる。</para>\r
- /// </summary>\r
- public int nインスタンスID\r
- {\r
- get;\r
- protected set;\r
- }\r
-\r
-\r
- // メソッド\r
-\r
- public CDirectShow()\r
- {\r
- }\r
- public CDirectShow( string fileName, IntPtr hWnd, bool bオーディオレンダラなし )\r
- {\r
- // 初期化。\r
-\r
- this.n幅px = 0;\r
- this.n高さpx = 0;\r
- this.b上下反転 = false;\r
- this.nスキャンライン幅byte = 0;\r
- this.nデータサイズbyte = 0;\r
- this.b音声のみ = false;\r
- this.graphBuilder = null;\r
- this.MediaCtrl = null;\r
- this.b再生中 = false;\r
- this.bループ再生 = false;\r
-\r
-\r
- // 静的リストに登録し、インスタンスIDを得る。\r
-\r
- CDirectShow.tインスタンスを登録する( this );\r
-\r
-\r
- // 並列処理準備。\r
-\r
- if( CDirectShow.n並列度 == 0 ) // 算出がまだなら算出する。\r
- CDirectShow.n並列度 = Environment.ProcessorCount; // 並列度=CPU数とする。\r
-\r
- unsafe\r
- {\r
- this.dgライン描画ARGB32 = new DGライン描画[ CDirectShow.n並列度 ];\r
- this.dgライン描画XRGB32 = new DGライン描画[ CDirectShow.n並列度 ];\r
-\r
- for( int i = 0; i < CDirectShow.n並列度; i++ )\r
- {\r
- this.dgライン描画ARGB32[ i ] = new DGライン描画( this.tライン描画ARGB32 );\r
- this.dgライン描画XRGB32[ i ] = new DGライン描画( this.tライン描画XRGB32 );\r
- }\r
- }\r
-\r
- try\r
- {\r
- int hr = 0;\r
-\r
-\r
- // グラフビルダを生成。\r
-\r
- this.graphBuilder = (IGraphBuilder) new FilterGraph();\r
-#if DEBUG\r
- // ROT への登録。\r
- this.rot = new DsROTEntry( graphBuilder );\r
-#endif\r
-\r
-\r
- // QueryInterface。存在しなければ null。\r
-\r
- this.MediaCtrl = this.graphBuilder as IMediaControl;\r
- this.MediaEventEx = this.graphBuilder as IMediaEventEx;\r
- this.MediaSeeking = this.graphBuilder as IMediaSeeking;\r
- this.BasicAudio = this.graphBuilder as IBasicAudio;\r
-\r
-\r
- // IMemoryRenderer をグラフに挿入。\r
-\r
- AMMediaType mediaType = null;\r
-\r
- this.memoryRendererObject = new MemoryRenderer();\r
- this.memoryRenderer = (IMemoryRenderer) this.memoryRendererObject;\r
- var baseFilter = (IBaseFilter) this.memoryRendererObject;\r
-\r
- hr = this.graphBuilder.AddFilter( baseFilter, "MemoryRenderer" );\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
-\r
- // fileName からグラフを自動生成。\r
-\r
- hr = this.graphBuilder.RenderFile( fileName, null ); // IMediaControl.RenderFile() は推奨されない\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
-\r
- // 音声のみ?\r
-\r
- {\r
- IBaseFilter videoRenderer;\r
- IPin videoInputPin;\r
- IBaseFilter audioRenderer;\r
- IPin audioInputPin;\r
- CDirectShow.SearchMMRenderers( this.graphBuilder, out videoRenderer, out videoInputPin, out audioRenderer, out audioInputPin );\r
- if ( videoRenderer == null && audioRenderer != null )\r
- {\r
- this.b音声のみ = true;\r
- }\r
- else\r
- {\r
- C共通.tCOMオブジェクトを解放する(ref videoInputPin);\r
- C共通.tCOMオブジェクトを解放する(ref videoRenderer);\r
- C共通.tCOMオブジェクトを解放する(ref audioInputPin);\r
- C共通.tCOMオブジェクトを解放する(ref audioRenderer);\r
- }\r
- }\r
-\r
-\r
- // イメージ情報を取得。\r
-\r
- if( !this.b音声のみ )\r
- {\r
- long n;\r
- int m;\r
- this.memoryRenderer.GetWidth( out n );\r
- this.n幅px = (int) n;\r
- this.memoryRenderer.GetHeight( out n );\r
- this.n高さpx = (int) n;\r
- this.memoryRenderer.IsBottomUp( out m );\r
- this.b上下反転 = ( m != 0 );\r
- this.memoryRenderer.GetBufferSize( out n );\r
- this.nデータサイズbyte = (int) n;\r
- this.nスキャンライン幅byte = (int) this.nデータサイズbyte / this.n高さpx;\r
- // C共通.tCOMオブジェクトを解放する( ref baseFilter ); なんかキャスト元のオブジェクトまで解放されるので解放禁止。\r
- }\r
-\r
-\r
- // グラフを修正する。\r
-\r
- if( bオーディオレンダラなし )\r
- {\r
- WaveFormat dummy1;\r
- byte[] dummy2;\r
- CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する( this.graphBuilder, out dummy1, out dummy2 );\r
- }\r
-\r
-\r
- // その他の処理。\r
-\r
- this.t再生準備開始(); // 1回以上 IMediaControl を呼び出してないと、IReferenceClock は取得できない。\r
- this.t遷移完了まで待って状態を取得する(); // 完全に Pause へ遷移するのを待つ。(環境依存)\r
-\r
-\r
- // イベント用ウィンドウハンドルを設定。\r
-\r
- this.MediaEventEx.SetNotifyWindow( hWnd, (int) WM_DSGRAPHNOTIFY, new IntPtr( this.nインスタンスID ) );\r
- }\r
-#if !DEBUG\r
- catch( Exception e )\r
- {\r
- C共通.t例外の詳細をログに出力する( e );\r
- this.Dispose();\r
- throw; // 例外発出。\r
- }\r
-#endif\r
- finally\r
- {\r
- }\r
- }\r
-\r
- public void t再生準備開始()\r
- {\r
- if( this.MediaCtrl != null )\r
- {\r
- int hr = this.MediaCtrl.Pause(); // 再生準備を開始する。ここでは準備が完了するまで待たない。\r
- DsError.ThrowExceptionForHR( hr );\r
- }\r
- }\r
- public void t再生開始()\r
- {\r
- if( this.MediaCtrl != null && --this.n再生一時停止呼び出しの累積回数 <= 0 )\r
- {\r
- //this.t遷移完了まで待って状態を取得する(); // 再生準備(だろう)がまだ完了してなければ、待つ。 → 意外と重い処理なので外部で判断して実行するよう変更する。(2011.8.7)\r
-\r
- int hr = this.MediaCtrl.Run(); // 再生開始。\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
- this.n再生一時停止呼び出しの累積回数 = 0; // 一時停止回数はここでリセットされる。\r
- this.b再生中 = true;\r
- }\r
- }\r
- public void t再生一時停止()\r
- {\r
- if( this.MediaCtrl != null && this.n再生一時停止呼び出しの累積回数 == 0 )\r
- {\r
- int hr = this.MediaCtrl.Pause();\r
- DsError.ThrowExceptionForHR( hr );\r
- }\r
- this.n再生一時停止呼び出しの累積回数++;\r
- this.b再生中 = false;\r
- }\r
- public void t再生停止()\r
- {\r
- if( this.MediaCtrl != null )\r
- {\r
- int hr = this.MediaCtrl.Stop();\r
- DsError.ThrowExceptionForHR( hr );\r
- }\r
-\r
- // 次への準備。\r
- //this.t再生位置を変更する( 0.0 ); → より細かく制御するために、FDK外部で制御するように変更。(2011.8.7)\r
- //this.t再生準備開始();\r
-\r
- this.n再生一時停止呼び出しの累積回数 = 0; // 停止すると、一時停止呼び出し累積回数はリセットされる。\r
- this.b再生中 = false;\r
- }\r
- public void t再生位置を変更( double db再生位置ms )\r
- {\r
- if( this.MediaSeeking == null )\r
- return;\r
-\r
- int hr = this.MediaSeeking.SetPositions(\r
- DsLong.FromInt64( (long) ( db再生位置ms * 1000.0 * 10.0 ) ),\r
- AMSeekingSeekingFlags.AbsolutePositioning,\r
- null,\r
- AMSeekingSeekingFlags.NoPositioning );\r
-\r
- DsError.ThrowExceptionForHR( hr );\r
- }\r
- public void t最初から再生開始()\r
- {\r
- this.t再生位置を変更( 0.0 );\r
- this.t再生開始();\r
- }\r
- public Eグラフの状態 t遷移完了まで待って状態を取得する()\r
- {\r
- var status = Eグラフの状態.未定;\r
-\r
- if( this.MediaCtrl != null )\r
- {\r
- FilterState fs;\r
- int hr = this.MediaCtrl.GetState( 1000, out fs ); // 遷移完了まで最大1000ms待つ。\r
- }\r
- return this.eグラフの状態;\r
- }\r
- public unsafe void t現時点における最新のスナップイメージをTextureに転写する( CTexture texture )\r
- {\r
- int hr;\r
-\r
- #region [ 再生してないなら何もせず帰還。(一時停止中はOK。)]\r
- //-----------------\r
- if( !this.b再生中 )\r
- return;\r
- //-----------------\r
- #endregion\r
- #region [ 音声のみなら何もしない。]\r
- //-----------------\r
- if( this.b音声のみ )\r
- return;\r
- //-----------------\r
- #endregion\r
-\r
- DataRectangle dr = texture.texture.LockRectangle( 0, LockFlags.Discard );\r
- try\r
- {\r
- if( this.nスキャンライン幅byte == dr.Pitch )\r
- {\r
- #region [ (A) ピッチが合うので、テクスチャに直接転送する。]\r
- //-----------------\r
- hr = this.memoryRenderer.GetCurrentBuffer( dr.DataPointer, this.nデータサイズbyte );\r
- DsError.ThrowExceptionForHR( hr );\r
- //-----------------\r
- #endregion\r
- }\r
- else\r
- {\r
- this.b上下反転 = false; // こちらの方法では常に正常\r
-\r
- #region [ (B) ピッチが合わないので、メモリに転送してからテクスチャに転送する。]\r
- //-----------------\r
-\r
- #region [ IMemoryRenderer からバッファにイメージデータを読み込む。]\r
- //-----------------\r
- if( this.ip == IntPtr.Zero )\r
- this.ip = Marshal.AllocCoTaskMem( this.nデータサイズbyte );\r
-\r
- hr = this.memoryRenderer.GetCurrentBuffer( this.ip, this.nデータサイズbyte );\r
- DsError.ThrowExceptionForHR( hr );\r
- //-----------------\r
- #endregion\r
-\r
- #region [ テクスチャにスナップイメージを転送。]\r
- //-----------------\r
- bool bARGB32 = true;\r
-\r
- switch( texture.Format )\r
- {\r
- case Format.A8R8G8B8:\r
- bARGB32 = true;\r
- break;\r
-\r
- case Format.X8R8G8B8:\r
- bARGB32 = false;\r
- break;\r
-\r
- default:\r
- return; // 未対応のフォーマットは無視。\r
- }\r
-\r
- // スレッドプールを使って並列転送する準備。\r
-\r
- this.ptrSnap = (byte*) this.ip.ToPointer();\r
- var ptr = stackalloc UInt32*[ CDirectShow.n並列度 ]; // stackalloc(GC対象外、メソッド終了時に自動開放)は、スタック変数相手にしか使えない。\r
- ptr[ 0 ] = (UInt32*) dr.DataPointer.ToPointer(); // ↓\r
- for( int i = 1; i < CDirectShow.n並列度; i++ ) // スタック変数で確保、初期化して…\r
- ptr[ i ] = ptr[ i - 1 ] + this.n幅px; // ↓\r
- this.ptrTexture = ptr; // スタック変数をクラスメンバに渡す(これならOK)。\r
-\r
-\r
- // 並列度が1ならシングルスレッド、2以上ならマルチスレッドで転送する。\r
- // → CPUが1つの場合、わざわざスレッドプールのスレッドで処理するのは無駄。\r
-\r
- if( CDirectShow.n並列度 == 1 )\r
- {\r
- if( bARGB32 )\r
- this.tライン描画ARGB32( 0 );\r
- else\r
- this.tライン描画XRGB32( 0 );\r
- }\r
- else\r
- {\r
- // 転送開始。\r
-\r
- var ar = new IAsyncResult[ CDirectShow.n並列度 ];\r
- for( int i = 0; i < CDirectShow.n並列度; i++ )\r
- {\r
- ar[ i ] = ( bARGB32 ) ?\r
- this.dgライン描画ARGB32[ i ].BeginInvoke( i, null, null ) :\r
- this.dgライン描画XRGB32[ i ].BeginInvoke( i, null, null );\r
- }\r
-\r
-\r
- // 転送完了待ち。\r
-\r
- for( int i = 0; i < CDirectShow.n並列度; i++ )\r
- {\r
- if( bARGB32 )\r
- this.dgライン描画ARGB32[ i ].EndInvoke( ar[ i ] );\r
- else\r
- this.dgライン描画XRGB32[ i ].EndInvoke( ar[ i ] );\r
- }\r
- }\r
-\r
- this.ptrSnap = null;\r
- this.ptrTexture = null;\r
- //-----------------\r
- #endregion\r
-\r
- //-----------------\r
- #endregion\r
- }\r
- }\r
- finally\r
- {\r
- texture.texture.UnlockRectangle( 0 );\r
- }\r
- }\r
-\r
- private IntPtr ip = IntPtr.Zero;\r
-\r
- public static void tグラフを解析しデバッグ出力する( IGraphBuilder graphBuilder )\r
- {\r
- if( graphBuilder == null )\r
- {\r
- Debug.WriteLine( "指定されたグラフが null です。" );\r
- return;\r
- }\r
-\r
- int hr = 0;\r
-\r
- IEnumFilters eFilters;\r
- hr = graphBuilder.EnumFilters( out eFilters );\r
- DsError.ThrowExceptionForHR( hr );\r
- {\r
- var filters = new IBaseFilter[ 1 ];\r
- while( eFilters.Next( 1, filters, IntPtr.Zero ) == CWin32.S_OK )\r
- {\r
- FilterInfo filterInfo;\r
- hr = filters[ 0 ].QueryFilterInfo( out filterInfo );\r
- DsError.ThrowExceptionForHR( hr );\r
- {\r
- Debug.WriteLine( filterInfo.achName ); // フィルタ名表示。\r
- if( filterInfo.pGraph != null )\r
- C共通.tCOMオブジェクトを解放する( ref filterInfo.pGraph );\r
- }\r
-\r
- IEnumPins ePins;\r
- hr = filters[ 0 ].EnumPins( out ePins );\r
- DsError.ThrowExceptionForHR( hr );\r
- {\r
- var pins = new IPin[ 1 ];\r
- while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )\r
- {\r
- PinInfo pinInfo;\r
- hr = pins[ 0 ].QueryPinInfo( out pinInfo );\r
- DsError.ThrowExceptionForHR( hr );\r
- {\r
- Debug.Write( " " + pinInfo.name ); // ピン名表示。\r
- Debug.Write( ( pinInfo.dir == PinDirection.Input ) ? " ← " : " → " );\r
-\r
- IPin connectPin;\r
- hr = pins[ 0 ].ConnectedTo( out connectPin );\r
- if( hr != CWin32.S_OK )\r
- Debug.WriteLine( "(未接続)" );\r
- else\r
- {\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
- PinInfo connectPinInfo;\r
- hr = connectPin.QueryPinInfo( out connectPinInfo );\r
- DsError.ThrowExceptionForHR( hr );\r
- {\r
- FilterInfo connectFilterInfo;\r
- hr = connectPinInfo.filter.QueryFilterInfo( out connectFilterInfo );\r
- DsError.ThrowExceptionForHR( hr );\r
- {\r
- Debug.Write( "[" + connectFilterInfo.achName + "]." ); // 接続先フィルタ名\r
-\r
- if( connectFilterInfo.pGraph != null )\r
- C共通.tCOMオブジェクトを解放する( ref connectFilterInfo.pGraph );\r
- }\r
-\r
- Debug.WriteLine( connectPinInfo.name ); // 接続先ピン名\r
- if( connectPinInfo.filter != null )\r
- C共通.tCOMオブジェクトを解放する( ref connectPinInfo.filter );\r
- DsUtils.FreePinInfo( connectPinInfo );\r
- }\r
- C共通.tCOMオブジェクトを解放する( ref connectPin );\r
- }\r
- if( pinInfo.filter != null )\r
- C共通.tCOMオブジェクトを解放する( ref pinInfo.filter );\r
- DsUtils.FreePinInfo( pinInfo );\r
- }\r
- C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );\r
- }\r
- }\r
- C共通.tCOMオブジェクトを解放する( ref ePins );\r
-\r
- C共通.tCOMオブジェクトを解放する( ref filters[ 0 ] );\r
- }\r
- }\r
- C共通.tCOMオブジェクトを解放する( ref eFilters );\r
-\r
- Debug.Flush();\r
- }\r
- public static void tオーディオレンダラをNullレンダラに変えてフォーマットを取得する( IGraphBuilder graphBuilder, out WaveFormat wfx, out byte[] wfx拡張データ )\r
- {\r
- int hr = 0;\r
-\r
- IBaseFilter audioRenderer = null;\r
- IPin rendererInputPin = null;\r
- IPin rendererConnectedOutputPin = null;\r
- IBaseFilter nullRenderer = null;\r
- IPin nullRendererInputPin = null;\r
- wfx = null;\r
- wfx拡張データ = new byte[ 0 ];\r
-\r
- try\r
- {\r
- // audioRenderer を探す。\r
-\r
- audioRenderer = CDirectShow.tオーディオレンダラを探して返す( graphBuilder );\r
- if( audioRenderer == null )\r
- return; // なかった\r
-\r
- #region [ 音量ゼロで一度再生する。(オーディオレンダラの入力ピンMediaTypeが、接続時とは異なる「正しいもの」に変わる可能性があるため。)]\r
- //-----------------\r
- {\r
- // ここに来た時点で、グラフのビデオレンダラは無効化(NullRendererへの置換や除去など)しておくこと。\r
- // さもないと、StopWhenReady() 時に一瞬だけ Activeウィンドウが表示されてしまう。\r
-\r
- var mediaCtrl = (IMediaControl) graphBuilder;\r
- var basicAudio = (IBasicAudio) graphBuilder;\r
- \r
- basicAudio.put_Volume( -10000 ); // 最小音量\r
- \r
-\r
- // グラフを再生してすぐ止める。(Paused → Stopped へ遷移する)\r
- \r
- mediaCtrl.StopWhenReady();\r
-\r
- \r
- // グラフが Stopped に遷移完了するまで待つ。(StopWhenReady() はグラフが Stopped になるのを待たずに帰ってくる。)\r
-\r
- FilterState fs = FilterState.Paused;\r
- hr = CWin32.S_FALSE;\r
- while( fs != FilterState.Stopped || hr != CWin32.S_OK )\r
- hr = mediaCtrl.GetState( 10, out fs );\r
- \r
-\r
- // 終了処理。\r
-\r
- basicAudio.put_Volume( 0 ); // 最大音量\r
- \r
- basicAudio = null;\r
- mediaCtrl = null;\r
- }\r
- //-----------------\r
- #endregion\r
-\r
- // audioRenderer の入力ピンを探す。\r
-\r
- rendererInputPin = t最初の入力ピンを探して返す( audioRenderer );\r
- if( rendererInputPin == null )\r
- return;\r
-\r
-\r
- // WAVEフォーマットを取得し、wfx 引数へ格納する。\r
-\r
- var type = new AMMediaType();\r
- hr = rendererInputPin.ConnectionMediaType( type );\r
- DsError.ThrowExceptionForHR( hr );\r
- try\r
- {\r
- #region [ type.formatPtr から wfx に、拡張領域を除くデータをコピーする。]\r
- //-----------------\r
- var wfxTemp = new WaveFormatEx(); // SlimDX.Multimedia.WaveFormat は Marshal.PtrToStructure() で使えないので、それが使える DirectShowLib.WaveFormatEx を介して取得する。(面倒…)\r
- Marshal.PtrToStructure( type.formatPtr, (object) wfxTemp );\r
-\r
- wfx = WaveFormat.CreateCustomFormat( (WaveFormatEncoding) wfxTemp.wFormatTag, wfxTemp.nSamplesPerSec, wfxTemp.nChannels, wfxTemp.nAvgBytesPerSec, wfxTemp.nBlockAlign, wfxTemp.wBitsPerSample );\r
- //-----------------\r
- #endregion\r
- #region [ 拡張領域が存在するならそれを wfx拡張データ に格納する。 ]\r
- //-----------------\r
- int nWaveFormatEx本体サイズ = 16 + 2; // sizeof( WAVEFORMAT ) + sizof( WAVEFORMATEX.cbSize )\r
- int nはみ出しサイズbyte = type.formatSize - nWaveFormatEx本体サイズ;\r
-\r
- if( nはみ出しサイズbyte > 0 )\r
- {\r
- wfx拡張データ = new byte[ nはみ出しサイズbyte ];\r
- var hGC = GCHandle.Alloc( wfx拡張データ, GCHandleType.Pinned ); // 動くなよー\r
- unsafe\r
- {\r
- byte* src = (byte*) type.formatPtr.ToPointer();\r
- byte* dst = (byte*) hGC.AddrOfPinnedObject().ToPointer();\r
- CWin32.CopyMemory( dst, src + nWaveFormatEx本体サイズ, (uint) nはみ出しサイズbyte );\r
- }\r
- hGC.Free();\r
- }\r
- //-----------------\r
- #endregion\r
- }\r
- finally\r
- {\r
- if( type != null )\r
- DsUtils.FreeAMMediaType( type );\r
- }\r
-\r
-\r
- // audioRenderer につながる出力ピンを探す。\r
-\r
- hr = rendererInputPin.ConnectedTo( out rendererConnectedOutputPin );\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
-\r
- // audioRenderer をグラフから切断する。\r
-\r
- rendererInputPin.Disconnect();\r
- rendererConnectedOutputPin.Disconnect();\r
-\r
-\r
- // audioRenderer をグラフから除去する。\r
-\r
- hr = graphBuilder.RemoveFilter( audioRenderer );\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
-\r
- // nullRenderer を作成し、グラフに追加する。\r
-\r
- nullRenderer = (IBaseFilter) new NullRenderer();\r
- hr = graphBuilder.AddFilter( nullRenderer, "Audio Null Renderer" );\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
-\r
- // nullRenderer の入力ピンを探す。\r
-\r
- hr = nullRenderer.FindPin( "In", out nullRendererInputPin );\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
-\r
- // nullRenderer をグラフに接続する。\r
-\r
- hr = rendererConnectedOutputPin.Connect( nullRendererInputPin, null );\r
- DsError.ThrowExceptionForHR( hr );\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref nullRendererInputPin );\r
- C共通.tCOMオブジェクトを解放する( ref nullRenderer );\r
- C共通.tCOMオブジェクトを解放する( ref rendererConnectedOutputPin );\r
- C共通.tCOMオブジェクトを解放する( ref rendererInputPin );\r
- C共通.tCOMオブジェクトを解放する( ref audioRenderer );\r
- }\r
- }\r
- public static void ConnectNullRendererFromSampleGrabber(IGraphBuilder graphBuilder, IBaseFilter sampleGrabber)\r
- {\r
- int hr = 0;\r
- IBaseFilter videoRenderer = null;\r
- IPin videoRendererInputPin = null;\r
- IBaseFilter audioRenderer = null;\r
- IPin audioRendererInputPin = null;\r
- IPin connectedOutputPin = null;\r
- IPin nullRendererInputPin = null;\r
- IPin grabberOutputPin = null;\r
- IPin grabberOutputConnectedPin = null;\r
-\r
- try\r
- {\r
- // videoRenderer を探す。\r
- CDirectShow.SearchMMRenderers(graphBuilder, out videoRenderer, out videoRendererInputPin, out audioRenderer, out audioRendererInputPin);\r
- if (videoRenderer != null && audioRendererInputPin != null)\r
- {\r
- // 既存のレンダラにつながっているピン対を取得\r
- hr = videoRendererInputPin.ConnectedTo(out connectedOutputPin);\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- // それらを切断。前段の出力ピンとビデオレンダラの入力ピンを切断する。双方向から切断しないとグラフから切り離されないので注意。\r
- hr = videoRendererInputPin.Disconnect();\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = connectedOutputPin.Disconnect();\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- // ビデオレンダラをグラフから除去し、ヌルレンダラを追加\r
- hr = graphBuilder.RemoveFilter(videoRenderer);\r
- DsError.ThrowExceptionForHR(hr);\r
- IBaseFilter nullRenderer = new NullRenderer() as IBaseFilter;\r
- hr = graphBuilder.AddFilter(nullRenderer, "Video Null Renderer");\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- // nullRenderer の入力ピンを探す。\r
- hr = nullRenderer.FindPin("In", out nullRendererInputPin);\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = nullRendererInputPin.Disconnect();\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- // グラバの Out と Null Renderer の In を接続する。\r
- hr = sampleGrabber.FindPin("Out", out grabberOutputPin);\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = grabberOutputPin.ConnectedTo(out grabberOutputConnectedPin);\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = grabberOutputConnectedPin.Disconnect();\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = grabberOutputPin.Disconnect();\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = grabberOutputPin.Connect(nullRendererInputPin, null);\r
- DsError.ThrowExceptionForHR(hr);\r
- }\r
-\r
- if( audioRenderer != null && audioRendererInputPin != null )\r
- {\r
- C共通.tCOMオブジェクトを解放する(ref connectedOutputPin);\r
-\r
- // 既存のレンダラにつながっているピン対を取得\r
- hr = audioRendererInputPin.ConnectedTo(out connectedOutputPin);\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- // それらを切断。前段の出力ピンとビデオレンダラの入力ピンを切断する。双方向から切断しないとグラフから切り離されないので注意。\r
- hr = audioRendererInputPin.Disconnect();\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = connectedOutputPin.Disconnect();\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- // ビデオレンダラをグラフから除去し、ヌルレンダラを追加\r
- hr = graphBuilder.RemoveFilter(audioRenderer);\r
- DsError.ThrowExceptionForHR(hr);\r
- IBaseFilter nullRenderer = new NullRenderer() as IBaseFilter;\r
- hr = graphBuilder.AddFilter(nullRenderer, "Audio Null Renderer");\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- C共通.tCOMオブジェクトを解放する(ref nullRendererInputPin);\r
- hr = nullRenderer.FindPin("In", out nullRendererInputPin);\r
- DsError.ThrowExceptionForHR(hr);\r
- hr = connectedOutputPin.Connect(nullRendererInputPin, null);\r
- DsError.ThrowExceptionForHR(hr);\r
- }\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する(ref connectedOutputPin);\r
- C共通.tCOMオブジェクトを解放する(ref videoRendererInputPin);\r
- C共通.tCOMオブジェクトを解放する(ref videoRenderer);\r
- C共通.tCOMオブジェクトを解放する(ref audioRenderer);\r
- C共通.tCOMオブジェクトを解放する(ref audioRendererInputPin);\r
- C共通.tCOMオブジェクトを解放する(ref nullRendererInputPin);\r
- C共通.tCOMオブジェクトを解放する(ref grabberOutputPin);\r
- C共通.tCOMオブジェクトを解放する(ref grabberOutputConnectedPin);\r
- }\r
- }\r
-\r
- private static IPin t最初の入力ピンを探して返す( IBaseFilter baseFilter )\r
- {\r
- int hr = 0;\r
-\r
- IPin firstInputPin = null;\r
-\r
- IEnumPins ePins;\r
- hr = baseFilter.EnumPins( out ePins );\r
- DsError.ThrowExceptionForHR( hr );\r
- try\r
- {\r
- var pins = new IPin[ 1 ];\r
- while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )\r
- {\r
- PinInfo pinfo = new PinInfo() { filter = null };\r
- try\r
- {\r
- hr = pins[ 0 ].QueryPinInfo( out pinfo );\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
- if( pinfo.dir == PinDirection.Input )\r
- {\r
- firstInputPin = pins[ 0 ];\r
- break;\r
- }\r
- }\r
- finally\r
- {\r
- if( pinfo.filter != null )\r
- C共通.tCOMオブジェクトを解放する( ref pinfo.filter );\r
- DsUtils.FreePinInfo( pinfo );\r
-\r
- if( firstInputPin == null )\r
- C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );\r
- }\r
- }\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref ePins );\r
- }\r
-\r
- return firstInputPin;\r
- }\r
- private static void SearchMMRenderers( IFilterGraph graph, out IBaseFilter videoRenderer, out IPin inputVPin, out IBaseFilter audioRenderer, out IPin inputAPin )\r
- {\r
- int hr = 0;\r
- string strVRフィルタ名 = null;\r
- string strVRピンID = null;\r
- string strARフィルタ名 = null;\r
- string strARピンID = null;\r
-\r
- // ビデオレンダラと入力ピンを探し、そのフィルタ名とピンIDを控える。\r
-\r
- IEnumFilters eFilters;\r
- hr = graph.EnumFilters( out eFilters );\r
- DsError.ThrowExceptionForHR( hr );\r
- try\r
- {\r
- var filters = new IBaseFilter[ 1 ];\r
- while( eFilters.Next( 1, filters, IntPtr.Zero ) == CWin32.S_OK )\r
- {\r
- try\r
- {\r
- #region [ 出力ピンがない(レンダラである)ことを確認する。]\r
- //-----------------\r
- IEnumPins ePins;\r
- bool b出力ピンがある = false;\r
-\r
- hr = filters[ 0 ].EnumPins( out ePins );\r
- DsError.ThrowExceptionForHR( hr );\r
- try\r
- {\r
- var pins = new IPin[ 1 ];\r
- while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )\r
- {\r
- try\r
- {\r
- if( b出力ピンがある )\r
- continue;\r
-\r
- PinDirection dir;\r
- hr = pins[ 0 ].QueryDirection( out dir );\r
- DsError.ThrowExceptionForHR( hr );\r
- if( dir == PinDirection.Output )\r
- b出力ピンがある = true;\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );\r
- }\r
- }\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref ePins );\r
- }\r
-\r
- if( b出力ピンがある )\r
- continue; // 次のフィルタへ\r
-\r
- //-----------------\r
- #endregion\r
- #region [ 接続中の入力ピンが MEDIATYPE_Video に対応していたら、フィルタ名とピンIDを取得する。]\r
- //-----------------\r
- hr = filters[ 0 ].EnumPins( out ePins );\r
- DsError.ThrowExceptionForHR( hr );\r
- try\r
- {\r
- var pins = new IPin[ 1 ];\r
- while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )\r
- {\r
- try\r
- {\r
- if( !string.IsNullOrEmpty( strVRフィルタ名 ) )\r
- continue;\r
-\r
- var mediaType = new AMMediaType();\r
-\r
- #region [ 現在接続中の MediaType を取得。つながってなければ次のピンへ。]\r
- //-----------------\r
- hr = pins[ 0 ].ConnectionMediaType( mediaType );\r
- if( hr == CWin32.VFW_E_NOT_CONNECTED )\r
- continue; // つながってない\r
- DsError.ThrowExceptionForHR( hr );\r
- //-----------------\r
- #endregion\r
-\r
- try\r
- {\r
- if( mediaType.majorType.Equals( MediaType.Video ) )\r
- {\r
- #region [ フィルタ名取得!]\r
- //-----------------\r
- FilterInfo filterInfo;\r
- hr = filters[ 0 ].QueryFilterInfo( out filterInfo );\r
- DsError.ThrowExceptionForHR( hr );\r
- strVRフィルタ名 = filterInfo.achName;\r
- C共通.tCOMオブジェクトを解放する( ref filterInfo.pGraph );\r
- //-----------------\r
- #endregion\r
- #region [ ピンID取得!]\r
- //-----------------\r
- hr = pins[ 0 ].QueryId( out strVRピンID );\r
- DsError.ThrowExceptionForHR( hr );\r
- //-----------------\r
- #endregion\r
- }\r
- else if( mediaType.majorType.Equals( MediaType.Audio ) )\r
- {\r
- FilterInfo filterInfo;\r
- hr = filters[0].QueryFilterInfo(out filterInfo);\r
- DsError.ThrowExceptionForHR(hr);\r
- strARフィルタ名 = filterInfo.achName;\r
- C共通.tCOMオブジェクトを解放する(ref filterInfo.pGraph);\r
- hr = pins[0].QueryId(out strARピンID);\r
- DsError.ThrowExceptionForHR(hr);\r
- }\r
- }\r
- finally\r
- {\r
- DsUtils.FreeAMMediaType( mediaType );\r
- }\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );\r
- }\r
- }\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref ePins );\r
- }\r
-\r
- //-----------------\r
- #endregion\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref filters[ 0 ] );\r
- }\r
- }\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref eFilters );\r
- }\r
-\r
-\r
- // 改めてフィルタ名とピンIDからこれらのインターフェースを取得し、戻り値として返す。\r
-\r
- videoRenderer = null;\r
- inputVPin = null;\r
- audioRenderer = null;\r
- inputAPin = null;\r
-\r
- if( !string.IsNullOrEmpty( strVRフィルタ名 ) )\r
- {\r
- hr = graph.FindFilterByName( strVRフィルタ名, out videoRenderer );\r
- DsError.ThrowExceptionForHR( hr );\r
-\r
- hr = videoRenderer.FindPin( strVRピンID, out inputVPin );\r
- DsError.ThrowExceptionForHR( hr );\r
- }\r
-\r
- if( !string.IsNullOrEmpty( strARフィルタ名 ) )\r
- {\r
- hr = graph.FindFilterByName(strARフィルタ名, out audioRenderer);\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- hr = audioRenderer.FindPin(strARピンID, out inputAPin);\r
- DsError.ThrowExceptionForHR(hr);\r
- }\r
- }\r
- private static IBaseFilter tオーディオレンダラを探して返す( IFilterGraph graph )\r
- {\r
- int hr = 0;\r
- IBaseFilter audioRenderer = null;\r
-\r
- IEnumFilters eFilters;\r
- hr = graph.EnumFilters( out eFilters );\r
- DsError.ThrowExceptionForHR( hr );\r
- try\r
- {\r
- var filters = new IBaseFilter[ 1 ];\r
- while( eFilters.Next( 1, filters, IntPtr.Zero ) == CWin32.S_OK )\r
- {\r
- if( ( filters[ 0 ] as IAMAudioRendererStats ) != null )\r
- {\r
- audioRenderer = filters[ 0 ];\r
- break;\r
- }\r
-\r
- C共通.tCOMオブジェクトを解放する( ref filters[ 0 ] );\r
- }\r
- }\r
- finally\r
- {\r
- C共通.tCOMオブジェクトを解放する( ref eFilters );\r
- }\r
- return audioRenderer;\r
- }\r
-\r
-\r
- #region [ 静的インスタンス管理 ]\r
- //-----------------\r
- public const int nインスタンスIDの最大数 = 100;\r
- protected static Dictionary<int, CDirectShow> dicインスタンス = new Dictionary<int, CDirectShow>(); // <インスタンスID, そのIDを持つインスタンス>\r
-\r
- public static CDirectShow tインスタンスを返す( int nインスタンスID )\r
- {\r
- if( CDirectShow.dicインスタンス.ContainsKey( nインスタンスID ) )\r
- return CDirectShow.dicインスタンス[ nインスタンスID ];\r
-\r
- return null;\r
- }\r
- protected static void tインスタンスを登録する( CDirectShow ds )\r
- {\r
- for( int i = 1; i < CDirectShow.nインスタンスIDの最大数; i++ )\r
- {\r
- if( !CDirectShow.dicインスタンス.ContainsKey( i ) ) // 空いている番号を使う。\r
- {\r
- ds.nインスタンスID = i;\r
- CDirectShow.dicインスタンス.Add( i, ds );\r
- break;\r
- }\r
- }\r
- }\r
- protected static void tインスタンスを解放する( int nインスタンスID )\r
- {\r
- if( CDirectShow.dicインスタンス.ContainsKey( nインスタンスID ) )\r
- CDirectShow.dicインスタンス.Remove( nインスタンスID );\r
- }\r
- //-----------------\r
- #endregion\r
-\r
- #region [ Dispose-Finalize パターン実装 ]\r
- //-----------------\r
- public virtual void Dispose()\r
- {\r
- this.Dispose( true );\r
- GC.SuppressFinalize( this ); // ちゃんと Dispose されたので、ファイナライズ不要であることを CLR に伝える。\r
- }\r
- protected virtual void Dispose( bool bManagedリソースも解放する )\r
- {\r
- if( bManagedリソースも解放する )\r
- {\r
- #region [ ROTから解放する。]\r
- //-----------------\r
-#if DEBUG\r
- C共通.tDisposeする( ref this.rot );\r
-#endif\r
- //-----------------\r
- #endregion\r
- \r
- CDirectShow.tインスタンスを解放する( this.nインスタンスID );\r
- }\r
-\r
- #region [ インターフェース参照をなくし、COMオブジェクトを解放する。 ]\r
- //-----------------\r
- if( this.ip != IntPtr.Zero )\r
- {\r
- Marshal.FreeCoTaskMem( this.ip );\r
- this.ip = IntPtr.Zero;\r
- }\r
-\r
- if( this.MediaCtrl != null )\r
- {\r
- this.MediaCtrl.Stop();\r
- this.MediaCtrl = null;\r
- }\r
-\r
- if( this.MediaEventEx != null )\r
- {\r
- this.MediaEventEx.SetNotifyWindow( IntPtr.Zero, 0, IntPtr.Zero );\r
- this.MediaEventEx = null;\r
- }\r
-\r
- if( this.MediaSeeking != null )\r
- this.MediaSeeking = null;\r
-\r
- if( this.BasicAudio != null )\r
- this.BasicAudio = null;\r
-\r
- C共通.tCOMオブジェクトを解放する( ref this.nullRenderer );\r
- C共通.tCOMオブジェクトを解放する( ref this.memoryRenderer );\r
- C共通.tCOMオブジェクトを解放する( ref this.memoryRendererObject );\r
- C共通.tCOMオブジェクトを解放する( ref this.graphBuilder );\r
- //-----------------\r
- #endregion\r
-\r
- C共通.t完全なガベージコレクションを実施する();\r
- }\r
- ~CDirectShow()\r
- {\r
- // ファイナライザが呼ばれたということは、Dispose() されなかったということ。\r
- // この場合、Managed リソースは先にファイナライズされている可能性があるので、Unmamaed リソースのみを解放する。\r
- \r
- this.Dispose( false );\r
- }\r
- //-----------------\r
- #endregion\r
-\r
- #region [ protected ]\r
- //-----------------\r
- protected MemoryRenderer memoryRendererObject = null;\r
- protected IMemoryRenderer memoryRenderer = null;\r
- protected IBaseFilter nullRenderer = null;\r
- protected int n再生一時停止呼び出しの累積回数 = 0;\r
- //-----------------\r
- #endregion\r
-\r
- #region [ private ]\r
- //-----------------\r
- private int _n音量 = 100;\r
-#if DEBUG\r
- private DsROTEntry rot = null;\r
-#endif\r
-\r
- // 可能な数のスレッドを使用して画像を転送する。大きい画像ほど有効。多すぎるとプール内のスレッドが空くまで待たされるので注意。\r
- private static int n並列度 = 0; // 0 の場合、最初の生成時に並列度を決定する。\r
-\r
- private DGライン描画[] dgライン描画ARGB32;\r
- private DGライン描画[] dgライン描画XRGB32;\r
- private unsafe delegate void DGライン描画( int n );\r
- private unsafe byte* ptrSnap = null;\r
- private unsafe UInt32** ptrTexture = null;\r
-\r
- private unsafe void tライン描画XRGB32( int n )\r
- {\r
- // Snap は RGB32、Textureは X8R8G8B8\r
-\r
- UInt32* ptrTexture = this.ptrTexture[ n ];\r
- for( int y = n; y < this.n高さpx; y += CDirectShow.n並列度 )\r
- {\r
- byte* ptrPixel = ptrSnap + ( ( ( this.n高さpx - y ) - 1 ) * this.nスキャンライン幅byte );\r
-\r
- // アルファ無視なので一括コピー。CopyMemory() は自前でループ展開するよりも速い。\r
- CWin32.CopyMemory( (void*) ptrTexture, (void*) ptrPixel, (uint) ( this.n幅px * 4 ) );\r
-\r
- ptrTexture += this.n幅px * CDirectShow.n並列度;\r
- }\r
- }\r
- private unsafe void tライン描画ARGB32( int n )\r
- {\r
- // Snap は RGB32、Textureは A8R8G8B8\r
-\r
- UInt32* ptrTexture = this.ptrTexture[ n ];\r
- for( int y = n; y < this.n高さpx; y += CDirectShow.n並列度 )\r
- {\r
- UInt32* ptrPixel = (UInt32*) ( ptrSnap + ( ( ( this.n高さpx - y ) - 1 ) * this.nスキャンライン幅byte ) );\r
-\r
- //for( int x = 0; x < this.n幅px; x++ )\r
- // *( ptrTexture + x ) = 0xFF000000 | *ptrPixel++;\r
- // ↓ループ展開により高速化。160fps の曲が 200fps まで上がった。\r
-\r
- if( this.n幅px == 0 ) goto LEXIT;\r
- UInt32* pt = ptrTexture;\r
- UInt32 nAlpha = 0xFF000000;\r
- int d = ( this.n幅px % 32 );\r
-\r
- switch( d )\r
- {\r
- case 1: goto L031;\r
- case 2: goto L030;\r
- case 3: goto L029;\r
- case 4: goto L028;\r
- case 5: goto L027;\r
- case 6: goto L026;\r
- case 7: goto L025;\r
- case 8: goto L024;\r
- case 9: goto L023;\r
- case 10: goto L022;\r
- case 11: goto L021;\r
- case 12: goto L020;\r
- case 13: goto L019;\r
- case 14: goto L018;\r
- case 15: goto L017;\r
- case 16: goto L016;\r
- case 17: goto L015;\r
- case 18: goto L014;\r
- case 19: goto L013;\r
- case 20: goto L012;\r
- case 21: goto L011;\r
- case 22: goto L010;\r
- case 23: goto L009;\r
- case 24: goto L008;\r
- case 25: goto L007;\r
- case 26: goto L006;\r
- case 27: goto L005;\r
- case 28: goto L004;\r
- case 29: goto L003;\r
- case 30: goto L002;\r
- case 31: goto L001;\r
- }\r
-\r
- L000: *pt++ = nAlpha | *ptrPixel++;\r
- L001: *pt++ = nAlpha | *ptrPixel++;\r
- L002: *pt++ = nAlpha | *ptrPixel++;\r
- L003: *pt++ = nAlpha | *ptrPixel++;\r
- L004: *pt++ = nAlpha | *ptrPixel++;\r
- L005: *pt++ = nAlpha | *ptrPixel++;\r
- L006: *pt++ = nAlpha | *ptrPixel++;\r
- L007: *pt++ = nAlpha | *ptrPixel++;\r
- L008: *pt++ = nAlpha | *ptrPixel++;\r
- L009: *pt++ = nAlpha | *ptrPixel++;\r
- L010: *pt++ = nAlpha | *ptrPixel++;\r
- L011: *pt++ = nAlpha | *ptrPixel++;\r
- L012: *pt++ = nAlpha | *ptrPixel++;\r
- L013: *pt++ = nAlpha | *ptrPixel++;\r
- L014: *pt++ = nAlpha | *ptrPixel++;\r
- L015: *pt++ = nAlpha | *ptrPixel++;\r
- L016: *pt++ = nAlpha | *ptrPixel++;\r
- L017: *pt++ = nAlpha | *ptrPixel++;\r
- L018: *pt++ = nAlpha | *ptrPixel++;\r
- L019: *pt++ = nAlpha | *ptrPixel++;\r
- L020: *pt++ = nAlpha | *ptrPixel++;\r
- L021: *pt++ = nAlpha | *ptrPixel++;\r
- L022: *pt++ = nAlpha | *ptrPixel++;\r
- L023: *pt++ = nAlpha | *ptrPixel++;\r
- L024: *pt++ = nAlpha | *ptrPixel++;\r
- L025: *pt++ = nAlpha | *ptrPixel++;\r
- L026: *pt++ = nAlpha | *ptrPixel++;\r
- L027: *pt++ = nAlpha | *ptrPixel++;\r
- L028: *pt++ = nAlpha | *ptrPixel++;\r
- L029: *pt++ = nAlpha | *ptrPixel++;\r
- L030: *pt++ = nAlpha | *ptrPixel++;\r
- L031: *pt++ = nAlpha | *ptrPixel++;\r
- if( ( pt - ptrTexture ) < this.n幅px ) goto L000;\r
-\r
- LEXIT:\r
- ptrTexture += this.n幅px * CDirectShow.n並列度;\r
- }\r
- }\r
- //-----------------\r
- #endregion\r
- }\r
-}\r