OSDN Git Service

163fb1339ac43ab9053995d2a5dcd01f3c347235
[dtxmania/dtxmania.git] / FDK / コード / 05.DirectShow / CDirectShow.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Runtime.InteropServices;
5 using System.IO;
6 using System.Drawing;
7 using System.Drawing.Imaging;
8 using System.Threading;
9 using SharpDX;
10 using SharpDX.Direct3D9;
11 using SharpDX.Multimedia;
12 using DirectShowLib;
13
14 namespace FDK
15 {
16         /// <summary>
17         /// <para>DirectShowを用いたクリップ(動画+音声)を扱う。</para>
18         /// <para>1つのクリップにつき1つの CDirectShow インスタンスを生成する。</para>
19         /// <para>再生の開始や停止などの操作の他、任意の時点でスナップイメージを取得することができる。</para>
20         /// </summary>
21         public class CDirectShow : IDisposable
22         {
23                 // プロパティ
24
25                 public const uint WM_DSGRAPHNOTIFY = CWin32.WM_APP + 1;
26
27                 public enum Eグラフの状態 { 完全停止中, 再生のみ停止中, 再生中, 完全停止へ遷移中, 再生のみ停止へ遷移中, 再生へ遷移中, 未定 }
28                 public Eグラフの状態 eグラフの状態
29                 {
30                         get
31                         {
32                                 var status = Eグラフの状態.未定;
33
34                                 if( this.MediaCtrl != null )
35                                 {
36                                         FilterState fs;
37                                         int hr = this.MediaCtrl.GetState( 0, out fs );          // それなりに重たいので注意。
38
39                                         if( hr == CWin32.E_FAIL )
40                                         {
41                                                 #region [ 失敗。]
42                                                 //-----------------
43                                                 status = Eグラフの状態.未定;
44                                                 //-----------------
45                                                 #endregion
46                                         }
47                                         else if( hr == CWin32.VFW_S_STATE_INTERMEDIATE )
48                                         {
49                                                 #region [ 遷移中。]
50                                                 //-----------------
51                                                 switch( fs )
52                                                 {
53                                                         case FilterState.Running:
54                                                                 status = Eグラフの状態.再生へ遷移中;
55                                                                 break;
56
57                                                         case FilterState.Paused:
58                                                                 status = Eグラフの状態.再生のみ停止へ遷移中;
59                                                                 break;
60
61                                                         case FilterState.Stopped:
62                                                                 status = Eグラフの状態.完全停止へ遷移中;
63                                                                 break;
64
65                                                         default:
66                                                                 status = Eグラフの状態.未定;
67                                                                 break;
68                                                 }
69                                                 //-----------------
70                                                 #endregion
71                                         }
72                                         else
73                                         {
74                                                 #region [ 安定状態。]
75                                                 //-----------------
76                                                 switch( fs )
77                                                 {
78                                                         case FilterState.Running:
79                                                                 status = Eグラフの状態.再生中;
80                                                                 break;
81
82                                                         case FilterState.Paused:
83                                                                 status = Eグラフの状態.再生のみ停止中;
84                                                                 break;
85
86                                                         case FilterState.Stopped:
87                                                                 status = Eグラフの状態.完全停止中;
88                                                                 break;
89
90                                                         default:
91                                                                 status = Eグラフの状態.未定;
92                                                                 break;
93                                                 }
94                                                 //-----------------
95                                                 #endregion
96                                         }
97                                 }
98                                 return status;
99                         }
100                 }
101                 public bool b再生中;
102                 public bool bループ再生;
103
104                 public int n幅px
105                 {
106                         get;
107                         protected set;
108                 }
109                 public int n高さpx
110                 {
111                         get;
112                         protected set;
113                 }
114                 public int nスキャンライン幅byte
115                 {
116                         get;
117                         protected set;
118                 }
119                 public int nデータサイズbyte
120                 {
121                         get;
122                         protected set;
123                 }
124                 public bool b上下反転
125                 {
126                         get;
127                         protected set;
128                 }
129
130                 public bool b音声のみ
131                 {
132                         get;
133                         protected set;
134                 }
135                 
136                 public long n現在のグラフの再生位置ms
137                 {
138                         get
139                         {
140                                 if( this.MediaSeeking == null )
141                                         return 0;
142
143                                 long current;
144                                 int hr = this.MediaSeeking.GetCurrentPosition( out current );
145                                 DsError.ThrowExceptionForHR( hr );
146                                 return (long) ( current / ( 1000.0 * 10.0 ) );
147                         }
148                 }
149                 /// <summary>
150                 /// <para>無音:0~100:原音。set のみ。</para>
151                 /// </summary>
152                 public int n音量
153                 {
154                         get
155                         {
156                                 return this._n音量;
157                         }
158                         set
159                         {
160                                 if( this.BasicAudio == null )
161                                         return;
162
163
164                                 // 値を保存。
165
166                                 this._n音量 = value;
167
168
169                                 // リニア音量をデシベル音量に変換。
170
171                                 int n音量db = 0;
172
173                                 if( value == 0 )
174                                 {
175                                         n音量db = -10000;     // 完全無音
176                                 }
177                                 else
178                                 {
179                                         n音量db = (int) ( ( 20.0 * Math.Log10( ( (double) value ) / 100.0 ) ) * 100.0 );
180                                 }
181
182
183                                 // デシベル音量でグラフの音量を変更。
184
185                                 this.BasicAudio.put_Volume( n音量db );
186                         }
187                 }
188                 /// <summary>
189                 /// <para>左:-100~中央:0~100:右。set のみ。</para>
190                 /// </summary>
191                 public int n位置
192                 {
193                         set
194                         {
195                                 if( this.BasicAudio == null )
196                                         return;
197
198                                 // リニア位置をデシベル位置に変換。
199
200                                 int n位置 = Math.Min( Math.Max( value, -100 ), +100 );
201                                 int n位置db = 0;
202
203                                 if( n位置 == 0 )
204                                 {
205                                         n位置db = 0;
206                                 }
207                                 else if( n位置 == -100 )
208                                 {
209                                         n位置db = -10000;
210                                 }
211                                 else if( n位置 == 100 )
212                                 {
213                                         n位置db = +10000;
214                                 }
215                                 else if( n位置 < 0 )
216                                 {
217                                         n位置db = (int) ( ( 20.0 * Math.Log10( ( (double) ( n位置 + 100 ) ) / 100.0 ) ) * 100.0 );
218                                 }
219                                 else
220                                 {
221                                         n位置db = (int) ( ( -20.0 * Math.Log10( ( (double) ( 100 - n位置 ) ) / 100.0 ) ) * 100.0 );
222                                 }
223
224                                 // デシベル位置でグラフの位置を変更。
225
226                                 this.BasicAudio.put_Balance( n位置db );
227                         }
228                 }
229                 public IMediaControl MediaCtrl;
230                 public IMediaEventEx MediaEventEx;
231                 public IMediaSeeking MediaSeeking;
232                 public IBasicAudio BasicAudio;
233                 public IGraphBuilder graphBuilder;
234
235                 /// <summary>
236                 /// <para>CDirectShowインスタンスに固有のID。</para>
237                 /// <para>DirectShow イベントをウィンドウに発信する際、MessageID として "WM_APP+インスタンスID" を発信する。</para>
238                 /// <para>これにより、受け側でイベント発信インスタンスを特定することが可能になる。</para>
239                 /// </summary>
240                 public int nインスタンスID
241                 {
242                         get;
243                         protected set;
244                 }
245
246
247                 // メソッド
248
249                 public CDirectShow()
250                 {
251                 }
252                 public CDirectShow( string fileName, IntPtr hWnd, bool bオーディオレンダラなし )
253                 {
254                         // 初期化。
255
256                         this.n幅px = 0;
257                         this.n高さpx = 0;
258                         this.b上下反転 = false;
259                         this.nスキャンライン幅byte = 0;
260                         this.nデータサイズbyte = 0;
261                         this.b音声のみ = false;
262                         this.graphBuilder = null;
263                         this.MediaCtrl = null;
264                         this.b再生中 = false;
265                         this.bループ再生 = false;
266
267
268                         // 静的リストに登録し、インスタンスIDを得る。
269
270                         CDirectShow.tインスタンスを登録する( this );
271
272
273                         // 並列処理準備。
274
275                         if( CDirectShow.n並列度 == 0 )       // 算出がまだなら算出する。
276                                 CDirectShow.n並列度 = Environment.ProcessorCount;    // 並列度=CPU数とする。
277
278                         unsafe
279                         {
280                                 this.dgライン描画ARGB32 = new DGライン描画[ CDirectShow.n並列度 ];
281                                 this.dgライン描画XRGB32 = new DGライン描画[ CDirectShow.n並列度 ];
282
283                                 for( int i = 0; i < CDirectShow.n並列度; i++ )
284                                 {
285                                         this.dgライン描画ARGB32[ i ] = new DGライン描画( this.tライン描画ARGB32 );
286                                         this.dgライン描画XRGB32[ i ] = new DGライン描画( this.tライン描画XRGB32 );
287                                 }
288                         }
289
290                         try
291                         {
292                                 int hr = 0;
293
294
295                                 // グラフビルダを生成。
296
297                                 this.graphBuilder = (IGraphBuilder) new FilterGraph();
298 #if DEBUG
299                                 // ROT への登録。
300                                 this.rot = new DsROTEntry( graphBuilder );
301 #endif
302
303
304                                 // QueryInterface。存在しなければ null。
305
306                                 this.MediaCtrl = this.graphBuilder as IMediaControl;
307                                 this.MediaEventEx = this.graphBuilder as IMediaEventEx;
308                                 this.MediaSeeking = this.graphBuilder as IMediaSeeking;
309                                 this.BasicAudio = this.graphBuilder as IBasicAudio;
310
311
312                                 // IMemoryRenderer をグラフに挿入。
313
314                                 AMMediaType mediaType = null;
315
316                                 this.memoryRendererObject = new MemoryRenderer();
317                                 this.memoryRenderer = (IMemoryRenderer) this.memoryRendererObject;
318                                 var baseFilter = (IBaseFilter) this.memoryRendererObject;
319
320                                 hr = this.graphBuilder.AddFilter( baseFilter, "MemoryRenderer" );
321                                 DsError.ThrowExceptionForHR( hr );
322
323
324                                 // fileName からグラフを自動生成。
325
326                                 hr = this.graphBuilder.RenderFile( fileName, null );    // IMediaControl.RenderFile() は推奨されない
327                                 DsError.ThrowExceptionForHR( hr );
328
329
330                                 // 音声のみ?
331
332                                 {
333                                         IBaseFilter videoRenderer;
334                                         IPin videoInputPin;
335                                         IBaseFilter audioRenderer;
336                                         IPin audioInputPin;
337                                         CDirectShow.SearchMMRenderers( this.graphBuilder, out videoRenderer, out videoInputPin, out audioRenderer, out audioInputPin );
338                                         if ( videoRenderer == null && audioRenderer != null )
339                                         {
340                                                 this.b音声のみ = true;
341                                         }
342                                         else
343                                         {
344                                                 C共通.tCOMオブジェクトを解放する(ref videoInputPin);
345                                                 C共通.tCOMオブジェクトを解放する(ref videoRenderer);
346                                                 C共通.tCOMオブジェクトを解放する(ref audioInputPin);
347                                                 C共通.tCOMオブジェクトを解放する(ref audioRenderer);
348                                         }
349                                 }
350
351
352                                 // イメージ情報を取得。
353
354                                 if( !this.b音声のみ )
355                                 {
356                                         long n;
357                                         int m;
358                                         this.memoryRenderer.GetWidth( out n );
359                                         this.n幅px = (int) n;
360                                         this.memoryRenderer.GetHeight( out n );
361                                         this.n高さpx = (int) n;
362                                         this.memoryRenderer.IsBottomUp( out m );
363                                         this.b上下反転 = ( m != 0 );
364                                         this.memoryRenderer.GetBufferSize( out n );
365                                         this.nデータサイズbyte = (int) n;
366                                         this.nスキャンライン幅byte = (int) this.nデータサイズbyte / this.n高さpx;
367                                         // C共通.tCOMオブジェクトを解放する( ref baseFilter );             なんかキャスト元のオブジェクトまで解放されるので解放禁止。
368                                 }
369
370
371                                 // グラフを修正する。
372
373                                 if( bオーディオレンダラなし )
374                                 {
375                                         WaveFormat dummy1;
376                                         byte[] dummy2;
377                                         CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する( this.graphBuilder, out dummy1, out dummy2 );
378                                 }
379
380
381                                 // その他の処理。
382
383                                 this.t再生準備開始();     // 1回以上 IMediaControl を呼び出してないと、IReferenceClock は取得できない。
384                                 this.t遷移完了まで待って状態を取得する();       // 完全に Pause へ遷移するのを待つ。(環境依存)
385
386
387                                 // イベント用ウィンドウハンドルを設定。
388
389                                 this.MediaEventEx.SetNotifyWindow( hWnd, (int) WM_DSGRAPHNOTIFY, new IntPtr( this.nインスタンスID ) );
390                         }
391 #if !DEBUG
392                         catch( Exception e )
393                         {
394                                 C共通.t例外の詳細をログに出力する( e );
395                                 this.Dispose();
396                                 throw;  // 例外発出。
397                         }
398 #endif
399                         finally
400                         {
401                         }
402                 }
403
404                 public void t再生準備開始()
405                 {
406                         if( this.MediaCtrl != null )
407                         {
408                                 int hr = this.MediaCtrl.Pause();                // 再生準備を開始する。ここでは準備が完了するまで待たない。
409                                 DsError.ThrowExceptionForHR( hr );
410                         }
411                 }
412                 public void t再生開始()
413                 {
414                         if( this.MediaCtrl != null && --this.n再生一時停止呼び出しの累積回数 <= 0 )
415                         {
416                                 //this.t遷移完了まで待って状態を取得する();             // 再生準備(だろう)がまだ完了してなければ、待つ。     → 意外と重い処理なので外部で判断して実行するよう変更する。(2011.8.7)
417
418                                 int hr = this.MediaCtrl.Run();                                  // 再生開始。
419                                 DsError.ThrowExceptionForHR( hr );
420
421                                 this.n再生一時停止呼び出しの累積回数 = 0;                // 一時停止回数はここでリセットされる。
422                                 this.b再生中 = true;
423                         }
424                 }
425                 public void t再生一時停止()
426                 {
427                         if( this.MediaCtrl != null && this.n再生一時停止呼び出しの累積回数 == 0 )
428                         {
429                                 int hr = this.MediaCtrl.Pause();
430                                 DsError.ThrowExceptionForHR( hr );
431                         }
432                         this.n再生一時停止呼び出しの累積回数++;
433                         this.b再生中 = false;
434                 }
435                 public void t再生停止()
436                 {
437                         if( this.MediaCtrl != null )
438                         {
439                                 int hr = this.MediaCtrl.Stop();
440                                 DsError.ThrowExceptionForHR( hr );
441                         }
442
443                         // 次への準備。
444                         //this.t再生位置を変更する( 0.0 );             → より細かく制御するために、FDK外部で制御するように変更。(2011.8.7)
445                         //this.t再生準備開始();
446
447                         this.n再生一時停止呼び出しの累積回数 = 0;        // 停止すると、一時停止呼び出し累積回数はリセットされる。
448                         this.b再生中 = false;
449                 }
450                 public void t再生位置を変更( double db再生位置ms )
451                 {
452                         if( this.MediaSeeking == null )
453                                 return;
454
455                         int hr = this.MediaSeeking.SetPositions(
456                                 DsLong.FromInt64( (long) ( db再生位置ms * 1000.0 * 10.0 ) ),
457                                 AMSeekingSeekingFlags.AbsolutePositioning,
458                                 null,
459                                 AMSeekingSeekingFlags.NoPositioning );
460
461                         DsError.ThrowExceptionForHR( hr );
462                 }
463                 public void t最初から再生開始()
464                 {
465                         this.t再生位置を変更( 0.0 );
466                         this.t再生開始();
467                 }
468                 public Eグラフの状態 t遷移完了まで待って状態を取得する()
469                 {
470                         var status = Eグラフの状態.未定;
471
472                         if( this.MediaCtrl != null )
473                         {
474                                 FilterState fs;
475                                 int hr = this.MediaCtrl.GetState( 1000, out fs );       // 遷移完了まで最大1000ms待つ。
476                         }
477                         return this.eグラフの状態;
478                 }
479                 public unsafe void t現時点における最新のスナップイメージをTextureに転写する( CTexture texture )
480                 {
481                         int hr;
482
483                         #region [ 再生してないなら何もせず帰還。(一時停止中はOK。)]
484                         //-----------------
485                         if( !this.b再生中 )
486                                 return;
487                         //-----------------
488                         #endregion
489                         #region [ 音声のみなら何もしない。]
490                         //-----------------
491                         if( this.b音声のみ )
492                                 return;
493                         //-----------------
494                         #endregion
495
496                         DataRectangle dr = texture.texture.LockRectangle( 0, LockFlags.Discard );
497                         try
498                         {
499                                 if( this.nスキャンライン幅byte == dr.Pitch )
500                                 {
501                                         #region [ (A) ピッチが合うので、テクスチャに直接転送する。]
502                                         //-----------------
503                                         hr = this.memoryRenderer.GetCurrentBuffer( dr.DataPointer, this.nデータサイズbyte );
504                                         DsError.ThrowExceptionForHR( hr );
505                                         //-----------------
506                                         #endregion
507                                 }
508                                 else
509                                 {
510                                         this.b上下反転 = false;             // こちらの方法では常に正常
511
512                                         #region [ (B) ピッチが合わないので、メモリに転送してからテクスチャに転送する。]
513                                         //-----------------
514
515                                         #region [ IMemoryRenderer からバッファにイメージデータを読み込む。]
516                                         //-----------------
517                                         if( this.ip == IntPtr.Zero )
518                                                 this.ip = Marshal.AllocCoTaskMem( this.nデータサイズbyte );
519
520                                         hr = this.memoryRenderer.GetCurrentBuffer( this.ip, this.nデータサイズbyte );
521                                         DsError.ThrowExceptionForHR( hr );
522                                         //-----------------
523                                         #endregion
524
525                                         #region [ テクスチャにスナップイメージを転送。]
526                                         //-----------------
527                                         bool bARGB32 = true;
528
529                                         switch( texture.Format )
530                                         {
531                                                 case Format.A8R8G8B8:
532                                                         bARGB32 = true;
533                                                         break;
534
535                                                 case Format.X8R8G8B8:
536                                                         bARGB32 = false;
537                                                         break;
538
539                                                 default:
540                                                         return;         // 未対応のフォーマットは無視。
541                                         }
542
543                                         // スレッドプールを使って並列転送する準備。
544
545                                         this.ptrSnap = (byte*) this.ip.ToPointer();
546                                         var ptr = stackalloc UInt32*[ CDirectShow.n並列度 ]; // stackalloc(GC対象外、メソッド終了時に自動開放)は、スタック変数相手にしか使えない。
547                                         ptr[ 0 ] = (UInt32*) dr.DataPointer.ToPointer();        //              ↓
548                                         for( int i = 1; i < CDirectShow.n並列度; i++ )                       // スタック変数で確保、初期化して…
549                                                 ptr[ i ] = ptr[ i - 1 ] + this.n幅px;                          //              ↓
550                                         this.ptrTexture = ptr;                                                                  // スタック変数をクラスメンバに渡す(これならOK)。
551
552
553                                         // 並列度が1ならシングルスレッド、2以上ならマルチスレッドで転送する。
554                                         // → CPUが1つの場合、わざわざスレッドプールのスレッドで処理するのは無駄。
555
556                                         if( CDirectShow.n並列度 == 1 )
557                                         {
558                                                 if( bARGB32 )
559                                                         this.tライン描画ARGB32( 0 );
560                                                 else
561                                                         this.tライン描画XRGB32( 0 );
562                                         }
563                                         else
564                                         {
565                                                 // 転送開始。
566
567                                                 var ar = new IAsyncResult[ CDirectShow.n並列度 ];
568                                                 for( int i = 0; i < CDirectShow.n並列度; i++ )
569                                                 {
570                                                         ar[ i ] = ( bARGB32 ) ?
571                                                                 this.dgライン描画ARGB32[ i ].BeginInvoke( i, null, null ) :
572                                                                 this.dgライン描画XRGB32[ i ].BeginInvoke( i, null, null );
573                                                 }
574
575
576                                                 // 転送完了待ち。
577
578                                                 for( int i = 0; i < CDirectShow.n並列度; i++ )
579                                                 {
580                                                         if( bARGB32 )
581                                                                 this.dgライン描画ARGB32[ i ].EndInvoke( ar[ i ] );
582                                                         else
583                                                                 this.dgライン描画XRGB32[ i ].EndInvoke( ar[ i ] );
584                                                 }
585                                         }
586
587                                         this.ptrSnap = null;
588                                         this.ptrTexture = null;
589                                         //-----------------
590                                         #endregion
591
592                                         //-----------------
593                                         #endregion
594                                 }
595                         }
596                         finally
597                         {
598                                 texture.texture.UnlockRectangle( 0 );
599                         }
600                 }
601
602                 private IntPtr ip = IntPtr.Zero;
603
604                 public static void tグラフを解析しデバッグ出力する( IGraphBuilder graphBuilder )
605                 {
606                         if( graphBuilder == null )
607                         {
608                                 Debug.WriteLine( "指定されたグラフが null です。" );
609                                 return;
610                         }
611
612                         int hr = 0;
613
614                         IEnumFilters eFilters;
615                         hr = graphBuilder.EnumFilters( out eFilters );
616                         DsError.ThrowExceptionForHR( hr );
617                         {
618                                 var filters = new IBaseFilter[ 1 ];
619                                 while( eFilters.Next( 1, filters, IntPtr.Zero ) == CWin32.S_OK )
620                                 {
621                                         FilterInfo filterInfo;
622                                         hr = filters[ 0 ].QueryFilterInfo( out filterInfo );
623                                         DsError.ThrowExceptionForHR( hr );
624                                         {
625                                                 Debug.WriteLine( filterInfo.achName );          // フィルタ名表示。
626                                                 if( filterInfo.pGraph != null )
627                                                         C共通.tCOMオブジェクトを解放する( ref filterInfo.pGraph );
628                                         }
629
630                                         IEnumPins ePins;
631                                         hr = filters[ 0 ].EnumPins( out ePins );
632                                         DsError.ThrowExceptionForHR( hr );
633                                         {
634                                                 var pins = new IPin[ 1 ];
635                                                 while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )
636                                                 {
637                                                         PinInfo pinInfo;
638                                                         hr = pins[ 0 ].QueryPinInfo( out pinInfo );
639                                                         DsError.ThrowExceptionForHR( hr );
640                                                         {
641                                                                 Debug.Write( "  " + pinInfo.name );     // ピン名表示。
642                                                                 Debug.Write( ( pinInfo.dir == PinDirection.Input ) ? " ← " : " → " );
643
644                                                                 IPin connectPin;
645                                                                 hr = pins[ 0 ].ConnectedTo( out connectPin );
646                                                                 if( hr != CWin32.S_OK )
647                                                                         Debug.WriteLine( "(未接続)" );
648                                                                 else
649                                                                 {
650                                                                         DsError.ThrowExceptionForHR( hr );
651
652                                                                         PinInfo connectPinInfo;
653                                                                         hr = connectPin.QueryPinInfo( out connectPinInfo );
654                                                                         DsError.ThrowExceptionForHR( hr );
655                                                                         {
656                                                                                 FilterInfo connectFilterInfo;
657                                                                                 hr = connectPinInfo.filter.QueryFilterInfo( out connectFilterInfo );
658                                                                                 DsError.ThrowExceptionForHR( hr );
659                                                                                 {
660                                                                                         Debug.Write( "[" + connectFilterInfo.achName + "]." );  // 接続先フィルタ名
661
662                                                                                         if( connectFilterInfo.pGraph != null )
663                                                                                                 C共通.tCOMオブジェクトを解放する( ref connectFilterInfo.pGraph );
664                                                                                 }
665
666                                                                                 Debug.WriteLine( connectPinInfo.name );         // 接続先ピン名
667                                                                                 if( connectPinInfo.filter != null )
668                                                                                         C共通.tCOMオブジェクトを解放する( ref connectPinInfo.filter );
669                                                                                 DsUtils.FreePinInfo( connectPinInfo );
670                                                                         }
671                                                                         C共通.tCOMオブジェクトを解放する( ref connectPin );
672                                                                 }
673                                                                 if( pinInfo.filter != null )
674                                                                         C共通.tCOMオブジェクトを解放する( ref pinInfo.filter );
675                                                                 DsUtils.FreePinInfo( pinInfo );
676                                                         }
677                                                         C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );
678                                                 }
679                                         }
680                                         C共通.tCOMオブジェクトを解放する( ref ePins );
681
682                                         C共通.tCOMオブジェクトを解放する( ref filters[ 0 ] );
683                                 }
684                         }
685                         C共通.tCOMオブジェクトを解放する( ref eFilters );
686
687                         Debug.Flush();
688                 }
689                 public static void tオーディオレンダラをNullレンダラに変えてフォーマットを取得する( IGraphBuilder graphBuilder, out WaveFormat wfx, out byte[] wfx拡張データ )
690                 {
691                         int hr = 0;
692
693                         IBaseFilter audioRenderer = null;
694                         IPin rendererInputPin = null;
695                         IPin rendererConnectedOutputPin = null;
696                         IBaseFilter nullRenderer = null;
697                         IPin nullRendererInputPin = null;
698                         wfx = null;
699                         wfx拡張データ = new byte[ 0 ];
700
701                         try
702                         {
703                                 // audioRenderer を探す。
704
705                                 audioRenderer = CDirectShow.tオーディオレンダラを探して返す( graphBuilder );
706                                 if( audioRenderer == null )
707                                         return;         // なかった
708
709                                 #region [ 音量ゼロで一度再生する。(オーディオレンダラの入力ピンMediaTypeが、接続時とは異なる「正しいもの」に変わる可能性があるため。)]
710                                 //-----------------
711                                 {
712                                         // ここに来た時点で、グラフのビデオレンダラは無効化(NullRendererへの置換や除去など)しておくこと。
713                                         // さもないと、StopWhenReady() 時に一瞬だけ Activeウィンドウが表示されてしまう。
714
715                                         var mediaCtrl = (IMediaControl) graphBuilder;
716                                         var basicAudio = (IBasicAudio) graphBuilder;
717                                         
718                                         basicAudio.put_Volume( -10000 );        // 最小音量
719                                         
720
721                                         // グラフを再生してすぐ止める。(Paused → Stopped へ遷移する)
722                                         
723                                         mediaCtrl.StopWhenReady();
724
725                 
726                                         // グラフが Stopped に遷移完了するまで待つ。(StopWhenReady() はグラフが Stopped になるのを待たずに帰ってくる。)
727
728                                         FilterState fs = FilterState.Paused;
729                                         hr = CWin32.S_FALSE;
730                                         while( fs != FilterState.Stopped || hr != CWin32.S_OK )
731                                                 hr = mediaCtrl.GetState( 10, out fs );
732                                         
733
734                                         // 終了処理。
735
736                                         basicAudio.put_Volume( 0 );                     // 最大音量
737                                         
738                                         basicAudio = null;
739                                         mediaCtrl = null;
740                                 }
741                                 //-----------------
742                                 #endregion
743
744                                 // audioRenderer の入力ピンを探す。
745
746                                 rendererInputPin = t最初の入力ピンを探して返す( audioRenderer );
747                                 if( rendererInputPin == null )
748                                         return;
749
750
751                                 // WAVEフォーマットを取得し、wfx 引数へ格納する。
752
753                                 var type = new AMMediaType();
754                                 hr = rendererInputPin.ConnectionMediaType( type );
755                                 DsError.ThrowExceptionForHR( hr );
756                                 try
757                                 {
758                                         #region [ type.formatPtr から wfx に、拡張領域を除くデータをコピーする。]
759                                         //-----------------
760                                         var wfxTemp = new WaveFormatEx();       // SlimDX.Multimedia.WaveFormat は Marshal.PtrToStructure() で使えないので、それが使える DirectShowLib.WaveFormatEx を介して取得する。(面倒…)
761                                         Marshal.PtrToStructure( type.formatPtr, (object) wfxTemp );
762
763                                         wfx = WaveFormat.CreateCustomFormat( (WaveFormatEncoding) wfxTemp.wFormatTag, wfxTemp.nSamplesPerSec, wfxTemp.nChannels, wfxTemp.nAvgBytesPerSec, wfxTemp.nBlockAlign, wfxTemp.wBitsPerSample );
764                                         //-----------------
765                                         #endregion
766                                         #region [ 拡張領域が存在するならそれを wfx拡張データ に格納する。 ]
767                                         //-----------------
768                                         int nWaveFormatEx本体サイズ = 16 + 2; // sizeof( WAVEFORMAT ) + sizof( WAVEFORMATEX.cbSize )
769                                         int nはみ出しサイズbyte = type.formatSize - nWaveFormatEx本体サイズ;
770
771                                         if( nはみ出しサイズbyte > 0 )
772                                         {
773                                                 wfx拡張データ = new byte[ nはみ出しサイズbyte ];
774                                                 var hGC = GCHandle.Alloc( wfx拡張データ, GCHandleType.Pinned );    // 動くなよー
775                                                 unsafe
776                                                 {
777                                                         byte* src = (byte*) type.formatPtr.ToPointer();
778                                                         byte* dst = (byte*) hGC.AddrOfPinnedObject().ToPointer();
779                                                         CWin32.CopyMemory( dst, src + nWaveFormatEx本体サイズ, (uint) nはみ出しサイズbyte );
780                                                 }
781                                                 hGC.Free();
782                                         }
783                                         //-----------------
784                                         #endregion
785                                 }
786                                 finally
787                                 {
788                                         if( type != null )
789                                                 DsUtils.FreeAMMediaType( type );
790                                 }
791
792
793                                 // audioRenderer につながる出力ピンを探す。
794
795                                 hr = rendererInputPin.ConnectedTo( out rendererConnectedOutputPin );
796                                 DsError.ThrowExceptionForHR( hr );
797
798
799                                 // audioRenderer をグラフから切断する。
800
801                                 rendererInputPin.Disconnect();
802                                 rendererConnectedOutputPin.Disconnect();
803
804
805                                 // audioRenderer をグラフから除去する。
806
807                                 hr = graphBuilder.RemoveFilter( audioRenderer );
808                                 DsError.ThrowExceptionForHR( hr );
809
810
811                                 // nullRenderer を作成し、グラフに追加する。
812
813                                 nullRenderer = (IBaseFilter) new NullRenderer();
814                                 hr = graphBuilder.AddFilter( nullRenderer, "Audio Null Renderer" );
815                                 DsError.ThrowExceptionForHR( hr );
816
817
818                                 // nullRenderer の入力ピンを探す。
819
820                                 hr = nullRenderer.FindPin( "In", out nullRendererInputPin );
821                                 DsError.ThrowExceptionForHR( hr );
822
823
824                                 // nullRenderer をグラフに接続する。
825
826                                 hr = rendererConnectedOutputPin.Connect( nullRendererInputPin, null );
827                                 DsError.ThrowExceptionForHR( hr );
828                         }
829                         finally
830                         {
831                                 C共通.tCOMオブジェクトを解放する( ref nullRendererInputPin );
832                                 C共通.tCOMオブジェクトを解放する( ref nullRenderer );
833                                 C共通.tCOMオブジェクトを解放する( ref rendererConnectedOutputPin );
834                                 C共通.tCOMオブジェクトを解放する( ref rendererInputPin );
835                                 C共通.tCOMオブジェクトを解放する( ref audioRenderer );
836                         }
837                 }
838                 public static void ConnectNullRendererFromSampleGrabber(IGraphBuilder graphBuilder, IBaseFilter sampleGrabber)
839                 {
840                         int hr = 0;
841                         IBaseFilter videoRenderer = null;
842                         IPin videoRendererInputPin = null;
843                         IBaseFilter audioRenderer = null;
844                         IPin audioRendererInputPin = null;
845                         IPin connectedOutputPin = null;
846                         IPin nullRendererInputPin = null;
847                         IPin grabberOutputPin = null;
848                         IPin grabberOutputConnectedPin = null;
849
850                         try
851                         {
852                                 // videoRenderer を探す。
853                                 CDirectShow.SearchMMRenderers(graphBuilder, out videoRenderer, out videoRendererInputPin, out audioRenderer, out audioRendererInputPin);
854                                 if (videoRenderer != null && audioRendererInputPin != null)
855                                 {
856                                         // 既存のレンダラにつながっているピン対を取得
857                                         hr = videoRendererInputPin.ConnectedTo(out connectedOutputPin);
858                                         DsError.ThrowExceptionForHR(hr);
859
860                                         // それらを切断。前段の出力ピンとビデオレンダラの入力ピンを切断する。双方向から切断しないとグラフから切り離されないので注意。
861                                         hr = videoRendererInputPin.Disconnect();
862                                         DsError.ThrowExceptionForHR(hr);
863                                         hr = connectedOutputPin.Disconnect();
864                                         DsError.ThrowExceptionForHR(hr);
865
866                                         // ビデオレンダラをグラフから除去し、ヌルレンダラを追加
867                                         hr = graphBuilder.RemoveFilter(videoRenderer);
868                                         DsError.ThrowExceptionForHR(hr);
869                                         IBaseFilter nullRenderer = new NullRenderer() as IBaseFilter;
870                                         hr = graphBuilder.AddFilter(nullRenderer, "Video Null Renderer");
871                                         DsError.ThrowExceptionForHR(hr);
872
873                                         // nullRenderer の入力ピンを探す。
874                                         hr = nullRenderer.FindPin("In", out nullRendererInputPin);
875                                         DsError.ThrowExceptionForHR(hr);
876                                         hr = nullRendererInputPin.Disconnect();
877                                         DsError.ThrowExceptionForHR(hr);
878
879                                         // グラバの Out と Null Renderer の In を接続する。
880                                         hr = sampleGrabber.FindPin("Out", out grabberOutputPin);
881                                         DsError.ThrowExceptionForHR(hr);
882                                         hr = grabberOutputPin.ConnectedTo(out grabberOutputConnectedPin);
883                                         DsError.ThrowExceptionForHR(hr);
884                                         hr = grabberOutputConnectedPin.Disconnect();
885                                         DsError.ThrowExceptionForHR(hr);
886                                         hr = grabberOutputPin.Disconnect();
887                                         DsError.ThrowExceptionForHR(hr);
888                                         hr = grabberOutputPin.Connect(nullRendererInputPin, null);
889                                         DsError.ThrowExceptionForHR(hr);
890                                 }
891
892                                 if( audioRenderer != null && audioRendererInputPin != null )
893                                 {
894                                         C共通.tCOMオブジェクトを解放する(ref connectedOutputPin);
895
896                                         // 既存のレンダラにつながっているピン対を取得
897                                         hr = audioRendererInputPin.ConnectedTo(out connectedOutputPin);
898                                         DsError.ThrowExceptionForHR(hr);
899
900                                         // それらを切断。前段の出力ピンとビデオレンダラの入力ピンを切断する。双方向から切断しないとグラフから切り離されないので注意。
901                                         hr = audioRendererInputPin.Disconnect();
902                                         DsError.ThrowExceptionForHR(hr);
903                                         hr = connectedOutputPin.Disconnect();
904                                         DsError.ThrowExceptionForHR(hr);
905
906                                         // ビデオレンダラをグラフから除去し、ヌルレンダラを追加
907                                         hr = graphBuilder.RemoveFilter(audioRenderer);
908                                         DsError.ThrowExceptionForHR(hr);
909                                         IBaseFilter nullRenderer = new NullRenderer() as IBaseFilter;
910                                         hr = graphBuilder.AddFilter(nullRenderer, "Audio Null Renderer");
911                                         DsError.ThrowExceptionForHR(hr);
912
913                                         C共通.tCOMオブジェクトを解放する(ref nullRendererInputPin);
914                                         hr = nullRenderer.FindPin("In", out nullRendererInputPin);
915                                         DsError.ThrowExceptionForHR(hr);
916                                         hr = connectedOutputPin.Connect(nullRendererInputPin, null);
917                                         DsError.ThrowExceptionForHR(hr);
918                                 }
919                         }
920                         finally
921                         {
922                                 C共通.tCOMオブジェクトを解放する(ref connectedOutputPin);
923                                 C共通.tCOMオブジェクトを解放する(ref videoRendererInputPin);
924                                 C共通.tCOMオブジェクトを解放する(ref videoRenderer);
925                                 C共通.tCOMオブジェクトを解放する(ref audioRenderer);
926                                 C共通.tCOMオブジェクトを解放する(ref audioRendererInputPin);
927                                 C共通.tCOMオブジェクトを解放する(ref nullRendererInputPin);
928                                 C共通.tCOMオブジェクトを解放する(ref grabberOutputPin);
929                                 C共通.tCOMオブジェクトを解放する(ref grabberOutputConnectedPin);
930                         }
931                 }
932
933                 private static IPin t最初の入力ピンを探して返す( IBaseFilter baseFilter )
934                 {
935                         int hr = 0;
936
937                         IPin firstInputPin = null;
938
939                         IEnumPins ePins;
940                         hr = baseFilter.EnumPins( out ePins );
941                         DsError.ThrowExceptionForHR( hr );
942                         try
943                         {
944                                 var pins = new IPin[ 1 ];
945                                 while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )
946                                 {
947                                         PinInfo pinfo = new PinInfo() { filter = null };
948                                         try
949                                         {
950                                                 hr = pins[ 0 ].QueryPinInfo( out pinfo );
951                                                 DsError.ThrowExceptionForHR( hr );
952
953                                                 if( pinfo.dir == PinDirection.Input )
954                                                 {
955                                                         firstInputPin = pins[ 0 ];
956                                                         break;
957                                                 }
958                                         }
959                                         finally
960                                         {
961                                                 if( pinfo.filter != null )
962                                                         C共通.tCOMオブジェクトを解放する( ref pinfo.filter );
963                                                 DsUtils.FreePinInfo( pinfo );
964
965                                                 if( firstInputPin == null )
966                                                         C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );
967                                         }
968                                 }
969                         }
970                         finally
971                         {
972                                 C共通.tCOMオブジェクトを解放する( ref ePins );
973                         }
974
975                         return firstInputPin;
976                 }
977                 private static void SearchMMRenderers( IFilterGraph graph, out IBaseFilter videoRenderer, out IPin inputVPin, out IBaseFilter audioRenderer, out IPin inputAPin )
978                 {
979                         int hr = 0;
980                         string strVRフィルタ名 = null;
981                         string strVRピンID = null;
982                         string strARフィルタ名 = null;
983                         string strARピンID = null;
984
985                         // ビデオレンダラと入力ピンを探し、そのフィルタ名とピンIDを控える。
986
987                         IEnumFilters eFilters;
988                         hr = graph.EnumFilters( out eFilters );
989                         DsError.ThrowExceptionForHR( hr );
990                         try
991                         {
992                                 var filters = new IBaseFilter[ 1 ];
993                                 while( eFilters.Next( 1, filters, IntPtr.Zero ) == CWin32.S_OK )
994                                 {
995                                         try
996                                         {
997                                                 #region [ 出力ピンがない(レンダラである)ことを確認する。]
998                                                 //-----------------
999                                                 IEnumPins ePins;
1000                                                 bool b出力ピンがある = false;
1001
1002                                                 hr = filters[ 0 ].EnumPins( out ePins );
1003                                                 DsError.ThrowExceptionForHR( hr );
1004                                                 try
1005                                                 {
1006                                                         var pins = new IPin[ 1 ];
1007                                                         while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )
1008                                                         {
1009                                                                 try
1010                                                                 {
1011                                                                         if( b出力ピンがある )
1012                                                                                 continue;
1013
1014                                                                         PinDirection dir;
1015                                                                         hr = pins[ 0 ].QueryDirection( out dir );
1016                                                                         DsError.ThrowExceptionForHR( hr );
1017                                                                         if( dir == PinDirection.Output )
1018                                                                                 b出力ピンがある = true;
1019                                                                 }
1020                                                                 finally
1021                                                                 {
1022                                                                         C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );
1023                                                                 }
1024                                                         }
1025                                                 }
1026                                                 finally
1027                                                 {
1028                                                         C共通.tCOMオブジェクトを解放する( ref ePins );
1029                                                 }
1030
1031                                                 if( b出力ピンがある )
1032                                                         continue;       // 次のフィルタへ
1033
1034                                                 //-----------------
1035                                                 #endregion
1036                                                 #region [ 接続中の入力ピンが MEDIATYPE_Video に対応していたら、フィルタ名とピンIDを取得する。]
1037                                                 //-----------------
1038                                                 hr = filters[ 0 ].EnumPins( out ePins );
1039                                                 DsError.ThrowExceptionForHR( hr );
1040                                                 try
1041                                                 {
1042                                                         var pins = new IPin[ 1 ];
1043                                                         while( ePins.Next( 1, pins, IntPtr.Zero ) == CWin32.S_OK )
1044                                                         {
1045                                                                 try
1046                                                                 {
1047                                                                         if( !string.IsNullOrEmpty( strVRフィルタ名 ) )
1048                                                                                 continue;
1049
1050                                                                         var mediaType = new AMMediaType();
1051
1052                                                                         #region [ 現在接続中の MediaType を取得。つながってなければ次のピンへ。]
1053                                                                         //-----------------
1054                                                                         hr = pins[ 0 ].ConnectionMediaType( mediaType );
1055                                                                         if( hr == CWin32.VFW_E_NOT_CONNECTED )
1056                                                                                 continue;       // つながってない
1057                                                                         DsError.ThrowExceptionForHR( hr );
1058                                                                         //-----------------
1059                                                                         #endregion
1060
1061                                                                         try
1062                                                                         {
1063                                                                                 if( mediaType.majorType.Equals( MediaType.Video ) )
1064                                                                                 {
1065                                                                                         #region [ フィルタ名取得!]
1066                                                                                         //-----------------
1067                                                                                         FilterInfo filterInfo;
1068                                                                                         hr = filters[ 0 ].QueryFilterInfo( out filterInfo );
1069                                                                                         DsError.ThrowExceptionForHR( hr );
1070                                                                                         strVRフィルタ名 = filterInfo.achName;
1071                                                                                         C共通.tCOMオブジェクトを解放する( ref filterInfo.pGraph );
1072                                                                                         //-----------------
1073                                                                                         #endregion
1074                                                                                         #region [ ピンID取得!]
1075                                                                                         //-----------------
1076                                                                                         hr = pins[ 0 ].QueryId( out strVRピンID );
1077                                                                                         DsError.ThrowExceptionForHR( hr );
1078                                                                                         //-----------------
1079                                                                                         #endregion
1080                                                                                 }
1081                                                                                 else if( mediaType.majorType.Equals( MediaType.Audio ) )
1082                                                                                 {
1083                                                                                         FilterInfo filterInfo;
1084                                                                                         hr = filters[0].QueryFilterInfo(out filterInfo);
1085                                                                                         DsError.ThrowExceptionForHR(hr);
1086                                                                                         strARフィルタ名 = filterInfo.achName;
1087                                                                                         C共通.tCOMオブジェクトを解放する(ref filterInfo.pGraph);
1088                                                                                         hr = pins[0].QueryId(out strARピンID);
1089                                                                                         DsError.ThrowExceptionForHR(hr);
1090                                                                                 }
1091                                                                         }
1092                                                                         finally
1093                                                                         {
1094                                                                                 DsUtils.FreeAMMediaType( mediaType );
1095                                                                         }
1096                                                                 }
1097                                                                 finally
1098                                                                 {
1099                                                                         C共通.tCOMオブジェクトを解放する( ref pins[ 0 ] );
1100                                                                 }
1101                                                         }
1102                                                 }
1103                                                 finally
1104                                                 {
1105                                                         C共通.tCOMオブジェクトを解放する( ref ePins );
1106                                                 }
1107
1108                                                 //-----------------
1109                                                 #endregion
1110                                         }
1111                                         finally
1112                                         {
1113                                                 C共通.tCOMオブジェクトを解放する( ref filters[ 0 ] );
1114                                         }
1115                                 }
1116                         }
1117                         finally
1118                         {
1119                                 C共通.tCOMオブジェクトを解放する( ref eFilters );
1120                         }
1121
1122
1123                         // 改めてフィルタ名とピンIDからこれらのインターフェースを取得し、戻り値として返す。
1124
1125                         videoRenderer = null;
1126                         inputVPin = null;
1127                         audioRenderer = null;
1128                         inputAPin = null;
1129
1130                         if( !string.IsNullOrEmpty( strVRフィルタ名 ) )
1131                         {
1132                                 hr = graph.FindFilterByName( strVRフィルタ名, out videoRenderer );
1133                                 DsError.ThrowExceptionForHR( hr );
1134
1135                                 hr = videoRenderer.FindPin( strVRピンID, out inputVPin );
1136                                 DsError.ThrowExceptionForHR( hr );
1137                         }
1138
1139                         if( !string.IsNullOrEmpty( strARフィルタ名 ) )
1140                         {
1141                                 hr = graph.FindFilterByName(strARフィルタ名, out audioRenderer);
1142                                 DsError.ThrowExceptionForHR(hr);
1143
1144                                 hr = audioRenderer.FindPin(strARピンID, out inputAPin);
1145                                 DsError.ThrowExceptionForHR(hr);
1146                         }
1147                 }
1148                 private static IBaseFilter tオーディオレンダラを探して返す( IFilterGraph graph )
1149                 {
1150                         int hr = 0;
1151                         IBaseFilter audioRenderer = null;
1152
1153                         IEnumFilters eFilters;
1154                         hr = graph.EnumFilters( out eFilters );
1155                         DsError.ThrowExceptionForHR( hr );
1156                         try
1157                         {
1158                                 var filters = new IBaseFilter[ 1 ];
1159                                 while( eFilters.Next( 1, filters, IntPtr.Zero ) == CWin32.S_OK )
1160                                 {
1161                                         if( ( filters[ 0 ] as IAMAudioRendererStats ) != null )
1162                                         {
1163                                                 audioRenderer = filters[ 0 ];
1164                                                 break;
1165                                         }
1166
1167                                         C共通.tCOMオブジェクトを解放する( ref filters[ 0 ] );
1168                                 }
1169                         }
1170                         finally
1171                         {
1172                                 C共通.tCOMオブジェクトを解放する( ref eFilters );
1173                         }
1174                         return audioRenderer;
1175                 }
1176
1177
1178                 #region [ 静的インスタンス管理 ]
1179                 //-----------------
1180                 public const int nインスタンスIDの最大数 = 100;
1181                 protected static Dictionary<int, CDirectShow> dicインスタンス = new Dictionary<int, CDirectShow>();       // <インスタンスID, そのIDを持つインスタンス>
1182
1183                 public static CDirectShow tインスタンスを返す( int nインスタンスID )
1184                 {
1185                         if( CDirectShow.dicインスタンス.ContainsKey( nインスタンスID ) )
1186                                 return CDirectShow.dicインスタンス[ nインスタンスID ];
1187
1188                         return null;
1189                 }
1190                 protected static void tインスタンスを登録する( CDirectShow ds )
1191                 {
1192                         for( int i = 1; i < CDirectShow.nインスタンスIDの最大数; i++ )
1193                         {
1194                                 if( !CDirectShow.dicインスタンス.ContainsKey( i ) )               // 空いている番号を使う。
1195                                 {
1196                                         ds.nインスタンスID = i;
1197                                         CDirectShow.dicインスタンス.Add( i, ds );
1198                                         break;
1199                                 }
1200                         }
1201                 }
1202                 protected static void tインスタンスを解放する( int nインスタンスID )
1203                 {
1204                         if( CDirectShow.dicインスタンス.ContainsKey( nインスタンスID ) )
1205                                 CDirectShow.dicインスタンス.Remove( nインスタンスID );
1206                 }
1207                 //-----------------
1208                 #endregion
1209
1210                 #region [ Dispose-Finalize パターン実装 ]
1211                 //-----------------
1212                 public virtual void Dispose()
1213                 {
1214                         this.Dispose( true );
1215                         GC.SuppressFinalize( this );    // ちゃんと Dispose されたので、ファイナライズ不要であることを CLR に伝える。
1216                 }
1217                 protected virtual void Dispose( bool bManagedリソースも解放する )
1218                 {
1219                         if( bManagedリソースも解放する )
1220                         {
1221                                 #region [ ROTから解放する。]
1222                                 //-----------------
1223 #if DEBUG
1224                                         C共通.tDisposeする( ref this.rot );
1225 #endif
1226                                 //-----------------
1227                                 #endregion
1228                                 
1229                                 CDirectShow.tインスタンスを解放する( this.nインスタンスID );
1230                         }
1231
1232                         #region [ インターフェース参照をなくし、COMオブジェクトを解放する。 ]
1233                         //-----------------
1234                         if( this.ip != IntPtr.Zero )
1235                         {
1236                                 Marshal.FreeCoTaskMem( this.ip );
1237                                 this.ip = IntPtr.Zero;
1238                         }
1239
1240                         if( this.MediaCtrl != null )
1241                         {
1242                                 this.MediaCtrl.Stop();
1243                                 this.MediaCtrl = null;
1244                         }
1245
1246                         if( this.MediaEventEx != null )
1247                         {
1248                                 this.MediaEventEx.SetNotifyWindow( IntPtr.Zero, 0, IntPtr.Zero );
1249                                 this.MediaEventEx = null;
1250                         }
1251
1252                         if( this.MediaSeeking != null )
1253                                 this.MediaSeeking = null;
1254
1255                         if( this.BasicAudio != null )
1256                                 this.BasicAudio = null;
1257
1258                         C共通.tCOMオブジェクトを解放する( ref this.nullRenderer );
1259                         C共通.tCOMオブジェクトを解放する( ref this.memoryRenderer );
1260                         C共通.tCOMオブジェクトを解放する( ref this.memoryRendererObject );
1261                         C共通.tCOMオブジェクトを解放する( ref this.graphBuilder );
1262                         //-----------------
1263                         #endregion
1264
1265                         C共通.t完全なガベージコレクションを実施する();
1266                 }
1267         ~CDirectShow()
1268                 {
1269                         // ファイナライザが呼ばれたということは、Dispose() されなかったということ。
1270                         // この場合、Managed リソースは先にファイナライズされている可能性があるので、Unmamaed リソースのみを解放する。
1271                         
1272                         this.Dispose( false );
1273         }
1274                 //-----------------
1275                 #endregion
1276
1277                 #region [ protected ]
1278                 //-----------------
1279                 protected MemoryRenderer memoryRendererObject = null;
1280                 protected IMemoryRenderer memoryRenderer = null;
1281                 protected IBaseFilter nullRenderer = null;
1282                 protected int n再生一時停止呼び出しの累積回数 = 0;
1283                 //-----------------
1284                 #endregion
1285
1286                 #region [ private ]
1287                 //-----------------
1288                 private int _n音量 = 100;
1289 #if DEBUG
1290                 private DsROTEntry rot = null;
1291 #endif
1292
1293                 // 可能な数のスレッドを使用して画像を転送する。大きい画像ほど有効。多すぎるとプール内のスレッドが空くまで待たされるので注意。
1294                 private static int n並列度 = 0;      // 0 の場合、最初の生成時に並列度を決定する。
1295
1296                 private DGライン描画[] dgライン描画ARGB32;
1297                 private DGライン描画[] dgライン描画XRGB32;
1298                 private unsafe delegate void DGライン描画( int n );
1299                 private unsafe byte* ptrSnap = null;
1300                 private unsafe UInt32** ptrTexture = null;
1301
1302                 private unsafe void tライン描画XRGB32( int n )
1303                 {
1304                         // Snap は RGB32、Textureは X8R8G8B8
1305
1306                         UInt32* ptrTexture = this.ptrTexture[ n ];
1307                         for( int y = n; y < this.n高さpx; y += CDirectShow.n並列度 )
1308                         {
1309                                 byte* ptrPixel = ptrSnap + ( ( ( this.n高さpx - y ) - 1 ) * this.nスキャンライン幅byte );
1310
1311                                 // アルファ無視なので一括コピー。CopyMemory() は自前でループ展開するよりも速い。
1312                                 CWin32.CopyMemory( (void*) ptrTexture, (void*) ptrPixel, (uint) ( this.n幅px * 4 ) );
1313
1314                                 ptrTexture += this.n幅px * CDirectShow.n並列度;
1315                         }
1316                 }
1317                 private unsafe void tライン描画ARGB32( int n )
1318                 {
1319                         // Snap は RGB32、Textureは A8R8G8B8
1320
1321                         UInt32* ptrTexture = this.ptrTexture[ n ];
1322                         for( int y = n; y < this.n高さpx; y += CDirectShow.n並列度 )
1323                         {
1324                                 UInt32* ptrPixel = (UInt32*) ( ptrSnap + ( ( ( this.n高さpx - y ) - 1 ) * this.nスキャンライン幅byte ) );
1325
1326                                 //for( int x = 0; x < this.n幅px; x++ )
1327                                 //      *( ptrTexture + x ) = 0xFF000000 | *ptrPixel++;
1328                                 //                      ↓ループ展開により高速化。160fps の曲が 200fps まで上がった。
1329
1330                                 if( this.n幅px == 0 ) goto LEXIT;
1331                                 UInt32* pt = ptrTexture;
1332                                 UInt32 nAlpha = 0xFF000000;
1333                                 int d = ( this.n幅px % 32 );
1334
1335                                 switch( d )
1336                                 {
1337                                         case 1: goto L031;
1338                                         case 2: goto L030;
1339                                         case 3: goto L029;
1340                                         case 4: goto L028;
1341                                         case 5: goto L027;
1342                                         case 6: goto L026;
1343                                         case 7: goto L025;
1344                                         case 8: goto L024;
1345                                         case 9: goto L023;
1346                                         case 10: goto L022;
1347                                         case 11: goto L021;
1348                                         case 12: goto L020;
1349                                         case 13: goto L019;
1350                                         case 14: goto L018;
1351                                         case 15: goto L017;
1352                                         case 16: goto L016;
1353                                         case 17: goto L015;
1354                                         case 18: goto L014;
1355                                         case 19: goto L013;
1356                                         case 20: goto L012;
1357                                         case 21: goto L011;
1358                                         case 22: goto L010;
1359                                         case 23: goto L009;
1360                                         case 24: goto L008;
1361                                         case 25: goto L007;
1362                                         case 26: goto L006;
1363                                         case 27: goto L005;
1364                                         case 28: goto L004;
1365                                         case 29: goto L003;
1366                                         case 30: goto L002;
1367                                         case 31: goto L001;
1368                                 }
1369
1370                         L000: *pt++ = nAlpha | *ptrPixel++;
1371                         L001: *pt++ = nAlpha | *ptrPixel++;
1372                         L002: *pt++ = nAlpha | *ptrPixel++;
1373                         L003: *pt++ = nAlpha | *ptrPixel++;
1374                         L004: *pt++ = nAlpha | *ptrPixel++;
1375                         L005: *pt++ = nAlpha | *ptrPixel++;
1376                         L006: *pt++ = nAlpha | *ptrPixel++;
1377                         L007: *pt++ = nAlpha | *ptrPixel++;
1378                         L008: *pt++ = nAlpha | *ptrPixel++;
1379                         L009: *pt++ = nAlpha | *ptrPixel++;
1380                         L010: *pt++ = nAlpha | *ptrPixel++;
1381                         L011: *pt++ = nAlpha | *ptrPixel++;
1382                         L012: *pt++ = nAlpha | *ptrPixel++;
1383                         L013: *pt++ = nAlpha | *ptrPixel++;
1384                         L014: *pt++ = nAlpha | *ptrPixel++;
1385                         L015: *pt++ = nAlpha | *ptrPixel++;
1386                         L016: *pt++ = nAlpha | *ptrPixel++;
1387                         L017: *pt++ = nAlpha | *ptrPixel++;
1388                         L018: *pt++ = nAlpha | *ptrPixel++;
1389                         L019: *pt++ = nAlpha | *ptrPixel++;
1390                         L020: *pt++ = nAlpha | *ptrPixel++;
1391                         L021: *pt++ = nAlpha | *ptrPixel++;
1392                         L022: *pt++ = nAlpha | *ptrPixel++;
1393                         L023: *pt++ = nAlpha | *ptrPixel++;
1394                         L024: *pt++ = nAlpha | *ptrPixel++;
1395                         L025: *pt++ = nAlpha | *ptrPixel++;
1396                         L026: *pt++ = nAlpha | *ptrPixel++;
1397                         L027: *pt++ = nAlpha | *ptrPixel++;
1398                         L028: *pt++ = nAlpha | *ptrPixel++;
1399                         L029: *pt++ = nAlpha | *ptrPixel++;
1400                         L030: *pt++ = nAlpha | *ptrPixel++;
1401                         L031: *pt++ = nAlpha | *ptrPixel++;
1402                                 if( ( pt - ptrTexture ) < this.n幅px ) goto L000;
1403
1404                         LEXIT:
1405                                 ptrTexture += this.n幅px * CDirectShow.n並列度;
1406                         }
1407                 }
1408                 //-----------------
1409                 #endregion
1410         }
1411 }