84 lines
2.6 KiB
C#
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);
|
|
}
|
|
} |