2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Threading.Tasks;
10 /// 活性化後の最初の進行描画時に、再生が開始される。
12 public unsafe class 動画 : Activity
14 public enum 再生状態ID { 未再生, 再生中, 再生終了済み }
15 public FDK.同期.RWLock<再生状態ID> 再生状態 { get; } = new RWLock<再生状態ID>( 再生状態ID.未再生 );
16 public bool 加算合成 { get; set; } = false;
17 public float 不透明度0to1 { get; set; } = 1.0f;
18 public bool ループ再生する { get; set; } = false;
20 public 動画( string 動画ファイルパス )
22 this.動画ファイルパス = FDK.フォルダ.絶対パスに含まれるフォルダ変数を展開して返す( 動画ファイルパス );
24 protected override void Onデバイス依存リソースの作成( デバイスリソース dr )
26 // todo: デバイスがリサイズされると動画もリセットされてしまう。活性化とコードを分離すること(課題)。
28 this.再生状態.Value = 再生状態ID.未再生;
29 this.前フレームの時刻 = FDK.カウンタ.QPCTimer.未使用;
32 string 変数付きファイルパス = フォルダ.絶対パスに含まれるフォルダ変数を展開して返す( this.動画ファイルパス ); // Log出力用。
33 var result = SharpDX.Result.Ok;
36 this.動画の生成に成功した = false;
38 // 動画ファイルパスを基に、SourceReaderEx, MediaType, フレームサイズ, 描画先WICビットマップを準備する。
40 #region " 動画ファイルパスの有効性を確認する。"
42 if( string.IsNullOrEmpty( this.動画ファイルパス ) )
44 Log.ERROR( $"動画ファイルパスが null または空文字列です。[{変数付きファイルパス}]" );
47 if( false == System.IO.File.Exists( this.動画ファイルパス ) )
49 Log.ERROR( $"動画ファイルが存在しません。[{変数付きファイルパス}]" );
54 #region " 動画のファイルパス(URI扱い)から SourceReaderEx を作成する。"
58 using( var 属性 = new SharpDX.MediaFoundation.MediaAttributes() )
60 // DXVAに対応しているGPUの場合にはそれをデコードに利用するよう指定する。
61 属性.Set<SharpDX.ComObject>( SharpDX.MediaFoundation.SourceReaderAttributeKeys.D3DManager, dr.DXGIDeviceManager );
63 // 追加のビデオプロセッシングを有効にする。
64 属性.Set<bool>( SharpDX.MediaFoundation.SourceReaderAttributeKeys.EnableAdvancedVideoProcessing, true ); // bool だったり
66 // 追加のビデオプロセッシングを有効にしたら、こちらは無効に。
67 属性.Set<int>( SharpDX.MediaFoundation.SinkWriterAttributeKeys.ReadwriteDisableConverters, 0 ); // int だったり
69 // 属性を使って、SourceReaderEx を生成。
70 using( var sourceReader = new SharpDX.MediaFoundation.SourceReader( this.動画ファイルパス, 属性 ) )
72 this.SourceReaderEx = sourceReader.QueryInterface<SharpDX.MediaFoundation.SourceReaderEx>();
76 catch( SharpDX.SharpDXException e )
78 Log.ERROR( $"SourceReaderEx の作成に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
79 result = e.ResultCode;
84 #region " 最初のビデオストリームを選択し、その他のすべてのストリームを非選択にする。"
88 this.SourceReaderEx.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.AllStreams, false );
90 catch( SharpDX.SharpDXException e )
92 Log.ERROR( $"すべてのストリームの選択解除に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
97 this.SourceReaderEx.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream, true );
99 catch( SharpDX.SharpDXException e )
101 Log.ERROR( $"最初のビデオストリームの選択に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
102 result = e.ResultCode;
107 #region " ARGB32 フォーマットに合わせたメディアタイプを作成し、SourceReaderEx に登録してデコーダを準備する。"
111 using( var mediaType = new SharpDX.MediaFoundation.MediaType() )
113 // フォーマットを部分メディアタイプの属性に設定。
114 mediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.MajorType, SharpDX.MediaFoundation.MediaTypeGuids.Video );
115 mediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.Subtype, SharpDX.MediaFoundation.VideoFormatGuids.Argb32 ); // ARGB32 フォーマットで固定。SourceReaderEx を使わない場合、H264 では NV12 しか選べないので注意。
117 // 部分メディアタイプを SourceReaderEx にセットする。SourceReaderEx は、必要なデコーダをロードするだろう。
118 this.SourceReaderEx.SetCurrentMediaType( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream, mediaType );
121 catch( SharpDX.SharpDXException e )
123 Log.ERROR( $"MediaType (Video, ARGB32) の設定または必要なデコーダの読み込みに失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
124 result = e.ResultCode;
129 #region " ビデオストリームが選択されていることを再度保証する。"
133 this.SourceReaderEx.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream, true );
135 catch( SharpDX.SharpDXException e )
137 Log.ERROR( $"最初のビデオストリームの選択に失敗しました(MediaType 設定後)。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
138 result = e.ResultCode;
143 #region " デコーダの読み込みにより完成した完全メディアタイプを取得する。"
147 this.MediaType = this.SourceReaderEx.GetCurrentMediaType( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream );
149 catch( SharpDX.SharpDXException e )
151 Log.ERROR( $"完全メディアタイプの取得に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
152 result = e.ResultCode;
157 #region " フレームサイズを取得する。動画の途中でのサイズ変更には対応しない。"
161 var packedFrameSize = this.MediaType.Get<long>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.FrameSize );
162 this.サイズdpx.Width = (int) ( ( packedFrameSize >> 32 ) & 0xFFFFFFFF );
163 this.サイズdpx.Height = (int) ( ( packedFrameSize ) & 0xFFFFFFFF );
165 catch( SharpDX.SharpDXException e )
167 Log.ERROR( $"フレームサイズの取得に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
168 result = e.ResultCode;
173 #region " 描画先WICビットマップを作成する。"
177 this.WICビットマップ = new SharpDX.WIC.Bitmap(
178 dr.WicImagingFactory2,
181 SharpDX.WIC.PixelFormat.Format32bppBGR,
182 SharpDX.WIC.BitmapCreateCacheOption.CacheOnLoad );
184 catch( SharpDX.SharpDXException e )
186 Log.ERROR( $"描画先 WIC ビットマップの作成に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
187 result = e.ResultCode;
193 this.動画の生成に成功した = true;
194 Log.Info( $"{Utilities.現在のメソッド名}: 動画を生成しました。[{変数付きファイルパス}]" );
196 #region " デコードの前処理を行う。"
199 Log.Info( $"{Utilities.現在のメソッド名}: 動画のセットアップ(フレームキャッシング)を行いました。[{変数付きファイルパス}]" );
203 // 準備完了。以降は、サンプルを読み込みたいときに、適宜 ReadSample() する。
204 // コールバックを使っていない(非同期である)ので、IMFSourceReader::ReadSample() はサンプルが用意できるまでブロックすることに注意。
211 //this.活性化していない = true; --> 失敗しても、一応活性化は成功とする。(進行描画はしない。)
214 protected override void Onデバイス依存リソースの解放( デバイスリソース dr )
216 // todo: デバイスがリサイズされると動画もリセットされてしまう。非活性化とコードを分離すること(課題)。
218 // デコード中なら、タスクが終了するまで待つ。
219 while( ( this.再生状態.Value == 再生状態ID.再生中 ) && ( this.デコーダ状態.Value == デコーダ状態ID.デコード中 ) )
220 System.Threading.Thread.Sleep( 500 );
224 Log.Info( $"{Utilities.現在のメソッド名}: 動画を解放しました。[{フォルダ.絶対パスに含まれるフォルダ変数を展開して返す( this.動画ファイルパス )}]" );
226 public void 進行描画する( デバイスリソース dr, SharpDX.RectangleF 描画先矩形dpx, float 不透明度0to1 = 1.0f, bool ループ再生する = false )
228 // Direct2D の行列は、設計単位じゃなく物理単位で計算するので注意。
230 dr.拡大行列DPXtoPX // スケーリング(1) DPX → PX
231 * SharpDX.Matrix3x2.Scaling( 描画先矩形dpx.Width / this.サイズdpx.Width, 描画先矩形dpx.Height / this.サイズdpx.Height ) // スケーリング(2)
232 * SharpDX.Matrix3x2.Translation( 描画先矩形dpx.Left * dr.拡大率DPXtoPX横方向, 描画先矩形dpx.Top * dr.拡大率DPXtoPX縦方向 ); // 平行移動(物理単位)、
235 this.進行描画する( dr, 変換行列2Dpx );
237 public void 進行描画する( デバイスリソース dr, SharpDX.Matrix3x2 変換行列 )
239 Debug.Assert( this.活性化している );
241 // 活性化でエラーが発生している場合は、何もしない(何も描画しない)。
242 if( false == this.動画の生成に成功した )
245 // 以下、再生状態とデコーダ状態に応じて処理分岐。
246 switch( this.再生状態.Value )
249 // (A) 未再生なら、デコードタスクを開始する。
250 this.再生状態.Value = 再生状態ID.再生中;
255 // (B) 再生が終了している場合は、何もしない(何も描画しない)。
259 // (C) 再生中なら、D2Dビットマップを描画する。
260 switch( this.デコーダ状態.Value )
263 // (C-a) タスクが次のサンプルフレームをデコード中なら、現在のD2Dビットマップ(直前のフレーム画像が入ってる)をもう一度描画する。
264 this.D2Dビットマップを描画する( dr, 変換行列 );
268 // (C-b) タスクの次のサンプルフレームのデコード処理が完了しているなら、サンプルをD2Dビットマップに転送し、それを描画し、デコードタスクを再び起動する。
269 this.サンプルをD2Dビットマップに転送する( dr );
270 this.D2Dビットマップを描画する( dr, 変換行列 );
275 // (C-c) タスクの次のサンプルフレームをスキップしたなら、現在のD2Dビットマップ(直前のフレーム画像が入ってる)をもう一度描画し、デコードタスクを再び起動する。
276 this.D2Dビットマップを描画する( dr, 変換行列 );
284 private enum デコーダ状態ID { 完了, デコード中, スキップ }
285 private readonly FDK.同期.RWLock<デコーダ状態ID> デコーダ状態 = new RWLock<デコーダ状態ID>( デコーダ状態ID.完了 );
286 private string 動画ファイルパス = "";
287 private bool 動画の生成に成功した = false; // 活性化時に成功の成否を設定。
288 private SharpDX.Result LastSharpDXResult = SharpDX.Result.Ok;
289 private SharpDX.MediaFoundation.Sample Sample = null;
290 private SharpDX.MediaFoundation.SourceReaderEx SourceReaderEx = null;
291 private SharpDX.WIC.Bitmap WICビットマップ = null; // MediaFoundation は WICBitmap に出力する。
292 private SharpDX.Direct2D1.Bitmap D2Dビットマップ = null; // WICBitmap をこれに転送して D2D に Drawする。
293 private SharpDX.MediaFoundation.MediaType MediaType = null;
294 private SharpDX.Size2 サイズdpx = new SharpDX.Size2( 1, 1 ); // CopyMemory()で使うので、Size2F じゃなく Size2 を使う。
295 private FDK.カウンタ.QPCTimer タイマ = new FDK.カウンタ.QPCTimer();
296 private long ループした際の先頭時刻 = 0;
297 private long 前フレームの時刻 = FDK.カウンタ.QPCTimer.未使用; // 未使用 = 先頭のフレームである
299 private unsafe void サンプルをD2Dビットマップに転送する( デバイスリソース dr )
301 var buffer = (SharpDX.MediaFoundation.MediaBuffer) null;
302 var buffer2d2 = (SharpDX.MediaFoundation.Buffer2D2) null;
305 #region " サンプルからサンプルバッファ (MediaBuffer) を取得する。"
309 buffer = this.Sample.ConvertToContiguousBuffer();
311 catch( SharpDX.SharpDXException e )
313 Log.ERROR( $"サンプルバッファの取得に失敗しました。(0x{e.HResult:x8})" );
314 this.LastSharpDXResult = e.ResultCode;
319 Log.ERROR( $"サンプルバッファの取得に失敗しました。(0x{e.HResult:x8})" );
324 #region " サンプルバッファを Buffer2D2 にキャストする。"
328 buffer2d2 = buffer.QueryInterface<SharpDX.MediaFoundation.Buffer2D2>();
330 catch( SharpDX.SharpDXException e )
332 Log.ERROR( $"サンプルバッファから Buffer2D2 へのキャストに失敗しました。(0x{e.HResult:x8})" );
333 this.LastSharpDXResult = e.ResultCode;
338 #region " サンプルバッファをロックする。"
340 byte[] scanLine0_bp = new byte[ 8 ]; // 「生ポインタ」が格納される。32bitなら[0~3]、64bitなら[0~7]が有効。(CPUではなく.NETに依存)
342 byte[] bufferStart_bp = new byte[ 8 ]; // 「生ポインタ」が格納される。こちらは使わない。
346 buffer2d2.Lock2DSize(
347 SharpDX.MediaFoundation.Buffer2DLockFlags.Read,
353 catch( SharpDX.SharpDXException e )
355 Log.ERROR( $"サンプルバッファのロックに失敗しました。(0x{e.HResult:x8})" );
356 this.LastSharpDXResult = e.ResultCode;
363 #region " サンプルバッファのネイティブ先頭アドレスを取得する。"
365 byte* scanLine0 = null;
368 scanLine0 = (byte*) this.生ポインタを格納したbyte配列からポインタを取得して返す( scanLine0_bp );
370 catch( SharpDX.SharpDXException e )
372 Log.ERROR( $"サンプルバッファのアドレスの取得に失敗しました。(0x{e.HResult:x8})" );
373 this.LastSharpDXResult = e.ResultCode;
378 #region " サンプルバッファから描画先WICビットマップへ、ARGB32 を G8B8R8X8 に変換しながらコピーする。"
380 if( null == this.D2Dビットマップ )
382 // (A) 初回は WICBitmap 経由で D2Dビットマップを新規生成する。
383 #region " サンプルバッファから描画先WICビットマップへ、ARGB32 を G8B8R8X8 に変換しながらコピーする。"
387 // 描画先WICビットマップをロックする。
388 using( var bitmapLock = this.WICビットマップ.Lock(
389 new SharpDX.Rectangle( 0, 0, this.WICビットマップ.Size.Width, this.WICビットマップ.Size.Height ),
390 SharpDX.WIC.BitmapLockFlags.Write ) )
392 // サンプルバッファからWICビットマップへ、ARGB32 を G8B8R8X8 に変換しながらコピー。
393 int bitmapStride = bitmapLock.Stride;
394 byte* src = scanLine0;
395 byte* dest = (byte*) bitmapLock.Data.DataPointer.ToPointer();
397 for( int y = 0; y < this.サイズdpx.Height; y++ )
399 // ARGB32 to G8B8R8X8 ではデータ変換が不要なので、一行を一気にコピー。
400 動画.CopyMemory( dest, src, this.サイズdpx.Width * 4 ); // ARGB=4バイト。
402 dest += bitmapStride; // bitmapStride は byte 単位
406 catch( SharpDX.SharpDXException e )
408 Log.ERROR( $"WICビットマップの Lock に失敗しました。(0x{e.HResult:x8})" );
409 this.LastSharpDXResult = e.ResultCode;
414 Log.ERROR( $"サンプルバッファから WIC ビットマップへのデータの転送に失敗しました。(0x{e.HResult:x8})" );
415 this.LastSharpDXResult = SharpDX.Result.GetResultFromException( e );
420 #region " 描画先WICビットマップからD2Dビットマップを生成する。 "
424 this.D2Dビットマップ = SharpDX.Direct2D1.Bitmap.FromWicBitmap(
428 catch( SharpDX.SharpDXException e )
430 Log.ERROR( $"D2Dビットマップの作成に失敗しました。(0x{e.HResult:x8})" );
431 this.LastSharpDXResult = e.ResultCode;
439 // (B) 2回目以降は直接 D2Dビットマップへコピーする。
440 this.D2Dビットマップ.CopyFromMemory( new IntPtr( scanLine0 ), pitch );
447 #region " サンプルバッファのロックを解除する。"
449 buffer2d2.Unlock2D();
456 FDK.Utilities.解放する( ref buffer2d2 );
457 FDK.Utilities.解放する( ref buffer );
458 if( this.LastSharpDXResult.Failure )
460 // 描画に失敗したら、全リソースを解放して再生終了。
461 this.再生状態.Value = 再生状態ID.再生終了済み;
466 private void D2Dビットマップを描画する( デバイスリソース dr, SharpDX.Matrix3x2 変換行列2Dpx )
468 if( null == this.D2Dビットマップ )
471 Utilities.D2DBatchDraw( dr.D2DContext1, () => {
473 // 変換行列とブレンドモードを設定する。
474 dr.D2DContext1.Transform = 変換行列2Dpx;
475 dr.D2DContext1.PrimitiveBlend = ( this.加算合成 ) ? SharpDX.Direct2D1.PrimitiveBlend.Add : SharpDX.Direct2D1.PrimitiveBlend.SourceOver;
478 dr.D2DContext1.DrawBitmap( this.D2Dビットマップ, this.不透明度0to1, SharpDX.Direct2D1.InterpolationMode.Linear );
481 private void デコードタスクを開始する()
483 // 再生中なら、デコードタスクをタスクとして起動する(タスクの完了を待たず、このメソッドはすぐ抜ける)。
484 if( this.再生状態.Value == 再生状態ID.再生中 )
487 this.デコードタスク( this.ループ再生する );
491 private void デコードタスク( bool ループ再生する )
493 // サンプル(フレーム)を1つ取得するタスク。
495 this.デコーダ状態.Value = デコーダ状態ID.デコード中;
496 this.LastSharpDXResult = SharpDX.Result.Ok;
499 var ストリームフラグ = SharpDX.MediaFoundation.SourceReaderFlags.None;
502 #region " SourceReader から次のサンプル(フレーム)を1つ取得する。"
508 this.Sample?.Dispose();
509 this.Sample = this.SourceReaderEx.ReadSample(
510 SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream,
511 SharpDX.MediaFoundation.SourceReaderControlFlags.None,
516 catch( SharpDX.SharpDXException e )
518 Log.ERROR( $"SourceReaderEx.ReadSample() に失敗しました。(0x{e.HResult:x8})" );
519 this.LastSharpDXResult = e.ResultCode;
525 #region " 取得結果フラグに応じて、必要な処理があれば行なう。"
526 //---------------------------------------------------
527 if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Endofstream ) ) // BOX化コストとか気にしない
531 if( ループ再生する ) // メンバじゃなくパラメータのほう。
534 FDK.Log.Info( "動画をループ再生します。" );
535 this.ループした際の先頭時刻 = this.前フレームの時刻; // このフラグがセットされるときは、ReadSample() で返されるサンプル時刻は 0 になってるので使えない。
536 this.SourceReaderEx.SetCurrentPosition( 0 ); // ストリーム再生位置を先頭へ。
537 this.デコードタスク( ループ再生する ); // 再帰で先頭サンプルを取得して終了。
543 FDK.Log.Info( "動画の再生を終了します。" );
544 this.再生状態.Value = 再生状態ID.再生終了済み;
545 this.LastSharpDXResult = SharpDX.Result.Ok; // SharpDX のエラーによる終了じゃないよと。
551 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Newstream ) )
555 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Nativemediatypechanged ) )
559 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Currentmediatypechanged ) )
563 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.StreamTick ) )
567 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.AllEffectsremoved ) )
571 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Error ) )
575 FDK.Log.Info( "エラーが発生したので、動画の再生を終了します。" );
576 this.再生状態.Value = 再生状態ID.再生終了済み;
577 this.LastSharpDXResult = SharpDX.Result.Fail;
582 //---------------------------------------------------
584 #region " 前フレームの時刻を、先頭時刻+サンプルの時刻 に設定する。"
586 if( FDK.カウンタ.QPCTimer.未使用 == 前フレームの時刻 ) // 最初のフレームである場合(ループ時は除く)
588 // 最初のフレームの取得には時間がかかることが多いので、最初のフレームを取得した場合のみ、タイマをサンプルの時刻にリセットする。
589 this.タイマ.リセットする( サンプルの時刻 );
592 サンプルの時刻 += this.ループした際の先頭時刻;
593 this.前フレームの時刻 = サンプルの時刻;
596 #region " サンプルの表示時刻までの時刻調整を行う。"
598 var 現在時刻 = this.タイマ.現在のリアルタイムカウント100ns単位;
601 // (A) サンプルの時刻が過去である → このサンプルとタスクは捨てる(さっさと次のサンプルへ移る)。
602 this.デコーダ状態.Value = デコーダ状態ID.スキップ;
607 // (B) サンプルの時刻が未来である → その時刻を過ぎるまで Sleep する。
608 while( 現在時刻 < サンプルの時刻 )
610 System.Threading.Thread.Sleep( 2 ); // 500fps の動画まで対応(理論上(汗
611 現在時刻 = タイマ.現在のリアルタイムカウント100ns単位;
619 #region " 失敗した、または EndOfStream に達した場合は、Sample を無効化する。"
621 if( this.LastSharpDXResult.Failure )
623 FDK.Log.Info( "SharpDX でエラーが発生したので、動画の再生を終了します。" );
624 this.再生状態.Value = 再生状態ID.再生終了済み;
625 FDK.Utilities.解放する( ref this.Sample );
630 this.デコーダ状態.Value = デコーダ状態ID.完了;
633 private void デコードキャッシング()
635 // 最初のほうのサンプルのデコードには 100~200 ms ほどかかってしまうので、あらかじめ少しデコードしてメモリにキャッシュさせることでこれを緩和する。
637 this.デコーダ状態.Value = デコーダ状態ID.デコード中;
641 for( int i = 0; i < 60; i++ ) // 60フレームもあれば、2つめのキーフレームくらいには届くだろう……
643 #region " SourceReader から次のサンプル(フレーム)を1つ取得しては解放する。"
645 var sample = (SharpDX.MediaFoundation.Sample) null;
646 int actualStreamIndex = 0;
647 var streamFlags = SharpDX.MediaFoundation.SourceReaderFlags.None;
651 sample = this.SourceReaderEx.ReadSample(
652 SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream,
653 SharpDX.MediaFoundation.SourceReaderControlFlags.None,
654 out actualStreamIndex,
658 catch( SharpDX.SharpDXException e )
660 Log.ERROR( $"SourceReaderEx.ReadSample() に失敗しました。(0x{e.HResult:x8})" );
661 this.LastSharpDXResult = e.ResultCode;
672 // SourceReader を先頭へリセット。
673 this.SourceReaderEx.SetCurrentPosition( 0 );
677 this.デコーダ状態.Value = デコーダ状態ID.完了;
680 private void 全リソースを解放する()
682 FDK.Utilities.解放する( ref this.D2Dビットマップ );
683 FDK.Utilities.解放する( ref this.WICビットマップ );
684 FDK.Utilities.解放する( ref this.Sample );
685 FDK.Utilities.解放する( ref this.MediaType );
686 FDK.Utilities.解放する( ref this.SourceReaderEx );
688 private unsafe void* 生ポインタを格納したbyte配列からポインタを取得して返す( byte[] 生ポインタ )
690 if( ( 4 == IntPtr.Size ) && System.BitConverter.IsLittleEndian )
692 // (A) 32bit, リトルエンディアン
694 for( int i = 0; i < 4; i++ )
695 生アドレス32bit += ( (int) 生ポインタ[ i ] ) << ( i * 8 );
696 return new IntPtr( 生アドレス32bit ).ToPointer();
698 else if( ( 8 == IntPtr.Size ) && System.BitConverter.IsLittleEndian )
700 // (B) 64bit, リトルエンディアン
702 for( int i = 0; i < 8; i++ )
703 生アドレス64bit += ( (int) 生ポインタ[ i ] ) << ( i * 8 );
704 return new IntPtr( 生アドレス64bit ).ToPointer();
706 else if( ( 4 == IntPtr.Size ) && ( false == System.BitConverter.IsLittleEndian ) )
708 // (C) 32bit, ビッグエンディアン
710 for( int i = 0; i < 4; i++ )
711 生アドレス32bit += ( (int) 生ポインタ[ 4 - i ] ) << ( i * 8 );
712 return new IntPtr( 生アドレス32bit ).ToPointer();
714 else if( ( 8 == IntPtr.Size ) && ( false == System.BitConverter.IsLittleEndian ) )
716 // (D) 64bit, ビッグエンディアン
718 for( int i = 0; i < 8; i++ )
719 生アドレス64bit += ( (int) 生ポインタ[ 8 - i ] ) << ( i * 8 );
720 return new IntPtr( 生アドレス64bit ).ToPointer();
723 throw new SharpDX.SharpDXException( SharpDX.Result.NotImplemented, "この .NET アーキテクチャには対応していません。" );
726 #region " Win32 API "
728 [System.Runtime.InteropServices.DllImport( "kernel32.dll", SetLastError = true )]
729 private static extern unsafe void CopyMemory( void* dst, void* src, int size );