// 生成と終了 /// <summary> /// コンストラクタ。 /// 指定された画像ファイルと矩形リストyamlファイルを使って、フォント画像を生成する。 /// </summary> /// <param name="文字幅補正dpx">文字と文字の間の(横方向の)間隔。拡大率の影響は受けない。負数もOK。</param> /// <param name="不透明度">透明: 0 ~ 1 :不透明</param> public フォント画像(Device1 d3dDevice1, VariablePath 文字盤の画像ファイルパス, VariablePath 文字盤の矩形リストファイルパス, float 文字幅補正dpx = 0f, float 透明度 = 1f) { this._文字盤 = new 画像(d3dDevice1, 文字盤の画像ファイルパス); this._矩形リスト = new 矩形リスト(文字盤の矩形リストファイルパス); this.文字幅補正dpx = 文字幅補正dpx; this.透明度 = 透明度; }
/// <summary> /// ファイルを逆シリアル化して、DataContract オブジェクトを生成する。 /// </summary> /// <remarks> /// DataContract 属性を持つ型の逆シリアル時には、コンストラクタは呼び出されないので注意。 /// 各メンバは 0 または null になるが、それがイヤなら OnDeserializing コールバックを用意して、逆シリアル化の前に初期化すること。 /// </remarks> public static T 復元する <T>(VariablePath ファイルパス, bool UseSimpleDictionaryFormat = true) where T : class, new() { T dataContract; using (var stream = File.OpenRead(ファイルパス.数なしパス)) { // BOM (0xEF,0xBB,0xBFの3バイト)があれば飛ばす。 stream.Position = (0xEF == stream.ReadByte()) ? 3 : 0; var culture = Thread.CurrentThread.CurrentCulture; try { var serialier = new DataContractJsonSerializer(typeof(T), new DataContractJsonSerializerSettings() { UseSimpleDictionaryFormat = UseSimpleDictionaryFormat }); dataContract = (T)serialier.ReadObject(stream); } finally { Thread.CurrentThread.CurrentCulture = culture; } } return(dataContract); }
// 生成と終了 /// <summary> /// コンストラクタ。 /// 指定された画像ファイルと矩形リストファイルを使って、テクスチャフォントを生成する。 /// </summary> public テクスチャフォント(VariablePath 文字盤の画像ファイルパス, VariablePath 文字盤設定ファイルパス) { this._文字盤 = new テクスチャ(文字盤の画像ファイルパス); // 設定ファイルを読み込んで、矩形リストを生成する。 { // yaml ファイルを読み込む。 var yaml = File.ReadAllText(文字盤設定ファイルパス.数なしパス); var deserializer = new YamlDotNet.Serialization.Deserializer(); var yamlMap = deserializer.Deserialize <YAMLマップ>(yaml); // 内容から矩形リストを作成。 this._文字盤の矩形リスト = new Dictionary <string, RectangleF>(); foreach (var kvp in yamlMap.矩形リスト) { if (4 == kvp.Value.Length) { this._文字盤の矩形リスト[kvp.Key] = new RectangleF(kvp.Value[0], kvp.Value[1], kvp.Value[2], kvp.Value[3]); } else { Log.ERROR($"矩形リストの書式が不正です。[{文字盤設定ファイルパス.変数付きパス}]"); } } } }
// 生成と終了 /// <summary> /// 指定した画像ファイルからテクスチャを作成する。 /// </summary> public テクスチャ(VariablePath 画像ファイルパス, BindFlags bindFlags = BindFlags.ShaderResource) { this._画像ファイルパス = 画像ファイルパス; this.ユーザ指定サイズ = Size2F.Zero; this._bindFlags = bindFlags; this._定数バッファ = this._定数バッファを作成する(); // テクスチャとシェーダーリソースビューを生成する。 if (this._画像ファイルパス.数なしパス.Nullでも空でもない()) { if (!System.IO.File.Exists(this._画像ファイルパス.数なしパス)) { Log.ERROR($"画像ファイルが存在しません。[{this._画像ファイルパス.変数付きパス}]"); return; } var テクスチャリソース = FDKUtilities.CreateShaderResourceViewFromFile( DXResources.Instance.D3D11Device1, this._bindFlags, this._画像ファイルパス); this._ShaderResourceView = テクスチャリソース.srv; this.サイズ = テクスチャリソース.viewSize; this.Texture = テクスチャリソース.texture; } }
// シリアライズ /// <summary> /// DataContract オブジェクトをシリアル化してファイルに保存する。 /// </summary> public static void 保存する(object 保存するオブジェクト, VariablePath ファイルパス, bool UseSimpleDictionaryFormat = true) { using (var stream = File.Open(ファイルパス.数なしパス, FileMode.Create)) { var culture = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; using (var writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, true, true)) { var serializer = new DataContractJsonSerializer(保存するオブジェクト.GetType(), new DataContractJsonSerializerSettings() { UseSimpleDictionaryFormat = UseSimpleDictionaryFormat }); serializer.WriteObject(writer, 保存するオブジェクト); writer.Flush(); } } finally { Thread.CurrentThread.CurrentCulture = culture; } } }
// 生成と終了 public 画像フォント(VariablePath 文字盤の画像ファイルパス, VariablePath 文字盤設定ファイルパス, float 文字幅補正dpx = 0f, float 透明度 = 1f) { this.文字幅補正dpx = 文字幅補正dpx; this.透明度 = 透明度; // 文字盤を生成する。 this._文字盤 = new 画像(文字盤の画像ファイルパス); // 設定ファイルを読み込んで、矩形リストを生成する。 { // yaml ファイルを読み込む。 var yaml = File.ReadAllText(文字盤設定ファイルパス.数なしパス); var deserializer = new YamlDotNet.Serialization.Deserializer(); var yamlMap = deserializer.Deserialize <YAMLマップ>(yaml); // 内容から矩形リストを作成。 this._矩形リスト = new Dictionary <string, RectangleF>(); foreach (var kvp in yamlMap.矩形リスト) { if (4 == kvp.Value.Length) { this._矩形リスト[kvp.Key] = new RectangleF(kvp.Value[0], kvp.Value[1], kvp.Value[2], kvp.Value[3]); } } } }
/// <summary> /// 指定した画像ファイルからテクスチャを作成する。 /// </summary> public テクスチャ(VariablePath 画像ファイルパス, BindFlags bindFlags = BindFlags.ShaderResource) { this._bindFlags = bindFlags; // ↓ どちらかを選択的に指定すること。 this._画像ファイルパス = 画像ファイルパス; // 選択 this.ユーザ指定サイズ = Size2F.Zero; // 非選択 }
public static void インスタンスをシリアライズしてファイルに保存する <T>(VariablePath XMLファイルパス, T target) { using (var sw = new StreamWriter( new FileStream(XMLファイルパス.数なしパス, FileMode.Create, FileAccess.Write, FileShare.ReadWrite), Encoding.UTF8)) { new XmlSerializer(typeof(T)).Serialize(sw, target); } }
/// <summary> /// コンストラクタ。 /// 指定されたファイルを指定されたフォーマットでデコードし、内部にオンメモリで保管する。 /// </summary> public MediaFoundationOnMemoryWaveSource(VariablePath ファイルパス, CSCore.WaveFormat deviceFormat) : base(ファイルパス, deviceFormat) { // 読み込み&デコード完了まで待機。 if (!(this._デコードタスク.Wait(60 * 1000))) { throw new TimeoutException($"デコードタスクがタイムアウトしました。[{ファイルパス.変数付きパス}]"); } }
// 生成と終了 public 画像(VariablePath 画像ファイルパス) { this.画像ファイルパス = 画像ファイルパス; if (画像ファイルパス?.数なしパス.Nullでも空でもない() ?? false) { this._Bitmapを生成する(this.画像ファイルパス); } }
public static T?ファイルをデシリアライズしてインスタンスを生成する <T>(VariablePath XMLファイル名) { using (var sr = new StreamReader( new FileStream(XMLファイル名.数なしパス, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Encoding.UTF8)) { return((T) new XmlSerializer(typeof(T)).Deserialize(sr)); } }
public void Open(VariablePath DBファイルパス) { // DBへ接続し、開く。(DBファイルが存在しない場合は自動的に生成される。) var db接続文字列 = new SqliteConnectionStringBuilder() { DataSource = DBファイルパス.数なしパス }.ToString(); this.Connection = new SqliteConnection(db接続文字列); this.Connection.Open(); }
// 生成と終了 public 描画可能画像(VariablePath 画像ファイルパス) : base(画像ファイルパス) { // 画像ファイルから生成する。 if (画像ファイルパス?.数なしパス.Nullでも空でもない() ?? false) { this._Bitmapを生成する( 画像ファイルパス, new BitmapProperties1 { BitmapOptions = BitmapOptions.Target, }); } }
public Video(VariablePath ファイルパス) { try { this._VideoSource = new MediaFoundationFileVideoSource(ファイルパス); } catch { Log.WARNING($"動画のデコードに失敗しました。[{ファイルパス.変数付きパス}"); this._VideoSource = null; return; } this._ファイルから生成した = true; }
/// <summary> /// コンストラクタ。 /// 指定された画像ファイルと矩形リストファイルを使って、テクスチャフォントを生成する。 /// </summary> public テクスチャフォント(VariablePath 文字盤の画像ファイルパス, VariablePath 文字盤設定ファイルパス) { this.子Activityを追加する(this._文字盤 = new テクスチャ(文字盤の画像ファイルパス)); var yaml = File.ReadAllText(文字盤設定ファイルパス.数なしパス); var deserializer = new YamlDotNet.Serialization.Deserializer(); var yamlMap = deserializer.Deserialize <YAMLマップ>(yaml); this._文字盤の矩形リスト = new Dictionary <string, RectangleF>(); foreach (var kvp in yamlMap.矩形リスト) { if (4 == kvp.Value.Length) { this._文字盤の矩形リスト[kvp.Key] = new RectangleF(kvp.Value[0], kvp.Value[1], kvp.Value[2], kvp.Value[3]); } } }
// グラフィック /// <summary> /// 画像ファイルからシェーダリソースビューを作成して返す。 /// </summary> /// <remarks> /// (参考: http://qiita.com/oguna/items/c516e09ee57d931892b6 ) /// </remarks> public static (SharpDX.Direct3D11.ShaderResourceView srv, Size2F viewSize, SharpDX.Direct3D11.Texture2D texture) CreateShaderResourceViewFromFile( SharpDX.Direct3D11.Device d3dDevice, SharpDX.Direct3D11.BindFlags bindFlags, VariablePath 画像ファイルパス) { var 出力 = ( srv : (SharpDX.Direct3D11.ShaderResourceView)null, viewSize : new Size2F(0, 0), texture : (SharpDX.Direct3D11.Texture2D)null); using (var image = new System.Drawing.Bitmap(画像ファイルパス.数なしパス)) { var 画像の矩形 = new System.Drawing.Rectangle(0, 0, image.Width, image.Height); using (var bitmap = image.Clone(画像の矩形, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { var ロック領域 = bitmap.LockBits(画像の矩形, System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat); var dataBox = new[] { new DataBox(ロック領域.Scan0, bitmap.Width * 4, bitmap.Height) }; var textureDesc = new SharpDX.Direct3D11.Texture2DDescription() { ArraySize = 1, BindFlags = bindFlags, CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None, Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm, Height = bitmap.Height, Width = bitmap.Width, MipLevels = 1, OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None, SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0), Usage = SharpDX.Direct3D11.ResourceUsage.Default }; var texture = new SharpDX.Direct3D11.Texture2D(d3dDevice, textureDesc, dataBox); bitmap.UnlockBits(ロック領域); 出力.srv = new SharpDX.Direct3D11.ShaderResourceView(d3dDevice, texture); 出力.texture = texture; } 出力.viewSize = new Size2F(画像の矩形.Width, 画像の矩形.Height); } return(出力); }
public void 矩形リストをyamlファイルから読み込む(VariablePath yamlファイルパス) { // yaml ファイルを読み込む。 var yamlText = File.ReadAllText(yamlファイルパス.数なしパス); var deserializer = new YamlDotNet.Serialization.Deserializer(); var yaml = deserializer.Deserialize <YAMLマップ>(yamlText); // 内容から矩形リストを作成。 foreach (var kvp in yaml.RectangleList) { if (4 == kvp.Value.Length) { this.文字列to矩形[kvp.Key] = new RectangleF(kvp.Value[0], kvp.Value[1], kvp.Value[2], kvp.Value[3]); } else { Log.ERROR($"矩形リストの書式が不正です。[{yamlファイルパス.変数付きパス}]"); } } }
// 生成と終了 /// <summary> /// 指定した画像ファイルから画像を作成する。 /// </summary> public 画像(Device1 d3dDevice1, VariablePath 画像ファイルパス, BindFlags bindFlags = BindFlags.ShaderResource) { //using var _ = new LogBlock( Log.現在のメソッド名 ); #region " 条件チェック " //---------------- if (string.IsNullOrEmpty(画像ファイルパス.数なしパス)) { Log.ERROR($"画像ファイルパスの指定がありません。"); return; } if (!File.Exists(画像ファイルパス.数なしパス)) { Log.ERROR($"画像ファイルが存在しません。[{画像ファイルパス.変数付きパス}]"); return; } //---------------- #endregion this._画像ファイルからシェーダリソースビューを作成して返す(d3dDevice1, bindFlags, 画像ファイルパス); }
public static MediaFoundationStreamingSources CreateFromFile(VariablePath ファイルパス, WaveFormat soundDeviceFormat) { var sources = new MediaFoundationStreamingSources(); #region " ファイルから SourceReaderEx を生成する。" //---------------- using (var ビデオ属性 = new MediaAttributes()) { // DXVAに対応しているGPUの場合には、それをデコードに利用するよう指定する。 ビデオ属性.Set(SourceReaderAttributeKeys.D3DManager, グラフィックデバイス.Instance.DXGIDeviceManager); // 追加のビデオプロセッシングを有効にする。 ビデオ属性.Set(SourceReaderAttributeKeys.EnableAdvancedVideoProcessing, true); // 真偽値が bool だったり // 追加のビデオプロセッシングを有効にしたら、こちらは無効に。 ビデオ属性.Set(SinkWriterAttributeKeys.ReadwriteDisableConverters, 0); // int だったり // 属性を使って、SourceReaderEx を生成。 using (var sourceReader = new SourceReader(ファイルパス.数なしパス, ビデオ属性)) // パスは URI 扱い sources._SourceReaderEx = sourceReader.QueryInterface <SourceReaderEx>(); } //---------------- #endregion #region " WaveFormat を生成。" //---------------- sources._Audioのフォーマット = new WaveFormat( soundDeviceFormat.SampleRate, 32, soundDeviceFormat.Channels, AudioEncoding.IeeeFloat); //---------------- #endregion sources._SourceReaderEx生成後の初期化(); return(sources); }
/// <summary> /// 指定されたフォルダ内に配置可能な、新しいログファイル名を生成して返す。 /// </summary> /// <param name="ログフォルダパス">ログファイルを配置するフォルダのパス。</param> /// <param name="ログファイルの接頭辞">ログファイル名に付与する接頭辞。</param> /// <param name="最大保存期間">フォルダ内に保存しておく最大の期間。</param> /// <returns>生成されたログファイル名。パス付き。</returns> /// <remarks> /// ログファイル名は、現在時刻をベースに名付けられる。 /// 同時に、フォルダ内に存在するすべてのファイルの更新時刻をチェックし、最大保存期間を超える古いファイルは、自動的に削除する。 /// </remarks> public static string ログファイル名を生成する(VariablePath ログフォルダパス, string ログファイルの接頭辞, TimeSpan 最大保存期間) { var 現在の日時 = DateTime.Now; if (Directory.Exists(ログフォルダパス.数なしパス)) { // (A) フォルダがある場合 → 最大保存期間を超える古いファイルを削除する。 var 削除対象ファイルs = Directory.GetFiles(ログフォルダパス.数なしパス).Where( (file) => (File.GetLastWriteTime(file) < (現在の日時 - 最大保存期間))); foreach (var path in 削除対象ファイルs) { File.Delete(path); } } else { // (B) フォルダがない場合 → 作成する。 Directory.CreateDirectory(ログフォルダパス.数なしパス); } // 現在の時刻をもとに、新しいログファイル名を生成して返す。 return(Path.Combine(ログフォルダパス.数なしパス, $"{ログファイルの接頭辞}{現在の日時.ToString( "yyyyMMdd-HHmmssffff" )}.txt")); }
/// <summary> /// 指定されたファイルの音声をデコードし、<see cref="ISampleSource"/> オブジェクトを返す。 /// 失敗すれば null 。 /// </summary> public static ISampleSource?Create(SoundDevice device, VariablePath path, double 再生速度 = 1.0) { if (!(File.Exists(path.数なしパス))) { Log.ERROR($"ファイルが存在しません。[{path.変数付きパス}]"); return(null); } var 拡張子 = Path.GetExtension(path.数なしパス).ToLower(); if (".ogg" == 拡張子) { #region " OggVorvis " //---------------- try { // ファイルを読み込んで IWaveSource を生成。 using var audioStream = new FileStream(path.数なしパス, FileMode.Open, FileAccess.Read); using var waveSource = new NVorbisOnStreamingSampleSource(audioStream, device.WaveFormat).ToWaveSource(); // IWaveSource をリサンプルして ISampleSource を生成。 return(new ResampledOnMemoryWaveSource(waveSource, device.WaveFormat, 再生速度).ToSampleSource()); } catch { // ダメだったので次へ。 } //---------------- #endregion } if (".wav" == 拡張子) { #region " WAV " //---------------- try { // ファイルを読み込んで IWaveSource を生成。 using var waveSource = new WavOnStreamingWaveSource(path, device.WaveFormat); if (waveSource.WaveFormat.WaveFormatTag == AudioEncoding.Pcm) // ここでは PCM WAV のみサポート { // IWaveSource をリサンプルして ISampleSource を生成。 return(new ResampledOnMemoryWaveSource(waveSource, device.WaveFormat, 再生速度).ToSampleSource()); } // PCM WAV 以外は次へ。 } catch { // ダメだったので次へ。 } //---------------- #endregion } if (".xa" == 拡張子) { #region " XA " //---------------- try { // ファイルを読み込んで IWaveSource を生成。 using var waveSource = new XAOnMemoryWaveSource(path, device.WaveFormat); // IWaveSource をリサンプルして ISampleSource を生成。 return(new ResampledOnMemoryWaveSource(waveSource, device.WaveFormat, 再生速度).ToSampleSource()); } catch { // ダメだったので次へ。 } //---------------- #endregion } #region " 全部ダメだったら MediaFoundation で試みる。" //---------------- try { // ファイルを読み込んで IWaveSource を生成。 using var waveSource = new MediaFoundationOnMemoryWaveSource(path, device.WaveFormat); // デコード完了まで待機。 if (!waveSource.DecodeComplete.Wait(60_1000)) // 最大1分 { throw new TimeoutException($"デコードタスクがタイムアウトしました。[{path.変数付きパス}]"); } // IWaveSource をリサンプルして ISampleSource を生成。 return(new ResampledOnMemoryWaveSource(waveSource, device.WaveFormat, 再生速度).ToSampleSource()); } catch { // ダメだった } //---------------- #endregion Log.ERROR($"未対応のオーディオファイルです。{path.変数付きパス}"); return(null); }
public 描画可能テクスチャ(VariablePath 画像ファイルパス) : base(画像ファイルパス, BindFlags.RenderTarget | BindFlags.ShaderResource) { }
public MediaFoundationFileVideoSource(VariablePath ファイルパス, double 再生速度 = 1.0) { this.再生速度 = Math.Max(0.01, Math.Min(10.0, 再生速度)); #region " フレームキューを生成。" //---------------- // キューサイズは3フレームとする。 this._FrameQueue = new BlockingQueue <VideoFrame>(3); //---------------- #endregion #region " ファイルから SourceReaderEx を生成する。" //---------------- using (var ビデオ属性 = new MediaAttributes()) { // DXVAに対応しているGPUの場合には、それをデコードに利用するよう指定する。 ビデオ属性.Set(SourceReaderAttributeKeys.D3DManager, グラフィックデバイス.Instance.DXGIDeviceManager); // 追加のビデオプロセッシングを有効にする。 ビデオ属性.Set(SourceReaderAttributeKeys.EnableAdvancedVideoProcessing, true); // 真偽値が bool だったり // 追加のビデオプロセッシングを有効にしたら、こちらは無効に。 ビデオ属性.Set(SinkWriterAttributeKeys.ReadwriteDisableConverters, 0); // int だったり // 属性を使って、SourceReaderEx を生成。 using (var sourceReader = new SourceReader(ファイルパス.数なしパス, ビデオ属性)) // パスは URI 扱い this._SourceReaderEx = sourceReader.QueryInterface <SourceReaderEx>(); } // 最初のビデオストリームだけを選択。 this._SourceReaderEx.SetStreamSelection(SourceReaderIndex.AllStreams, false); this._SourceReaderEx.SetStreamSelection(SourceReaderIndex.FirstVideoStream, true); //---------------- #endregion #region " ビデオの長さを取得する。" //---------------- this.総演奏時間sec = FDKUtilities.換_100ns単位からsec単位へ( this._SourceReaderEx.GetPresentationAttribute(SourceReaderIndex.MediaSource, PresentationDescriptionAttributeKeys.Duration)) / this.再生速度; //---------------- #endregion #region " デコーダを選択し、完全メディアタイプを取得する。" //---------------- // 部分メディアタイプを設定する。 using (var videoMediaType = new MediaType()) { // フォーマットは ARGB32 で固定とする。(SourceReaderEx を使わない場合、H264 では ARGB32 が選べないので注意。) videoMediaType.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Video); videoMediaType.Set(MediaTypeAttributeKeys.Subtype, VideoFormatGuids.Argb32); // 部分メディアタイプを SourceReaderEx にセットする。SourceReaderEx は、必要なデコーダをロードするだろう。 this._SourceReaderEx.SetCurrentMediaType(SourceReaderIndex.FirstVideoStream, videoMediaType); } // 完成されたメディアタイプを取得する。 this._MediaType = this._SourceReaderEx.GetCurrentMediaType(SourceReaderIndex.FirstVideoStream); //---------------- #endregion #region " ビデオのフレームサイズを取得する。" //---------------- long packedFrameSize = this._MediaType.Get(MediaTypeAttributeKeys.FrameSize); // 動画の途中でのサイズ変更には対応しない。 this.フレームサイズ = new Size2F((packedFrameSize >> 32) & 0xFFFFFFFF, (packedFrameSize) & 0xFFFFFFFF); //---------------- #endregion }
public SQLiteDB(VariablePath DBファイルパス) { this.Open(DBファイルパス); }
protected void Bitmapを生成する(ImagingFactory2 imagingFactory2, DeviceContext d2dDeviceContext, VariablePath 画像ファイルパス, BitmapProperties1?bitmapProperties1 = null) { var decoder = (BitmapDecoder?)null; var sourceFrame = (BitmapFrameDecode?)null; var converter = (FormatConverter?)null; try { // 以下、生成に失敗しても例外は発生しない。ただ描画メソッドで表示されなくなるだけ。 #region " 事前チェック。" //----------------- if (string.IsNullOrEmpty(画像ファイルパス.数なしパス)) { Log.ERROR($"画像ファイルパスが null または空文字列です。[{画像ファイルパス.変数付きパス}]"); return; } if (!File.Exists(画像ファイルパス.数なしパス)) { Log.ERROR($"画像ファイルが存在しません。[{画像ファイルパス.変数付きパス}]"); return; } //----------------- #endregion #region " 画像ファイルに対応できるデコーダを見つける。" //----------------- try { decoder = new BitmapDecoder( imagingFactory2, 画像ファイルパス.数なしパス, NativeFileAccess.Read, DecodeOptions.CacheOnLoad); } catch (SharpDXException e) { Log.ERROR($"画像ファイルに対応するコーデックが見つかりません。(0x{e.HResult:x8})[{画像ファイルパス.変数付きパス}]"); return; } //----------------- #endregion #region " 最初のフレームをデコードし、取得する。" //----------------- try { sourceFrame = decoder.GetFrame(0); } catch (SharpDXException e) { Log.ERROR($"画像ファイルの最初のフレームのデコードに失敗しました。(0x{e.HResult:x8})[{画像ファイルパス.変数付きパス}]"); return; } //----------------- #endregion #region " 32bitPBGRA へのフォーマットコンバータを生成する。" //----------------- try { // WICイメージングファクトリから新しいコンバータを生成。 converter = new FormatConverter(imagingFactory2); // コンバータに変換元フレームや変換後フォーマットなどを設定。 converter.Initialize( sourceRef: sourceFrame, dstFormat: SharpDX.WIC.PixelFormat.Format32bppPBGRA, // Premultiplied BGRA dither: BitmapDitherType.None, paletteRef: null, alphaThresholdPercent: 0.0, paletteTranslate: BitmapPaletteType.MedianCut); } catch (SharpDXException e) { Log.ERROR($"32bitPBGRA へのフォーマットコンバータの生成または初期化に失敗しました。(0x{e.HResult:x8})[{画像ファイルパス.変数付きパス}]"); return; } //----------------- #endregion #region " コンバータを使って、フレームを WICビットマップ経由で D2D ビットマップに変換する。" //----------------- try { // WIC ビットマップを D2D ビットマップに変換する。 this.Bitmap?.Dispose(); this.Bitmap = bitmapProperties1 switch { null => Bitmap1.FromWicBitmap(d2dDeviceContext, converter), _ => Bitmap1.FromWicBitmap(d2dDeviceContext, converter, bitmapProperties1), }; } catch (SharpDXException e) { Log.ERROR($"Direct2D1.Bitmap1 への変換に失敗しました。(0x{e.HResult:x8})[{画像ファイルパス.変数付きパス}]"); return; } //----------------- #endregion this.サイズ = new Size2F(this.Bitmap.PixelSize.Width, this.Bitmap.PixelSize.Height); } finally { converter?.Dispose(); sourceFrame?.Dispose(); decoder?.Dispose(); } }
public Video(DXGIDeviceManager deviceManager, DeviceContext d2dDeviceContext, VariablePath ファイルパス, double 再生速度 = 1.0) : this() { using var _ = new LogBlock(Log.現在のメソッド名); this.再生速度 = 再生速度; try { this._VideoSource = new MediaFoundationFileVideoSource(deviceManager, d2dDeviceContext, ファイルパス, 再生速度); } catch { Log.WARNING($"動画のデコードに失敗しました。[{ファイルパス.変数付きパス}"); this._VideoSource = null; return; } this._ファイルから生成した = true; }
public 画像(VariablePath 画像ファイルパス) { this._画像ファイルパス = 画像ファイルパス; }
/// <summary> /// コンストラクタ。 /// 指定されたファイルを指定されたフォーマットでデコードし、内部にオンメモリで保管する。 /// </summary> public MediaFoundationOnMemoryWaveSource(VariablePath ファイルパス, CSCore.WaveFormat deviceFormat) : base(ファイルパス, deviceFormat) { }
/// <summary> /// 指定されたファイルに対応するデータを(未生成なら)生成し、返す。 /// 生成に失敗したら null。 /// </summary> public T?作成する(VariablePath ファイルパス) { try { if (!File.Exists(ファイルパス.数なしパス)) { Log.ERROR($"ファイルが存在しません。[{ファイルパス.変数付きパス}]"); return(null); // 失敗 } var fileInfo = new FileInfo(ファイルパス.数なしパス); if (this._キャッシュデータリスト.TryGetValue(ファイルパス.数なしパス, out var キャッシュ情報)) // キャッシュにある { if (キャッシュ情報.ファイルの最終更新日時 == fileInfo.LastWriteTime) // ファイルは更新されていない { #region " (A) データがキャッシュに存在していて、ファイルも更新されていない場合 → それを貸与する " //---------------- キャッシュ情報.最終貸与世代 = this.現世代; // 更新 return(キャッシュ情報.生成データ); //---------------- #endregion } else { #region " (B) データがキャッシュに存在しているが、ファイルが更新されている場合 → 再作成して貸与する " //---------------- (キャッシュ情報.生成データ as IDisposable)?.Dispose(); キャッシュ情報.生成データ = this.ファイルからデータを生成する?.Invoke(ファイルパス); if (キャッシュ情報.生成データ is null) { this._キャッシュデータリスト.Remove(ファイルパス.数なしパス); return(null); // 失敗 } キャッシュ情報.ファイルの最終更新日時 = fileInfo.LastWriteTime; キャッシュ情報.最終貸与世代 = 現世代; return(キャッシュ情報.生成データ); //---------------- #endregion } } else { #region " (C) データがキャッシュに存在しない場合 → 新規作成して貸与する " //---------------- var 生成データ = this.ファイルからデータを生成する?.Invoke(ファイルパス); if (生成データ is null) { return(null); // 失敗 } this._キャッシュデータリスト.Add( // キャッシュに追加 ファイルパス.数なしパス, new キャッシュ情報 <T>() { ファイルパス = ファイルパス, ファイルの最終更新日時 = fileInfo.LastWriteTime, 生成データ = 生成データ, 最終貸与世代 = this.現世代, }); return(生成データ); //---------------- #endregion } } catch { return(null); // 例外発生 } }
// 生成と終了 public MediaFoundationFileVideoSource(DXGIDeviceManager deviceManager, DeviceContext d2dDeviceContext, VariablePath ファイルパス, double 再生速度 = 1.0) { using var _ = new LogBlock(Log.現在のメソッド名); this._D2DDeviceContext = d2dDeviceContext; this.再生速度 = Math.Clamp(再生速度, min: 0.01, max: 10.0); #region " フレームキューを生成。" //---------------- // キューサイズは3フレームとする。 this._FrameQueue = new BlockingQueue <VideoFrame>(3); //---------------- #endregion #region " ファイルから SourceReaderEx を生成する。" //---------------- using (var ビデオ属性 = new MediaAttributes()) { // DXVAに対応しているGPUの場合には、それをデコードに利用するよう指定する。 ビデオ属性.Set(SourceReaderAttributeKeys.D3DManager, deviceManager); // 追加のビデオプロセッシングを有効にする。 ビデオ属性.Set(SourceReaderAttributeKeys.EnableAdvancedVideoProcessing, true); // 真偽値が bool だったり // 追加のビデオプロセッシングを有効にしたら、こちらは無効に。 ビデオ属性.Set(SinkWriterAttributeKeys.ReadwriteDisableConverters, 0); // int だったり // 属性を使って、SourceReaderEx を生成。 using var sourceReader = new SourceReader(ファイルパス.数なしパス, ビデオ属性); // パスは URI 扱い this._SourceReaderEx = sourceReader.QueryInterface <SourceReaderEx>(); } // 最初のビデオストリームだけを選択。 this._SourceReaderEx.SetStreamSelection(SourceReaderIndex.AllStreams, false); this._SourceReaderEx.SetStreamSelection(SourceReaderIndex.FirstVideoStream, true); //---------------- #endregion #region " ビデオの長さ(総演奏時間)を取得する。" //---------------- { var mediaSourceDuration = this._SourceReaderEx.GetPresentationAttribute(SourceReaderIndex.MediaSource, PresentationDescriptionAttributeKeys.Duration); this.総演奏時間sec = (long)(mediaSourceDuration / this.再生速度 / 10_000_000.0); } //---------------- #endregion #region " デコーダを選択し、完全メディアタイプを取得する。" //---------------- // 部分メディアタイプを設定する。 using (var 部分MediaType = new MediaType()) { // フォーマットは ARGB32 で固定とする。(SourceReaderEx を使わない場合、H264 では ARGB32 が選べないので注意。) 部分MediaType.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Video); 部分MediaType.Set(MediaTypeAttributeKeys.Subtype, VideoFormatGuids.Argb32); // 部分メディアタイプを SourceReaderEx にセットする。SourceReaderEx は、必要なデコーダをロードするだろう。 this._SourceReaderEx.SetCurrentMediaType(SourceReaderIndex.FirstVideoStream, 部分MediaType); } // 完成されたメディアタイプを取得する。 this._MediaType = this._SourceReaderEx.GetCurrentMediaType(SourceReaderIndex.FirstVideoStream); //---------------- #endregion #region " ビデオのフレームサイズを取得する。(動画の途中でのサイズ変更は考慮しない。)" //---------------- long packedFrameSize = this._MediaType.Get(MediaTypeAttributeKeys.FrameSize); this.フレームサイズ = new Size2F((packedFrameSize >> 32) & 0xFFFFFFFF, (packedFrameSize) & 0xFFFFFFFF); //---------------- #endregion this._デコードキャンセル = new CancellationTokenSource(); this._デコード起動完了通知 = new ManualResetEventSlim(false); this._一時停止解除通知 = new ManualResetEventSlim(true); }