Exemplo n.º 1
0
        public static void LoadAndWaitForMPUrlSourceFilter(string url, OnlineVideos.MPUrlSourceFilter.IFilterStateEx filterStateEx)
        {
            //string url = ApplyMPUrlSourceFilterSiteUserSettings(_resourceAccessor.ResourcePathName);
            int result = filterStateEx.LoadAsync(url);

            if (result < 0)
            {
                throw new UPnPRendererExceptions("Loading URL async error:  {0}", result);
            }

            WaitUntilReady(filterStateEx.IsStreamOpened, 1, "Check stream open error");
            WaitUntilReady(filterStateEx.IsFilterReadyToConnectPins, 50, "IsFilterReadyToConnectPins error");
        }
Exemplo n.º 2
0
        /// <summary>
        /// This function can be called by a background thread. It finishes building the graph and
        /// waits until the buffer is filled to the configured percentage.
        /// If a filter in the graph requires the full file to be downloaded, the function will return only afterwards.
        /// </summary>
        /// <returns>true, when playback can be started</returns>
        public bool BufferFile(Sites.SiteUtilBase siteUtil)
        {
            Thread renderPinsThread = null;

            VideoRendererStatistics.VideoState = VideoRendererStatistics.State.VideoPresent; // prevents the BlackRectangle on first time playback
            bool        PlaybackReady    = false;
            IBaseFilter sourceFilter     = null;
            string      sourceFilterName = null;

            try
            {
                sourceFilterName = GetSourceFilterName(m_strCurrentFile);

                int result = graphBuilder.FindFilterByName(sourceFilterName, out sourceFilter);
                if (result != 0)
                {
                    string errorText = DirectShowLib.DsError.GetErrorText(result);
                    if (errorText != null)
                    {
                        errorText = errorText.Trim();
                    }
                    Log.Instance.Warn("BufferFile : FindFilterByName returned '{0}'{1}", "0x" + result.ToString("X8"), !string.IsNullOrEmpty(errorText) ? " : (" + errorText + ")" : "");
                    return(false);
                }

                OnlineVideos.MPUrlSourceFilter.IFilterStateEx filterStateEx = sourceFilter as OnlineVideos.MPUrlSourceFilter.IFilterStateEx;

                if (filterStateEx != null)
                {
                    // MediaPortal IPTV filter and url source splitter
                    Log.Instance.Info("BufferFile : using 'MediaPortal IPTV filter and url source splitter' as source filter");

                    String url = OnlineVideos.MPUrlSourceFilter.UrlBuilder.GetFilterUrl(siteUtil, m_strCurrentFile);

                    Log.Instance.Info("BufferFile : loading url: '{0}'", url);
                    result = filterStateEx.LoadAsync(url);

                    if (result < 0)
                    {
                        throw new OnlineVideosException(FilterError.ErrorDescription(filterStateEx, result));
                    }

                    while (!this.BufferingStopped)
                    {
                        Boolean opened = false;

                        result = filterStateEx.IsStreamOpened(out opened);

                        if (result < 0)
                        {
                            throw new OnlineVideosException(FilterError.ErrorDescription(filterStateEx, result));
                        }

                        if (opened)
                        {
                            break;
                        }

                        Thread.Sleep(1);
                    }

                    // buffer before starting playback
                    bool filterConnected        = false;
                    bool filterIsReadyToConnect = false;
                    percentageBuffered = 0.0f;
                    long total = 0, current = 0, last = 0;

                    while (!PlaybackReady && graphBuilder != null && !BufferingStopped)
                    {
                        result = ((IAMOpenProgress)sourceFilter).QueryProgress(out total, out current);
                        if ((result != 0) && (result != 0x00040260))
                        {
                            // 0x00040260 - VFW_S_ESTIMATED - correct state, but value is estimated
                            throw new OnlineVideosException(FilterError.ErrorDescription(filterStateEx, result));
                        }

                        result = filterStateEx.IsFilterReadyToConnectPins(out filterIsReadyToConnect);
                        if (result != 0)
                        {
                            throw new OnlineVideosException(FilterError.ErrorDescription(filterStateEx, result));
                        }

                        percentageBuffered = (float)current / (float)total * 100.0f;
                        // after configured percentage has been buffered, connect the graph

                        if (!filterConnected && (percentageBuffered >= PluginConfiguration.Instance.playbuffer || skipBuffering))
                        {
                            if (filterIsReadyToConnect)
                            {
                                result = filterStateEx.GetCacheFileName(out cacheFile);
                                if (result != 0)
                                {
                                    throw new OnlineVideosException(FilterError.ErrorDescription(filterStateEx, result));
                                }

                                if (skipBuffering)
                                {
                                    Log.Instance.Debug("Buffering skipped at {0}%", percentageBuffered);
                                }
                                filterConnected  = true;
                                renderPinsThread = new Thread(delegate()
                                {
                                    try
                                    {
                                        Log.Instance.Debug("BufferFile : Rendering unconnected output pins of source filter ...");
                                        // add audio and video filter from MP Movie Codec setting section
                                        AddPreferredFilters(graphBuilder, sourceFilter);
                                        // connect the pin automatically -> will buffer the full file in cases of bad metadata in the file or request of the audio or video filter
                                        DirectShowUtil.RenderUnconnectedOutputPins(graphBuilder, sourceFilter);
                                        Log.Instance.Debug("BufferFile : Playback Ready.");
                                        PlaybackReady = true;
                                    }
                                    catch (ThreadAbortException)
                                    {
                                        Thread.ResetAbort();
                                        Log.Instance.Info("RenderUnconnectedOutputPins foribly aborted.");
                                    }
                                    catch (Exception ex)
                                    {
                                        Log.Instance.Warn(ex.Message);
                                        StopBuffering();
                                    }
                                })
                                {
                                    IsBackground = true, Name = "OVGraph"
                                };
                                renderPinsThread.Start();
                            }
                        }

                        // log every percent
                        if (current > last && current - last >= (double)total * 0.01)
                        {
                            Log.Instance.Debug("Buffering: {0}/{1} KB ({2}%)", current / 1024, total / 1024, (int)percentageBuffered);
                            last = current;
                        }
                        // set the percentage to a gui property, formatted according to percentage, so the user knows very early if anything is buffering
                        string formatString = "###";
                        if (percentageBuffered == 0f)
                        {
                            formatString = "0.0";
                        }
                        else if (percentageBuffered < 1f)
                        {
                            formatString = ".00";
                        }
                        else if (percentageBuffered < 10f)
                        {
                            formatString = "0.0";
                        }
                        else if (percentageBuffered < 100f)
                        {
                            formatString = "##";
                        }
                        GUIPropertyManager.SetProperty("#OnlineVideos.buffered", percentageBuffered.ToString(formatString, System.Globalization.CultureInfo.InvariantCulture));
                        Thread.Sleep(50); // no need to do this more often than 20 times per second
                    }
                }
                else
                {
                    Marshal.ThrowExceptionForHR(((IFileSourceFilter)sourceFilter).Load(m_strCurrentFile, null));

                    Log.Instance.Info("BufferFile : using unknown filter as source filter");

                    if (sourceFilter is IAMOpenProgress && !m_strCurrentFile.Contains("live=true") && !m_strCurrentFile.Contains("RtmpLive=1"))
                    {
                        // buffer before starting playback
                        bool filterConnected = false;
                        percentageBuffered = 0.0f;
                        long total = 0, current = 0, last = 0;
                        do
                        {
                            result = ((IAMOpenProgress)sourceFilter).QueryProgress(out total, out current);
                            Marshal.ThrowExceptionForHR(result);

                            percentageBuffered = (float)current / (float)total * 100.0f;
                            // after configured percentage has been buffered, connect the graph
                            if (!filterConnected && (percentageBuffered >= PluginConfiguration.Instance.playbuffer || skipBuffering))
                            {
                                //cacheFile = filterState.GetCacheFileName();
                                if (skipBuffering)
                                {
                                    Log.Instance.Debug("Buffering skipped at {0}%", percentageBuffered);
                                }
                                filterConnected  = true;
                                renderPinsThread = new Thread(delegate()
                                {
                                    try
                                    {
                                        Log.Instance.Debug("BufferFile : Rendering unconnected output pins of source filter ...");
                                        // add audio and video filter from MP Movie Codec setting section
                                        AddPreferredFilters(graphBuilder, sourceFilter);
                                        // connect the pin automatically -> will buffer the full file in cases of bad metadata in the file or request of the audio or video filter
                                        DirectShowUtil.RenderUnconnectedOutputPins(graphBuilder, sourceFilter);
                                        Log.Instance.Debug("BufferFile : Playback Ready.");
                                        PlaybackReady = true;
                                    }
                                    catch (ThreadAbortException)
                                    {
                                        Thread.ResetAbort();
                                        Log.Instance.Info("RenderUnconnectedOutputPins foribly aborted.");
                                    }
                                    catch (Exception ex)
                                    {
                                        Log.Instance.Warn(ex.Message);
                                        StopBuffering();
                                    }
                                })
                                {
                                    IsBackground = true, Name = "OVGraph"
                                };
                                renderPinsThread.Start();
                            }
                            // log every percent
                            if (current > last && current - last >= (double)total * 0.01)
                            {
                                Log.Instance.Debug("Buffering: {0}/{1} KB ({2}%)", current / 1024, total / 1024, (int)percentageBuffered);
                                last = current;
                            }
                            // set the percentage to a gui property, formatted according to percentage, so the user knows very early if anything is buffering
                            string formatString = "###";
                            if (percentageBuffered == 0f)
                            {
                                formatString = "0.0";
                            }
                            else if (percentageBuffered < 1f)
                            {
                                formatString = ".00";
                            }
                            else if (percentageBuffered < 10f)
                            {
                                formatString = "0.0";
                            }
                            else if (percentageBuffered < 100f)
                            {
                                formatString = "##";
                            }
                            GUIPropertyManager.SetProperty("#OnlineVideos.buffered", percentageBuffered.ToString(formatString, System.Globalization.CultureInfo.InvariantCulture));
                            Thread.Sleep(50); // no need to do this more often than 20 times per second
                        }while (!PlaybackReady && graphBuilder != null && !BufferingStopped);
                    }
                    else
                    {
                        // add audio and video filter from MP Movie Codec setting section
                        AddPreferredFilters(graphBuilder, sourceFilter);
                        // connect the pin automatically -> will buffer the full file in cases of bad metadata in the file or request of the audio or video filter
                        DirectShowUtil.RenderUnconnectedOutputPins(graphBuilder, sourceFilter);
                        percentageBuffered = 100.0f; // no progress reporting possible
                        GUIPropertyManager.SetProperty("#TV.Record.percent3", percentageBuffered.ToString());
                        PlaybackReady = true;
                    }
                }
            }
            catch (ThreadAbortException)
            {
                Thread.ResetAbort();
            }
            catch (OnlineVideosException)
            {
                throw;
            }
            catch (COMException comEx)
            {
                Log.Instance.Warn(comEx.ToString());

                string errorText = DirectShowLib.DsError.GetErrorText(comEx.ErrorCode);
                if (errorText != null)
                {
                    errorText = errorText.Trim();
                }
                if (!string.IsNullOrEmpty(errorText))
                {
                    throw new OnlineVideosException(errorText);
                }
            }
            catch (Exception ex)
            {
                Log.Instance.Warn(ex.ToString());
            }
            finally
            {
                if (sourceFilter != null)
                {
                    // the render pin thread was already started and is still runnning
                    if (renderPinsThread != null && (renderPinsThread.ThreadState & ThreadState.Stopped) == 0)
                    {
                        // buffering was stopped by the user -> abort the thread
                        if (BufferingStopped)
                        {
                            renderPinsThread.Abort();
                        }
                    }

                    // playback is not ready but the source filter is already downloading -> abort the operation
                    if (!PlaybackReady)
                    {
                        Log.Instance.Info("Buffering was aborted.");
                        if (sourceFilter is IAMOpenProgress)
                        {
                            ((IAMOpenProgress)sourceFilter).AbortOperation();
                        }
                        Thread.Sleep(100);                                    // give it some time
                        int result = graphBuilder.RemoveFilter(sourceFilter); // remove the filter from the graph to prevent lockup later in Dispose
                    }

                    // release the COM pointer that we created
                    DirectShowUtil.ReleaseComObject(sourceFilter);
                }
            }

            return(PlaybackReady);
        }