Пример #1
0
        /// <summary>
        /// Continuously converts frmes and places them on the corresponding
        /// block buffer. This task is responsible for keeping track of the clock
        /// and calling the render methods appropriate for the current clock position.
        /// </summary>
        internal void RunBlockRenderingWorker()
        {
            try
            {
                #region 0. Initialize Running State

                // Holds the main media type
                var main = Container.Components.Main.MediaType;

                // Holds the auxiliary media types
                var auxs = Container.Components.MediaTypes.Where(t => t != main).ToArray();

                // Holds all components
                var all = Container.Components.MediaTypes.ToArray();

                // Holds a snapshot of the current block to render
                var currentBlock = new MediaTypeDictionary <MediaBlock>();

                // Keeps track of how many blocks were rendered in the cycle.
                var renderedBlockCount = 0;

                // reset render times for all components
                foreach (var t in all)
                {
                    LastRenderTime[t] = TimeSpan.MinValue;
                }

                // Ensure the other workers are running
                PacketReadingCycle?.WaitOne();
                FrameDecodingCycle?.WaitOne();

                // Set the initial clock position
                Clock.Position = Blocks[main].RangeStartTime;
                var wallClock = Clock.Position;

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

                #endregion

                while (IsTaskCancellationPending == false)
                {
                    #region 1. Control and Capture

                    // Reset the rendered count to 0
                    renderedBlockCount = 0;

                    // Capture current clock position for the rest of this cycle
                    BlockRenderingCycle?.Reset();

                    // capture the wall clock for this cycle
                    wallClock = Clock.Position;

                    #endregion

                    #region 2. Handle Block Rendering

                    // Capture the blocks to render
                    foreach (var t in all)
                    {
                        currentBlock[t] = HasDecoderSeeked ? null : 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)
                        {
                            continue;
                        }

                        // Render by forced signal (TimeSpan.MinValue)
                        if (LastRenderTime[t] == TimeSpan.MinValue)
                        {
                            renderedBlockCount += SendBlockToRenderer(currentBlock[t], wallClock);
                            continue;
                        }

                        // Render because we simply have not rendered
                        if (currentBlock[t].StartTime != LastRenderTime[t])
                        {
                            renderedBlockCount += SendBlockToRenderer(currentBlock[t], wallClock);
                            continue;
                        }
                    }

                    #endregion

                    #region 6. Finalize the Rendering Cycle

                    // Signal the rendering cycle was set.
                    BlockRenderingCycle?.Set();

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

                    // Delay the thread for a bit if we have no more stuff to process
                    if (IsSeeking == false && renderedBlockCount <= 0 && Commands.PendingCount <= 0)
                    {
                        Task.Delay(1).GetAwaiter().GetResult();
                    }

                    #endregion
                }
            }
            catch (ThreadAbortException)
            {
            }
            finally
            {
                // Always exit notifying the cycle is done.
                BlockRenderingCycle?.Set();
            }
        }
Пример #2
0
        /// <summary>
        /// Starts the block rendering worker.
        /// </summary>
        private void StartBlockRenderingWorker()
        {
            if (HasBlockRenderingWorkerExited != null)
            {
                return;
            }

            HasBlockRenderingWorkerExited = new ManualResetEvent(false);

            // Synchronized access to parts of the run cycle
            var isRunningRenderingCycle = false;

            // Holds the main media type
            var main = Container.Components.Main.MediaType;

            // Holds the auxiliary media types
            var auxs = Container.Components.MediaTypes.ExcludeMediaType(main);

            // Holds all components
            var all = Container.Components.MediaTypes.DeepCopy();

            // Holds a snapshot of the current block to render
            var currentBlock = new MediaTypeDictionary <MediaBlock>();

            // Keeps track of how many blocks were rendered in the cycle.
            var renderedBlockCount = new MediaTypeDictionary <int>();

            // reset render times for all components
            foreach (var t in all)
            {
                LastRenderTime[t] = TimeSpan.MinValue;
            }

            // Ensure packet reading is running
            PacketReadingCycle.WaitOne();

            // wait for main component blocks or EOF or cancellation pending
            while (CanReadMoreFramesOf(main) && Blocks[main].Count <= 0)
            {
                FrameDecodingCycle.WaitOne();
            }

            // Set the initial clock position
            // TODO: maybe update media start time offset to this Minimum, initial Start Time intead of relying on contained meta?
            Clock.Update(Blocks[main].RangeStartTime); // .GetMinStartTime()
            var wallClock = WallClock;

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

            // The Render timer is responsible for sending frames to renders
            BlockRenderingWorker = new Timer((s) =>
            {
                #region Detect a Timer Stop

                if (IsTaskCancellationPending || HasBlockRenderingWorkerExited.IsSet() || IsDisposed)
                {
                    HasBlockRenderingWorkerExited.Set();
                    return;
                }

                #endregion

                #region Run the Rendering Cycle

                // Updatete Status  Properties
                State.UpdateBufferingProperties();

                // Don't run the cycle if it's already running
                if (isRunningRenderingCycle)
                {
                    // TODO: Maybe Log a frame skip here?
                    return;
                }

                try
                {
                    #region 1. Control and Capture

                    // Flag the current rendering cycle
                    isRunningRenderingCycle = true;

                    // Reset the rendered count to 0
                    foreach (var t in all)
                    {
                        renderedBlockCount[t] = 0;
                    }

                    // Capture current clock position for the rest of this cycle
                    BlockRenderingCycle.Reset();

                    #endregion

                    #region 2. Handle Block Rendering

                    // Wait for the seek op to finish before we capture blocks
                    if (HasDecoderSeeked)
                    {
                        SeekingDone.WaitOne();
                    }

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

                    // Capture the blocks to render
                    foreach (var t in all)
                    {
                        currentBlock[t] = 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)
                        {
                            continue;
                        }

                        // Render by forced signal (TimeSpan.MinValue)
                        if (LastRenderTime[t] == TimeSpan.MinValue)
                        {
                            renderedBlockCount[t] += SendBlockToRenderer(currentBlock[t], wallClock);
                            continue;
                        }

                        // Render because we simply have not rendered
                        if (currentBlock[t].StartTime != LastRenderTime[t])
                        {
                            renderedBlockCount[t] += SendBlockToRenderer(currentBlock[t], wallClock);
                            continue;
                        }
                    }

                    #endregion

                    #region 6. 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)
                    {
                        Renderers[t]?.Update(wallClock);
                    }

                    #endregion
                }
                catch (ThreadAbortException) { /* swallow */ }
                catch { if (!IsDisposed)
                        {
                            throw;
                        }
                }
                finally
                {
                    // Always exit notifying the cycle is done.
                    BlockRenderingCycle.Set();
                    isRunningRenderingCycle = false;
                }

                #endregion
            },
                                             this, // the state argument passed on to the ticker
                                             0,
                                             (int)Constants.Interval.HighPriority.TotalMilliseconds);
        }
Пример #3
0
        /// <summary>
        /// Starts the block rendering worker.
        /// </summary>
        private void StartBlockRenderingWorker()
        {
            if (HasBlockRenderingWorkerExited != null)
            {
                return;
            }

            HasBlockRenderingWorkerExited = new ManualResetEvent(false);

            // Synchronized access to parts of the run cycle
            var isRunningPropertyUpdates = false;
            var isRunningRenderingCycle  = false;

            // Holds the main media type
            var main = Container.Components.Main.MediaType;

            // Holds the auxiliary media types
            var auxs = Container.Components.MediaTypes.ExcludeMediaType(main);

            // Holds all components
            var all = Container.Components.MediaTypes.DeepCopy();

            // Holds a snapshot of the current block to render
            var currentBlock = new MediaTypeDictionary <MediaBlock>();

            // Keeps track of how many blocks were rendered in the cycle.
            var renderedBlockCount = new MediaTypeDictionary <int>();

            // reset render times for all components
            foreach (var t in all)
            {
                LastRenderTime[t] = TimeSpan.MinValue;
            }

            // Ensure the other workers are running
            PacketReadingCycle.WaitOne();
            FrameDecodingCycle.WaitOne();

            // Set the initial clock position
            Clock.Position = Blocks[main].RangeStartTime;
            var wallClock = Clock.Position;

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

            // The Property update timer is responsible for timely updates to properties outside of the worker threads
            BlockRenderingWorker = new Timer((s) =>
            {
                #region Detect a Timer Stop

                if (IsTaskCancellationPending || HasBlockRenderingWorkerExited.IsSet() || m_IsDisposing.Value)
                {
                    HasBlockRenderingWorkerExited.Set();
                    return;
                }

                #endregion

                #region Run the property Updates

                if (isRunningPropertyUpdates == false)
                {
                    isRunningPropertyUpdates = true;

                    try
                    {
                        UpdatePosition(IsOpen ? Clock?.Position ?? TimeSpan.Zero : TimeSpan.Zero);
                        UpdateBufferingProperties();
                    }
                    catch (Exception ex)
                    {
                        Log(MediaLogMessageType.Error, $"{nameof(BlockRenderingWorker)} callabck failed. {ex.GetType()}: {ex.Message}");
                    }
                    finally
                    {
                        isRunningPropertyUpdates = false;
                    }
                }

                #endregion

                #region Run the Rendering Cycle

                // Don't run the cycle if it's already running
                if (isRunningRenderingCycle)
                {
                    // TODO: Log a frame skip
                    return;
                }

                try
                {
                    #region 1. Control and Capture

                    // Flag the current rendering cycle
                    isRunningRenderingCycle = true;

                    // Reset the rendered count to 0
                    foreach (var t in all)
                    {
                        renderedBlockCount[t] = 0;
                    }

                    // Capture current clock position for the rest of this cycle
                    BlockRenderingCycle.Reset();

                    // capture the wall clock for this cycle
                    wallClock = Clock.Position;

                    #endregion

                    #region 2. Handle Block Rendering

                    // Wait for the seek op to finish before we capture blocks
                    if (HasDecoderSeeked)
                    {
                        SeekingDone.WaitOne();
                    }

                    // Capture the blocks to render
                    foreach (var t in all)
                    {
                        currentBlock[t] = 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)
                        {
                            continue;
                        }

                        // Render by forced signal (TimeSpan.MinValue)
                        if (LastRenderTime[t] == TimeSpan.MinValue)
                        {
                            renderedBlockCount[t] += SendBlockToRenderer(currentBlock[t], wallClock);
                            continue;
                        }

                        // Render because we simply have not rendered
                        if (currentBlock[t].StartTime != LastRenderTime[t])
                        {
                            renderedBlockCount[t] += SendBlockToRenderer(currentBlock[t], wallClock);
                            continue;
                        }
                    }

                    #endregion

                    #region 6. 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)
                    {
                        Renderers[t]?.Update(wallClock);
                    }

                    #endregion
                }
                catch (ThreadAbortException) { }
                catch { throw; }
                finally
                {
                    // Always exit notifying the cycle is done.
                    BlockRenderingCycle.Set();
                    isRunningRenderingCycle = false;
                }

                #endregion
            },
                                             this, // the state argument passed on to the ticker
                                             0,
                                             (int)Constants.Interval.HighPriority.TotalMilliseconds);
        }