/// <summary> /// Performs a seek operation to the specified position. /// </summary> /// <param name="position">The position.</param> private void Seek(TimeSpan position) { SeekingDone.Wait(); var startTime = DateTime.UtcNow; var resumeClock = Clock.IsRunning; Clock.Pause(); SeekingDone.Reset(); PacketReadingCycle.Wait(); FrameDecodingCycle.Wait(); BlockRenderingCycle.Wait(); // Clear Blocks and frames, reset the render times foreach (var t in Container.Components.MediaTypes) { Frames[t].Clear(); Blocks[t].Clear(); LastRenderTime[t] = TimeSpan.MinValue; } // Populate frame with after-seek operation var frames = Container.Seek(position); foreach (var frame in frames) { Frames[frame.MediaType].Push(frame); } // Resume the clock if it was running before the seek operation OnPropertyChanged(nameof(Position)); if (resumeClock) { Clock.Play(); } Container.Log(MediaLogMessageType.Debug, $"SEEK D: Elapsed: {startTime.DebugElapsedUtc()}"); RequestedSeekPosition = null; SeekingDone.Set(); }
/// <summary> /// Logs a block rendering operation as a Trace Message /// if the debugger is attached. /// </summary> /// <param name="container">The container.</param> /// <param name="block">The block.</param> /// <param name="clockPosition">The clock position.</param> /// <param name="renderIndex">Index of the render.</param> internal static void LogRenderBlock(this MediaContainer container, MediaBlock block, TimeSpan clockPosition, int renderIndex) { if (Debugger.IsAttached == false) { return; } try { var drift = TimeSpan.FromTicks(clockPosition.Ticks - block.StartTime.Ticks); container?.Log(MediaLogMessageType.Trace, ($"{block.MediaType.ToString().Substring(0, 1)} " + $"BLK: {block.StartTime.Debug()} | " + $"CLK: {clockPosition.Debug()} | " + $"DFT: {drift.TotalMilliseconds,4:0} | " + $"IX: {renderIndex,3} | " + $"PQ: {container?.Components[block.MediaType]?.PacketBufferLength / 1024d,7:0.0}k | " + $"TQ: {container?.Components.PacketBufferLength / 1024d,7:0.0}k")); } catch { // swallow } }
public async Task CloseAsync() { Container?.Log(MediaLogMessageType.Debug, $"{nameof(CloseAsync)}: Entered"); Clock.Pause(); IsTaskCancellationPending = true; // Wait for cycles to complete. await Task.Run(() => { while (!BlockRenderingCycle.Wait(1)) { } while (!FrameDecodingCycle.Wait(1)) { } while (!PacketReadingCycle.Wait(1)) { } }); BlockRenderingTask?.Join(); FrameDecodingTask?.Join(); PacketReadingTask?.Join(); BlockRenderingTask = null; FrameDecodingTask = null; PacketReadingTask = null; foreach (var renderer in Renderers.Values) { renderer.Close(); } Renderers.Clear(); // Reset the clock Clock.Reset(); Container?.Log(MediaLogMessageType.Debug, $"{nameof(CloseAsync)}: Completed"); // Dispose the container if (Container != null) { Container.Dispose(); Container = null; } // Dispose the Blocks for all components foreach (var kvp in Blocks) { kvp.Value.Dispose(); } Blocks.Clear(); // Dispose the Frames for all components foreach (var kvp in Frames) { kvp.Value.Dispose(); } Frames.Clear(); // Clear the render times LastRenderTime.Clear(); // Update notification properties UpdateMediaProperties(); MediaState = MediaState.Close; }
/// <summary> /// Opens the specified media Asynchronously /// </summary> /// <param name="uri">The URI.</param> /// <returns></returns> private async Task OpenAsync(Uri uri) { try { await Task.Run(() => { var mediaUrl = uri.IsFile ? uri.LocalPath : uri.ToString(); Container = new MediaContainer(mediaUrl); RaiseMediaOpeningEvent(); Container.Log(MediaLogMessageType.Debug, $"{nameof(OpenAsync)}: Entered"); Container.Initialize(); }); foreach (var t in Container.Components.MediaTypes) { Blocks[t] = new MediaBlockBuffer(MaxBlocks[t], t); Frames[t] = new MediaFrameQueue(); LastRenderTime[t] = TimeSpan.MinValue; Renderers[t] = CreateRenderer(t); } IsTaskCancellationPending = false; BlockRenderingCycle.Set(); FrameDecodingCycle.Set(); PacketReadingCycle.Set(); PacketReadingTask = new Thread(RunPacketReadingWorker) { IsBackground = true }; FrameDecodingTask = new Thread(RunFrameDecodingWorker) { IsBackground = true }; BlockRenderingTask = new Thread(RunBlockRenderingWorker) { IsBackground = true }; PacketReadingTask.Start(); FrameDecodingTask.Start(); BlockRenderingTask.Start(); RaiseMediaOpenedEvent(); if (LoadedBehavior == MediaState.Play) { Play(); } } catch (Exception ex) { RaiseMediaFailedEvent(ex); } finally { UpdateMediaProperties(); Container.Log(MediaLogMessageType.Debug, $"{nameof(OpenAsync)}: Completed"); } }