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)); }
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); } }
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)); }
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); }
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 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); }
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); }
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); }
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 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); }
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); }