/// <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 }
/// <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; } }