diff --git a/FFMpegCore.Examples/Program.cs b/FFMpegCore.Examples/Program.cs index ac4bce5..f926d94 100644 --- a/FFMpegCore.Examples/Program.cs +++ b/FFMpegCore.Examples/Program.cs @@ -3,6 +3,7 @@ using FFMpegCore.Enums; using FFMpegCore.Extensions.System.Drawing.Common; using FFMpegCore.Pipes; +using SkiaSharp; var inputPath = "/path/to/input"; var outputPath = "/path/to/output"; @@ -79,7 +80,7 @@ await FFMpegArguments FFMpeg.PosterWithAudio(inputPath, inputAudioPath, outputPath); // or #pragma warning disable CA1416 - using var image = Image.FromFile(inputImagePath); + using var image = SKBitmap.Decode(inputImagePath); image.AddAudio(inputAudioPath, outputPath); #pragma warning restore CA1416 } diff --git a/FFMpegCore.Extensions.System.Drawing.Common/BitmapExtensions.cs b/FFMpegCore.Extensions.System.Drawing.Common/BitmapExtensions.cs index 14cecaa..b8a0c83 100644 --- a/FFMpegCore.Extensions.System.Drawing.Common/BitmapExtensions.cs +++ b/FFMpegCore.Extensions.System.Drawing.Common/BitmapExtensions.cs @@ -1,13 +1,17 @@ -using System.Drawing; +using SkiaSharp; namespace FFMpegCore.Extensions.System.Drawing.Common { public static class BitmapExtensions { - public static bool AddAudio(this Image poster, string audio, string output) + public static bool AddAudio(this SKBitmap poster, string audio, string output) { var destination = $"{Environment.TickCount}.png"; - poster.Save(destination); + using (var fileStream = File.OpenWrite(destination)) + { + poster.Encode(fileStream, SKEncodedImageFormat.Png, default); // PNG does not respect the quality parameter + } + try { return FFMpeg.PosterWithAudio(destination, audio, output); diff --git a/FFMpegCore.Extensions.System.Drawing.Common/BitmapVideoFrameWrapper.cs b/FFMpegCore.Extensions.System.Drawing.Common/BitmapVideoFrameWrapper.cs index 5462ca2..0439721 100644 --- a/FFMpegCore.Extensions.System.Drawing.Common/BitmapVideoFrameWrapper.cs +++ b/FFMpegCore.Extensions.System.Drawing.Common/BitmapVideoFrameWrapper.cs @@ -1,7 +1,5 @@ -using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.InteropServices; -using FFMpegCore.Pipes; +using FFMpegCore.Pipes; +using SkiaSharp; namespace FFMpegCore.Extensions.System.Drawing.Common { @@ -13,44 +11,24 @@ public class BitmapVideoFrameWrapper : IVideoFrame, IDisposable public string Format { get; private set; } - public Bitmap Source { get; private set; } + public SKBitmap Source { get; private set; } - public BitmapVideoFrameWrapper(Bitmap bitmap) + public BitmapVideoFrameWrapper(SKBitmap bitmap) { Source = bitmap ?? throw new ArgumentNullException(nameof(bitmap)); - Format = ConvertStreamFormat(bitmap.PixelFormat); + Format = ConvertStreamFormat(bitmap.ColorType); } public void Serialize(Stream stream) { - var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat); - - try - { - var buffer = new byte[data.Stride * data.Height]; - Marshal.Copy(data.Scan0, buffer, 0, buffer.Length); - stream.Write(buffer, 0, buffer.Length); - } - finally - { - Source.UnlockBits(data); - } + var data = Source.Bytes; + stream.Write(data, 0, data.Length); } public async Task SerializeAsync(Stream stream, CancellationToken token) { - var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat); - - try - { - var buffer = new byte[data.Stride * data.Height]; - Marshal.Copy(data.Scan0, buffer, 0, buffer.Length); - await stream.WriteAsync(buffer, 0, buffer.Length, token).ConfigureAwait(false); - } - finally - { - Source.UnlockBits(data); - } + var data = Source.Bytes; + await stream.WriteAsync(data, 0, data.Length, token).ConfigureAwait(false); } public void Dispose() @@ -58,27 +36,20 @@ public void Dispose() Source.Dispose(); } - private static string ConvertStreamFormat(PixelFormat fmt) + private static string ConvertStreamFormat(SKColorType fmt) { switch (fmt) { - case PixelFormat.Format16bppGrayScale: - return "gray16le"; - case PixelFormat.Format16bppRgb555: - return "bgr555le"; - case PixelFormat.Format16bppRgb565: - return "bgr565le"; - case PixelFormat.Format24bppRgb: - return "bgr24"; - case PixelFormat.Format32bppArgb: + case SKColorType.Gray8: + return "gray8"; + case SKColorType.Bgra8888: return "bgra"; - case PixelFormat.Format32bppPArgb: - //This is not really same as argb32 - return "argb"; - case PixelFormat.Format32bppRgb: + case SKColorType.Rgb888x: + return "rgb"; + case SKColorType.Rgba8888: return "rgba"; - case PixelFormat.Format48bppRgb: - return "rgb48le"; + case SKColorType.Rgb565: + return "rgb565"; default: throw new NotSupportedException($"Not supported pixel format {fmt}"); } diff --git a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegCore.Extensions.System.Drawing.Common.csproj b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegCore.Extensions.System.Drawing.Common.csproj index aafb577..b0d6349 100644 --- a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegCore.Extensions.System.Drawing.Common.csproj +++ b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegCore.Extensions.System.Drawing.Common.csproj @@ -11,7 +11,7 @@ - + diff --git a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs index f36f83d..8cd0f26 100644 --- a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs +++ b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs @@ -1,5 +1,6 @@ using System.Drawing; using FFMpegCore.Pipes; +using SkiaSharp; namespace FFMpegCore.Extensions.System.Drawing.Common { @@ -14,7 +15,7 @@ public static class FFMpegImage /// 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) + public static SKBitmap Snapshot(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0) { var source = FFProbe.Analyse(input); var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex); @@ -26,8 +27,8 @@ public static Bitmap Snapshot(string input, Size? size = null, TimeSpan? capture .ProcessSynchronously(); ms.Position = 0; - using var bitmap = new Bitmap(ms); - return bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat); + using var bitmap = SKBitmap.Decode(ms); + return bitmap.Copy(); } /// /// Saves a 'png' thumbnail to an in-memory bitmap @@ -38,7 +39,7 @@ public static Bitmap Snapshot(string input, Size? size = null, TimeSpan? capture /// 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) + 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) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex); @@ -50,7 +51,7 @@ await arguments .ProcessAsynchronously(); ms.Position = 0; - return new Bitmap(ms); + return SKBitmap.Decode(ms); } } }