Beispiel #1
0
        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());
            }
        }