using NewTek;
using NewTek.NDI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
using OpenCvSharp;
using System.Diagnostics;

namespace VIZ.Framework.Common
{
    /// <summary>
    /// OpenCV接收视频任务
    /// </summary>
    public class OpenCVStreamRecvVideoTask : OpenCVStreamTaskBase
    {
        /// <summary>
        /// OpenCV接收视频任务
        /// </summary>
        /// <param name="stream">OpenCV流</param>
        public OpenCVStreamRecvVideoTask(OpenCVStream stream) : base(stream)
        {

        }

        /// <summary>
        /// 任务名称
        /// </summary>
        public override OpenCVStreamTaskNames Name => OpenCVStreamTaskNames.RECV_VIDEO;

        /// <summary>
        /// 计时器
        /// </summary>
        private readonly Stopwatch renderTimer = new Stopwatch();

        /// <summary>
        /// 执行
        /// </summary>
        protected override void Execute()
        {
            while (this.IsStarted)
            {
                long begin = this.renderTimer.ElapsedMilliseconds;
                this.renderTimer.Start();

                lock (this.Stream.read_frame_lock_object)
                {
                    // 处理一帧
                    this.ExecuteOne();
                }

                this.renderTimer.Stop();
                long end = this.renderTimer.ElapsedMilliseconds;
                int wait = (int)((1000d / this.Stream.PropertyInfos.Fps) - (end - begin));

                if (wait > 0)
                {
                    Thread.Sleep(wait);
                }
            }
        }

        /// <summary>
        /// 执行一帧
        /// </summary>
        public void ExecuteOne()
        {
            Mat src = new Mat();
            Mat mat = new Mat();

            if (!this.Stream.VideoCapture.Read(src))
            {
                src.Dispose();
                Thread.Sleep(5);
                return;
            }
            Cv2.CvtColor(src, mat, ColorConversionCodes.BGR2BGRA);

            OpenCVStreeamVideoFrame videoFrame = new OpenCVStreeamVideoFrame();
            videoFrame.Width = mat.Width;
            videoFrame.Height = mat.Height;
            videoFrame.Length = mat.Width * mat.Height * 4;
            videoFrame.TimeStamp = TimeSpan.FromMilliseconds(this.Stream.VideoCapture.PosMsec).Ticks;
            videoFrame.DataStream = new SharpDX.DataStream(videoFrame.Length, true, true);
            videoFrame.IsEnd = this.Stream.VideoCapture.PosFrames == this.Stream.PropertyInfos.FrameCount;
            unsafe
            {
                Buffer.MemoryCopy(mat.DataPointer, videoFrame.DataStream.DataPointer.ToPointer(), videoFrame.Length, videoFrame.Length);
            }

            this.Stream.VideoFrameQueue.Enqueue(videoFrame);

            src.Dispose();
            mat.Dispose();
        }
    }
}
