private void Grid_Loaded(object sender, RoutedEventArgs e)
        {
            SceneExtractorArguments arguments = new SceneExtractorArguments
            {
                InputFile       = _video,
                OutputDirectory = FfmpegWrapper.CreateRandomTempDirectory()
            };

            SceneExtractorWrapper wrapper = new SceneExtractorWrapper(arguments, _viewmodel.Settings.FfmpegPath);

            wrapper.Execute();

            var scenes = new List <SceneViewModel>();

            foreach (string imageFile in Directory.EnumerateFiles(arguments.OutputDirectory))
            {
                string number = Path.GetFileNameWithoutExtension(imageFile);
                int    frame  = int.Parse(number);

                SceneFrame scene = arguments.Result.Single(w => w.Index == frame);

                scenes.Add(new SceneViewModel
                {
                    IsSelected = false,
                    TimeStamp  = scene.TimeStamp,
                    Duration   = scene.Duration,
                    Preview    = new BitmapImage(new Uri(imageFile, UriKind.Absolute))
                });
            }

            Scenes = scenes;
        }
Beispiel #2
0
        public MainForm()
        {
            InitializeComponent();

            var executingAssembly = Assembly.GetExecutingAssembly();

            Icon  = Icon.ExtractAssociatedIcon(executingAssembly.Location);
            Text += $" - {executingAssembly.GetName().Version}";

            AppendLog(Text);

            _openFileDialog = new OpenFileDialog()
            {
                CheckFileExists = true,
                CheckPathExists = true,
            };

            _saveFileDialog = new SaveFileDialog()
            {
                DefaultExt      = ".png",
                Filter          = "Bitmap|*.bmp|Jpeg|*.jpg|Png|*.png|Gif|*.gif|All files|*.*",
                FilterIndex     = 3, // 1 based
                OverwritePrompt = true,
            };

            _ffmpegWrapper              = new FfmpegWrapper("ffmpeg.exe");
            _imageProcessor             = new ImageProcessor();
            _barCodeParametersValidator = new BarCodeParametersValidator();

            useInputHeightForOutputCheckBox.Checked = true;
            generateButton.Text = GenerateButtonText;
        }
Beispiel #3
0
        public void FfmpegWrapper_GetMediaDuration_Returns_Correct_Value()
        {
            CreateTestVideoIfNecessary();
            var ffmpegWrapper = new FfmpegWrapper(FfmpegExecutablePath);

            var duration = ffmpegWrapper.GetMediaDuration(TestVideoFileName, CancellationToken.None);

            Assert.AreEqual(TimeSpan.FromSeconds(TestVideoDuration), duration);
        }
Beispiel #4
0
        public Stream GetVideoByName(string name)
        //public async Task<Stream> GetVideoByName(string name)
        {
            var fileName = string.Empty;

            switch (name)
            {
            case "video":
                var outputStream = new MemoryStream();
                outputStream.Write(jsmpHeader);
                var width = BitConverter.GetBytes((UInt16)1920);
                outputStream.Write(width);
                var height = BitConverter.GetBytes((UInt16)1080);
                outputStream.Write(height);

                var inputfileName = @"D:\Projects\Others\R-Pi\RemoteFiles\video-h264";
                fileName = @"D:\Projects\Others\R-Pi\RemoteFiles\video-mp4";
                using (var logFile = new StreamWriter("FFMpegLog.txt"))
                {
                    using (var ffmpeg = new FfmpegWrapper())
                    {
                        ffmpeg.ConvertStream(inputfileName, outputStream, logFile);

                        //using (var inputStream = new FileStream(inputfileName, FileMode.Open))
                        //{
                        //    ffmpeg.ConvertStream(inputStream, outputStream, logFile);


                        //    //ffmpeg.ConvertFile(inputfileName, fileName, logFile);
                    }

                    logFile.Flush();
                }
                return(outputStream);

            case "nature":
            default:
                fileName = @"D:\Projects\Others\R-Pi\RemoteFiles\nature2.mp4";
                var fileStream = File.OpenRead(fileName);
                return(fileStream);
            }

            //return await _client.GetStreamAsync(fileName);
        }
Beispiel #5
0
        public void FfmpegWrapper_GetImagesFromMedia_Returns_Expected_Values(int requestedFrameCount)
        {
            CreateTestVideoIfNecessary();
            var ffmpegWrapper = new FfmpegWrapper(FfmpegExecutablePath);

            var images = ffmpegWrapper.GetImagesFromMedia(
                TestVideoFileName,
                requestedFrameCount,
                CancellationToken.None)
                         .ToList();

            CollectionAssert.AllItemsAreNotNull(images);
            Assert.AreEqual(requestedFrameCount, images.Count);
            foreach (var image in images)
            {
                Assert.AreEqual(TestVideoWidth, image.Width);
                Assert.AreEqual(TestVideoHeight, image.Height);
            }
        }
    public async Task FfmpegWrapper_GetImagesFromMedia_Returns_Expected_Values(int requestedFrameCount)
    {
        CreateTestVideoIfNecessary();
        var ffmpegWrapper = new FfmpegWrapper(FfmpegExecutablePath);

        var images = ffmpegWrapper.GetImagesFromMedia(
            TestVideoFileName,
            requestedFrameCount,
            CancellationToken.None)
                     .ToList();

        CollectionAssert.AllItemsAreNotNull(images);
        Assert.AreEqual(requestedFrameCount, images.Count);
        foreach (var bitmapStream in images)
        {
            var imageInfo = await Task.Run(() => ImageFileInfo.Load(bitmapStream));

            Assert.AreEqual(TestVideoWidth, imageInfo.Frames[0].Width);
            Assert.AreEqual(TestVideoHeight, imageInfo.Frames[0].Height);
        }
    }
        protected override GeneratorResult ProcessInternal(ThumbnailBannerGeneratorSettings settings, GeneratorEntry entry)
        {
            try
            {
                entry.State = JobStates.Processing;

                _wrapper = new FfmpegWrapper(FfmpegExePath);

                var videoInfo = _wrapper.GetVideoInfo(settings.VideoFile);

                if (!videoInfo.IsGoodEnough())
                {
                    entry.State    = JobStates.Done;
                    entry.DoneType = JobDoneTypes.Failure;
                    entry.Update("Failed", 1);
                    return(GeneratorResult.Failed());
                }

                TimeSpan duration  = videoInfo.Duration;
                TimeSpan intervall = duration.Divide(settings.Columns * settings.Rows + 1);

                var frameArguments = new FrameConverterArguments
                {
                    Width               = 800,
                    Intervall           = intervall.TotalSeconds,
                    StatusUpdateHandler = (progress) => { entry.Update(null, progress); },
                    InputFile           = settings.VideoFile,
                    OutputDirectory     = FfmpegWrapper.CreateRandomTempDirectory()
                };

                entry.Update("Extracting Frames", 0);

                var frames = _wrapper.ExtractFrames(frameArguments);

                if (_canceled)
                {
                    return(GeneratorResult.Failed());
                }

                entry.Update("Saving Thumbnails", 1);

                List <ThumbnailBannerGeneratorImage> images = new List <ThumbnailBannerGeneratorImage>();

                foreach (var frame in frames)
                {
                    images.Add(new ThumbnailBannerGeneratorImage
                    {
                        Image    = frame.Item2,
                        Position = frame.Item1
                    });
                }

                ThumbnailBannerGeneratorData data = new ThumbnailBannerGeneratorData();
                data.Settings  = settings;
                data.Images    = images.ToArray();
                data.VideoName = settings.VideoFile;
                data.VideoInfo = videoInfo;
                data.FileSize  = new FileInfo(settings.VideoFile).Length;

                var result = CreateBanner(data);

                JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create((BitmapSource)result));
                using (FileStream stream = new FileStream(settings.OutputFile, FileMode.Create))
                    encoder.Save(stream);

                Directory.Delete(frameArguments.OutputDirectory);

                entry.DoneType = JobDoneTypes.Success;
                entry.Update("Done", 1);

                return(GeneratorResult.Succeeded(settings.OutputFile));
            }
            catch (Exception)
            {
                entry.Update("Failed", 1);
                entry.DoneType = JobDoneTypes.Failure;

                return(GeneratorResult.Failed());
            }
            finally
            {
                entry.State = JobStates.Done;

                if (_canceled)
                {
                    entry.DoneType = JobDoneTypes.Cancelled;
                    entry.Update("Cancelled", 1);
                }
            }
        }
Beispiel #8
0
        protected override GeneratorResult ProcessInternal(HeatmapGeneratorSettings settings, GeneratorEntry entry)
        {
            try
            {
                entry.State = JobStates.Processing;

                _wrapper = new FfmpegWrapper(FfmpegExePath);

                var videoInfo = _wrapper.GetVideoInfo(settings.VideoFile);

                if (videoInfo.Duration <= TimeSpan.Zero)
                {
                    entry.State    = JobStates.Done;
                    entry.DoneType = JobDoneTypes.Failure;
                    entry.Update("Failed", 1);
                    return(GeneratorResult.Failed());
                }

                TimeSpan duration = videoInfo.Duration;

                //TODO

                string script  = ViewModel.GetScriptFile(settings.VideoFile);
                var    actions = ViewModel.LoadScriptActions(script, null);

                if (actions == null || actions.Count == 0)
                {
                    entry.State    = JobStates.Done;
                    entry.DoneType = JobDoneTypes.Failure;
                    entry.Update("Failed", 1);
                    return(GeneratorResult.Failed());
                }

                List <TimedPosition> timeStamps = ViewModel.FilterDuplicates(actions.ToList()).Cast <FunScriptAction>().Select(f => new
                                                                                                                               TimedPosition
                {
                    Position  = f.Position,
                    TimeStamp = f.TimeStamp
                }).ToList();

                Brush heatmap = HeatMapGenerator.Generate3(timeStamps, TimeSpan.FromSeconds(10), TimeSpan.Zero, duration, 1.0, out Geometry bounds);
                bounds.Transform = new ScaleTransform(settings.Width, settings.Height);
                var rect = new Rect(0, 0, settings.Width, settings.Height);

                DrawingVisual visual = new DrawingVisual();
                using (DrawingContext context = visual.RenderOpen())
                {
                    if (!settings.TransparentBackground)
                    {
                        context.DrawRectangle(Brushes.Black, null, rect);
                    }

                    if (settings.MovementRange)
                    {
                        context.PushClip(bounds);
                    }

                    context.DrawRectangle(heatmap, null, rect);

                    if (settings.AddShadow)
                    {
                        LinearGradientBrush shadow = new LinearGradientBrush();
                        shadow.StartPoint = new Point(0.5, 0);
                        shadow.EndPoint   = new Point(0.5, 1);

                        shadow.GradientStops.Add(new GradientStop(Color.FromArgb(0xFF - 0x20, 0, 0, 0), 0));
                        shadow.GradientStops.Add(new GradientStop(Color.FromArgb(0xFF - 0xcc, 0, 0, 0), 0.98));
                        shadow.GradientStops.Add(new GradientStop(Color.FromArgb(0xFF - 0x50, 0, 0, 0), 0.98));
                        shadow.GradientStops.Add(new GradientStop(Color.FromArgb(0xFF - 0x50, 0, 0, 0), 1));

                        context.DrawRectangle(shadow, null, rect);
                    }

                    if (settings.MovementRange)
                    {
                        context.Pop();
                    }
                }

                RenderTargetBitmap bitmap = new RenderTargetBitmap(settings.Width, settings.Height, 96, 96, PixelFormats.Pbgra32);
                bitmap.Render(visual);

                PngBitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(bitmap));

                using (FileStream stream = new FileStream(settings.OutputFile, FileMode.Create))
                    encoder.Save(stream);

                entry.DoneType = JobDoneTypes.Success;
                entry.Update("Done", 1);

                return(GeneratorResult.Succeeded(settings.OutputFile));
            }
            catch (Exception)
            {
                entry.Update("Failed", 1);
                entry.DoneType = JobDoneTypes.Failure;

                return(GeneratorResult.Failed());
            }
            finally
            {
                entry.State = JobStates.Done;

                if (_canceled)
                {
                    entry.DoneType = JobDoneTypes.Cancelled;
                    entry.Update("Cancelled", 1);
                }
            }
        }
        protected override GeneratorResult ProcessInternal(PreviewGeneratorSettings settings, GeneratorEntry entry)
        {
            entry.State = JobStates.Processing;

            List <string> tempFiles = new List <string>();

            try
            {
                _wrapper = new FfmpegWrapper(FfmpegExePath);

                List <string> sectionFileNames = new List <string>();

                if (settings.TimeFrames.Any(tf => tf.IsFactor))
                {
                    VideoInfo info = _wrapper.GetVideoInfo(settings.VideoFile);

                    if (!info.IsGoodEnough())
                    {
                        entry.State    = JobStates.Done;
                        entry.DoneType = JobDoneTypes.Failure;
                        entry.Update("Failed", 1);
                        return(GeneratorResult.Failed());
                    }

                    TimeSpan duration = info.Duration;

                    settings.TimeFrames.ForEach(tf => tf.CalculateStart(duration));
                }

                ClipExtractorArguments clipArguments = new ClipExtractorArguments
                {
                    InputFile = settings.VideoFile,
                    Width     = settings.Width,
                    Height    = settings.Height,
                    Framerate = settings.Framerate
                };

                for (int i = 0; i < settings.TimeFrames.Count; i++)
                {
                    string sectionFileName = Path.Combine(Path.GetTempPath(),
                                                          Path.GetFileName(settings.VideoFile) + $"-clip_{i}.mkv");
                    sectionFileNames.Add(sectionFileName);
                    tempFiles.Add(sectionFileName);

                    var timeFrame = settings.TimeFrames[i];

                    clipArguments.Duration      = timeFrame.Duration;
                    clipArguments.StartTimeSpan = timeFrame.StartTimeSpan;
                    clipArguments.OutputFile    = sectionFileName;

                    entry.Update($"Generating GIF (1/4): Clipping Video Section {i + 1}/{settings.TimeFrames.Count}",
                                 ((i / (double)settings.TimeFrames.Count)) / 4.0);

                    if (!_wrapper.Execute(clipArguments))
                    {
                        return(GeneratorResult.Failed());
                    }

                    if (_canceled)
                    {
                        return(GeneratorResult.Failed());
                    }
                }

                entry.Update("Generating GIF (2/4): Merging Clips", 1 / 4.0);

                string clipFileName = "";

                if (sectionFileNames.Count == 1)
                {
                    clipFileName = sectionFileNames[0];
                }
                else
                {
                    ClipMergeArguments mergeArguments = new ClipMergeArguments
                    {
                        InputFile  = settings.VideoFile,
                        ClipFiles  = sectionFileNames.ToArray(),
                        OutputFile = Path.Combine(Path.GetTempPath(), Path.GetFileName(settings.VideoFile) + $"-clip.mkv")
                    };

                    clipFileName = mergeArguments.OutputFile;
                    tempFiles.Add(clipFileName);

                    if (!_wrapper.Execute(mergeArguments))
                    {
                        return(GeneratorResult.Failed());
                    }

                    if (_canceled)
                    {
                        return(GeneratorResult.Failed());
                    }
                }

                entry.Update("Generating GIF (3/4): Extracting Palette", 2 / 4.0);

                string paletteFile = clipFileName + "-palette.png";

                PaletteExtractorArguments paletteArguments = new PaletteExtractorArguments
                {
                    InputFile  = clipFileName,
                    OutputFile = paletteFile
                };

                tempFiles.Add(paletteFile);

                if (!_wrapper.Execute(paletteArguments))
                {
                    return(GeneratorResult.Failed());
                }

                if (_canceled)
                {
                    return(GeneratorResult.Failed());
                }

                entry.Update("Generating GIF (3/4): Creating GIF", 3 / 4.0);

                string gifFileName = settings.OutputFile;

                GifCreatorArguments gifArguments = new GifCreatorArguments();
                gifArguments.InputFile   = clipFileName;
                gifArguments.PaletteFile = paletteFile;
                gifArguments.OutputFile  = gifFileName;
                gifArguments.Framerate   = settings.Framerate;

                if (!_wrapper.Execute(gifArguments))
                {
                    return(GeneratorResult.Failed());
                }

                if (_canceled)
                {
                    return(GeneratorResult.Failed());
                }

                entry.Update("Done!", 4 / 4.0);
                bool success = File.Exists(gifFileName);

                if (success)
                {
                    entry.DoneType = JobDoneTypes.Success;
                }
                else
                {
                    entry.DoneType = JobDoneTypes.Failure;
                }

                OnDone(new Tuple <bool, string>(success, gifFileName));

                if (success)
                {
                    return(GeneratorResult.Succeeded(gifFileName));
                }

                return(GeneratorResult.Failed());
            }
            catch
            {
                entry.DoneType = JobDoneTypes.Failure;
                return(GeneratorResult.Failed());
            }
            finally
            {
                entry.State = JobStates.Done;

                if (_canceled)
                {
                    entry.DoneType = JobDoneTypes.Cancelled;
                }

                foreach (string tempFile in tempFiles)
                {
                    if (File.Exists(tempFile))
                    {
                        File.Delete(tempFile);
                    }
                }
            }
        }
 public FfmpegThumbnailGenerator(FfmpegWrapper ffmpeg, FileManager fileManager, string tempFileLocation)
 {
     _ffmpeg = ffmpeg;
     _fileManager = fileManager;
     _tempFileLocation = tempFileLocation;
 }
        protected override GeneratorResult ProcessInternal(ThumbnailGeneratorSettings settings, GeneratorEntry entry)
        {
            try
            {
                entry.State = JobStates.Processing;

                _wrapper = new FfmpegWrapper(FfmpegExePath);

                double intervall = settings.Intervall;

                if (settings.Intervall < 1)
                {
                    var info = _wrapper.GetVideoInfo(settings.VideoFile);
                    if (!info.IsGoodEnough())
                    {
                        entry.Update("Failed", 1);
                        entry.DoneType = JobDoneTypes.Failure;
                        return(GeneratorResult.Failed());
                    }

                    const double targetFrameCount = 500.0;

                    intervall = info.Duration.TotalSeconds / targetFrameCount;
                    intervall = Math.Min(Math.Max(1, intervall), 10);
                }

                FrameConverterArguments arguments = new FrameConverterArguments
                {
                    StatusUpdateHandler = (progress) => { entry.Update(null, progress); },
                    InputFile           = settings.VideoFile,
                    OutputDirectory     = FfmpegWrapper.CreateRandomTempDirectory(),
                    Intervall           = intervall,
                    Width    = settings.Width,
                    Height   = settings.Height,
                    ClipLeft = settings.ClipLeft,
                    DeLense  = settings.ClipLeft
                };

                string thumbfile = Path.ChangeExtension(settings.VideoFile, "thumbs");
                entry.Update("Extracting Frames", 0);

                var frames = _wrapper.ExtractFrames(arguments);

                if (_canceled)
                {
                    return(GeneratorResult.Failed());
                }

                entry.Update("Saving Thumbnails", 1);

                VideoThumbnailCollection thumbnails = new VideoThumbnailCollection();
                foreach (var frame in frames)
                {
                    thumbnails.Add(frame.Item1, frame.Item2);
                }

                using (FileStream stream = new FileStream(thumbfile, FileMode.Create, FileAccess.Write))
                {
                    thumbnails.Save(stream);
                }

                thumbnails.Dispose();

                entry.DoneType = JobDoneTypes.Success;
                entry.Update("Done", 1);

                return(GeneratorResult.Succeeded(thumbfile));
            }
            catch (Exception)
            {
                entry.DoneType = JobDoneTypes.Failure;
                return(GeneratorResult.Failed());
            }
            finally
            {
                entry.State = JobStates.Done;

                if (_canceled)
                {
                    entry.DoneType = JobDoneTypes.Cancelled;
                }
            }
        }
    public void Generate_All_Barcode_Settings_Combinations()
    {
        Assert.Inconclusive("Uncomment me to run the test");

        var ffmpegWrapper   = new FfmpegWrapper(FfmpegExecutablePath);
        var streamProcessor = new ImageStreamProcessor();

        var allGenerators = new List <IBarGenerator>();

        // Legacy (reference)
        allGenerators.Add(GdiBarGenerator.CreateLegacy(false));
        // Legacy (reference) smoothed
        allGenerators.Add(GdiBarGenerator.CreateLegacy(true));

        foreach (var average in new[] { GdiAverage.No, GdiAverage.OnePass })
        {
            foreach (var interpolationMode in new[] { InterpolationMode.HighQualityBicubic, InterpolationMode.NearestNeighbor, InterpolationMode.Bicubic })
            {
                allGenerators.Add(new GdiBarGenerator(average: average, scalingMode: ScalingMode.Sane, interpolationMode: interpolationMode));
            }
        }

        foreach (var average in new[] { false, true })
        {
            foreach (var interpolation in new[]
            {
                InterpolationSettings.Average,
                InterpolationSettings.CubicSmoother,
                InterpolationSettings.NearestNeighbor,
            })
            {
                allGenerators.Add(new MagicScalerBarGenerator("noname", average: average, interpolation: interpolation));
            }
        }

        CreateTestVideoIfNecessary();
        var inputPath = TestVideoFilePath;

        inputPath = @"G:\videos\In Bruges (2008)\In.Bruges.2008.720p.BrRip.x264.YIFY.mp4";

        {
            var results = streamProcessor.CreateBarCodes(
                new BarCodeParameters
            {
                Width                = 1280,
                BarWidth             = 1,
                InputPath            = inputPath,
                GeneratorOutputPaths = allGenerators.ToDictionary(x => x, x => x.Name)
            },
                ffmpegWrapper,
                CancellationToken.None,
                progress: null,
                log: x => TestContext.WriteLine(x));

            foreach (var result in results)
            {
                result.Value.Save($"{result.Key.Name}.png");
            }
        }

        //{
        //    var results = streamProcessor.CreateBarCodes(
        //        inputPath,
        //        new BarCodeParameters { Width = 500, BarWidth = 50 },
        //        ffmpegWrapper,
        //         CancellationToken.None,
        //         progress: null,
        //         log: x => TestContext.WriteLine(x),
        //         allGenerators.ToArray());

        //    foreach (var result in results)
        //    {
        //        result.Value.Save($"50-{result.Key.Name}.png");
        //    }
        //}
    }
Beispiel #13
0
 public VideoRecorder(string ffmpegBinPath = @"c:/Program Files (x86)/ffmpeg/bin/")
 {
     ffmpeg = new FfmpegWrapper(ffmpegBinPath);
     SetVideoCaptureFileName();
 }
Beispiel #14
0
        protected override GeneratorResult ProcessInternal(PreviewGeneratorSettings settings, GeneratorEntry entry)
        {
            entry.State = JobStates.Processing;

            List <string> tempFiles = new List <string>();

            int totalSteps = settings.OverlayScriptPositions ? 5 : 4;
            int stepsDone  = 0;

            try
            {
                _wrapper = new FfmpegWrapper(FfmpegExePath);

                List <string> sectionFileNames = new List <string>();

                if (settings.TimeFrames.Any(tf => tf.IsFactor))
                {
                    VideoInfo info = _wrapper.GetVideoInfo(settings.VideoFile);

                    if (!info.IsGoodEnough())
                    {
                        entry.State    = JobStates.Done;
                        entry.DoneType = JobDoneTypes.Failure;
                        entry.Update("Failed", 1);
                        return(GeneratorResult.Failed());
                    }

                    TimeSpan duration = info.Duration;

                    settings.TimeFrames.ForEach(tf => tf.CalculateStart(duration));
                }

                ClipExtractorArguments clipArguments = new ClipExtractorArguments
                {
                    InputFile = settings.VideoFile,
                    Width     = settings.Width,
                    Height    = settings.Height,
                    Framerate = settings.Framerate,
                    ClipLeft  = settings.ClipLeft,
                    DeLense   = settings.ClipLeft
                };

                VideoInfo clipInfo = null;

                for (int i = 0; i < settings.TimeFrames.Count; i++)
                {
                    string sectionFileName = Path.Combine(Path.GetTempPath(),
                                                          Path.GetFileName(settings.VideoFile) + $"-clip_{i}.mkv");
                    sectionFileNames.Add(sectionFileName);
                    tempFiles.Add(sectionFileName);

                    var timeFrame = settings.TimeFrames[i];

                    clipArguments.Duration      = timeFrame.Duration;
                    clipArguments.StartTimeSpan = timeFrame.StartTimeSpan;
                    clipArguments.OutputFile    = sectionFileName;

                    entry.Update($"Generating GIF ({stepsDone + 1}/{totalSteps}): Clipping Video Section {i + 1}/{settings.TimeFrames.Count}",
                                 (stepsDone / (double)totalSteps) + ((i / (double)settings.TimeFrames.Count)) / totalSteps);

                    if (!_wrapper.Execute(clipArguments))
                    {
                        return(GeneratorResult.Failed());
                    }

                    if (clipInfo == null)
                    {
                        clipInfo = _wrapper.GetVideoInfo(sectionFileName);
                    }

                    if (_canceled)
                    {
                        return(GeneratorResult.Failed());
                    }
                }

                stepsDone++;

                if (settings.OverlayScriptPositions)
                {
                    string script  = ViewModel.GetScriptFile(settings.VideoFile);
                    var    actions = ViewModel.LoadScriptActions(script, null)?.OfType <FunScriptAction>().ToList();

                    Size barSize = new Size(clipInfo.Resolution.Horizontal, 20);

                    if (actions != null && actions.Count > 0)
                    {
                        PositionBar bar = new PositionBar
                        {
                            Width  = barSize.Width,
                            Height = barSize.Height,
                            TotalDisplayedDuration = TimeSpan.FromSeconds(5),
                            Background             = Brushes.Black,
                            Positions = new PositionCollection(actions.Select(a => new TimedPosition()
                            {
                                Position  = a.Position,
                                TimeStamp = a.TimeStamp
                            })),
                            DrawCircles = false,
                            DrawLines   = false,
                        };

                        for (int i = 0; i < settings.TimeFrames.Count; i++)
                        {
                            TimeSpan start = settings.TimeFrames[i].StartTimeSpan;
                            TimeSpan max   = start + settings.TimeFrames[i].Duration;

                            TimeSpan progress = start;

                            string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
                            Directory.CreateDirectory(tempDir);

                            string overlayFileName = Path.Combine(Path.GetTempPath(),
                                                                  Path.GetFileName(settings.VideoFile) + $"-overlay_{i}.mkv");

                            tempFiles.Add(overlayFileName);

                            int frame = 0;

                            entry.Update($"Generating GIF ({stepsDone + 1}/{totalSteps}): Overlaying Positions {i + 1}/{settings.TimeFrames.Count}",
                                         (stepsDone / (double)totalSteps) + ((i / (double)settings.TimeFrames.Count)) / totalSteps);

                            double expectedFrames = 1 + (settings.TimeFrames[i].Duration.TotalSeconds * clipInfo.FrameRate);

                            while (progress <= max)
                            {
                                progress = start + TimeSpan.FromSeconds(frame / clipInfo.FrameRate);

                                bar.Progress = progress;

                                var bitmap = RenderToBitmap(bar, barSize);

                                PngBitmapEncoder encoder = new PngBitmapEncoder();

                                encoder.Frames.Add(BitmapFrame.Create(bitmap));

                                using (FileStream f = new FileStream(Path.Combine(tempDir, $"frame{frame:0000}.png"),
                                                                     FileMode.CreateNew))
                                    encoder.Save(f);

                                frame++;
                            }

                            FrameMergeArguments frameMergeArguments = new FrameMergeArguments
                            {
                                Framerate  = clipInfo.FrameRate,
                                InputFile  = Path.Combine(tempDir, "frame%04d.png"),
                                OutputFile = overlayFileName
                            };

                            if (!_wrapper.Execute(frameMergeArguments))
                            {
                                return(GeneratorResult.Failed());
                            }

                            var clipInfo2 = _wrapper.GetVideoInfo(overlayFileName);

                            Directory.Delete(tempDir, true);

                            string mergeFileName = Path.Combine(Path.GetTempPath(),
                                                                Path.GetFileName(settings.VideoFile) + $"-merge_{i}.mkv");

                            tempFiles.Add(mergeFileName);

                            VideoOverlayArguments overlayArguments = new VideoOverlayArguments
                            {
                                InputFile  = sectionFileNames[i],
                                Overlay    = overlayFileName,
                                OutputFile = mergeFileName,
                                PosX       = 0,
                                PosY       = clipInfo.Resolution.Vertical - 20
                            };

                            if (!_wrapper.Execute(overlayArguments))
                            {
                                return(GeneratorResult.Failed());
                            }

                            sectionFileNames[i] = mergeFileName;
                        }
                    }

                    stepsDone++;
                }

                entry.Update($"Generating GIF ({stepsDone + 1}/{totalSteps}): Merging Clips", stepsDone / (double)totalSteps);

                string clipFileName;

                if (sectionFileNames.Count == 1)
                {
                    clipFileName = sectionFileNames[0];
                }
                else
                {
                    ClipMergeArguments mergeArguments = new ClipMergeArguments
                    {
                        InputFile  = settings.VideoFile,
                        ClipFiles  = sectionFileNames.ToArray(),
                        OutputFile = Path.Combine(Path.GetTempPath(), Path.GetFileName(settings.VideoFile) + $"-clip.mkv")
                    };

                    clipFileName = mergeArguments.OutputFile;
                    tempFiles.Add(clipFileName);

                    if (!_wrapper.Execute(mergeArguments))
                    {
                        return(GeneratorResult.Failed());
                    }

                    if (_canceled)
                    {
                        return(GeneratorResult.Failed());
                    }
                }

                stepsDone++;

                entry.Update($"Generating GIF ({stepsDone + 1}/{totalSteps}): Extracting Palette", stepsDone / (double)totalSteps);

                string paletteFile = clipFileName + "-palette.png";

                PaletteExtractorArguments paletteArguments = new PaletteExtractorArguments
                {
                    InputFile  = clipFileName,
                    OutputFile = paletteFile
                };

                tempFiles.Add(paletteFile);

                if (!_wrapper.Execute(paletteArguments))
                {
                    return(GeneratorResult.Failed());
                }

                if (_canceled)
                {
                    return(GeneratorResult.Failed());
                }

                stepsDone++;

                entry.Update($"Generating GIF ({stepsDone + 1}/{totalSteps}): Creating GIF", stepsDone / (double)totalSteps);

                string gifFileName = settings.OutputFile;

                GifCreatorArguments gifArguments = new GifCreatorArguments();
                gifArguments.InputFile   = clipFileName;
                gifArguments.PaletteFile = paletteFile;
                gifArguments.OutputFile  = gifFileName;
                gifArguments.Framerate   = settings.Framerate;

                if (!_wrapper.Execute(gifArguments))
                {
                    return(GeneratorResult.Failed());
                }

                if (_canceled)
                {
                    return(GeneratorResult.Failed());
                }

                stepsDone++;

                entry.Update("Done", 1.0);
                bool success = File.Exists(gifFileName);

                if (success)
                {
                    entry.DoneType = JobDoneTypes.Success;
                }
                else
                {
                    entry.DoneType = JobDoneTypes.Failure;
                }

                OnDone(new Tuple <bool, string>(success, gifFileName));

                if (success)
                {
                    return(GeneratorResult.Succeeded(gifFileName));
                }

                return(GeneratorResult.Failed());
            }
            catch (Exception e)
            {
                entry.DoneType = JobDoneTypes.Failure;
                return(GeneratorResult.Failed());
            }
            finally
            {
                entry.State = JobStates.Done;

                if (_canceled)
                {
                    entry.DoneType = JobDoneTypes.Cancelled;
                }

                foreach (string tempFile in tempFiles)
                {
                    if (File.Exists(tempFile))
                    {
                        File.Delete(tempFile);
                    }
                }
            }
        }
    public IReadOnlyDictionary <IBarGenerator, Bitmap> CreateBarCodes(
        BarCodeParameters parameters,
        FfmpegWrapper ffmpeg,
        CancellationToken cancellationToken,
        IProgress <double> progress = null,
        Action <string> log         = null)
    {
        var barCount           = (int)Math.Round((double)parameters.Width / parameters.BarWidth);
        var bitmapStreamSource = ffmpeg.GetImagesFromMedia(parameters.InputPath, barCount, cancellationToken, log);

        var barGenerators = parameters.GeneratorOutputPaths.Keys.ToArray();

        Bitmap[]   finalBitmaps        = new Bitmap[barGenerators.Length];
        Graphics[] finalBitmapGraphics = new Graphics[barGenerators.Length];

        int actualBarHeight = 0;

        int x = 0;

        foreach (var bitmapStream in bitmapStreamSource)
        {
            if (x == 0)
            {
                var imageInfo = ImageFileInfo.Load(bitmapStream);

                actualBarHeight = parameters.Height ?? imageInfo.Frames.First().Height;

                for (int i = 0; i < barGenerators.Length; i++)
                {
                    finalBitmaps[i]        = new Bitmap(parameters.Width, actualBarHeight);
                    finalBitmapGraphics[i] = Graphics.FromImage(finalBitmaps[i]);
                }
            }

            using (bitmapStream)
            {
                for (int i = 0; i < barGenerators.Length; i++)
                {
                    bitmapStream.Position = 0;
                    var bar      = barGenerators[i].GetBar(bitmapStream, parameters.BarWidth, actualBarHeight);
                    var srcRect  = new Rectangle(0, 0, bar.Width, bar.Height);
                    var destRect = new Rectangle(x, 0, parameters.BarWidth, actualBarHeight);
                    finalBitmapGraphics[i].DrawImage(bar, destRect, srcRect, GraphicsUnit.Pixel);
                }

                x += parameters.BarWidth;

                progress?.Report((double)x / parameters.Width);
            }
        }

        for (int i = 0; i < barGenerators.Length; i++)
        {
            finalBitmapGraphics[i]?.Dispose();
        }

        var result = new Dictionary <IBarGenerator, Bitmap>();

        for (int i = 0; i < barGenerators.Length; i++)
        {
            result.Add(barGenerators[i], finalBitmaps[i]);
        }

        return(result);
    }
Beispiel #16
0
    public MainForm()
    {
        InitializeComponent();

        var executingAssembly = Assembly.GetExecutingAssembly();

        Icon  = Icon.ExtractAssociatedIcon(executingAssembly.Location);
        Text += $" - {executingAssembly.GetName().Version}";

        _barGenerators = new List <BarGeneratorViewModel>
        {
            new BarGeneratorViewModel(
                new MagicScalerBarGenerator("Normal", average: false),
                "The default mode to generate barcodes.\r\nIt scales images using a resampling algorithm that takes care of gamma correction and produces correct color averages.",
                initialCheckState: true),
            new BarGeneratorViewModel(
                new MagicScalerBarGenerator("Normal (smoothed)", "_smoothed", average: true, InterpolationSettings.CubicSmoother),
                "Almost the same as the 'Normal' mode, but vertically smoothed.\r\nIt also uses a 'cubic smoother' resampling algorithm that generates images sharper than the normal algorithm.",
                initialCheckState: false),
            new BarGeneratorViewModel(
                GdiBarGenerator.CreateLegacy(average: false),
                "The mode used in previous versions.\r\nIt's relatively fast, but the algorithm used to scale images is of poor quality.\r\nThis mode is not recommended, and only here for backward-compatibility.",
                initialCheckState: false),
            new BarGeneratorViewModel(
                GdiBarGenerator.CreateLegacy(average: true),
                "Same as 'Legacy', but vertically smoothed.",
                initialCheckState: false),
        };

        barGeneratorList.DisplayMember = nameof(BarGeneratorViewModel.DisplayName);
        barGeneratorList.Items.Clear();
        foreach (var item in _barGenerators)
        {
            barGeneratorList.Items.Add(item, isChecked: item.Checked);
        }

        barGeneratorList.SelectedItem = _barGenerators.First(x => x.Checked); // So that the right panel displays something.
        barGeneratorList.SelectedItem = null;                                 // Unselect so a click on the line will not uncheck the item.

        AppendLog(Text);

        _openFileDialog = new OpenFileDialog()
        {
            CheckFileExists = true,
            CheckPathExists = true,
        };

        _saveFileDialog = new SaveFileDialog()
        {
            DefaultExt      = ".png",
            Filter          = "Bitmap|*.bmp|Jpeg|*.jpg|Png|*.png|Gif|*.gif|All files|*.*",
            FilterIndex     = 3, // 1 based
            OverwritePrompt = true,
        };

        _ffmpegWrapper              = new FfmpegWrapper("ffmpeg.exe");
        _imageProcessor             = new ImageStreamProcessor();
        _barCodeParametersValidator = new BarCodeParametersValidator();

        useInputHeightForOutputCheckBox.Checked = true;
        generateButton.Text = GenerateButtonText;
    }