private static async Task <string> RunFFMpeg(string basePath, string baseOutputPath, int fps, string filePrefix = "") { int random = new Random().Next(1_000); //GlobalFFOptions.Configure(options => options.BinaryFolder = Program.Settings.FFMpegPath); Xabe.FFmpeg.FFmpeg.SetExecutablesPath(Program.ApplicationSetting.FFMpegPath); var files = Directory.GetFiles(Path.Combine(basePath)).ToList().OrderBy(i => i); string fileName = Path.Combine(baseOutputPath, $"movie_{random}.mp4"); if (!string.IsNullOrWhiteSpace(filePrefix)) { fileName = Path.Combine(baseOutputPath, $"{filePrefix}_{random}.mp4"); } var conversion = new Conversion(); conversion.SetInputFrameRate(fps); conversion.BuildVideoFromImages(files); //conversion.SetOutputFormat(Xabe.FFmpeg.Format.webm); // Wider rage support conversion.SetFrameRate(fps); conversion.SetPixelFormat(PixelFormat.yuv420p); conversion.SetOutput(fileName); await conversion.Start(); return(fileName); }
public async Task CreateMoviePlace(bool stacked, int groupByHour, int fps, bool drawDots) { var author = Context.Message.Author; if (author.Id != Program.ApplicationSetting.Owner) { Context.Channel.SendMessageAsync("You aren't allowed to run this command", false); return; } // Get users that havent pinged the role in the last 72h var sqlQuery = @" SELECT HOUR(PlacedDateTime), DATE(PlacedDateTime), COUNT(*) FROM PlaceBoardHistory GROUP BY HOUR(PlacedDateTime), DATE(PlacedDateTime) ORDER BY DATE(PlacedDateTime), HOUR(PlacedDateTime)"; Stopwatch watch = new Stopwatch(); watch.Start(); List <GraphEntryInfo> messageTimes = new List <GraphEntryInfo>(); var queryResult = await SQLHelper.GetQueryResults(null, sqlQuery, true, 10_000_000, true, true); Context.Channel.SendMessageAsync($"Retrieved data in {watch.ElapsedMilliseconds}ms"); var parsedInfo = new ParsedGraphInfo() { ChannelId = 1, Info = new Dictionary <DateTimeOffset, int>(), ChannelName = "eth-place-bots", Color = new SKColor(255, 0, 0) }; var firstDateTime = DateTimeOffset.MaxValue; var lastDateTime = DateTimeOffset.MinValue; foreach (var item in queryResult.Data) { int hours = Convert.ToInt32(item[0]); DateTime dateTime = Convert.ToDateTime(item[1]); int count = Convert.ToInt32(item[2]); var key = new DateTimeOffset(dateTime).AddHours(hours); parsedInfo.Info.Add(key, count); if (firstDateTime > key) { firstDateTime = key; } if (lastDateTime < key) { lastDateTime = key; } } double maxFrames = 600; int bound = (int)((lastDateTime - firstDateTime).TotalMinutes / maxFrames); Context.Channel.SendMessageAsync($"Group by {bound} minutes, Total mins {(lastDateTime - firstDateTime).TotalMinutes}"); Context.Channel.SendMessageAsync($"Total frames {parsedInfo.Info.Count()}"); //int val = 0; //foreach (var group in groups) //{ // val += group.Value; // dataPointsSpam.Add(group.TimeStamp.DateTime, val); //} (string basePath, string baseOutputPath) = MovieHelper.CleanAndCreateMovieFolders(); if (stacked) { var values = parsedInfo.Info.OrderBy(i => i.Key); int val = 0; foreach (var info in values) { val += info.Value; parsedInfo.Info[info.Key] = val; } } try { List <Task> tasks = new List <Task>(); for (int i = 2; i <= parsedInfo.Info.Count; i++) { if (i % 250 == 0) { Context.Channel.SendMessageAsync($"Frame gen {i} out of {parsedInfo.Info.Count}"); } var startTime = parsedInfo.Info.Keys.Take(i).Min(); var endTime = parsedInfo.Info.Keys.Take(i).Max(); int maxY = 0; // TODO calculate the rolling info foreach (var info in parsedInfo.Info) { // only consider until this key if (info.Key > endTime) { continue; } if (maxY < info.Value) { maxY = info.Value; } } var drawInfo = DrawingHelper.GetEmptyGraphics(); var padding = DrawingHelper.DefaultPadding; padding.Left = 150; // large numbers var labels = DrawingHelper.GetLabels(startTime.DateTime, endTime.DateTime, 0, maxY, 6, 10, " msg"); var gridSize = new GridSize(drawInfo.Bitmap, padding); DrawingHelper.DrawGrid(drawInfo.Canvas, gridSize, padding, labels.XAxisLabels, labels.YAxisLabels, $"Messages count"); // TODO optimize some lines + move to draw helper var dataPoints = parsedInfo.Info.Where(j => j.Key <= endTime).OrderBy(i => i.Key).ToDictionary(j => j.Key.DateTime, j => j.Value); // todo add 2. y Axis on the right var dataPointList = DrawingHelper.GetPoints(dataPoints, gridSize, true, startTime.DateTime, endTime.DateTime, false, maxY); var highestPoint = -1f; if (dataPoints.Count() > 0) { highestPoint = dataPointList.Min(i => i.Y); } DrawingHelper.DrawLine(drawInfo.Canvas, drawInfo.Bitmap, dataPointList, new SKPaint() { Color = parsedInfo.Color }, 6, "#" + parsedInfo.ChannelName, 0, 0, drawDots, highestPoint); //new Pen(System.Drawing.Color.LightGreen) tasks.Add(MovieHelper.SaveToDisk(basePath, i, drawInfo.Bitmap, drawInfo.Canvas)); } await Context.Channel.SendMessageAsync("Finished processing, waiting for SaveToDisk"); Task.WaitAll(tasks.ToArray()); await Context.Channel.SendMessageAsync("Saving finished. Starting FFMpeg"); int random = new Random().Next(1_000_000_000); //GlobalFFOptions.Configure(options => options.BinaryFolder = Program.Settings.FFMpegPath); Xabe.FFmpeg.FFmpeg.SetExecutablesPath(Program.ApplicationSetting.FFMpegPath); var files = Directory.GetFiles(Path.Combine(basePath)).ToList().OrderBy(i => i); string fileName = Path.Combine(baseOutputPath, $"movie_{random}.mp4"); var conversion = new Conversion(); conversion.SetInputFrameRate(fps); conversion.BuildVideoFromImages(files); conversion.SetFrameRate(fps); conversion.SetPixelFormat(PixelFormat.rgb24); conversion.SetOutput(fileName); conversion.OnProgress += Conversion_OnProgress; await conversion.Start(); //var imageInfos = Directory.GetFiles(Path.Combine(basePath)).ToList().OrderBy(i => i).Select(i => ImageInfo.FromPath(i)).ToArray(); //FFMpeg.JoinImageSequence(fileName, frameRate: 30, imageInfos); await Context.Channel.SendFileAsync(fileName); } catch (Exception ex) { _logger.LogError(ex, "Error while creating movie"); await Context.Channel.SendMessageAsync(ex.ToString()); } }