init commit
This commit is contained in:
578
desktop_global/VideoReader/Decoder.cs
Normal file
578
desktop_global/VideoReader/Decoder.cs
Normal file
@@ -0,0 +1,578 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user