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($"タスクを終了します。"); }