Ejemplo n.º 1
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.º 2
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.º 3
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 );    // デコードデータが蓄積されるまで待機(手抜き
        }