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; public bool save_video; 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 fpsAver; public ConcurrentDictionary frames; private Thread saveVideo; private bool startSaveVideo; private bool blockSaveVideo; private DateTime endAddSaveVideo = DateTime.MinValue; private ConcurrentDictionary save = new ConcurrentDictionary(); private int fps = 30; private byte[] configN; private ConcurrentQueue outstr = new ConcurrentQueue(); private ConcurrentQueue outstr1 = new ConcurrentQueue(); private ConcurrentQueue save_buff = new ConcurrentQueue(); private object block = new object(); private string name = DateTime.Now.Ticks + ".tmp"; private string nam0 = DateTime.Now.Ticks + ".tm0"; private long GetImgEndFrame; private long GetImgEndKey = long.MaxValue; public long min { get { if (frames.Count > 0) { return frames.Keys.Min(); } return 0L; } set { } } public long max { get { if (frames.Count > 0) { return frames.Keys.Max(); } 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(); frames = new ConcurrentDictionary(); 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 queue = new Queue(); if (save.ContainsKey(-1L)) { List list = new List(); queue.Enqueue(save[-1L]); int num2 = save.Count; long[] array = save.Keys.OrderBy((long zn) => zn).ToArray(); foreach (long num4 in array) { 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 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 queue = new Queue(); if (!save.ContainsKey(-1L)) { return; } queue.Enqueue(save[-1L]); foreach (KeyValuePair item in save.OrderBy((KeyValuePair 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); } save.TryAdd(num, new byte[1] { (byte)((num == endkey) ? 1u : 0u) }.Concat(mas).ToArray()); 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; _ = 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 > 18000) { frames.TryRemove(frames.Keys.Min(), out var _); } } public unsafe Bitmap GetImg(long numb) { //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Expected O, but got Unknown if (save_video_flag) { return null; } Bitmap result = null; _ = 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); _ = ref aVPacket; ffmpeg.av_init_packet(&aVPacket); aVPacket.data = (sbyte*)data; aVPacket.size = value.data.Length; ffmpeg.avcodec_decode_video2(ptr, ptr2, &num2, &aVPacket); ffmpeg.av_free_packet(&aVPacket); num3++; GetImgEndFrame = num4; } } if (num2 == 1) { dec = true; SwsContext* intPtr = 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* ptr3 = 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*)ptr3, pConvertedFrameBuffer, AVPixelFormat.AV_PIX_FMT_BGR24, ptr->coded_width, ptr->coded_height); ffmpeg.sws_scale(intPtr, &ptr2->data0, ptr2->linesize, 0, ptr->height, &ptr3->data0, ptr3->linesize); IntPtr intPtr2 = new IntPtr(ptr3->data0); result = new Bitmap(ptr->coded_width, ptr->coded_height, *ptr3->linesize, (PixelFormat)137224, intPtr2); ffmpeg.av_free(ptr3); ffmpeg.sws_freeContext(intPtr); } } } } 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; } }