Ejemplo n.º 1
0
        /// <summary>
        ///     指定したサイズの、空のテクスチャを作成する。
        /// </summary>
        public テクスチャ(Size2F サイズ, BindFlags bindFlags = BindFlags.ShaderResource)
        {
            this._画像ファイルパス = null;
            this.ユーザ指定サイズ  = サイズ;

            this._bindFlags = bindFlags;
            this._定数バッファ    = this._定数バッファを作成する();

            // テクスチャとシェーダーリソースビューを生成する。

            if ((0f >= this.ユーザ指定サイズ.Width) && (0f >= this.ユーザ指定サイズ.Height))
            {
                Log.ERROR($"テクスチャサイズが不正です。[{this.ユーザ指定サイズ}]");
                return;
            }

            var テクスチャリソース = FDKUtilities.CreateShaderResourceView(
                DXResources.Instance.D3D11Device1,
                this._bindFlags,
                new Size2((int)this.ユーザ指定サイズ.Width, (int)this.ユーザ指定サイズ.Height));

            this._ShaderResourceView = テクスチャリソース.srv;
            this.サイズ     = this.ユーザ指定サイズ;
            this.Texture = テクスチャリソース.texture;
        }
Ejemplo n.º 2
0
        public void 描画する(DeviceContext dc, Matrix3x2 換行列2D, float 透明度0to1 = 1.0f)
        {
            if (null == this._VideoSource)
            {
                return;
            }

            long 次のフレームの表示予定時刻100ns = this._VideoSource.Peek(); // 次のフレームがなければ負数

            if (0 <= 次のフレームの表示予定時刻100ns)
            {
                if ((null != this._最後に描画したフレーム) && (次のフレームの表示予定時刻100ns < this._最後に描画したフレーム.表示時刻100ns))
                {
                    // (A) 次のフレームが前のフレームより過去 → ループしたので、タイマをリセットしてから描画する。
                    this._再生タイマ.リセットする(QPCTimer.秒をカウントに変換して返す(FDKUtilities.換_100ns単位からsec単位へ(次のフレームの表示予定時刻100ns)));
                    this._次のフレームを読み込んで描画する(dc, 換行列2D, 透明度0to1);
                }
                else if (次のフレームの表示予定時刻100ns <= this._再生タイマ.現在のリアルタイムカウント100ns)
                {
                    // (B) 次のフレームの表示時刻に達したので描画する。
                    this._次のフレームを読み込んで描画する(dc, 換行列2D, 透明度0to1);
                }
                else
                {
                    // (C) 次のフレームの表示時刻にはまだ達していない → 最後に描画したフレームを再描画しておく
                    this.最後のフレームを再描画する(dc, 換行列2D, 透明度0to1);
                }
            }
            else
            {
                // (D) デコードが追い付いてない、またはループせず再生が終わっている → 何も表示しない。デコードが追い付いてないなら点滅するだろう。
                this._最後に描画したフレーム?.Dispose();
                this._最後に描画したフレーム = null;
            }
        }
Ejemplo n.º 3
0
        // 生成と終了


        /// <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;
            }
        }
Ejemplo n.º 4
0
        protected override void On活性化()
        {
            var d3dDevice = グラフィックデバイス.Instance.D3DDevice;

            Debug.Assert(null != d3dDevice, "D3DDevice が取得されていません。");

            #region " 定数バッファを生成する。"
            //----------------
            var cBufferDesc = new BufferDescription()
            {
                Usage               = ResourceUsage.Dynamic,                        // 動的使用法
                BindFlags           = BindFlags.ConstantBuffer,                     // 定数バッファ
                CpuAccessFlags      = CpuAccessFlags.Write,                         // CPUから書き込む
                OptionFlags         = ResourceOptionFlags.None,
                SizeInBytes         = SharpDX.Utilities.SizeOf <ST定数バッファの転送元データ>(), // バッファサイズ
                StructureByteStride = 0,
            };
            this._ConstantBuffer = new SharpDX.Direct3D11.Buffer(d3dDevice, cBufferDesc);
            //----------------
            #endregion

            #region " テクスチャとシェーダーリソースビューを生成する。"
            //----------------
            if (this._画像ファイルパス?.数なしパス.Nullでも空でもない() ?? false)
            {
                // (A) 画像ファイルから生成する場合。
                if (false == System.IO.File.Exists(this._画像ファイルパス.数なしパス))
                {
                    Log.ERROR($"画像ファイルが存在しません。[{this._画像ファイルパス.変数付きパス}]");
                    return;
                }
                var 戻り値 = FDKUtilities.CreateShaderResourceViewFromFile(
                    d3dDevice,
                    this._bindFlags,
                    this._画像ファイルパス);
                this._ShaderResourceView = 戻り値.srv;
                this.サイズ     = 戻り値.viewSize;
                this.Texture = 戻り値.texture;
            }
            else if ((0f < this.ユーザ指定サイズ.Width) && (0f < this.ユーザ指定サイズ.Height))
            {
                // (B) サイズを指定して空のテクスチャを生成する場合。
                var 戻り値 = FDKUtilities.CreateShaderResourceView(
                    d3dDevice,
                    this._bindFlags,
                    new Size2((int)this.ユーザ指定サイズ.Width, (int)this.ユーザ指定サイズ.Height));
                this._ShaderResourceView = 戻り値.srv;
                this.Texture             = 戻り値.texture;

                this.サイズ = this.ユーザ指定サイズ;
            }
            else
            {
                throw new InvalidOperationException();
            }
            //----------------
            #endregion
        }
Ejemplo n.º 5
0
        public static int 最小公倍数を返す(int m, int n)
        {
            if ((0 >= m) || (0 >= n))
            {
                throw new Exception("引数に0以下の数は指定できません。");
            }

            return(m * n / FDKUtilities.最大公約数を返す(m, n));
        }
Ejemplo n.º 6
0
        public static (int 分子, int 分母) 約分する(int 分子, int 分母)
        {
            if (0 == 分子)
            {
                return(0, 1);
            }

            int 最大公約数 = 1;

            while (1 != (最大公約数 = FDKUtilities.最大公約数を返す(分子, 分母)))
            {
                分子 /= 最大公約数;
                分母 /= 最大公約数;
            }

            return(分子, 分母);
        }
Ejemplo n.º 7
0
        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
        }
Ejemplo n.º 8
0
        private void _デコードタスクエントリ(object obj引数)
        {
            Log.現在のスレッドに名前をつける("ビデオデコード");


            var 引数 = ((double 再生開始時刻sec, double 再生速度))obj引数;

            double 再生速度      = Math.Max(0.01, Math.Min(10.0, 引数.再生速度));
            double 再生開始時刻sec = Math.Max(0.0, 引数.再生開始時刻sec) / 再生速度;

            long 再生開始時刻100ns = FDKUtilities.換_sec単位から100ns単位へ(再生開始時刻sec);


            #region " 再生開始時刻までシーク(1)。"
            //----------------
            if (0.0 < 再生開始時刻sec)
            {
                if (this.総演奏時間sec <= 再生開始時刻sec)
                {
                    Log.Info($"再生開始時刻が総演奏時間を超えています。タスクを終了します。");
                    return;
                }

                // 再生開始時刻 が 0 なら、これを呼び出さないこと(ガタつきの原因になるため)。
                this._SourceReaderEx.SetCurrentPosition(再生開始時刻100ns);
            }
            //----------------
            #endregion

            // シーク(1)では、SetCurrentPosition() の仕様により、「指定された位置を超えない一番近いキーフレーム」までしか移動できない。
            // なので、残りのシーク(キーフレームから再生開始時刻まで)を、メインループ内で引き続き行う。
            // (残りのシークが終わって、ようやく デコード起動完了通知 がセットされる。)

            bool シーク中である = (0.0 < 再生開始時刻sec);

            if (!シーク中である)
            {
                this._デコード起動完了通知.Set(); // シークはしない
            }
            // メインループ。

            while (true)
            {
                if (this._デコードキャンセル.Token.IsCancellationRequested)
                {
                    Log.Info($"キャンセル通知を受信しました。");
                    break;
                }


                if (!this._サンプルをひとつデコードしてフレームをキューへ格納する(再生速度))
                {
                    break;  // エラーまたは再生終了
                }
                if (シーク中である)
                {
                    #region " 再生開始時刻までシーク(2)。"
                    //----------------
                    var frame = this._FrameQueue.Peek();    // 今格納されたフレームを覗く

                    if (frame.表示時刻100ns >= 再生開始時刻100ns)
                    {
                        // シーク終了;今回のフレームから再生の対象(なのでTakeしない)。
                        シーク中である = false;

                        // シークが終わったので、呼び出し元に起動完了を通知する。
                        this._デコード起動完了通知.Set();
                    }
                    else
                    {
                        // 取り出して、すぐに破棄。
                        frame = this._FrameQueue.Take();
                        frame.Dispose();
                        frame = null;
                    }
                    //----------------
                    #endregion
                }
            }

            Log.Info($"タスクを終了します。");
        }
Ejemplo n.º 9
0
        private void _SourceReaderEx生成後の初期化()
        {
            Debug.Assert(null != this._SourceReaderEx);

            #region " ストリームを列挙して、Video と Audio の実ストリーム番号を調べる。"
            //----------------
            try
            {
                for (int index = 0; true; index++)  // 例外が発生するまでループ
                {
                    using (var mediaType = this._SourceReaderEx.GetCurrentMediaType(index))
                    {
                        if (mediaType.MajorType == MediaTypeGuids.Video)
                        {
                            this._Videoのストリーム番号 = index;
                        }
                        else if (mediaType.MajorType == MediaTypeGuids.Audio)
                        {
                            this._Audioのストリーム番号 = index;
                        }
                    }
                }
            }
            catch (SharpDXException e)
            {
                if (e.ResultCode == SharpDX.MediaFoundation.ResultCode.InvalidStreamNumber)
                {
                    // 列挙完了
                }
                else
                {
                    throw;
                }
            }
            //----------------
            #endregion

            this._SourceReaderEx.SetStreamSelection(SourceReaderIndex.AllStreams, false);

            this._長さsec = FDKUtilities.換_100ns単位からsec単位へ(
                this._SourceReaderEx.GetPresentationAttribute(SourceReaderIndex.MediaSource, PresentationDescriptionAttributeKeys.Duration));

            if (0 <= this._Videoのストリーム番号)
            {
                #region " Video の初期化 "
                //----------------
                this._SourceReaderEx.SetStreamSelection(this._Videoのストリーム番号, true);

                // 部分メディアタイプを設定する。
                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(this._Videoのストリーム番号, videoMediaType);
                }

                // 完成されたメディアタイプを取得する。
                this._VideoのMediaType = this._SourceReaderEx.GetCurrentMediaType(this._Videoのストリーム番号);

                // ビデオのフレームサイズを取得する。
                long packedFrameSize = this._VideoのMediaType.Get(MediaTypeAttributeKeys.FrameSize);   // 動画の途中でのサイズ変更には対応しない。
                this._Videoのフレームサイズ = new Size2F((packedFrameSize >> 32) & 0xFFFFFFFF, (packedFrameSize) & 0xFFFFFFFF);
                //----------------
                #endregion

                this._VideoSource = new StreamingVideoSource(this._Videoのフレームサイズ);
            }
            if (0 <= this._Audioのストリーム番号)
            {
                #region " Audio の初期化 "
                //----------------
                this._SourceReaderEx.SetStreamSelection(this._Audioのストリーム番号, true);

                // 部分メディアタイプを設定する。
                var wf = SharpDX.Multimedia.WaveFormat.CreateIeeeFloatWaveFormat(this._Audioのフォーマット.SampleRate, this._Audioのフォーマット.Channels);
                MediaFactory.CreateAudioMediaType(ref wf, out AudioMediaType audioMediaType);

                // 作成した部分メディアタイプを SourceReader にセットする。必要なデコーダが見つからなかったら、ここで例外が発生する。
                using (audioMediaType)
                    this._SourceReaderEx.SetCurrentMediaType(this._Audioのストリーム番号, audioMediaType);

                // 完成されたメディアタイプを取得する。
                this._AudioのMediaType = this._SourceReaderEx.GetCurrentMediaType(this._Audioのストリーム番号);

                // フォーマットを取得する(念のため)。
                var _CscoreAudioMediaType = new CSCore.MediaFoundation.MFMediaType(this._AudioのMediaType.NativePointer);    // ネイティブポインタの共有で生成したのでDispose不要。
                this._Audioのフォーマット    = _CscoreAudioMediaType.ToWaveFormat(CSCore.MediaFoundation.MFWaveFormatExConvertFlags.Normal);
                _CscoreAudioMediaType = null;
                //----------------
                #endregion

                this._WaveSource = new StreamingWaveSource(this._Audioのフォーマット);
            }

            #region " デコード開始。"
            //----------------
            this._デコードキャンセル  = new CancellationTokenSource();
            this._デコード起動完了通知 = new ManualResetEvent(false);
            this._デコードタスク    = Task.Factory.StartNew(this._デコードタスクエントリ, this._デコードキャンセル.Token);
            this._デコード起動完了通知.WaitOne();
            //----------------
            #endregion

            //Thread.Sleep( 500 );    // デコードデータが蓄積されるまで待機(手抜き
        }