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;

namespace VIZ.Framework.Common
{
    /// <summary>
    /// 查找NDI流任务
    /// </summary>
    public class NDIStreamRecvVideoTask : NDIStreamTaskBase
    {
        /// <summary>
        /// 查找NDI流任务
        /// </summary>
        /// <param name="stream">NDI流</param>
        public NDIStreamRecvVideoTask(NDIStream stream) : base(stream)
        {

        }

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

        /// <summary>
        /// 之前的视频帧时间戳
        /// </summary>
        private long old_video_timestamp = 0;

        /// <summary>
        /// 执行
        /// </summary>
        protected override void Execute()
        {
            while (this.IsStarted)
            {
                if (this.Stream.RecvInstancePtr == IntPtr.Zero || this.Stream.RecvSyncInstancePtr == IntPtr.Zero)
                {
                    Thread.Sleep(1);

                    continue;
                }

                // 执行
                this._Execute();
            }
        }

        /// <summary>
        /// 执行
        /// </summary>
        private void _Execute()
        {
            // 获取NDI视频帧
            NDIlib.video_frame_v2_t frame = new NDIlib.video_frame_v2_t();
            NDIlib.framesync_capture_video(this.Stream.RecvSyncInstancePtr, ref frame, NDIlib.frame_format_type_e.frame_format_type_progressive);

            // 如果该帧的时间戳与之前的帧时间戳一致
            // 那么认为没有获取到新的一帧画面
            if (this.old_video_timestamp == frame.timestamp)
            {
                NDIlib.framesync_free_video(this.Stream.RecvSyncInstancePtr, ref frame);
                Thread.Sleep(10);

                return;
            }
            // 否则
            // 获取到新的一帧画面
            this.old_video_timestamp = frame.timestamp;

            // 如果新的一帧画面的时间戳为0 || 帧没有数据
            if (frame.timestamp == 0 || frame.p_data == IntPtr.Zero || frame.p_data == null)
            {
                NDIlib.framesync_free_video(this.Stream.RecvSyncInstancePtr, ref frame);
                Thread.Sleep(10);

                return;
            }

            // 视频帧队列最大容量 
            // 如果超过该容量，那么会抛弃对队列头部的处理
            if (this.Stream.VideoFrameQueue.Count > NDIStream.VIDEO_FRAME_QUEUE_MAX_COUNT + this.Stream.Option.DelayFrame)
            {
                this.Stream.VideoFrameQueue.TryDequeue(out IVideoFrame remove);
                remove?.Dispose();
            }

            NDIStreamVideoFrame videoFrame = new NDIStreamVideoFrame();
            videoFrame.Width = frame.xres;
            videoFrame.Height = frame.yres;
            videoFrame.Length = frame.xres * frame.yres * 4;
            videoFrame.TimeStamp = frame.timestamp;
            videoFrame.DataStream = new SharpDX.DataStream(videoFrame.Length, true, true);
            unsafe
            {
                Buffer.MemoryCopy(frame.p_data.ToPointer(), videoFrame.DataStream.DataPointer.ToPointer(), videoFrame.Length, videoFrame.Length);
            }

            this.Stream.VideoFrameQueue.Enqueue(videoFrame);

            // 尝试释放帧数据
            NDIlib.framesync_free_video(this.Stream.RecvSyncInstancePtr, ref frame);

            Thread.Sleep(10);
        }
    }
}
