Files
2025-10-09 09:57:24 +09:00

579 lines
13 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading;
using FFmpeg.AutoGen;
using VideoReader.Properties;
namespace VideoReader;
internal class Decoder
{
public struct Fram
{
public long num;
public long key;
public byte[] data;
public Fram(long Num, long Key, byte[] Data)
{
num = Num;
key = Key;
data = Data;
}
}
private bool save_video_flag = false;
public bool save_video = false;
private DateTime endFrame = DateTime.Now;
private unsafe AVCodec* codec;
private unsafe sbyte* pConvertedFrameBuffer = null;
private unsafe sbyte* pConvertedFrameBufferEnd = null;
public long endkey;
private DateTime timeForFPS = DateTime.MinValue;
private int frameForFPS;
public double FPS;
private bool dec;
private Queue<double> fpsAver;
public ConcurrentDictionary<long, Fram> frames;
private Thread saveVideo;
private bool startSaveVideo;
private bool blockSaveVideo = false;
private DateTime endAddSaveVideo = DateTime.MinValue;
private ConcurrentDictionary<long, byte[]> save = new ConcurrentDictionary<long, byte[]>();
private int fps = 30;
private byte[] configN = null;
private ConcurrentQueue<string> outstr = new ConcurrentQueue<string>();
private ConcurrentQueue<string> outstr1 = new ConcurrentQueue<string>();
private ConcurrentQueue<byte[]> save_buff = new ConcurrentQueue<byte[]>();
private object block = new object();
private string name = $"{DateTime.Now.Ticks.ToString()}.tmp";
private string nam0 = $"{DateTime.Now.Ticks.ToString()}.tm0";
private long GetImgEndFrame = 0L;
private long GetImgEndKey = long.MaxValue;
public long min
{
get
{
if (frames.Count > 0)
{
try
{
return frames.Keys.Min();
}
catch (Exception value)
{
Console.WriteLine(value);
while (frames.Count > 6000)
{
frames.TryRemove(frames.First().Key, out var _);
}
return frames.First().Key;
}
}
return 0L;
}
set
{
}
}
public long max
{
get
{
if (frames.Count > 0)
{
try
{
return frames.Keys.Max();
}
catch (Exception value)
{
Console.WriteLine(value);
while (frames.Count > 6000)
{
frames.TryRemove(frames.First().Key, out var _);
}
return frames.Last().Key;
}
}
return 0L;
}
set
{
}
}
public long count
{
get
{
if (frames.Count > 0)
{
return frames.Count;
}
return 0L;
}
set
{
}
}
public void Init()
{
frameForFPS = 0;
fpsAver = new Queue<double>();
frames = new ConcurrentDictionary<long, Fram>();
endkey = -1L;
timeForFPS = DateTime.MinValue;
FPS = 0.0;
dec = false;
}
private void SaveVideo()
{
while (startSaveVideo)
{
int num = fps * 60;
if (save.Count > num || (DateTime.Now - endAddSaveVideo).TotalSeconds > 10.0)
{
Queue<byte[]> queue = new Queue<byte[]>();
if (save.ContainsKey(-1L))
{
List<long> list = new List<long>();
queue.Enqueue(save[-1L]);
int num2 = save.Count;
long[] array = save.Keys.OrderBy((long zn) => zn).ToArray();
long[] array2 = array;
foreach (long num4 in array2)
{
if (num2-- <= 0)
{
break;
}
if (num4 != -1)
{
if (save.TryGetValue(num4, out var value))
{
queue.Enqueue(value);
}
list.Add(num4);
}
}
Save(queue);
foreach (long item in list)
{
save.TryRemove(item, out var _);
}
}
}
Thread.Sleep(1000);
}
}
private unsafe void Save(Queue<byte[]> sav)
{
if (Program.FrameRate != fps)
{
fps = Program.FrameRate;
}
if (!Settings.Default.SaveVideo || sav.Count <= 1)
{
return;
}
save_video_flag = true;
Form1.forListing.Enqueue("Начало записи.");
try
{
AVCodecContext* ptr = ffmpeg.avcodec_alloc_context3(codec);
ptr->width = 1280;
ptr->height = 720;
bool flag = false;
string text = $"{Directory.GetCurrentDirectory()}\\video\\";
if (!Directory.Exists(text))
{
Directory.CreateDirectory(text);
}
string text2 = $"{DateTime.Now.Ticks}.mp4";
byte[] first = sav.Dequeue();
Form1.forListing.Enqueue(text2);
text2 = $"{text}{text2}";
AVOutputFormat* oformat = ffmpeg.av_guess_format(null, text2, null);
AVFormatContext* ptr2 = ffmpeg.avformat_alloc_context();
ptr2->oformat = oformat;
AVStream* ptr3 = ffmpeg.avformat_new_stream(ptr2, codec);
ptr3->codec = ptr;
ptr3->time_base.den = fps;
ptr3->time_base.num = 1;
ptr3->codec->time_base.den = fps;
ptr3->codec->time_base.num = 1;
if (ffmpeg.avio_open(&ptr2->pb, text2, 3) < 0)
{
Console.WriteLine("Cannot open file");
}
ffmpeg.avformat_write_header(ptr2, null);
AVPacket aVPacket = default(AVPacket);
ffmpeg.av_init_packet(&aVPacket);
long num = 1L;
while (sav.Count > 0)
{
byte[] array = sav.Dequeue();
if (!flag && array[0] == 1)
{
flag = true;
}
if (!flag)
{
continue;
}
byte[] array2 = first.Concat(array.Skip(1)).ToArray();
fixed (byte* data = &array2[0])
{
aVPacket.data = (sbyte*)data;
aVPacket.size = array2.Length;
aVPacket.pts = ffmpeg.av_rescale_q(num++, ptr3->codec->time_base, ptr3->time_base);
ffmpeg.av_interleaved_write_frame(ptr2, &aVPacket);
}
}
ffmpeg.av_free_packet(&aVPacket);
ffmpeg.av_write_trailer(ptr2);
for (int i = 0; i < ptr2->nb_streams; i++)
{
ffmpeg.av_freep(&ptr2->streams[i]->codec);
ffmpeg.av_freep(ptr2->streams + i);
}
ffmpeg.avio_close(ptr2->pb);
ffmpeg.av_free(ptr2);
ffmpeg.avcodec_close(ptr);
Form1.forListing.Enqueue("Завершение записи.");
}
catch (AccessViolationException)
{
}
catch (Exception value)
{
Console.WriteLine(value);
}
save_video_flag = false;
}
public unsafe Decoder()
{
Init();
ffmpeg.av_register_all();
ffmpeg.avcodec_register_all();
codec = ffmpeg.avcodec_find_decoder(AVCodecID.AV_CODEC_ID_H264);
if (codec == null)
{
throw new ApplicationException("Unsupported codec");
}
}
public void Close()
{
savevideo();
Thread.Sleep(300);
try
{
startSaveVideo = false;
Queue<byte[]> queue = new Queue<byte[]>();
if (!save.ContainsKey(-1L))
{
return;
}
queue.Enqueue(save[-1L]);
foreach (KeyValuePair<long, byte[]> item in save.OrderBy((KeyValuePair<long, byte[]> zn) => zn.Key))
{
if (item.Key != -1)
{
queue.Enqueue(item.Value);
save.TryRemove(item.Key, out var _);
}
}
Save(queue);
}
catch (Exception value2)
{
Console.WriteLine(value2);
}
}
~Decoder()
{
Close();
}
private void savevideo()
{
if (save_buff.Count == 0)
{
return;
}
lock (block)
{
try
{
string arg = $"{Directory.GetCurrentDirectory()}\\video\\";
FileStream fileStream = new FileStream($"{arg}{DateTime.Now:yyyyMMddHHmmss}.vs", FileMode.CreateNew);
fileStream.WriteByte(0);
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
byte[] result;
while (save_buff.TryDequeue(out result))
{
binaryWriter.Write(result.Count());
binaryWriter.Write(result);
}
binaryWriter.Flush();
binaryWriter.Close();
fileStream.Close();
}
catch (Exception)
{
}
}
}
private void addFrame(long num, long endkey, byte[] conf, byte[] mas)
{
Fram value = new Fram(num, endkey, conf.Concat(mas).ToArray());
frames.TryAdd(num, value);
if (save_video)
{
if (save_buff.Count == 0)
{
save_buff.Enqueue(conf);
}
byte[] first = ((value.key != value.num) ? new byte[1] : new byte[1] { 1 });
save_buff.Enqueue(first.Union(value.data).ToArray());
}
if (save_buff.Count > 14400)
{
new Thread((ThreadStart)delegate
{
savevideo();
}).Start();
}
if (!save.ContainsKey(-1L))
{
save.TryAdd(-1L, conf);
}
endAddSaveVideo = DateTime.Now;
outstr.Enqueue($"{num};{endkey};{mas.Length};{DateTime.Now:HH:mm:ss.fffffff}");
num++;
frameForFPS++;
if (timeForFPS == DateTime.MinValue)
{
timeForFPS = DateTime.Now;
}
if ((DateTime.Now - timeForFPS).TotalSeconds > 1.0)
{
double item = (double)frameForFPS / (DateTime.Now - timeForFPS).TotalSeconds;
fpsAver.Enqueue(item);
FPS = fpsAver.Average();
if (fpsAver.Count > 60)
{
fpsAver.Dequeue();
}
frameForFPS = 0;
timeForFPS = DateTime.Now;
}
}
public void AddFrameArray(byte[] buf)
{
endFrame = DateTime.Now;
DateTime now = DateTime.Now;
try
{
long num = BitConverter.ToInt32(buf, 0);
long num2 = num;
configN = buf.Skip(8).Take(BitConverter.ToInt32(buf, 4)).ToArray();
buf = buf.Skip(configN.Length + 8).ToArray();
int num3 = 0;
while (num3 < buf.Length)
{
byte[] array = buf.Skip(num3 + 4).Take(BitConverter.ToInt32(buf, num3)).ToArray();
num3 += array.Length + 4;
addFrame(num2, num, configN, array);
num2++;
}
TrimBuffer();
}
catch (Exception value)
{
Console.WriteLine(value);
}
Form1.t_Frame.Enqueue((DateTime.Now - now).TotalMilliseconds);
}
public void AddNNFrame(byte[] buf)
{
endFrame = DateTime.Now;
DateTime now = DateTime.Now;
long ticks = DateTime.Now.Ticks;
if (buf[0] == 2)
{
outstr.Enqueue("!");
configN = buf.Skip(1).ToArray();
}
else if (configN != null)
{
long num = BitConverter.ToInt32(buf.Skip(1).Take(4).Reverse()
.ToArray(), 0);
byte[] array = new byte[0];
if (buf[0] == 1)
{
endkey = num;
array = buf.Skip(5).ToArray();
}
else
{
endkey = BitConverter.ToInt32(buf.Skip(5).Take(4).Reverse()
.ToArray(), 0);
array = buf.Skip(9).ToArray();
}
outstr.Enqueue($"{num};{endkey};{DateTime.Now:HH:mm:ss.fffffff}");
try
{
addFrame(num, endkey, configN, array);
TrimBuffer();
}
catch (Exception ex)
{
Console.WriteLine(num);
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
Form1.t_Frame.Enqueue((DateTime.Now - now).TotalMilliseconds);
}
}
private void TrimBuffer()
{
while (frames.Count > 9000)
{
frames.TryRemove(frames.Keys.Min(), out var _);
}
}
public unsafe Bitmap GetImg(long numb)
{
//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
//IL_02cf: Expected O, but got Unknown
if (save_video_flag)
{
return null;
}
Bitmap result = null;
bool flag = true;
DateTime now = DateTime.Now;
try
{
AVCodecContext* ptr = ffmpeg.avcodec_alloc_context3(codec);
if ((codec->capabilities & 8) == 8)
{
ptr->flags |= 65536;
}
int num = ffmpeg.avcodec_open2(ptr, codec, null);
if (num < 0)
{
Console.WriteLine("Ошибка инициализации кодека: " + num);
}
try
{
if (frames.ContainsKey(numb))
{
Fram fram = frames[numb];
if (frames.ContainsKey(fram.key))
{
GetImgEndFrame = frames[numb].key;
int num2 = 0;
AVFrame* ptr2 = ffmpeg.av_frame_alloc();
int num3 = 0;
Fram value;
for (long num4 = GetImgEndFrame; num4 <= numb && frames.TryGetValue(num4, out value); num4++)
{
fixed (byte* data = value.data)
{
AVPacket aVPacket = default(AVPacket);
AVPacket* ptr3 = &aVPacket;
ffmpeg.av_init_packet(&aVPacket);
aVPacket.data = (sbyte*)data;
aVPacket.size = value.data.Length;
int num5 = ffmpeg.avcodec_decode_video2(ptr, ptr2, &num2, &aVPacket);
ffmpeg.av_free_packet(&aVPacket);
num3++;
GetImgEndFrame = num4;
}
}
if (num2 == 1)
{
dec = true;
SwsContext* ptr4 = ffmpeg.sws_getCachedContext(null, ptr->coded_width, ptr->coded_height, ptr->pix_fmt, ptr->coded_width, ptr->coded_height, AVPixelFormat.AV_PIX_FMT_BGR24, 1, null, null, null);
if (pConvertedFrameBuffer != null)
{
ffmpeg.av_free(pConvertedFrameBuffer);
}
AVFrame* ptr5 = ffmpeg.av_frame_alloc();
pConvertedFrameBuffer = (sbyte*)ffmpeg.av_malloc((ulong)ffmpeg.avpicture_get_size(AVPixelFormat.AV_PIX_FMT_BGR24, ptr->coded_width, ptr->coded_height));
ffmpeg.avpicture_fill((AVPicture*)ptr5, pConvertedFrameBuffer, AVPixelFormat.AV_PIX_FMT_BGR24, ptr->coded_width, ptr->coded_height);
ffmpeg.sws_scale(ptr4, &ptr2->data0, ptr2->linesize, 0, ptr->height, &ptr5->data0, ptr5->linesize);
IntPtr intPtr = new IntPtr(ptr5->data0);
result = new Bitmap(ptr->coded_width, ptr->coded_height, *ptr5->linesize, (PixelFormat)137224, intPtr);
ffmpeg.av_free(ptr5);
ffmpeg.sws_freeContext(ptr4);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
ffmpeg.avcodec_close(ptr);
}
catch (Exception ex2)
{
Console.WriteLine(ex2.Message);
Console.WriteLine(ex2.StackTrace);
}
return result;
}
}