示例#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
 private void CloseStream(Stream stream, string logName)
 {
     try
     {
         if (stream != null)
         {
             stream.Close();
         }
     }
     catch (Exception e)
     {
         StreamLog.Info(context.Identifier, "Encoding: Failed to close {0} stream: {1}", logName, e.Message);
     }
 }
示例#3
0
        public Stream DoStream(WebMediaType type, int?provider, string itemId, string clientDescription, string profileName, long startPosition, int?idleTimeout)
        {
            if (!IsClientAuthorized())
            {
                Log.Warn("Host {0} isn't authorized to call DoStream", WCFUtil.GetClientIPAddress());
                WCFUtil.SetResponseCode(HttpStatusCode.Unauthorized);
                return(Stream.Null);
            }

            // calculate timeout, which is by default 5 minutes for direct streaming and 5 seconds for transcoded streams
            var profile = Configuration.StreamingProfiles.Transcoders.FirstOrDefault(x => x.Name == profileName);

            if (profile == null)
            {
                Log.Warn("Called DoStream with non-existing profile {0}", profileName);
                return(Stream.Null);
            }
            int timeout = profile.Transcoder == typeof(Transcoders.Direct).FullName ? 5 * 60 : 5;

            if (idleTimeout.HasValue)
            {
                timeout = idleTimeout.Value;
            }

            // This only works with profiles that actually return something in the RetrieveStream method (i.e. no RTSP or CustomTranscoderData)
            string identifier = String.Format("dostream-{0}", new Random().Next(10000, 99999));

            StreamLog.Debug(identifier, "DoStream: using timeout={0}", timeout);

            if (!InitStream(type, provider, itemId, null, clientDescription, identifier, timeout))
            {
                StreamLog.Info(identifier, "DoStream: InitStream() failed");
                FinishStream(identifier);
                return(Stream.Null);
            }

            if (String.IsNullOrEmpty(StartStream(identifier, profileName, startPosition)))
            {
                StreamLog.Info(identifier, "DoStream: StartStream failed");
                FinishStream(identifier);
                return(Stream.Null);
            }

            StreamLog.Info(identifier, "DoStream: succeeded, returning stream");
            return(RetrieveStream(identifier));
        }
示例#4
0
        public WebBoolResult FinishStream(string identifier)
        {
            StreamLog.Debug(identifier, "Called FinishStream");
            _stream.KillStream(identifier);

            lock (_timeshiftings)
            {
                if (_timeshiftings.ContainsKey(identifier) && _timeshiftings[identifier] != null)
                {
                    StreamLog.Info(identifier, "Cancelling timeshifting");
                    Connections.TAS.CancelCurrentTimeShifting("mpextended-" + identifier);
                    _timeshiftings.Remove(identifier);
                }
            }

            return(true);
        }
示例#5
0
        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);
        }
示例#6
0
        public bool Setup()
        {
            // setup output named pipe
            DataOutputStream = new NamedPipe();
            string output = ((NamedPipe)DataOutputStream).Url;

            StreamLog.Info(context.Identifier, "VLCManagedEncoder: starting output named pipe {0}", output);
            ((NamedPipe)DataOutputStream).Start(false);

            // prepare sout, needs some trickery for vlc
            string realSout = sout.Replace("#OUT#", @"\" + output);

            // debug
            StreamLog.Debug(context.Identifier, "VLCManagedEncoder: sout {0}", realSout);
            StreamLog.Debug(context.Identifier, "VLCManagedEncoder: arguments {0}", String.Join("|", arguments));

            // start vlc
            transcoder = new VLCTranscoder();
            transcoder.SetArguments(arguments);
            transcoder.SetMediaName(Guid.NewGuid().ToString());
            transcoder.SetSout(realSout);

            // setup input
            if (inputMethod == InputMethod.NamedPipe)
            {
                transcoderInputStream = new NamedPipe();
                StreamLog.Info(context.Identifier, "VLCManagedEncoder: starting input named pipe {0}", transcoderInputStream);
                ((NamedPipe)transcoderInputStream).Start(false);
                inputPath = "stream://" + transcoderInputStream.Url; // use special syntax for VLC to pick up named pipe
            }
            StreamLog.Debug(context.Identifier, "VLCManagedEncoder: input {0}", inputPath);
            transcoder.SetInput(inputPath);

            // start transcoding
            transcoder.StartTranscoding();
            // doesn't work
            //transcoder.Seek(startPos * 1.0 / context.MediaInfo.Duration * 1000);

            context.TranscodingInfo.Supported = true;
            return(true);
        }
示例#7
0
        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);
        }
示例#8
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);
 }
示例#9
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);
        }
示例#10
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);
        }
示例#11
0
        public bool Setup()
        {
            // sets up streams
            string input       = "";
            string output      = "";
            bool   needsStdin  = false;
            bool   needsStdout = false;

            // input
            if (inputMethod == TransportMethod.NamedPipe)
            {
                transcoderInputStream = new NamedPipe();
                input = ((NamedPipe)transcoderInputStream).Url;
                StreamLog.Info(context.Identifier, "Encoding: starting input named pipe {0}", input);
                ((NamedPipe)transcoderInputStream).Start(false);
                doInputCopy = true;
            }
            else if (inputMethod == TransportMethod.StandardIn)
            {
                needsStdin  = true;
                doInputCopy = true;
            }

            // output stream
            if (outputMethod == TransportMethod.NamedPipe)
            {
                DataOutputStream = new NamedPipe();
                output           = ((NamedPipe)DataOutputStream).Url;
                StreamLog.Info(context.Identifier, "Encoding: starting output named pipe {0}", output);
                ((NamedPipe)DataOutputStream).Start(false);
            }
            else if (outputMethod == TransportMethod.StandardOut)
            {
                needsStdout = true;
            }

            // arguments substitution
            arguments = arguments.Replace("#IN#", input).Replace("#OUT#", output);

            // start transcoder
            if (!SpawnTranscoder(needsStdin, needsStdout))
            {
                return(false);
            }

            // finish stream setup
            if (inputMethod == TransportMethod.StandardIn)
            {
                transcoderInputStream = transcoderApplication.StandardInput.BaseStream;
            }
            if (outputMethod == TransportMethod.StandardOut)
            {
                DataOutputStream = transcoderApplication.StandardOutput.BaseStream;
            }

            // setup log stream
            if (!DebugOutput && logStream == LogStream.StandardOut && IsLogStreamConnected && outputMethod != TransportMethod.StandardOut)
            {
                LogOutputStream = transcoderApplication.StandardOutput.BaseStream;
            }
            else if (!DebugOutput && logStream == LogStream.StandardError && IsLogStreamConnected)
            {
                LogOutputStream = transcoderApplication.StandardError.BaseStream;
            }
            else
            {
                LogOutputStream = new MemoryStream(4096);
            }

            return(true);
        }