Beispiel #1
0
        public override Stream ProvideCustomActionFile(string action, string param)
        {
            if (action == "playlist")
            {
                WCFUtil.SetContentType("application/vnd.apple.mpegurl");
                string playlistPath = Path.Combine(TemporaryDirectory, "index.m3u8");
                if (!File.Exists(playlistPath))
                {
                    StreamLog.Warn(Identifier, "HTTPLiveStreamer: Client requested index.m3u8 that doesn't exist for identifier '{0}'", Identifier);
                    return(Stream.Null);
                }

                // FFMpeg outputs the local segment paths in the playlist, replace with url
                string playlist = ReplacePathsWithURLs(playlistPath);
                if (playlist == string.Empty)
                {
                    // The playlist file is empty until the first segment has finished being encoded,
                    // wait for next segment to begin and retry.
                    string segmentPath = Path.Combine(TemporaryDirectory, "000001.ts");
                    while (!File.Exists(segmentPath))
                    {
                        System.Threading.Thread.Sleep(100);
                    }
                    playlist = ReplacePathsWithURLs(playlistPath);
                }
                return(new MemoryStream(Encoding.UTF8.GetBytes(playlist)));
            }

            return(base.ProvideCustomActionFile(action, param));
        }
 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);
         }
     }
 }
Beispiel #3
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);
        }
Beispiel #4
0
        protected virtual VLCParameters GenerateVLCParameters(string options, string tsOptions, bool disableSeeking, string encoderOptions, string tsEncoderOptions, string muxerOptions)
        {
            List <string> arguments = options.Split(' ').Where(x => x.Length > 0).ToList();

            // input
            string inURL = "";

            if (Context.NeedsInputReaderUnit)
            {
                inURL = @"stream://\#IN#";
            }
            else
            {
                inURL = Context.Source.GetPath();
            }

            // add tv options if specified
            if ((Context.IsTv || Context.MediaInfo.Container == "MPEG-TS") && tsOptions.Length > 0)
            {
                arguments.AddRange(tsOptions.Split(' ').Where(x => x.Length > 0));
            }

            // position (disabling this is probably a bad idea as some things (watch sharing, transcoding info) fail then, which results in faulty clients.)
            if (Context.StartPosition > 0 && !disableSeeking)
            {
                arguments.Add("--start-time=" + (Context.StartPosition / 1000));
            }

            // audio track
            if (Context.AudioTrackId != null)
            {
                arguments.Add("--audio-track=" + Context.MediaInfo.AudioStreams.Where(x => x.ID == Context.AudioTrackId).First().Index);
            }
            else
            {
                StreamLog.Warn(Identifier, "VLC streaming without audio track is not implemented yet");
            }

            // subtitle selection
            string subtitleTranscoder;

            if (Context.SubtitleTrackId == null)
            {
                subtitleTranscoder = "scodec=none";
            }
            else
            {
                WebSubtitleStream stream = Context.MediaInfo.SubtitleStreams.First(x => x.ID == Context.SubtitleTrackId);
                if (stream.Filename != null)
                {
                    arguments.Add("--sub-file=" + stream.Filename);
                }
                else
                {
                    arguments.Add("--sub-track=" + stream.Index);
                }
                subtitleTranscoder = "soverlay";
            }

            // create parameters
            string sout;

            if (!String.IsNullOrEmpty(encoderOptions))
            {
                sout = "#transcode{" + encoderOptions + "," + subtitleTranscoder;
                if ((Context.IsTv || Context.MediaInfo.Container == "MPEG-TS") && !String.IsNullOrEmpty(tsEncoderOptions))
                {
                    sout += "," + tsEncoderOptions;
                }
                if (!Context.Profile.TranscoderParameters.ContainsKey("noResize") || Context.Profile.TranscoderParameters["noResize"] != "yes")
                {
                    sout += ",width=" + Context.OutputSize.Width + ",height=" + Context.OutputSize.Height;
                }
                sout += "}" + muxerOptions;
            }
            else
            {
                sout = "#" + muxerOptions.Substring(1);
            }

            // return
            return(new VLCParameters()
            {
                Sout = sout,
                Arguments = arguments.ToArray(),
                Input = inURL
            });
        }
        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();
        }