/// <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();
        }
Пример #2
0
 /// <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");
            }
        }