public void BuildPipeline(StreamContext context, EncoderUnit.LogStream log) { // input bool doInputReader = context.Source.NeedsInputReaderUnit; if(doInputReader) { context.Pipeline.AddDataUnit(context.Source.GetInputReaderUnit(), 1); } // get parameters VLCParameters vlcparam = GenerateVLCParameters(context); string path = @"\#OUT#"; string sout = vlcparam.Sout.Replace("#OUT#", path); // generate vlc argument string var quotedArgList = vlcparam.Arguments.Select(x => x.Replace("\"", "\\\"")); string vlcArguments = "\"" + String.Join("\" \"", quotedArgList) + "\""; string arguments = GenerateArguments(vlcparam.Input, sout, vlcArguments); // add the unit EncoderUnit.TransportMethod input = doInputReader ? EncoderUnit.TransportMethod.NamedPipe : EncoderUnit.TransportMethod.Other; EncoderUnit.TransportMethod outputMethod = readOutputStream ? EncoderUnit.TransportMethod.NamedPipe : EncoderUnit.TransportMethod.Other; // waiting for output pipe is meaningless for VLC as it opens it way earlier then that it actually writes to it. Instead, log parsing // in VLCWrapped handles the delay (yes, this class is standalone probably useless but is provided for debugging). EncoderUnit unit = new EncoderUnit(context.Profile.CodecParameters["path"], arguments, input, outputMethod, log); unit.DebugOutput = false; // change this for debugging context.Pipeline.AddDataUnit(unit, 5); }
public override void BuildPipeline(StreamContext context) { base.BuildPipeline(context); // add metadata injection unit context.Pipeline.AddDataUnit(new FLVMetadataInjector(context), 15); }
public void BuildPipeline(StreamContext context) { // we ignore our arguments :) context.TranscodingInfo.Supported = false; context.Pipeline.AddDataUnit(context.Source.GetInputReaderUnit(), 1); return; }
public VLCManagedEncoder(string sout, string[] arguments, StreamContext context, InputMethod inputMethod) { this.sout = sout; this.arguments = arguments; this.inputMethod = inputMethod; this.context = context; }
public override void BuildPipeline(StreamContext context) { SetupAssemblyLoader(); // input bool doInputReader = context.Source.NeedsInputReaderUnit; if (doInputReader) { context.Pipeline.AddDataUnit(context.Source.GetInputReaderUnit(), 1); } // get parameters VLCParameters vlcparam = GenerateVLCParameters(context); int duration = (int)Math.Round((decimal)context.MediaInfo.Duration / 1000); // add the unit VLCManagedEncoder unit; if (doInputReader) { unit = new VLCManagedEncoder(vlcparam.Sout, vlcparam.Arguments, context, VLCManagedEncoder.InputMethod.NamedPipe); } else { unit = new VLCManagedEncoder(vlcparam.Sout, vlcparam.Arguments, context, VLCManagedEncoder.InputMethod.File, context.Source.GetPath()); } context.Pipeline.AddDataUnit(unit, 5); }
protected override Tuple<string, string> GetEncoderMuxerParameters(StreamContext context) { return new Tuple<string, string>( context.Profile.CodecParameters["encoder"], context.Profile.CodecParameters["muxer"].Replace("#ADDRESS#", String.Format(address, "")) ); }
public void StartStream(StreamContext context, Reference <WebTranscodingInfo> infoRef) { // ignore when not needed if (!enabled || (context.Source.MediaType != WebStreamMediaType.Movie && context.Source.MediaType != WebStreamMediaType.TVEpisode)) { return; } // do some cleanup foreach (string id in streams.Where(x => x.Value.Stale).Select(x => x.Value.Id).ToList()) { streams.Remove(id); } // generate identifier string identifier = GetIdentifierFromMediaSource(context.Source); // start if non-existent if (!streams.ContainsKey(identifier)) { StreamState state = new StreamState() { Id = identifier, Context = context, TranscodingInfo = infoRef, Canceled = false, Stale = false }; // get mediadescriptor and rough runtime Log.Debug("WatchSharing: synchronizing start watching event to service"); if (context.Source.MediaType == WebStreamMediaType.TVEpisode) { state.MediaDescriptor = MPEServices.MAS.GetTVEpisodeDetailedById(context.Source.Provider, context.Source.Id); state.Runtime = MPEServices.MAS.GetTVShowDetailedById(context.Source.Provider, ((WebTVEpisodeDetailed)state.MediaDescriptor).ShowId).Runtime * 60000; } else if (context.Source.MediaType == WebStreamMediaType.Movie) { state.MediaDescriptor = MPEServices.MAS.GetMovieDetailedById(context.Source.Provider, context.Source.Id); state.Runtime = ((WebMovieDetailed)state.MediaDescriptor).Runtime * 60000; } // get exact runtime if available if (context.MediaInfo.Duration > 60) { state.Runtime = (int)context.MediaInfo.Duration; } streams[identifier] = state; state.BackgroundThread = ThreadManager.Start("WatchWorker", new ParameterizedThreadStart(this.BackgroundWorker), identifier); } else { // just update the progress which will be send next time Log.Info("WatchSharing: Picking up old stream"); streams[identifier].Canceled = false; streams[identifier].Context = context; } }
public EncoderUnit(string transcoder, string arguments, TransportMethod inputMethod, TransportMethod outputMethod, LogStream logStream, StreamContext context) { this.transcoderPath = transcoder; this.arguments = arguments; this.inputMethod = inputMethod; this.outputMethod = outputMethod; this.logStream = logStream; this.context = context; }
public override void BuildPipeline(StreamContext context) { base.BuildPipeline(context, EncoderUnit.LogStream.StandardOut); // setup output parsing var einfo = new Reference<WebTranscodingInfo>(() => context.TranscodingInfo, x => { context.TranscodingInfo = x; }); VLCWrapperParsingUnit logunit = new VLCWrapperParsingUnit(einfo, context.MediaInfo, context.StartPosition); context.Pipeline.AddLogUnit(logunit, 6); }
public void BuildPipeline(StreamContext context) { this.context = context; obj.BuildPipeline(context); segmenterUnit = new HTTPLiveStreamingUnit(Identifier); segmenterUnit.DebugOutput = false; // change for debugging context.Pipeline.AddDataUnit(segmenterUnit, 20); }
public void RetrieveStreamCalled(StreamContext context) { WCFUtil.SetContentLength(context.Source.GetFileInfo().Size); // there has to be a better way to do this object mime = RegistryReader.ReadKey(Microsoft.Win32.RegistryHive.ClassesRoot, Path.GetExtension(context.Source.GetFileInfo().Name), "Content Type"); if (mime != null) { WCFUtil.SetContentType(mime.ToString()); } }
public void BuildPipeline(StreamContext context) { // add input bool doInputReader = context.Source.NeedsInputReaderUnit; if (doInputReader) { context.Pipeline.AddDataUnit(context.Source.GetInputReaderUnit(), 1); } // calculate stream mappings (no way I'm going to add subtitle support; it's just broken) string mappings = ""; if (context.AudioTrackId != null) { mappings = String.Format("-map v:0 -map a:{0}", context.MediaInfo.AudioStreams.First(x => x.ID == context.AudioTrackId).Index); } // calculate full argument string string arguments; bool doResize = !context.Profile.CodecParameters.ContainsKey("noResize") || context.Profile.CodecParameters["noResize"] != "true"; if (context.Profile.HasVideoStream && doResize) { arguments = String.Format( "-y {0} -i \"#IN#\" -s {1} -aspect {2}:{3} {4} {5} \"#OUT#\"", context.StartPosition != 0 ? "-ss " + (context.StartPosition / 1000) : "", context.OutputSize, context.OutputSize.Width, context.OutputSize.Height, mappings, context.Profile.CodecParameters["codecParameters"] ); } else { arguments = String.Format( "-y {0} -i \"#IN#\" {1} {2} \"#OUT#\"", context.StartPosition != 0 ? "-ss " + (context.StartPosition / 1000) : "", mappings, context.Profile.CodecParameters["codecParameters"] ); } // fix input thing if (!doInputReader) arguments = arguments.Replace("#IN#", context.Source.GetPath()); // add unit EncoderUnit.TransportMethod input = doInputReader ? EncoderUnit.TransportMethod.NamedPipe : EncoderUnit.TransportMethod.Other; EncoderUnit unit = new EncoderUnit(Configuration.Streaming.FFMpegPath, arguments, input, EncoderUnit.TransportMethod.NamedPipe, EncoderUnit.LogStream.StandardError); unit.DebugOutput = false; // change this for debugging context.Pipeline.AddDataUnit(unit, 5); // setup output parsing var einfo = new Reference<WebTranscodingInfo>(() => context.TranscodingInfo, x => { context.TranscodingInfo = x; }); FFMpegLogParsingUnit logunit = new FFMpegLogParsingUnit(einfo, context.StartPosition); logunit.LogMessages = true; logunit.LogProgress = true; context.Pipeline.AddLogUnit(logunit, 6); }
protected VLCParameters GenerateVLCParameters(StreamContext context) { var encmuxparam = GetEncoderMuxerParameters(context); return GenerateVLCParameters( context, context.Profile.CodecParameters.ContainsKey("options") ? context.Profile.CodecParameters["options"] : "", context.Profile.CodecParameters.ContainsKey("tsOptions") ? context.Profile.CodecParameters["tsOptions"] : "", context.Profile.CodecParameters.ContainsKey("disableSeeking") && context.Profile.CodecParameters["disableSeeking"] == "yes", encmuxparam.Item1, encmuxparam.Item2 ); }
public HTTPLiveStreamer(string identifier, StreamContext context) { Identifier = identifier; Context = context; // create temporary directory TemporaryDirectory = Path.Combine(Path.GetTempPath(), "MPExtended", "httplivestreaming-" + identifier + "-" + new Random().Next(100000, 999999)); if (Directory.Exists(TemporaryDirectory)) { Directory.Delete(TemporaryDirectory, true); } Directory.CreateDirectory(TemporaryDirectory); // parse the <httpLiveRemoveOld> config option now for a tiny performance boost if (Context.Profile.TranscoderParameters.ContainsKey("httpLiveRemoveOld")) Int32.TryParse(Context.Profile.TranscoderParameters["httpLiveRemoveOld"], out keepSegments); }
public HTTPLiveStreamer(string identifier, StreamContext context) { Identifier = identifier; Context = context; // create temporary directory TemporaryDirectory = Path.Combine(Path.GetTempPath(), "MPExtended", "httplivestreaming-" + identifier + "-" + new Random().Next(100000, 999999)); if (Directory.Exists(TemporaryDirectory)) { Directory.Delete(TemporaryDirectory, true); } Directory.CreateDirectory(TemporaryDirectory); // parse the <httpLiveRemoveOld> config option now for a tiny performance boost if (Context.Profile.TranscoderParameters.ContainsKey("httpLiveRemoveOld")) { Int32.TryParse(Context.Profile.TranscoderParameters["httpLiveRemoveOld"], out keepSegments); } }
public override void BuildPipeline(StreamContext context) { // VLC doesn't support output parsing, but subclasses do BuildPipeline(context, EncoderUnit.LogStream.None); }
public VLCHTTPLiveStreamer(string identifier, StreamContext context) : base(identifier, context) { }
protected virtual Tuple<string, string> GetEncoderMuxerParameters(StreamContext context) { return new Tuple<string, string>( context.Profile.CodecParameters["encoder"], context.Profile.CodecParameters["muxer"] ); }
public abstract void BuildPipeline(StreamContext context);
public Resolution CalculateSize(StreamContext context) { return CalculateSize(context.Profile, context.Source, context.MediaInfo); }
protected VLCParameters GenerateVLCParameters(StreamContext context, string options, string tsOptions, bool disableSeeking, string encoderOptions, string muxerOptions) { List<string> arguments = options.Split(' ').Where(x => x.Length > 0).ToList(); // input string inURL = ""; if (context.Source.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 { Log.Warn("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 = "#transcode{" + encoderOptions + ",width=" + context.OutputSize.Width + ",height=" + context.OutputSize.Height + "," + subtitleTranscoder + "}" + muxerOptions; // return return new VLCParameters() { Sout = sout, Arguments = arguments.ToArray(), Input = inURL }; }
public VLCManagedEncoder(string sout, string[] arguments, StreamContext context, InputMethod inputMethod, string input) : this(sout, arguments, context, inputMethod) { this.inputPath = input; }
public void StartStream(StreamContext context, Reference <WebTranscodingInfo> infoRef) { // ignore when not needed if (!enabled || (context.Source.MediaType != WebMediaType.Movie && context.Source.MediaType != WebMediaType.TVEpisode)) { return; } // do some cleanup foreach (string id in streams.Where(x => x.Value.Stale).Select(x => x.Value.Id).ToList()) { streams.Remove(id); } // generate identifier string identifier = GetIdentifierFromMediaSource(context.Source); // start if non-existent if (!streams.ContainsKey(identifier)) { StreamState state = new StreamState() { Id = identifier, Context = context, TranscodingInfo = infoRef, Canceled = false, Stale = false }; // get mediadescriptor and rough runtime Log.Debug("WatchSharing: synchronizing start watching event to service"); if (context.Source.MediaType == WebMediaType.TVEpisode) { state.MediaDescriptor = Connections.MAS.GetTVEpisodeDetailedById(context.Source.Provider, context.Source.Id); state.Runtime = Connections.MAS.GetTVShowDetailedById(context.Source.Provider, ((WebTVEpisodeDetailed)state.MediaDescriptor).ShowId).Runtime * 60000; } else if (context.Source.MediaType == WebMediaType.Movie) { state.MediaDescriptor = Connections.MAS.GetMovieDetailedById(context.Source.Provider, context.Source.Id); state.Runtime = ((WebMovieDetailed)state.MediaDescriptor).Runtime * 60000; } // get exact runtime if available if (context.MediaInfo.Duration > 60) { state.Runtime = (int)context.MediaInfo.Duration; } // send start watching event Task.Factory.StartNew(delegate() { if (state.Context.Source.MediaType == WebMediaType.TVEpisode) { services.ExecuteForAll(s => CallForEpisode(identifier, s.StartWatchingEpisode)); } else if (state.Context.Source.MediaType == WebMediaType.Movie) { services.ExecuteForAll(s => s.StartWatchingMovie((WebMovieDetailed)state.MediaDescriptor)); } }).LogOnException(); // and start the background timer streams[identifier] = state; state.BackgroundTimers = new List <WatchSharingTimer>(); foreach (IWatchSharingService service in services) { var thisTimer = new WatchSharingTimer(identifier, service); thisTimer.Elapsed += TimerElapsed; thisTimer.Start(); state.BackgroundTimers.Add(thisTimer); } } else { // just update the progress which will be send next time Log.Info("WatchSharing: Picking up old stream"); streams[identifier].Canceled = false; streams[identifier].Context = context; } }
public Resolution CalculateSize(StreamContext context) { return(CalculateSize(context.Profile, context.Source, context.MediaInfo)); }
public void StartStream(StreamContext context, Reference<WebTranscodingInfo> infoRef) { // ignore when not needed if (!enabled || (context.Source.MediaType != WebStreamMediaType.Movie && context.Source.MediaType != WebStreamMediaType.TVEpisode)) { return; } // do some cleanup foreach (string id in streams.Where(x => x.Value.Stale).Select(x => x.Value.Id).ToList()) { streams.Remove(id); } // generate identifier string identifier = GetIdentifierFromMediaSource(context.Source); // start if non-existent if (!streams.ContainsKey(identifier)) { StreamState state = new StreamState() { Id = identifier, Context = context, TranscodingInfo = infoRef, Canceled = false, Stale = false }; // get mediadescriptor and rough runtime Log.Debug("WatchSharing: synchronizing start watching event to service"); if (context.Source.MediaType == WebStreamMediaType.TVEpisode) { state.MediaDescriptor = MPEServices.MAS.GetTVEpisodeDetailedById(context.Source.Provider, context.Source.Id); state.Runtime = MPEServices.MAS.GetTVShowDetailedById(context.Source.Provider, ((WebTVEpisodeDetailed)state.MediaDescriptor).ShowId).Runtime * 60000; } else if (context.Source.MediaType == WebStreamMediaType.Movie) { state.MediaDescriptor = MPEServices.MAS.GetMovieDetailedById(context.Source.Provider, context.Source.Id); state.Runtime = ((WebMovieDetailed)state.MediaDescriptor).Runtime * 60000; } // get exact runtime if available if (context.MediaInfo.Duration > 60) { state.Runtime = (int)context.MediaInfo.Duration; } streams[identifier] = state; state.BackgroundThread = ThreadManager.Start("WatchWorker", new ParameterizedThreadStart(this.BackgroundWorker), identifier); } else { // just update the progress which will be send next time Log.Info("WatchSharing: Picking up old stream"); streams[identifier].Canceled = false; streams[identifier].Context = context; } }
public FLVMetadataInjector(StreamContext context) { this.context = context; }
public abstract void BuildPipeline(StreamContext context, int position);
protected VLCParameters GenerateVLCParameters(StreamContext context, int position) { List<string> arguments = context.Profile.CodecParameters["options"].Split(' ').Where(x => x.Length > 0).ToList(); // input string inURL = ""; if (context.Pipeline.GetDataUnit(1) != null && context.Pipeline.GetDataUnit(1) is InputUnit) { inURL = "stream://#IN#"; } else { inURL = context.Source.GetPath(); } // add tv options if specified if (context.IsTv && context.Profile.CodecParameters.ContainsKey("tvOptions") && context.Profile.CodecParameters["tvOptions"].Length > 0) { arguments.AddRange(context.Profile.CodecParameters["tvOptions"].Split(' ').Where(x => x.Length > 0)); } // position if (position > 0) { // FIXME: temporary allow disabling it as it breaks some profiles if (!context.Profile.CodecParameters.ContainsKey("disableSeeking") || context.Profile.CodecParameters["disableSeeking"] == "no") { arguments.Add("--start-time=" + position); } } // audio track if (context.AudioTrackId != null) { arguments.Add("--audio-track=" + context.MediaInfo.AudioStreams.Where(x => x.ID == context.AudioTrackId).First().Index); } else { Log.Warn("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 = "#transcode{" + context.Profile.CodecParameters["encoder"] + ",width=" + context.OutputSize.Width + ",height=" + context.OutputSize.Height + "," + subtitleTranscoder + "}" + context.Profile.CodecParameters["muxer"]; // return return new VLCParameters() { Sout = sout, Arguments = arguments.ToArray(), Input = inURL }; }
public EncoderUnit(string transcoder, string arguments, TransportMethod inputMethod, TransportMethod outputMethod, LogStream logStream, StreamContext context) : this(transcoder, arguments, inputMethod, outputMethod, logStream) { this.context = context; }
public FFMpegHTTPLiveStreamer(string identifier, StreamContext context) : base(identifier, context) { indexUrl = WCFUtil.GetCurrentRoot() + "StreamingService/stream/CustomTranscoderData?identifier=" + identifier + "&action=segment¶meters="; }