예제 #1
0
        /// <inheritdoc />
        protected override void ExecuteCycleLogic(CancellationToken ct)
        {
            // Update Status Properties
            var main         = Container.Components.MainMediaType;
            var all          = MediaCore.Renderers.Keys.ToArray();
            var currentBlock = new MediaTypeDictionary <MediaBlock>();

            if (HasInitialized == false)
            {
                // wait for main component blocks or EOF or cancellation pending
                if (MediaCore.Blocks[main].Count <= 0)
                {
                    return;
                }

                // Set the initial clock position
                MediaCore.ChangePosition(MediaCore.Blocks[main].RangeStartTime);

                // Wait for renderers to be ready
                foreach (var t in all)
                {
                    MediaCore.Renderers[t]?.WaitForReadyState();
                }

                // Mark as initialized
                HasInitialized.Value = true;
            }

            #region Run the Rendering Cycle

            try
            {
                // TODO: wait for active seek command
                try { Commands.WaitForSeekBlocks(ct); }
                catch { return; }

                #region 2. Handle Block Rendering

                // capture the wall clock for this cycle
                var wallClock = MediaCore.WallClock;

                // Capture the blocks to render
                foreach (var t in all)
                {
                    // Get the audio, video, or subtitle block to render
                    currentBlock[t] = t == MediaType.Subtitle && MediaCore.PreloadedSubtitles != null ?
                                      MediaCore.PreloadedSubtitles[wallClock] :
                                      MediaCore.Blocks[t][wallClock];
                }

                // Render each of the Media Types if it is time to do so.
                foreach (var t in all)
                {
                    // Skip rendering for nulls
                    if (currentBlock[t] == null || currentBlock[t].IsDisposed)
                    {
                        continue;
                    }

                    // Render by forced signal (TimeSpan.MinValue) or because simply it is time to do so
                    if (MediaCore.LastRenderTime[t] == TimeSpan.MinValue || currentBlock[t].StartTime != MediaCore.LastRenderTime[t])
                    {
                        SendBlockToRenderer(currentBlock[t], wallClock);
                    }
                }

                #endregion

                #region 3. Finalize the Rendering Cycle

                // Call the update method on all renderers so they receive what the new wall clock is.
                foreach (var t in all)
                {
                    MediaCore.Renderers[t]?.Update(wallClock);
                }

                #endregion
            }
            catch (Exception ex)
            {
                MediaCore.LogError(Aspects.RenderingWorker, "Error while in rendering worker cycle", ex);
                throw;
            }
            finally
            {
                // Check End of Media Scenarios
                if (MediaCore.HasDecodingEnded &&
                    Commands.IsSeeking == false &&
                    MediaCore.WallClock >= MediaCore.LastRenderTime[main] &&
                    MediaCore.WallClock >= MediaCore.Blocks[main].RangeEndTime)
                {
                    // Rendered all and nothing else to render
                    if (State.HasMediaEnded == false)
                    {
                        MediaCore.Clock.Pause();
                        var endPosition = MediaCore.ChangePosition(MediaCore.Blocks[main].RangeEndTime);
                        State.UpdateMediaEnded(true, endPosition);
                        State.UpdateMediaState(PlaybackStatus.Stop);
                        foreach (var mt in Container.Components.MediaTypes)
                        {
                            MediaCore.InvalidateRenderer(mt);
                        }
                    }
                }
                else
                {
                    State.UpdateMediaEnded(false, TimeSpan.Zero);
                }

                // Update the Position
                if (!ct.IsCancellationRequested)
                {
                    State.UpdatePosition();
                }
            }

            #endregion
        }
예제 #2
0
        /// <inheritdoc />
        protected override void ExecuteCycleLogic(CancellationToken ct)
        {
            // Update Status Properties
            var main         = Container.Components.MainMediaType;
            var all          = MediaCore.Renderers.Keys.ToArray();
            var currentBlock = new MediaTypeDictionary <MediaBlock>();

            if (HasInitialized == false)
            {
                // wait for main component blocks or EOF or cancellation pending
                if (MediaCore.Blocks[main].Count <= 0)
                {
                    return;
                }

                // Set the initial clock position
                MediaCore.ChangePosition(MediaCore.Blocks[main].RangeStartTime);

                // Wait for renderers to be ready
                foreach (var t in all)
                {
                    MediaCore.Renderers[t]?.WaitForReadyState();
                }

                // Mark as initialized
                HasInitialized.Value = true;
            }

            #region Run the Rendering Cycle

            try
            {
                #region 1. Wait for any seek operation to make blocks available in a loop

                while (!ct.IsCancellationRequested &&
                       Commands.IsActivelySeeking &&
                       !MediaCore.Blocks[main].IsInRange(MediaCore.WallClock))
                {
                    // Check if we finally have seek blocks available
                    // if we don't get seek blocks in range and we are not step-seeking,
                    // then we simply break out of the loop and render whatever it is we have
                    // to create the illussion of smooth seeking. For precision seeking we
                    // continue the loop.
                    if (!Commands.WaitForSeekBlocks(DefaultPeriod.Milliseconds) &&
                        Commands.ActiveSeekMode == CommandManager.SeekMode.Normal)
                    {
                        break;
                    }
                }

                #endregion

                #region 2. Handle Block Rendering

                // Capture the blocks to render at a fixed wall clock position
                // so all blocks are aligned to the same timestamp
                var wallClock = MediaCore.WallClock;

                foreach (var t in all)
                {
                    // skip blocks if we are seeking and they are not video blocks
                    if (Commands.IsSeeking && t != MediaType.Video)
                    {
                        currentBlock[t] = null;
                        continue;
                    }

                    // Get the audio, video, or subtitle block to render
                    currentBlock[t] = t == MediaType.Subtitle && MediaCore.PreloadedSubtitles != null ?
                                      MediaCore.PreloadedSubtitles[wallClock] :
                                      MediaCore.Blocks[t][wallClock];
                }

                // Render each of the Media Types if it is time to do so.
                foreach (var t in all)
                {
                    // Don't send null blocks to renderer
                    if (currentBlock[t] == null || currentBlock[t].IsDisposed)
                    {
                        continue;
                    }

                    // Render by forced signal (TimeSpan.MinValue) or because simply it is time to do so
                    if (MediaCore.LastRenderTime[t] == TimeSpan.MinValue || currentBlock[t].StartTime != MediaCore.LastRenderTime[t])
                    {
                        SendBlockToRenderer(currentBlock[t], wallClock);
                    }
                }

                #endregion

                #region 3. Finalize the Rendering Cycle

                // Call the update method on all renderers so they receive what the new wall clock is.
                foreach (var t in all)
                {
                    MediaCore.Renderers[t]?.Update(wallClock);
                }

                #endregion
            }
            catch (Exception ex)
            {
                MediaCore.LogError(Aspects.RenderingWorker, "Error while in rendering worker cycle", ex);
                throw;
            }
            finally
            {
                // Check End of Media Scenarios
                if (Commands.IsSeeking == false &&
                    MediaCore.HasDecodingEnded &&
                    MediaCore.WallClock >= MediaCore.LastRenderTime[main] &&
                    MediaCore.WallClock >= MediaCore.Blocks[main].RangeEndTime)
                {
                    // Rendered all and nothing else to render
                    if (State.HasMediaEnded == false)
                    {
                        MediaCore.Clock.Pause();
                        var endPosition = MediaCore.ChangePosition(MediaCore.Blocks[main].RangeEndTime);
                        State.UpdateMediaEnded(true, endPosition);
                        State.UpdateMediaState(PlaybackStatus.Stop);
                        foreach (var mt in Container.Components.MediaTypes)
                        {
                            MediaCore.InvalidateRenderer(mt);
                        }
                    }
                }
                else
                {
                    State.UpdateMediaEnded(false, TimeSpan.Zero);
                }

                // Update the Position
                if (!ct.IsCancellationRequested && Commands.IsSeeking == false)
                {
                    State.UpdatePosition();
                }
            }

            #endregion
        }