private async void Transcode(Movie movie, Transcode transcodeProfile, Server server, string callbackUrl) { var client = new SshClient(server.Ip, "root", server.RootPassword); try { string successCallbackUrl = callbackUrl.Replace("STATE", StreamState.Ready.ToString()); var options = new Dictionary <string, string> { { "hls_time", "4" }, { "hls_playlist_type", "vod" } }; string transcoder = FFMPEGCommand.MakeCommand(transcodeProfile, movie.Source, $"/var/hls/{movie.StreamKey}", options); string prepareCommand = $"mkdir /var/hls/{movie.StreamKey}"; prepareCommand += $" && cd /var/hls/{movie.StreamKey}"; prepareCommand += $" && mkdir 1080p 720p 480p 360p"; client.Connect(); client.RunCommand(prepareCommand); var cmd = client.CreateCommand($"nohup sh -c '{transcoder} && curl -i -X GET {successCallbackUrl}' >/dev/null 2>&1 & echo $!"); var result = cmd.Execute(); int pid = int.Parse(result); client.RunCommand($"disown -h {pid}"); client.Disconnect(); client.Dispose(); } catch (Exception) { string failCallbackUrl = callbackUrl.Replace("STATE", StreamState.Error.ToString()); var httpClient = new HttpClient(); await httpClient.GetAsync(failCallbackUrl); } }
public async Task <IActionResult> Edit(int id) { var channel = await channelRepository.GetById(id, new string[] { "ChannelServers" }); if (channel != null) { if (channel.SourceTranscodedCount < channel.SourceCount) { channel.SourceTranscodedCount++; } if (channel.SourceCount == channel.SourceTranscodedCount) { var server = await serverRepository.GetById(channel.ChannelServers.FirstOrDefault().ServerId); ThreadPool.QueueUserWorkItem(queue => { try { string input = $"/var/hls/{channel.StreamKey}/sources/RESOLUTION/source_list.txt"; string output = $"/var/hls/{channel.StreamKey}"; List <string> transcoders = FFMPEGCommand.ChannelCommand(input, output); var client = new SshClient(server.Ip, "root", server.RootPassword); client.Connect(); foreach (var transcoder in transcoders) { var cmd = client.CreateCommand($"nohup {transcoder} >/dev/null 2>&1 & echo $!"); var result = cmd.Execute(); int pid = int.Parse(result); client.RunCommand($"disown -h {pid}"); } client.Disconnect(); client.Dispose(); } catch { } }); channel.State = StreamState.Live; await hub.Clients.All.SendAsync("UpdateSignal", new { id, state = (int)StreamState.Live }); } await channelRepository.Edit(channel); } return(Ok()); }
public async Task Update(int sourceId, StreamState state) { var stream = await streamRepository.GetById(sourceId, new string[] { "StreamServers", "StreamServers.Server", "Transcode" }); if (stream == null) { return; } if (stream.State == state) { return; } if (state == StreamState.Live) { var options = new Dictionary <string, string> { { "hls_time", "4" }, { "hls_playlist_type", "event" } }; if (!stream.Record) { options.Add("hls_flags", "delete_segments"); } string transcode = FFMPEGCommand.MakeCommand(stream.Transcode, stream.Source, $"/var/hls/{stream.StreamKey}", options); string prepareCommand = $"mkdir /var/hls/{stream.StreamKey}"; prepareCommand += $" && cd /var/hls/{stream.StreamKey}"; prepareCommand += $" && mkdir 1080p 720p 480p 360p"; stream.StreamServers = (List <StreamServer>)Start((IList <StreamServer>)stream.StreamServers, prepareCommand, transcode); } else if (state == StreamState.Stopped) { string prepareCommand = $"rm -rf /var/hls/{stream.StreamKey}"; stream.StreamServers = (List <StreamServer>)Stop((IList <StreamServer>)stream.StreamServers, prepareCommand); } stream.State = state; await streamRepository.Edit(stream); await Clients.All.SendAsync("Update", new { sourceId, state = (int)state }); }
private async void Transcode(Channel channel, Transcode transcodeProfile, Server server, string callbackUrl) { var client = new SshClient(server.Ip, "root", server.RootPassword); try { string successCallbackUrl = callbackUrl.Replace("/STATE", string.Empty); string streamDirectory = $"/var/hls/{channel.StreamKey}"; string prepareCommand = $"mkdir {streamDirectory}"; string[] resolutions = new string[] { "1080p", "720p", "480p", "360p" }; prepareCommand += $" && cd {streamDirectory}"; prepareCommand += " && mkdir 1080p 720p 480p 360p sources"; prepareCommand += " && cd sources"; prepareCommand += " && mkdir 1080p 720p 480p 360p"; foreach (string resolution in resolutions) { StringBuilder sourceList = new StringBuilder(); for (int i = 0; i < channel.SourcePath.Length; i++) { sourceList.Append($"file '{streamDirectory}/sources/{resolution}/{i}.ts'\n"); } prepareCommand += $" && printf \"{sourceList}\" > {streamDirectory}/sources/{resolution}/source_list.txt"; } client.Connect(); client.RunCommand(prepareCommand); for (int i = 0; i < channel.SourcePath.Length; i++) { var options = new Dictionary <string, string> { { "custom_output", string.Empty }, { "custom_output_1080p", $"{streamDirectory}/sources/1080p/{i}.ts" }, { "custom_output_720p", $"{streamDirectory}/sources/720p/{i}.ts" }, { "custom_output_480p", $"{streamDirectory}/sources/480p/{i}.ts" }, { "custom_output_360p", $"{streamDirectory}/sources/360p/{i}.ts" } }; string transcoder = FFMPEGCommand.MakeCommand(transcodeProfile, channel.SourcePath[i], string.Empty, options); var cmd = client.CreateCommand($"nohup sh -c '{transcoder} && curl -i -X GET {successCallbackUrl}' >/dev/null 2>&1 & echo $!"); var result = cmd.Execute(); int pid = int.Parse(result); client.RunCommand($"disown -h {pid}"); } client.Disconnect(); client.Dispose(); } catch (Exception) { string failCallbackUrl = callbackUrl.Replace("STATE", StreamState.Error.ToString()); var httpClient = new HttpClient(); await httpClient.GetAsync(failCallbackUrl); } }
public CommandBase(string executePath) { FFMPEGCommand = new FFMPEGCommand(executePath); }
public string WritePart() { FFMPEGCommand.AddInput(VideoPath); FFMPEGCommand.AddInput(AudioPath); /* * FFMPEGCommand.AddFlag(new SimpleFlag("filter_complex", "[0:a][1:a]amix=duration=first[aout]")); */ FilterComplexExpression fadeExpression = new FilterComplexExpression() .AddInputIdentifier("1:a") .AddFilter(new Filter() .SetName("volume") .SetValue(AudioVolume.ToString())) .AddFilter(new Filter() .SetName("afade") .AddAttribute("t", "in") .AddAttribute("st", "0") .AddAttribute("d", AudioFadeDuration.ToString())) .AddFilter(new Filter() .SetName("afade") .AddAttribute("t", "out") .AddAttribute("st", (VideoDuration - AudioFadeDuration).ToString()) .AddAttribute("d", AudioFadeDuration.ToString())) .SetOutputIdentifier("afaded"); FilterComplexExpression mixExpression = new FilterComplexExpression() .AddInputIdentifier("0:a") .AddInputIdentifier("afaded") .AddFilter(new Filter() .SetName("amix") .AddAttribute("duration", "first")) .SetOutputIdentifier("acompressed"); /* Audio Compressor. */ FilterComplexExpression compressorExpression = new FilterComplexExpression() .AddInputIdentifier("acompressed") .AddFilter(new Filter() .SetName("acompressor") .AddAttribute("threshold", Threshold.ToString()) .AddAttribute("ratio", Ratio) .AddAttribute("attack", Attack.ToString()) .AddAttribute("release", Release.ToString()) .AddAttribute("makeup", MakeupGain.ToString())) .SetOutputIdentifier("aout"); FilterComplexFlag fcf = new FilterComplexFlag() .AddFilterComplexExpression(fadeExpression) .AddFilterComplexExpression(mixExpression) .AddFilterComplexExpression(compressorExpression); FFMPEGCommand.AddFlag(fcf); FFMPEGCommand.AddFlag(new SimpleFlag("map", "0:v")); FFMPEGCommand.AddFlag(new SimpleFlag("map", "[aout]")); FFMPEGCommand.AddFlag(new SimpleFlag("c:v", "copy")); FFMPEGCommand.AddFlag(new SimpleFlag("y", null)); return(FFMPEGCommand.WritePart()); }
public MixAudioIntoVideoCommand SetOutput(string output) { FFMPEGCommand.SetOutput(output); return(this); }