2 using System.Collections.Concurrent;
3 using System.Collections.Generic;
4 using System.Diagnostics;
9 public class 動画 : FDK.Activity
11 public string 動画ファイルパス
17 public SharpDX.Size2F サイズdpx
44 public 動画( string 動画ファイルパス, int キューのサイズ = 16 )
46 this.動画ファイルパス = FDK.フォルダ.絶対パスに含まれるフォルダ変数を展開して返す( 動画ファイルパス );
47 this._キューのサイズ = キューのサイズ;
50 public void 再生を開始する( double 開始位置sec = 0.0, bool ループ再生する = false )
52 this._ループ再生する = ループ再生する;
55 this._デコードタスク = System.Threading.Tasks.Task.Factory.StartNew( this._デコードタスクエントリ, (object) 開始位置sec );
56 this._デコードタスク起動完了.WaitOne();
59 public void 進行描画する( デバイスリソース dr, SharpDX.RectangleF 描画先矩形dpx, float 不透明度0to1 = 1.0f )
61 // Direct2D の行列は、設計単位じゃなく物理単位で計算するので注意。
63 dr.拡大行列DPXtoPX // スケーリング(1) DPX → PX
64 * SharpDX.Matrix3x2.Scaling( 描画先矩形dpx.Width / this.サイズdpx.Width, 描画先矩形dpx.Height / this.サイズdpx.Height ) // スケーリング(2)
65 * SharpDX.Matrix3x2.Translation( 描画先矩形dpx.Left * dr.拡大率DPXtoPX横方向, 描画先矩形dpx.Top * dr.拡大率DPXtoPX縦方向 ); // 平行移動(物理単位)、
67 this.進行描画する( dr, 変換行列2Dpx, 不透明度0to1 );
70 public void 進行描画する( デバイスリソース dr, SharpDX.Matrix3x2 変換行列, float 不透明度0to1 = 1.0f )
74 if( null == this._デコードタスク || // 再生をまだ開始していないか、あるいはすでに再生を完了してデコードタスクを終了済みである。
75 null == this._SourceReaderEx || // 動画の準備に失敗した。
76 null == this._MediaType || // 同上
77 null == this._WicBitmap ) // 同上
84 Action<FrameQueueItem> 次のフレームを表示する = ( frame ) => {
85 this._次のフレームを取り出す( out frame );
86 this._最後に表示したフレーム?.Dispose();
87 this._最後に表示したフレーム = frame;
88 this._D2DBitmapを描画する( dr, 変換行列, frame.D2DBitmap, 不透明度0to1 );
90 Action 前のフレームを表示する = () => {
91 this._D2DBitmapを描画する( dr, 変換行列, this._最後に表示したフレーム?.D2DBitmap, 不透明度0to1 );
94 var フレーム = (FrameQueueItem) null;
95 this._次のフレームを確認する( out フレーム );
98 if( null != フレーム ) // 次のフレームがある。
100 // (A) 次のフレームが前のフレームより過去 → ループしたので、タイマをリセットする。
101 if( ( null != this._最後に表示したフレーム ) &&
102 ( フレーム.表示時刻sec < this._最後に表示したフレーム.表示時刻sec ) )
104 this._再生タイマ.Value.リセットする( FDK.カウンタ.QPCTimer.秒をカウントに変換して返す( フレーム.表示時刻sec ) );
108 // (B) 次のフレームの表示時刻に達した。
109 else if( フレーム.表示時刻sec <= this._再生タイマ.Value.現在のリアルタイムカウントsec )
114 // (C) 次のフレームの表示時刻にはまだ達していない。
121 // (D) デコードが追い付いてない、またはループせず再生が終わっている。
124 // 何も表示しない → 真っ黒画像。デコードが追い付いてないなら点滅するだろう。
128 protected override void On活性化( デバイスリソース dr )
130 this._デコードタスク = null; // タスクが起動していないときは null であることを保証する。
131 this._デコードタスク起動完了 = new System.Threading.AutoResetEvent( false );
132 this._キューが空いた = new System.Threading.ManualResetEvent( true );
133 this._デコードタスクを終了せよ = new System.Threading.AutoResetEvent( false );
134 this._再生タイマ.Value = new カウンタ.QPCTimer();
137 protected override void On非活性化( デバイスリソース dr )
139 this._キューが空いた.Close();
140 this._デコードタスクを終了せよ.Close();
143 protected override void Onデバイス依存リソースの作成( デバイスリソース dr )
145 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
148 this._デコードタスク用D2DDeviceContext参照 = dr.D2DContext1;
149 this._フレームキュー = new ConcurrentQueue<FrameQueueItem>();
150 this._最後に表示したフレーム = null;
152 // 動画ファイルから、SourceReaderEx, MediaType, WicBitmap を生成する。
154 string 変数付きファイルパス = フォルダ.絶対パスに含まれるフォルダ変数を展開して返す( 動画ファイルパス ); // Log出力用。
156 #region " 動画ファイルパスの有効性を確認する。"
158 if( string.IsNullOrEmpty( 動画ファイルパス ) )
160 Log.ERROR( $"動画ファイルパスが null または空文字列です。[{変数付きファイルパス}]" );
163 if( false == System.IO.File.Exists( 動画ファイルパス ) )
165 Log.ERROR( $"動画ファイルが存在しません。[{変数付きファイルパス}]" );
170 #region " SourceReaderEx を生成する。"
174 using( var 属性 = new SharpDX.MediaFoundation.MediaAttributes() )
176 // DXVAに対応しているGPUの場合には、それをデコードに利用するよう指定する。
177 属性.Set<SharpDX.ComObject>( SharpDX.MediaFoundation.SourceReaderAttributeKeys.D3DManager, dr.DXGIDeviceManager );
179 // 追加のビデオプロセッシングを有効にする。
180 属性.Set<bool>( SharpDX.MediaFoundation.SourceReaderAttributeKeys.EnableAdvancedVideoProcessing, true ); // 真偽値が bool だったり
182 // 追加のビデオプロセッシングを有効にしたら、こちらは無効に。
183 属性.Set<int>( SharpDX.MediaFoundation.SinkWriterAttributeKeys.ReadwriteDisableConverters, 0 ); // int だったり
185 // 属性を使って、SourceReaderEx を生成。
186 using( var sourceReader = new SharpDX.MediaFoundation.SourceReader( 動画ファイルパス, 属性 ) ) // パスは URI 扱い
188 this._SourceReaderEx = sourceReader.QueryInterface<SharpDX.MediaFoundation.SourceReaderEx>();
192 catch( SharpDX.SharpDXException e )
194 Log.ERROR( $"SourceReaderEx の作成に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
199 #region " 最初のビデオストリームを選択し、その他のすべてのストリームを非選択にする。"
203 this._SourceReaderEx.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.AllStreams, false );
204 this._SourceReaderEx.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream, true );
206 catch( SharpDX.SharpDXException e )
208 Log.ERROR( $"ストリームの選択に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
213 #region " 部分 MediaType を作成し、SourceReaderEx に登録する。"
217 using( var mediaType = new SharpDX.MediaFoundation.MediaType() )
219 // フォーマットは ARGB32 で固定とする。(SourceReaderEx を使わない場合、H264 では ARGB32 が選べないので注意。)
220 mediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.MajorType, SharpDX.MediaFoundation.MediaTypeGuids.Video );
221 mediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.Subtype, SharpDX.MediaFoundation.VideoFormatGuids.Argb32 );
223 // 部分メディアタイプを SourceReaderEx にセットする。SourceReaderEx は、必要なデコーダをロードするだろう。
224 this._SourceReaderEx.SetCurrentMediaType( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream, mediaType );
227 catch( SharpDX.SharpDXException e )
229 Log.ERROR( $"MediaType (Video, ARGB32) の設定または必要なデコーダの読み込みに失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
234 #region " ビデオストリームが選択されていることを再度保証する。"
238 this._SourceReaderEx.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream, true );
240 catch( SharpDX.SharpDXException e )
242 Log.ERROR( $"最初のビデオストリームの選択に失敗しました(MediaType 設定後)。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
247 #region " 完全 MediaType と動画の情報を取得する。"
251 this._MediaType = this._SourceReaderEx.GetCurrentMediaType( SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream );
253 catch( SharpDX.SharpDXException e )
255 Log.ERROR( $"完全メディアタイプの取得に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
262 // 動画の途中でのサイズ変更には対応しない。
263 var packedFrameSize = this._MediaType.Get<long>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.FrameSize );
264 this.サイズdpx = new SharpDX.Size2F( ( packedFrameSize >> 32 ) & 0xFFFFFFFF, ( packedFrameSize ) & 0xFFFFFFFF );
266 catch( SharpDX.SharpDXException e )
268 Log.ERROR( $"フレームサイズの取得に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
275 this.長さsec = this._SourceReaderEx.GetPresentationAttribute(
276 SharpDX.MediaFoundation.SourceReaderIndex.MediaSource,
277 SharpDX.MediaFoundation.PresentationDescriptionAttributeKeys.Duration
278 ) / ( 1000.0 * 1000.0 * 10.0 );
280 catch( SharpDX.SharpDXException e )
282 Log.ERROR( $"動画の長さの取得に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
287 #region " 描画先となる WicBitmap を作成する。"
291 this._WicBitmap = new SharpDX.WIC.Bitmap(
292 dr.WicImagingFactory2,
293 (int) this.サイズdpx.Width,
294 (int) this.サイズdpx.Height,
295 SharpDX.WIC.PixelFormat.Format32bppBGR,
296 SharpDX.WIC.BitmapCreateCacheOption.CacheOnLoad );
298 catch( SharpDX.SharpDXException e )
300 Log.ERROR( $"描画先となる WICビットマップの作成に失敗しました。(0x{e.HResult:x8})[{変数付きファイルパス}]" );
310 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
314 protected override void Onデバイス依存リソースの解放( デバイスリソース dr )
316 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
318 #region " デコードタスクが起動していたら、終了する。"
320 if( null != this._デコードタスク )
322 this._デコードタスクを終了せよ.Set();
324 if( !this._デコードタスク.Wait( 2000 ) )
325 FDK.Log.WARNING( "デコードタスクの終了待ちがタイムアウトしました。" );
327 this._デコードタスク = null;
332 FDK.Utilities.解放する( ref this._最後に表示したフレーム );
333 FDK.Utilities.解放する( ref this._WicBitmap );
334 FDK.Utilities.解放する( ref this._MediaType );
335 FDK.Utilities.解放する( ref this._SourceReaderEx );
338 this._フレームキュー = null;
339 this._デコードタスク用D2DDeviceContext参照 = null;
341 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
344 private int _キューのサイズ = 0;
345 private class FrameQueueItem : IDisposable
347 public double 表示時刻sec = 0;
348 public SharpDX.Direct2D1.Bitmap D2DBitmap = null;
350 public void Dispose()
352 FDK.Utilities.解放する( ref this.D2DBitmap );
355 private ConcurrentQueue<FrameQueueItem> _フレームキュー = null;
356 private FrameQueueItem _最後に表示したフレーム = null;
357 private bool _ループ再生する = false;
358 private System.Threading.Tasks.Task _デコードタスク = null;
359 private System.Threading.AutoResetEvent _デコードタスク起動完了 = null;
360 private System.Threading.ManualResetEvent _キューが空いた = null;
361 private System.Threading.AutoResetEvent _デコードタスクを終了せよ = null;
362 private SharpDX.MediaFoundation.SourceReaderEx _SourceReaderEx = null;
363 private SharpDX.MediaFoundation.MediaType _MediaType = null;
364 private SharpDX.WIC.Bitmap _WicBitmap = null; // MediaFoundation は WICBitmap に出力する。
365 private SharpDX.Direct2D1.DeviceContext1 _デコードタスク用D2DDeviceContext参照 = null; // D2Dはスレッドセーフであること。
367 private void _キューをクリアする()
369 while( 0 < this._フレームキュー.Count )
371 var item = (FrameQueueItem) null;
372 if( this._フレームキュー.TryDequeue( out item ) )
376 this._キューが空いた?.Set();
379 private void _次のフレームを確認する( out FrameQueueItem フレーム )
381 if( ( 0 == this._フレームキュー.Count ) ||
382 ( false == this._フレームキュー.TryPeek( out フレーム ) ) ) // キューから取り出さない
384 フレーム = null; // キューが空だったか、Peek が一歩遅かった?(ないはずだが
388 private void _次のフレームを取り出す( out FrameQueueItem フレーム )
390 if( ( 0 == this._フレームキュー.Count ) ||
391 ( false == this._フレームキュー.TryDequeue( out フレーム ) ) ) // キューから取り出す
393 フレーム = null; // キューが空だったか、Peek が一歩遅かった?(ないはずだが
401 private void _D2DBitmapを描画する( デバイスリソース dr, SharpDX.Matrix3x2 変換行列2Dpx, SharpDX.Direct2D1.Bitmap D2DBitmap, float 不透明度 )
403 if( null == D2DBitmap )
406 FDK.Utilities.D2DBatchDraw( dr.D2DContext1, () => {
407 dr.D2DContext1.Transform = 変換行列2Dpx;
408 dr.D2DContext1.PrimitiveBlend = ( this.加算合成 ) ? SharpDX.Direct2D1.PrimitiveBlend.Add : SharpDX.Direct2D1.PrimitiveBlend.SourceOver;
409 dr.D2DContext1.DrawBitmap( D2DBitmap, 不透明度, SharpDX.Direct2D1.InterpolationMode.Linear );
415 private FDK.同期.RWLock<FDK.カウンタ.QPCTimer> _再生タイマ = new 同期.RWLock<カウンタ.QPCTimer>();
417 private void _デコードタスクエントリ( object obj再生開始位置sec )
419 FDK.Log.Info( "デコードタスクを起動しました。" );
421 var 再生開始位置sec = (double) obj再生開始位置sec;
423 if( 0.0 < 再生開始位置sec )
424 this._再生位置までストリームを進める( 再生開始位置sec );
426 const int EVID_キューが空いた = 0;
427 const int EVID_デコードタスクを終了せよ = 1;
428 var events = new System.Threading.WaitHandle[ 2 ];
429 events[ EVID_キューが空いた ] = this._キューが空いた;
430 events[ EVID_デコードタスクを終了せよ ] = this._デコードタスクを終了せよ;
432 this._デコードタスク起動完了.Set();
434 this._再生タイマ.Value.リセットする( FDK.カウンタ.QPCTimer.秒をカウントに変換して返す( 再生開始位置sec ) );
436 while( System.Threading.WaitHandle.WaitAny( events ) == EVID_キューが空いた )
438 // キューが空いてるので、サンプルを1つデコードする。
439 if( this._サンプルをひとつデコードしてフレームをキューへ格納する() )
441 // キューがいっぱいになったら、空くまで待つ。
442 if( _キューのサイズ == this._フレームキュー.Count )
444 this._キューが空いた.Reset(); // 次の while で空くのを待つ。
449 break; // エラーあるいはストリーム終了 → デコードタスクを終了する。
453 this._デコードタスク = null;
455 FDK.Log.Info( "デコードタスクを終了しました。" );
459 /// 格納できたかスキップした場合は true、エラーあるいはストリーム終了なら false。
461 private bool _サンプルをひとつデコードしてフレームをキューへ格納する()
463 var sample = (SharpDX.MediaFoundation.Sample) null;
464 var bitmap = (SharpDX.Direct2D1.Bitmap) null;
468 long サンプルの表示時刻100ns = 0;
470 #region " ソースリーダーから次のサンプルをひとつデコードする。"
472 var ストリームフラグ = SharpDX.MediaFoundation.SourceReaderFlags.None;
475 sample = this._SourceReaderEx.ReadSample(
476 SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream,
477 SharpDX.MediaFoundation.SourceReaderControlFlags.None,
480 out サンプルの表示時刻100ns );
482 if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Endofstream ) ) // BOX化コストとか気にしない
488 FDK.Log.Info( "動画をループ再生します。" );
489 this._SourceReaderEx.SetCurrentPosition( 0 );
490 return this._サンプルをひとつデコードしてフレームをキューへ格納する();
494 FDK.Log.Info( "動画の再生を終了します。" );
500 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Error ) )
504 throw new SharpDX.SharpDXException( SharpDX.Result.Fail );
508 //else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Newstream ) )
511 //else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Nativemediatypechanged ) )
514 //else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Currentmediatypechanged ) )
516 // 動画の途中でのサイズ変更には対応しない。
518 //else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.StreamTick ) )
521 //else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.AllEffectsremoved ) )
524 //---------------------------------------------------
527 //if( サンプルの表示時刻100ns < this.再生タイマ.Value.現在のリアルタイムカウント100ns単位 )
528 // return true; // もう表示時刻は通り過ぎてるのでスキップする。---> この実装だとループのし始めには常に true になってしまうので却下。
530 this._サンプルをビットマップに転送する( sample, out bitmap );
532 this._フレームキュー.Enqueue( new FrameQueueItem() {
534 表示時刻sec = サンプルの表示時刻100ns / ( 10.0 * 1000.0 * 1000.0 ),
537 bitmap = null; // キューに格納したので、ここでは Dispose しない。
541 FDK.Log.Info( $"エラーが発生したので、動画の再生を終了します。[{e.Message}]" );
553 private void _再生位置までストリームを進める( double 再生位置sec )
555 #region " ストリームがシーク不可なら何もしない。"
557 var flags = this._SourceReaderEx.GetPresentationAttribute(
558 SharpDX.MediaFoundation.SourceReaderIndex.MediaSource,
559 SharpDX.MediaFoundation.SourceReaderAttributeKeys.MediaSourceCharacteristics );
560 if( ( flags & (int) SharpDX.MediaFoundation.MediaSourceCharacteristics.CanSeek ) == 0 )
562 FDK.Log.WARNING( "この動画はシークできないようです。" );
572 long 再生位置100ns = (long) ( 再生位置sec * 1000.0 * 1000.0 * 10.0 );
573 this._SourceReaderEx.SetCurrentPosition( 再生位置100ns );
575 // キーフレームから再生位置100nsまで ReadSample する。
577 var ストリームフラグ = SharpDX.MediaFoundation.SourceReaderFlags.None;
579 long サンプルの表示時刻100ns = 0;
581 while( サンプルの表示時刻100ns < 再生位置100ns )
584 var sample = this._SourceReaderEx.ReadSample(
585 SharpDX.MediaFoundation.SourceReaderIndex.FirstVideoStream,
586 SharpDX.MediaFoundation.SourceReaderControlFlags.None,
589 out サンプルの表示時刻100ns );
594 if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Endofstream ) )
599 else if( ストリームフラグ.HasFlag( SharpDX.MediaFoundation.SourceReaderFlags.Error ) )
602 FDK.Log.ERROR( $"動画の再生位置を移動中に、エラーが発生しました。" );
609 FDK.Log.Info( $"動画の再生位置を {再生位置sec}sec へ移動しました。" );
612 private void _ストックする()
614 for( int i = 0; i < this._キューのサイズ; i++ )
615 this._サンプルをひとつデコードしてフレームをキューへ格納する();
617 this._キューが空いた.Reset(); // 埋まった
620 private unsafe void _サンプルをビットマップに転送する( SharpDX.MediaFoundation.Sample Sample, out SharpDX.Direct2D1.Bitmap D2DBitmap )
622 var buffer = (SharpDX.MediaFoundation.MediaBuffer) null;
623 var buffer2d2 = (SharpDX.MediaFoundation.Buffer2D2) null;
626 #region " サンプルからサンプルバッファ (MediaBuffer) を取得する。"
630 buffer = Sample.ConvertToContiguousBuffer();
634 Log.ERROR( $"サンプルバッファの取得に失敗しました。(0x{e.HResult:x8})" );
639 #region " サンプルバッファを Buffer2D2 にキャストする。"
643 buffer2d2 = buffer.QueryInterface<SharpDX.MediaFoundation.Buffer2D2>();
645 catch( SharpDX.SharpDXException e )
647 Log.ERROR( $"サンプルバッファから Buffer2D2 へのキャストに失敗しました。(0x{e.HResult:x8})" );
652 #region " サンプルバッファをロックする。"
654 byte[] scanLine0_bp = new byte[ 8 ]; // 「生ポインタ」が格納される。32bitなら[0~3]、64bitなら[0~7]が有効。(CPUではなく.NETに依存)
656 byte[] bufferStart_bp = new byte[ 8 ]; // 「生ポインタ」が格納される。こちらは使わない。
660 buffer2d2.Lock2DSize(
661 SharpDX.MediaFoundation.Buffer2DLockFlags.Read,
667 catch( SharpDX.SharpDXException e )
669 Log.ERROR( $"サンプルバッファのロックに失敗しました。(0x{e.HResult:x8})" );
676 #region " サンプルバッファのネイティブ先頭アドレスを取得する。"
678 byte* scanLine0 = null;
681 scanLine0 = (byte*) this._生ポインタを格納したbyte配列からポインタを取得して返す( scanLine0_bp );
683 catch( SharpDX.SharpDXException e )
685 Log.ERROR( $"サンプルバッファのアドレスの取得に失敗しました。(0x{e.HResult:x8})" );
690 #region " サンプルから WicBitmap へ画像をコピーする。"
694 // 描画先である WICBitmap をロックする。
695 using( var bitmapLock = this._WicBitmap.Lock(
696 new SharpDX.Rectangle( 0, 0, this._WicBitmap.Size.Width, this._WicBitmap.Size.Height ),
697 SharpDX.WIC.BitmapLockFlags.Write ) )
699 // サンプルバッファからWICビットマップへ、ARGB32 を G8B8R8X8 に変換しながらコピーする。
700 int bitmapStride = bitmapLock.Stride;
701 byte* src = scanLine0;
702 byte* dest = (byte*) bitmapLock.Data.DataPointer.ToPointer();
704 if( pitch != bitmapStride )
706 for( int y = 0; y < this.サイズdpx.Height; y++ )
708 // ARGB32 to G8B8R8X8 ではデータ変換が不要なので、一行を一気にコピー。
709 動画.CopyMemory( dest, src, (int) this.サイズdpx.Width * 4 ); // ARGB=4バイト。
711 dest += bitmapStride; // bitmapStride は byte 単位
716 // ARGB32 to G8B8R8X8 ではデータ変換が不要、かつ pitch と bitmapStride が等しいので、全行を一括してコピー。
717 動画.CopyMemory( dest, src, (int) ( this.サイズdpx.Width * this.サイズdpx.Height * 4 ) ); // ARGB=4バイト。
721 catch( SharpDX.SharpDXException e )
723 Log.ERROR( $"WicBitmap の Lock に失敗しました。(0x{e.HResult:x8})" );
728 Log.ERROR( $"サンプルバッファから WIC ビットマップへのデータの転送に失敗しました。(0x{e.HResult:x8})" );
733 #region " WicBitmap から D2DBitmap を生成する。"
737 D2DBitmap = SharpDX.Direct2D1.Bitmap.FromWicBitmap( this._デコードタスク用D2DDeviceContext参照, this._WicBitmap );
739 catch( SharpDX.SharpDXException e )
741 Log.ERROR( $"D2Dビットマップの作成に失敗しました。(0x{e.HResult:x8})" );
749 #region " サンプルバッファのロックを解除する。"
751 buffer2d2.Unlock2D();
758 FDK.Utilities.解放する( ref buffer2d2 );
759 FDK.Utilities.解放する( ref buffer );
763 private unsafe void* _生ポインタを格納したbyte配列からポインタを取得して返す( byte[] 生ポインタ )
765 if( ( 4 == IntPtr.Size ) && System.BitConverter.IsLittleEndian )
767 #region " (A) 32bit, リトルエンディアン "
771 for( int i = 0; i < 4; i++ )
772 生アドレス32bit += ( (int) 生ポインタ[ i ] ) << ( i * 8 );
774 return new IntPtr( 生アドレス32bit ).ToPointer();
778 else if( ( 8 == IntPtr.Size ) && System.BitConverter.IsLittleEndian )
780 #region " (B) 64bit, リトルエンディアン "
783 for( int i = 0; i < 8; i++ )
784 生アドレス64bit += ( (int) 生ポインタ[ i ] ) << ( i * 8 );
786 return new IntPtr( 生アドレス64bit ).ToPointer();
790 else if( ( 4 == IntPtr.Size ) && ( false == System.BitConverter.IsLittleEndian ) )
792 #region " (C) 32bit, ビッグエンディアン "
795 for( int i = 0; i < 4; i++ )
796 生アドレス32bit += ( (int) 生ポインタ[ 4 - i ] ) << ( i * 8 );
798 return new IntPtr( 生アドレス32bit ).ToPointer();
802 else if( ( 8 == IntPtr.Size ) && ( false == System.BitConverter.IsLittleEndian ) )
804 #region " (D) 64bit, ビッグエンディアン "
807 for( int i = 0; i < 8; i++ )
808 生アドレス64bit += ( (int) 生ポインタ[ 8 - i ] ) << ( i * 8 );
810 return new IntPtr( 生アドレス64bit ).ToPointer();
815 throw new SharpDX.SharpDXException( SharpDX.Result.NotImplemented, "この .NET アーキテクチャには対応していません。" );
818 #region " Win32 API "
820 [System.Runtime.InteropServices.DllImport( "kernel32.dll", SetLastError = true )]
821 private static extern unsafe void CopyMemory( void* dst, void* src, int size );