Dispenser/DispenserUI/ViewModels/Recorder/MJpegImageVideoEncoder.cs

84 lines
2.6 KiB
C#

using System;
using System.IO;
using SharpAvi;
using SharpAvi.Codecs;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats;
namespace DispenserUI.ViewModels.Recorder;
public class MJpegImageVideoEncoder : IVideoEncoder
{
private readonly int _width;
private readonly int _height;
private readonly JpegEncoder _jpegEncoder;
private readonly MemoryStream _buffer;
/// <summary>
/// Creates a new instance of <see cref="T:SharpAvi.Codecs.MJpegImageSharpVideoEncoder" />.
/// </summary>
/// <param name="width">Frame width.</param>
/// <param name="height">Frame height.</param>
/// <param name="quality">
/// Compression quality in the range [1..100].
/// Less values mean less size and lower image quality.
/// </param>
public MJpegImageVideoEncoder(int width, int height, int quality)
{
this._width = width;
this._height = height;
_buffer = new MemoryStream(this.MaxEncodedSize);
_jpegEncoder = new JpegEncoder
{
Quality = quality,
};
}
/// <summary>Video codec.</summary>
public FourCC Codec => CodecIds.MotionJpeg;
/// <summary>Number of bits per pixel in encoded image.</summary>
public BitsPerPixel BitsPerPixel => BitsPerPixel.Bpp24;
/// <summary>Maximum size of encoded frmae.</summary>
public int MaxEncodedSize => Math.Max(_width * _height * 3, 1024);
/// <summary>Encodes a frame.</summary>
public int EncodeFrame(
byte[] source,
int srcOffset,
byte[] destination,
int destOffset,
out bool isKeyFrame)
{
int num;
using (MemoryStream destination1 = new MemoryStream(destination))
{
destination1.Position = destOffset;
num = LoadAndEncodeImage(source.AsSpan(srcOffset), destination1);
}
isKeyFrame = true;
return num;
}
/// <summary>Encodes a frame.</summary>
public int EncodeFrame(ReadOnlySpan<byte> source, Span<byte> destination, out bool isKeyFrame)
{
_buffer.SetLength(0L);
var length = LoadAndEncodeImage(source, _buffer);
_buffer.GetBuffer().AsSpan(0, length).CopyTo(destination);
isKeyFrame = true;
return length;
}
private int LoadAndEncodeImage(ReadOnlySpan<byte> source, Stream destination)
{
var position = (int)destination.Position;
using (var image = Image.LoadPixelData<Bgra32>(source, _width, _height))
_jpegEncoder.Encode(image, destination);
destination.Flush();
return (int)(destination.Position - position);
}
}