Пример #1
0
        public WebBoolResult InitStream(WebMediaType type, int?provider, string itemId, int?offset, string clientDescription, string identifier, int?idleTimeout)
        {
            AuthorizeStreaming();
            if (type == WebMediaType.TV)
            {
                int channelId = Int32.Parse(itemId);
                lock (_timeshiftings)
                {
                    StreamLog.Info(identifier, "Starting timeshifting on channel {0} for client {1}", channelId, clientDescription);
                    var card = Connections.TAS.SwitchTVServerToChannelAndGetVirtualCard("mpextended-" + identifier, channelId);
                    if (card == null)
                    {
                        StreamLog.Error(identifier, "Failed to start timeshifting for stream");
                        return(false);
                    }
                    else
                    {
                        StreamLog.Debug(identifier, "Timeshifting started!");
                        _timeshiftings[identifier] = card;
                        itemId = card.TimeShiftFileName;
                    }
                }
            }

            StreamLog.Info(identifier, "Called InitStream with type={0}; provider={1}; itemId={2}; offset={3}; clientDescription={4}; idleTimeout={5}",
                           type, provider, itemId, offset, clientDescription, idleTimeout);
            return(_stream.InitStream(identifier, clientDescription, new MediaSource(type, provider, itemId, offset), idleTimeout.HasValue ? idleTimeout.Value : 5 * 60));
        }
Пример #2
0
 public bool Setup()
 {
     try
     {
         using (var context = NetworkContextFactory.CreateImpersonationContext())
         {
             DataOutputStream = new FileStream(context.RewritePath(source), FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
         }
     }
     catch (Exception e)
     {
         StreamLog.Error(identifier, "Failed to setup ImpersonationInputUnit", e);
         return(false);
     }
     return(true);
 }
Пример #3
0
 public bool Setup()
 {
     try
     {
         if (source.IndexOf(".ts.tsbuffer") != -1)
         {
             StreamLog.Info(identifier, "Using TsBuffer to read input");
             DataOutputStream = new TsBuffer(this.source);
         }
         else
         {
             StreamLog.Info(identifier, "Using FileStream to read input");
             DataOutputStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
         }
     }
     catch (Exception e)
     {
         StreamLog.Error(identifier, "Failed to setup InputProcessingUnit", e);
         return(false);
     }
     return(true);
 }
Пример #4
0
 public bool Setup()
 {
     data.Value.Failed = false;
     vlcIsStarted      = false;
     processThread     = new Thread(delegate()
     {
         try
         {
             ParseOutputStream(InputStream, data, position, false);
         }
         catch (ThreadAbortException)
         {
         }
         catch (Exception ex)
         {
             StreamLog.Error(identifier, "VLCLogParsing failed with exception", ex);
         }
     });
     processThread.Name = "VLCLogParsing";
     processThread.Start();
     return(true);
 }
Пример #5
0
        public bool Stop()
        {
            // close streams
            CloseStream(InputStream, "input");
            CloseStream(transcoderInputStream, "transcoder input");
            CloseStream(DataOutputStream, "transcoder output");

            try
            {
                if (transcoderApplication != null && !transcoderApplication.HasExited)
                {
                    StreamLog.Debug(context.Identifier, "Encoding: Killing transcoder");
                    transcoderApplication.Stop();
                }
            }
            catch (Exception e)
            {
                StreamLog.Error(context.Identifier, "Encoding: Failed to kill transcoder", e);
            }

            return(true);
        }
Пример #6
0
 public bool Setup()
 {
     // this might be better placed in the Start() method, but EncoderUnit.Start() depends on this
     data.Value.Supported = true;
     data.Value.Failed    = false;
     processThread        = new Thread(delegate()
     {
         try
         {
             ParseOutputStream(InputStream, data, startPosition, LogMessages, LogProgress, identifier);
         }
         catch (ThreadAbortException)
         {
             // ThreadAbortException is already handled in ParseOutputStream, but rethrown when the method is left. Don't be noisy.
         }
         catch (Exception ex)
         {
             StreamLog.Error(identifier, "FFMpegLogParsing brutally came to an end", ex);
         }
     });
     processThread.Name = "FFMpegLog";
     processThread.Start();
     return(true);
 }
Пример #7
0
        private bool SpawnTranscoder(bool needsStdin, bool needsStdout)
        {
            ProcessStartInfo start = new ProcessStartInfo(transcoderPath, arguments);

            start.UseShellExecute        = false;
            start.RedirectStandardInput  = needsStdin;
            start.RedirectStandardOutput = needsStdout || (!DebugOutput && logStream == LogStream.StandardOut && IsLogStreamConnected);
            start.RedirectStandardError  = !DebugOutput && logStream == LogStream.StandardError && IsLogStreamConnected;
            start.WindowStyle            = DebugOutput ? ProcessWindowStyle.Normal : ProcessWindowStyle.Hidden;
            start.CreateNoWindow         = !DebugOutput;

            StreamLog.Info(context.Identifier, "Encoder: Transcoder configuration dump");
            StreamLog.Info(context.Identifier, "Encoder:   hasStdin {0}, hasStdout {1}, hasStderr {2}", start.RedirectStandardInput, start.RedirectStandardOutput, start.RedirectStandardError);
            StreamLog.Info(context.Identifier, "Encoder:   path {0}", transcoderPath);
            StreamLog.Info(context.Identifier, "Encoder:   arguments {0}", arguments);

            try
            {
                transcoderApplication           = new TranscoderProcess();
                transcoderApplication.StartInfo = start;
                if (context.Source.NeedsImpersonation)
                {
                    transcoderApplication.StartAsUser(Configuration.Services.NetworkImpersonation.Domain, Configuration.Services.NetworkImpersonation.Username, Configuration.Services.NetworkImpersonation.GetPassword());
                }
                else
                {
                    transcoderApplication.Start();
                }
            }
            catch (Win32Exception e)
            {
                StreamLog.Error(context.Identifier, "Encoding: Failed to start transcoder", e);
                return(false);
            }
            return(true);
        }
Пример #8
0
        private static void ParseOutputStream(Stream outputStream, Reference <WebTranscodingInfo> saveData, long startPosition, bool logMessages, bool logProgress, string identifier)
        {
            StreamReader reader = new StreamReader(outputStream);

            string line;

            while ((line = reader.ReadLine()) != null)
            {
                try
                {
                    bool canBeErrorLine = true;

                    if (line.StartsWith("frame="))
                    {
                        // format of an output line (yes, we're doomed as soon as ffmpeg changes it output):
                        // frame=  923 fps=256 q=31.0 size=    2712kB time=00:05:22.56 bitrate= 601.8kbits/s
                        Match match = Regex.Match(line, @"frame=([ 0-9]*) fps=([ 0-9]*) q=[^ ]* L?size=([ 0-9]*)kB time=([0-9]{2}):([0-9]{2}):([0-9]{2})\.[0-9]{2} bitrate=([ .0-9]*)kbits/s", RegexOptions.IgnoreCase);
                        if (match.Success)
                        {
                            canBeErrorLine = false;
                            lock (saveData)
                            {
                                saveData.Value.TranscodedTime      = (Int32.Parse(match.Groups[4].Value) * 3600 + Int32.Parse(match.Groups[5].Value) * 60 + Int32.Parse(match.Groups[6].Value)) * 1000;
                                saveData.Value.TranscodedFrames    = Int32.Parse(match.Groups[1].Value);
                                saveData.Value.TranscodingPosition = startPosition + saveData.Value.TranscodedTime;
                                saveData.Value.TranscodingFPS      = Int32.Parse(match.Groups[2].Value);
                                saveData.Value.OutputBitrate       = (int)Math.Round(Decimal.Parse(match.Groups[7].Value, System.Globalization.CultureInfo.InvariantCulture));
                            }

                            if (!logProgress) // we don't log output
                            {
                                continue;
                            }
                        }
                    }

                    if (line.StartsWith("video:"))
                    {
                        // process the result line to see if it completed successfully (example):
                        // video:5608kB audio:781kB global headers:0kB muxing overhead 13.235302%
                        Match resultMatch = Regex.Match(line, @"video:([0-9]*)kB audio:([0-9]*)kB global headers:([0-9]*)kB muxing overhead[^%]*%", RegexOptions.IgnoreCase);
                        saveData.Value.Finished = true;
                        canBeErrorLine          = false;
                    }

                    // show error messages
                    if (logMessages && canBeErrorLine)
                    {
                        StreamLog.Trace(identifier, "ffmpeg: " + line);
                    }
                }
                catch (ThreadAbortException)
                {
                    saveData.Value.Failed   = true;
                    saveData.Value.Finished = true;
                    reader.Close();
                    return;
                }
                catch (Exception e)
                {
                    StreamLog.Error(identifier, "Failure during parsing of ffmpeg output", e);
                }
            }

            saveData.Value.Finished = true;
            reader.Close();
            return;
        }
Пример #9
0
        private void ParseOutputStream(Stream stdoutStream, Reference <WebTranscodingInfo> data, long startPosition, bool logProgress)
        {
            StreamReader reader = new StreamReader(stdoutStream);
            TranscodingInfoCalculator calculator = new TranscodingInfoCalculator(position, 25, 500, info.Duration); //VLCWrapper prints twice a second

            string line;

            try
            {
                while ((line = reader.ReadLine()) != null)
                {
                    try
                    {
                        StreamLog.Trace(identifier, "VLCWrapperParsing: read line {0}", line);

                        // just for debugging of the wrapper tool
                        if (line.StartsWith("A") || line.StartsWith("I") || line == "S started" || line == "S null")
                        {
                            continue;
                        }

                        // propagate start event to Start() method
                        if (line == "S playing")
                        {
                            vlcIsStarted = true;
                            continue;
                        }

                        // events
                        if (line == "S error")
                        {
                            vlcIsStarted        = true;
                            data.Value.Finished = true;
                            data.Value.Failed   = true;
                            break;
                        }

                        if (line == "S finished")
                        {
                            data.Value.Finished = true;
                            continue;
                        }

                        // the actual progress parsing
                        if (line.StartsWith("P"))
                        {
                            // Starting with VLCWrapper 0.2, the output format has changed. It is 'P [time in milliseconds]' now, which is quite easy for
                            // us to handle. With VLC 2 it also returns the time as a 64-bit integer, so we don't have overflow anymore either, but that risk
                            // is with milliseconds quite small anyhow: it requires 596 hours of video.
                            long milliseconds = Int64.Parse(line.Substring(2));
                            calculator.NewTime((int)milliseconds);
                            calculator.SaveStats(data);
                            continue;
                        }

                        StreamLog.Warn(identifier, "VLCWrapperParsing: encountered unknown line {0}", line);
                    }
                    catch (ThreadAbortException)
                    {
                        data.Value.Finished = true;
                        reader.Close();
                        return;
                    }
                    catch (Exception e)
                    {
                        StreamLog.Error(identifier, "Failure during parsing of VLC output", e);
                    }
                }
            }
            catch (ThreadAbortException)
            {
                // The double try-catch is to make sure that the parsing doesn't stop when it can't process a single line, but that we don't
                // log too much noise when a ThreadAbortException occurs while in the ReadLine() method. Funnily enough, this exception is
                // rethrown when we leave the catch block, so duplicate some code from below...
                data.Value.Finished = true;
                reader.Close();
                return;
            }

            data.Value.Finished = true;
            reader.Close();
        }