private void InfoTimerTick(object source, ElapsedEventArgs args)
 {
     while (true)
     {
         try
         {
             // let's ignore the time here, for reasons detailed in VLCWrapperParsingUnit.cs around line 115
             float position = transcoder.GetPosition();
             StreamLog.Trace(context.Identifier, "VLCManagedInfo: calling NewPercentage with position {0}", position);
             calculator.NewPercentage(position);
             calculator.SaveStats(infoReference);
         }
         catch (Exception ex)
         {
             StreamLog.Warn(context.Identifier, "Failed to get VLC data", ex);
         }
     }
 }
        public bool Stop()
        {
            StreamLog.Debug(context.Identifier, "VLCManagedEncoder: Stopping transcoding");
            try
            {
                DataOutputStream.Close();
            }
            catch (Exception e)
            {
                StreamLog.Info(context.Identifier, "VLCManagedEncoder: Failed to close data output stream", e);
            }

            inputTimer.Enabled = false;
            StreamLog.Trace(context.Identifier, "VLCManagedEncoder: Trying to stop vlc");
            transcoder.StopTranscoding();
            transcoder = null;
            StreamLog.Debug(context.Identifier, "VLCManagedEncoder: Stopped transcoding");

            return(true);
        }
        public bool Start()
        {
            // setup input
            if (inputMethod == InputMethod.NamedPipe)
            {
                ((NamedPipe)transcoderInputStream).WaitTillReady();
                StreamLog.Info(context.Identifier, "VLCManagedEncoder: Copy stream of type {0} into transcoder input pipe", InputStream.ToString());
                StreamCopy.AsyncStreamCopy(InputStream, transcoderInputStream, "transinput");
            }

            // delay start of next unit till our output stream is ready
            StreamLog.Info(context.Identifier, "VLCManagedEncoder: Waiting till output named pipe is ready");
            ((NamedPipe)DataOutputStream).WaitTillReady();

            // TODO: wait for state machine

            // setup the data reading
            infoReference = new Reference <WebTranscodingInfo>(() => context.TranscodingInfo, x => { context.TranscodingInfo = x; });
            if (context.MediaInfo.Duration > 0)
            {
                StreamLog.Trace(context.Identifier, "VLCManagedInfo: duration known; is {0}", context.MediaInfo.Duration);
                calculator = new TranscodingInfoCalculator(context.StartPosition, 25, POLL_DATA_TIME, context.MediaInfo.Duration);
            }
            else
            {
                StreamLog.Trace(context.Identifier, "VLCManagedInfo: duration unknown");
                calculator = new TranscodingInfoCalculator(context.StartPosition, 25, POLL_DATA_TIME);
            }

            // and setup the timer
            inputTimer = new Timer()
            {
                AutoReset = true,
                Interval  = POLL_DATA_TIME
            };
            inputTimer.Elapsed += InfoTimerTick;
            inputTimer.Start();
            return(true);
        }
Beispiel #4
0
        public bool Start()
        {
            // wait for the input pipe to be ready
            if (transcoderInputStream is NamedPipe)
            {
                ((NamedPipe)transcoderInputStream).WaitTillReady();
            }

            // copy the inputStream to the transcoderInputStream
            if (doInputCopy)
            {
                StreamLog.Info(context.Identifier, "Encoding: Copy stream of type {0} into transcoder input stream of type {1}", InputStream.ToString(), transcoderInputStream.ToString());
                StreamCopy.AsyncStreamCopy(InputStream, transcoderInputStream, "transinput");
            }

            // delay start of next unit till our output stream is ready
            if (DataOutputStream is NamedPipe && (outputMethod == TransportMethod.NamedPipe || outputMethod == TransportMethod.StandardOut))
            {
                StreamLog.Trace(context.Identifier, "Transcoder running: {0}", !transcoderApplication.HasExited);
                StreamLog.Info(context.Identifier, "Encoding: Waiting till output named pipe is ready");

                var pipe        = (NamedPipe)DataOutputStream;
                var checkFailed = context != null && context.TranscodingInfo != null;
                while (!pipe.IsReady && !(checkFailed && context.TranscodingInfo.Failed))
                {
                    System.Threading.Thread.Sleep(100);
                }

                if (checkFailed && context.TranscodingInfo.Failed)
                {
                    StreamLog.Warn(context.Identifier, "Encoding: Aborting wait because transcoder application failed and will never setup output named pipe.");
                    return(false);
                }
            }

            return(true);
        }
        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;
        }
        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();
        }