Exemple #1
0
        /// <summary>
        /// Initializes the media block buffers and
        /// starts packet reader, frame decoder, and block rendering workers.
        /// </summary>
        internal void StartWorkers()
        {
            // Initialize the block buffers
            foreach (var t in Container.Components.MediaTypes)
            {
                Blocks[t]    = new MediaBlockBuffer(Constants.MaxBlocks[t], t);
                Renderers[t] = Platform.CreateRenderer(t, this);
                InvalidateRenderer(t);
            }

            // Create the renderer for the preloaded subs
            if (PreloadedSubtitles != null)
            {
                Renderers[PreloadedSubtitles.MediaType] = Platform.CreateRenderer(PreloadedSubtitles.MediaType, this);
                InvalidateRenderer(PreloadedSubtitles.MediaType);
            }

            Clock.SpeedRatio = Constants.Controller.DefaultSpeedRatio;
            Commands.IsStopWorkersPending = false;

            // Set the initial state of the task cycles.
            BlockRenderingCycle.Complete();
            FrameDecodingCycle.Begin();
            PacketReadingCycle.Begin();

            // Create the thread runners
            PacketReadingTask = new Thread(RunPacketReadingWorker)
            {
                IsBackground = true, Name = nameof(PacketReadingTask), Priority = ThreadPriority.Normal
            };

            FrameDecodingTask = new Thread(RunFrameDecodingWorker)
            {
                IsBackground = true, Name = nameof(FrameDecodingTask), Priority = ThreadPriority.AboveNormal
            };

            // Fire up the threads
            PacketReadingTask.Start();
            FrameDecodingTask.Start();
            StartBlockRenderingWorker();
        }
        /// <summary>
        /// Runs the read task which keeps a packet buffer as full as possible.
        /// It reports on DownloadProgress by enqueueing an update to the property
        /// in order to avoid any kind of disruption to this thread caused by the UI thread.
        /// </summary>
        internal void RunPacketReadingWorker()
        {
            #region Worker State Setup

            // The delay provider prevents 100% core usage
            var delay = new DelayProvider();

            // Holds the packet count for each read cycle
            var packetsRead = new MediaTypeDictionary <int>();

            // State variables for media types
            var t = MediaType.None;

            // Signal the start of a buffering operation
            State.SignalBufferingStarted();

            #endregion

            #region Worker Loop

            try
            {
                // Worker logic begins here
                while (Commands.IsStopWorkersPending == false)
                {
                    // Determine what to do on a priority command
                    if (Commands.IsExecutingDirectCommand)
                    {
                        if (Commands.IsClosing)
                        {
                            break;
                        }
                        if (Commands.IsChanging)
                        {
                            Commands.WaitForDirectCommand();
                        }
                    }

                    // Wait for seeking or changing to be done.
                    Commands.WaitForActiveSeekCommand();

                    // Enter a packet reading cycle
                    PacketReadingCycle.Begin();

                    // Initialize Packets read to 0 for each component and state variables
                    foreach (var k in Container.Components.MediaTypes)
                    {
                        packetsRead[k] = 0;
                    }

                    // Start to perform the read loop
                    // NOTE: Disrupting the packet reader causes errors in UPD streams. Disrupt as little as possible
                    while (ShouldReadMorePackets &&
                           CanReadMorePackets &&
                           Commands.IsActivelySeeking == false)
                    {
                        // Perform a packet read. t will hold the packet type.
                        try { t = Container.Read(); }
                        catch (MediaContainerException) { continue; }

                        // Discard packets that we don't need (i.e. MediaType == None)
                        if (Container.Components.MediaTypes.HasMediaType(t) == false)
                        {
                            continue;
                        }

                        // Update the packet count for the components
                        packetsRead[t] += 1;

                        // Ensure we have read at least some packets from main and auxiliary streams.
                        if (packetsRead.ContainsMoreThan(0))
                        {
                            break;
                        }
                    }

                    // finish the reading cycle.
                    PacketReadingCycle.Complete();

                    // Don't evaluate a pause/delay condition if we are seeking
                    if (Commands.IsActivelySeeking)
                    {
                        continue;
                    }

                    // Wait some if we have a full packet buffer or we are unable to read more packets (i.e. EOF).
                    if (ShouldReadMorePackets == false ||
                        CanReadMorePackets == false ||
                        packetsRead.GetSum() <= 0)
                    {
                        delay.WaitOne();
                    }
                }
            }
            catch { throw; }
            finally
            {
                // Always exit notifying the reading cycle is done.
                PacketReadingCycle.Complete();
                delay.Dispose();
            }

            #endregion
        }
Exemple #3
0
        /// <summary>
        /// Runs the read task which keeps a packet buffer as full as possible.
        /// It reports on DownloadProgress by enqueueing an update to the property
        /// in order to avoid any kind of disruption to this thread caused by the UI thread.
        /// </summary>
        internal void RunPacketReadingWorker()
        {
            #region Worker State Setup

            // The delay provider prevents 100% core usage
            var delay = new DelayProvider();

            // Holds the packet count for each read cycle
            var packetsRead = new MediaTypeDictionary <int>();

            // State variables for media types
            var t = MediaType.None;

            // Store Container in local variable to prevent NullReferenceException
            // when dispose occurs sametime with read cycle
            var mediaContainer = Container;

            #endregion

            #region Worker Loop

            try
            {
                // Worker logic begins here
                while (IsTaskCancellationPending == false)
                {
                    // Wait for seeking or changing to be done.
                    MediaChangingDone.Wait();
                    SeekingDone.Wait();

                    // Enter a packet reading cycle
                    PacketReadingCycle.Begin();

                    // Initialize Packets read to 0 for each component and state variables
                    foreach (var k in mediaContainer.Components.MediaTypes)
                    {
                        packetsRead[k] = 0;
                    }

                    // Start to perform the read loop
                    // NOTE: Disrupting the packet reader causes errors in UPD streams. Disrupt as little as possible
                    while (CanReadMorePackets && ShouldReadMorePackets && IsTaskCancellationPending == false)
                    {
                        // Perform a packet read. t will hold the packet type.
                        try
                        {
                            t = mediaContainer.Read();
                        }
                        catch (MediaContainerException)
                        {
                            continue;
                        }

                        // Discard packets that we don't need (i.e. MediaType == None)
                        if (mediaContainer.Components.MediaTypes.HasMediaType(t) == false)
                        {
                            continue;
                        }

                        // Update the packet count for the components
                        packetsRead[t] += 1;

                        // Ensure we have read at least some packets from main and auxiliary streams.
                        if (packetsRead.FundamentalsGreaterThan(0))
                        {
                            break;
                        }
                    }

                    // finish the reading cycle.
                    PacketReadingCycle.Complete();

                    // Don't evaluate a pause condition if we are seeking
                    if (SeekingDone.IsInProgress)
                    {
                        continue;
                    }

                    // Wait some if we have a full packet buffer or we are unable to read more packets (i.e. EOF).
                    if (ShouldReadMorePackets == false ||
                        CanReadMorePackets == false ||
                        packetsRead.GetSum() <= 0)
                    {
                        delay.WaitOne();
                    }
                }
            }
            catch (ThreadAbortException) { /* swallow */ }
            catch { if (!IsDisposed)
                    {
                        throw;
                    }
            }
            finally
            {
                // Always exit notifying the reading cycle is done.
                PacketReadingCycle.Complete();
                delay.Dispose();
            }

            #endregion
        }
        /// <summary>
        /// Runs the read task which keeps a packet buffer as full as possible.
        /// It reports on DownloadProgress by enqueueing an update to the property
        /// in order to avoid any kind of disruption to this thread caused by the UI thread.
        /// </summary>
        internal void RunPacketReadingWorker()
        {
            var delay            = TimeSpan.FromMilliseconds(10);
            var needsMorePackets = false;

            IsSyncBuffering = false;

            try
            {
                // Worker logic begins here
                while (Commands.IsStopWorkersPending == false)
                {
                    // Determine what to do on a priority command
                    if (Commands.IsExecutingDirectCommand)
                    {
                        if (Commands.IsClosing)
                        {
                            break;
                        }
                        if (Commands.IsChanging)
                        {
                            Commands.WaitForDirectCommand();
                        }
                    }

                    // Wait for seeking or changing to be done.
                    Commands.WaitForActiveSeekCommand();

                    // Enter a packet reading cycle
                    PacketReadingCycle.Begin();

                    // Perform a packet read. t will hold the packet type.
                    if (ShouldWorkerReadPackets)
                    {
                        try { Container.Read(); }
                        catch (MediaContainerException) { break; }
                    }
                    else
                    {
                        // Give it a break until there are packet changes
                        // this prevent pegging the cpu core
                        BufferChangedEvent.Begin();
                        while (IsWorkerInterruptRequested == false)
                        {
                            needsMorePackets = ShouldWorkerReadPackets;

                            // We now need more packets, we need to stop waiting
                            if (needsMorePackets)
                            {
                                break;
                            }

                            // we are sync-buffering but we don't need more packets
                            if (IsSyncBuffering && needsMorePackets == false)
                            {
                                break;
                            }

                            // We detected a change in buffered packets
                            if (BufferChangedEvent.Wait(delay))
                            {
                                break;
                            }
                        }
                    }

                    // No more sync-buffering if we have enough data
                    if (CanExitSyncBuffering)
                    {
                        IsSyncBuffering = false;
                    }

                    // finish the reading cycle.
                    PacketReadingCycle.Complete();
                }
            }
            catch { throw; }
            finally
            {
                // Always exit notifying the reading cycle is done.
                PacketReadingCycle.Complete();
                IsSyncBuffering = false;
            }
        }