Beispiel #1
0
        public void ProcessRenderOptions()
        {
            using (var temporaryFilesStorage = new TemporaryFilesStorage())
            {
                var subject = new Subject <double>();

                // ReSharper disable once ImpureMethodCallOnReadonlyValueField
                // Внутри происходит регистрация через ссылку на родительский CancellationTokenSource.
                this.cancellationToken.Register(() => subject.OnNext(0));
                using (var ffMpeg = new FFMpeg(temporaryFilesStorage, this.rendererProcessPriorityClass, subject.AsObservable()))
                {
                    ffMpeg.LogMessage($"Started rendering of {this.outputFile}", string.Empty);

                    var cutInfos = this.VideoRenderOptions.Select(
                        v =>
                    {
                        if (string.IsNullOrEmpty(v.FilePath))
                        {
                            return(new FFMpegCutInfo(v.VideoStreamPath, v.AudioStreamPath, v.StartSecond, v.StartSecond + v.DurationSeconds, v.IsMuted));
                        }

                        return(new FFMpegCutInfo(v.FilePath, v.StartSecond, v.StartSecond + v.DurationSeconds, v.IsMuted));
                    }).ToList();

                    this.CutAndConcatAndRenderTextAndImageAndTimeWarps(cutInfos, ffMpeg, temporaryFilesStorage);
                }
            }
        }
Beispiel #2
0
 public byte[] GetFrameFromVideoAsByte(string videoFile, double positionMs, FFMpegImageSize imageSize)
 {
     using (var tempFileStorage = new TemporaryFilesStorage())
     {
         using (var mhandler = new FFMpeg(tempFileStorage))
         {
             return(mhandler.GetBitmapFromVideoAsByte(videoFile, positionMs, imageSize));
         }
     }
 }
Beispiel #3
0
 public async Task <byte[]> GetFrameFromVideoAsByteAsync(string videoFile, double positionMs, FFMpegImageSize imageSize)
 {
     return(await await Task.Factory.StartNew(
                async() =>
     {
         using (var tempFileStorage = new TemporaryFilesStorage())
         {
             using (var mhandler = new FFMpeg(tempFileStorage))
             {
                 return mhandler.GetBitmapFromVideoAsByte(videoFile, positionMs, imageSize);
             }
         }
     },
                TaskCreationOptions.RunContinuationsAsynchronously));
 }
        public void ProcessRenderOptions()
        {
            using (var temporaryFilesStorage = new TemporaryFilesStorage())
            {
                var subject = new Subject <double>();

                // ReSharper disable once ImpureMethodCallOnReadonlyValueField
                // Внутри происходит регистрация через ссылку на родительский CancellationTokenSource.
                this.cancellationToken.Register(() => subject.OnNext(0));
                using (var ffMpeg = new FFMpeg(temporaryFilesStorage, this.rendererProcessPriorityClass, subject.AsObservable()))
                {
                    ffMpeg.LogMessage($"Started rendering of {this.outputFile}", string.Empty);

                    var cutOptionsBuilder = new CutOptionsBuilder(this.videoRenderOptions, this.outputSize, this.globalExportProgress, temporaryFilesStorage, false);

                    Parallel.ForEach(
                        cutOptionsBuilder.CutOptions,
                        cutOptions =>
                    {
                        if (this.cancellationToken.IsCancellationRequested)
                        {
                            this.cancellationToken.ThrowIfCancellationRequested();
                        }

                        // ReSharper disable once AccessToDisposedClosure
                        // выполнение замыкания всегда будет происходить до Dispose.
                        this.CutAndDrawTextAndDrawImageAndApplyTimeWarp(ffMpeg, cutOptions, temporaryFilesStorage);
                    });
                    if (cutOptionsBuilder.FilesToConcat.Count == 1)
                    {
                        File.Move(cutOptionsBuilder.FilesToConcat.Single(), this.outputFile);
                    }
                    else
                    {
                        if (this.cancellationToken.IsCancellationRequested)
                        {
                            this.cancellationToken.ThrowIfCancellationRequested();
                        }

                        var tempFileForConcat = temporaryFilesStorage.GetIntermediateFile(cutOptionsBuilder.OutputExtension);
                        ffMpeg.Concat(tempFileForConcat, this.outputSize, "copy", "copy", this.globalExportProgress, cutOptionsBuilder.FilesToConcat.ToArray());
                        ffMpeg.Convert(tempFileForConcat, this.outputFile, this.globalExportProgress);
                    }
                }
            }
        }
        private void CutAndDrawTextAndDrawImageAndApplyTimeWarp(
            FFMpeg ffMpeg,
            FFMpegCutOptions cutOptions,
            TemporaryFilesStorage temporaryFilesStorage)
        {
            EnsureFileDoesNotExist(cutOptions.OutputFile);
            var extensionForResultFile = Path.GetExtension(cutOptions.OutputFile);
            var imagesExist            = cutOptions.ImagesTimeTable != null && cutOptions.ImagesTimeTable.Any();
            var timeWarpExists         = cutOptions.TimeWarps != null && cutOptions.TimeWarps.Any();

            if (!cutOptions.OverlayText.Any() && !imagesExist && !timeWarpExists)
            {
                ffMpeg.Cut(cutOptions);
                return;
            }
            var intermediateFile1 = temporaryFilesStorage.GetIntermediateFile(extensionForResultFile);

            ffMpeg.Cut(cutOptions.CloneWithOtherOutput(intermediateFile1));

            if (cutOptions.OverlayText.Any())
            {
                var intermediateFile2 = (imagesExist || timeWarpExists) ? temporaryFilesStorage.GetIntermediateFile(extensionForResultFile) : cutOptions.OutputFile;
                ffMpeg.DrawText(intermediateFile1, cutOptions.OverlayText, intermediateFile2, cutOptions.GlobalExportProgress);
                File.Delete(intermediateFile1);
                intermediateFile1 = intermediateFile2;
            }
            if (imagesExist)
            {
                var intermediateFile3 = timeWarpExists ? temporaryFilesStorage.GetIntermediateFile(extensionForResultFile) : cutOptions.OutputFile;
                ffMpeg.DrawImage(intermediateFile1, cutOptions.ImagesTimeTable, intermediateFile3, cutOptions.GlobalExportProgress);
                File.Delete(intermediateFile1);
                intermediateFile1 = intermediateFile3;
            }
            if (timeWarpExists)
            {
                ffMpeg.ApplyTimeWarp(intermediateFile1, cutOptions.TimeWarps, cutOptions.OutputFile, this.globalExportProgress);
                File.Delete(intermediateFile1);
            }
        }
Beispiel #6
0
        protected override void CutAndConcatAndRenderTextAndImageAndTimeWarps(List <FFMpegCutInfo> cutInfos, FFMpeg ffMpeg, TemporaryFilesStorage temporaryFilesStorage)
        {
            foreach (var videoRenderOption in this.VideoRenderOptions)
            {
                if (videoRenderOption.OverlayTextTimeTable != null && videoRenderOption.OverlayTextTimeTable.Any())
                {
                    var textImages = videoRenderOption.OverlayTextTimeTable.Select(
                        v =>
                    {
                        const int FontSizeFor1024Width = 30;
                        var fontSize = this.OutputSize.IsEmpty ? FontSizeFor1024Width : ((double)this.OutputSize.Width / 1024) * FontSizeFor1024Width;
                        var image    = StringUtils.DrawTextOnImage(v.Lines.Aggregate((t, c) => t + c), Color.Transparent, Color.DarkGreen, new Font(SystemFonts.DefaultFont.FontFamily, (int)fontSize), this.OutputSize.Width - 10);
                        var left     = this.OutputSize.Width / 2 - image.Width / 2;
                        var top      = this.OutputSize.Height - image.Height - 15;
                        return(new DrawImageTimeRecord(image.ToBytes(ImageFormat.Bmp), left, top, v.StartSecond, v.EndSecond));
                    });
                    videoRenderOption.ImagesTimeTable.AddRange(textImages);
                    videoRenderOption.OverlayTextTimeTable.Clear();
                }
            }

            base.CutAndConcatAndRenderTextAndImageAndTimeWarps(cutInfos, ffMpeg, temporaryFilesStorage);
        }
Beispiel #7
0
        protected virtual void CutAndConcatAndRenderTextAndImageAndTimeWarps(List <FFMpegCutInfo> cutInfos, FFMpeg ffMpeg, TemporaryFilesStorage temporaryFilesStorage)
        {
            var textTimeTableForConcatenatedEpisodeGroups   = new List <TextTimeRecord>();
            var imagesTimeTableForConcatenatedEpisodeGroups = new List <DrawImageTimeRecord>();
            var timeWarpForConcatenatedEpisodeGroups        = new List <TimeWarpRecord>();
            var currentPosition = 0.0;

            foreach (var videoRenderOption in this.VideoRenderOptions)
            {
                if (videoRenderOption.OverlayTextTimeTable != null && videoRenderOption.OverlayTextTimeTable.Any())
                {
                    textTimeTableForConcatenatedEpisodeGroups.AddRange(
                        videoRenderOption.OverlayTextTimeTable.Select(v => new TextTimeRecord(v.Lines,
                                                                                              v.StartSecond + currentPosition,
                                                                                              v.EndSecond + currentPosition)));
                }
                if (videoRenderOption.ImagesTimeTable != null && videoRenderOption.ImagesTimeTable.Any())
                {
                    imagesTimeTableForConcatenatedEpisodeGroups.AddRange(
                        videoRenderOption.ImagesTimeTable.Select(v => new DrawImageTimeRecord(v.ImageData,
                                                                                              v.LeftOffset,
                                                                                              v.TopOffset,
                                                                                              v.ImageStartSecond + currentPosition,
                                                                                              v.ImageEndSecond + currentPosition)));
                }
                if (videoRenderOption.TimeWarpSettings != null && videoRenderOption.TimeWarpSettings.Any())
                {
                    timeWarpForConcatenatedEpisodeGroups.AddRange(
                        videoRenderOption.TimeWarpSettings.Select(v =>
                                                                  new TimeWarpRecord(v.StartSecond + currentPosition, v.EndSecond + currentPosition, v.Coefficient)));
                }
                currentPosition += videoRenderOption.DurationSeconds;
            }

            var pathForConcatenatedEpisodes = timeWarpForConcatenatedEpisodeGroups.Any()
                    ? temporaryFilesStorage.GetIntermediateFile(Path.GetExtension(this.outputFile))
                    : this.outputFile;

            ffMpeg.CutAndConcatAndDrawImagesAndText(
                cutInfos,
                imagesTimeTableForConcatenatedEpisodeGroups,
                textTimeTableForConcatenatedEpisodeGroups,
                this.OutputSize,
                pathForConcatenatedEpisodes,
                this.globalExportProgress);

            if (timeWarpForConcatenatedEpisodeGroups.Any())
            {
                ffMpeg.ApplyTimeWarp(pathForConcatenatedEpisodes, timeWarpForConcatenatedEpisodeGroups, this.outputFile, this.globalExportProgress);
            }
        }
 public CutOptionsBuilder(IList <VideoRenderOption> videoRenderOptions, Size outputSize, IGlobalExportProgress globalExportProgress, TemporaryFilesStorage temporaryFilesStorage, bool ignoreOverlays)
 {
     this.temporaryFilesStorage = temporaryFilesStorage;
     this.BuildCutOptions(videoRenderOptions, outputSize, globalExportProgress, ignoreOverlays);
 }