/// <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");
            }
        }
Beispiel #2
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()
        {
            try
            {
                // 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;

                var main = mediaContainer.Components.Main.MediaType;
                var auxs = mediaContainer.Components.MediaTypes.Where(c => c != main && (c == MediaType.Audio || c == MediaType.Video)).ToArray();
                var all  = auxs.Union(new[] { main }).ToArray();

                // State variables for bytes read (give-up condition)
                var startBytesRead   = 0UL;
                var currentBytesRead = 0UL;

                // Worker logic begins here
                while (IsTaskCancellationPending == false)
                {
                    // Enter a read cycle
                    SeekingDone?.WaitOne();

                    // Enter a packet reading cycle
                    PacketReadingCycle?.Reset();

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

                        startBytesRead   = mediaContainer.Components.TotalBytesRead;
                        currentBytesRead = 0UL;

                        // Start to perform the read loop
                        while (CanReadMorePackets)
                        {
                            // Perform a packet read. t will hold the packet type.
                            t = mediaContainer.Read();

                            // Discard packets that we don't need (i.e. MediaType == None)
                            if (mediaContainer.Components.MediaTypes.Contains(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.Where(k => all.Contains(k.Key)).All(c => c.Value > 0))
                            {
                                break;
                            }

                            // The give-up condition is that in spite of efforts to read at least one of each,
                            // we could not find the required packet types.
                            currentBytesRead = mediaContainer.Components.TotalBytesRead - startBytesRead;
                            if (currentBytesRead > (ulong)DownloadCacheLength)
                            {
                                break;
                            }
                        }
                    }

                    // finish the reading cycle.
                    PacketReadingCycle?.Set();

                    // Wait some if we have a full packet buffer or we are unable to read more packets (i.e. EOF).
                    if (mediaContainer.Components.PacketBufferLength >= DownloadCacheLength || CanReadMorePackets == false || currentBytesRead <= 0)
                    {
                        Task.Delay(1).GetAwaiter().GetResult();
                    }
                }
            }
            catch (ThreadAbortException)
            {
            }
            finally
            {
                // Always exit notifying the reading cycle is done.
                PacketReadingCycle?.Set();
            }
        }
        /// <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()
        {
            // 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;

            var main = mediaContainer.Components.Main.MediaType;
            var auxs = mediaContainer.Components.MediaTypes.FundamentalAuxsFor(main);
            var all  = main.JoinMediaTypes(auxs);

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

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

                    // 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.
                        t = mediaContainer.Read();

                        // 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.Set();

                    // Don't evaluate a pause condition if we are seeking
                    if (SeekingDone.IsSet() == false)
                    {
                        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)
                    {
                        Task.Delay(1).GetAwaiter().GetResult();
                    }
                }
            }
            catch (ThreadAbortException) { /* swallow */ }
            catch { if (!IsDisposed)
                    {
                        throw;
                    }
            }
            finally
            {
                // Always exit notifying the reading cycle is done.
                PacketReadingCycle.Set();
            }
        }