using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FFMpegCore.Enums;
using FFMpegCore.Helpers;
using FFMpegCore.Pipes;
namespace FFMpegCore.Extensions.System.Drawing.Common
{
public static class FFMpegImage
{
public static void ConversionSizeExceptionCheck(Image image)
=> FFMpegHelper.ConversionSizeExceptionCheck(image.Size.Width, image.Size.Height);
///
/// Converts an image sequence to a video.
///
/// Output video file.
/// FPS
/// Image sequence collection
/// Output video information.
public static bool JoinImageSequence(string output, double frameRate = 30, params ImageInfo[] images)
{
var tempFolderName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString());
var temporaryImageFiles = images.Select((imageInfo, index) =>
{
using var image = Image.FromFile(imageInfo.FullName);
FFMpegHelper.ConversionSizeExceptionCheck(image.Width, image.Height);
var destinationPath = Path.Combine(tempFolderName, $"{index.ToString().PadLeft(9, '0')}{imageInfo.Extension}");
Directory.CreateDirectory(tempFolderName);
File.Copy(imageInfo.FullName, destinationPath);
return destinationPath;
}).ToArray();
var firstImage = images.First();
try
{
return FFMpegArguments
.FromFileInput(Path.Combine(tempFolderName, "%09d.png"), false)
.OutputToFile(output, true, options => options
.Resize(firstImage.Width, firstImage.Height)
.WithFramerate(frameRate))
.ProcessSynchronously();
}
finally
{
Cleanup(temporaryImageFiles);
Directory.Delete(tempFolderName);
}
}
///
/// Adds a poster image to an audio file.
///
/// Source image file.
/// Source audio file.
/// Output video file.
///
public static bool PosterWithAudio(string image, string audio, string output)
{
FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4);
using (var img = Image.FromFile(image))
FFMpegHelper.ConversionSizeExceptionCheck(img);
return FFMpegArguments
.FromFileInput(image, false, options => options
.Loop(1))
.AddFileInput(audio)
.OutputToFile(output, true, options => options
.WithVideoCodec(VideoCodec.LibX264)
.CopyChannel()
.WithConstantRateFactor(21)
.WithAudioBitrate(AudioQuality.Normal)
.UsingShortest())
.ProcessSynchronously();
}
///
/// Saves a 'png' thumbnail to an in-memory bitmap
///
/// Source video file.
/// Seek position where the thumbnail should be taken.
/// Thumbnail size. If width or height equal 0, the other will be computed automatically.
/// Selected video stream index.
/// Input file index
/// Bitmap with the requested snapshot.
public static Bitmap Snapshot(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
{
var source = FFProbe.Analyse(input);
var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
using var ms = new MemoryStream();
arguments
.OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
.ForceFormat("rawvideo")))
.ProcessSynchronously();
ms.Position = 0;
using var bitmap = new Bitmap(ms);
return bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat);
}
///
/// Saves a 'png' thumbnail to an in-memory bitmap
///
/// Source video file.
/// Seek position where the thumbnail should be taken.
/// Thumbnail size. If width or height equal 0, the other will be computed automatically.
/// Selected video stream index.
/// Input file index
/// Bitmap with the requested snapshot.
public static async Task SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
{
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
using var ms = new MemoryStream();
await arguments
.OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
.ForceFormat("rawvideo")))
.ProcessAsynchronously();
ms.Position = 0;
return new Bitmap(ms);
}
private static void Cleanup(IEnumerable pathList)
{
foreach (var path in pathList)
{
if (File.Exists(path))
File.Delete(path);
}
}
}
}