using OpenCvSharp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;

namespace VIZ.Framework.Common
{
    /// <summary>
    /// 视频录制
    /// </summary>
    public class VideoControlRecording : ModelBase
    {
        #region MaxFrameCount -- 最大帧数

        private int maxFrameCount;
        /// <summary>
        /// 最大帧数
        /// </summary>
        public int MaxFrameCount
        {
            get { return maxFrameCount; }
            set { maxFrameCount = value; this.RaisePropertyChanged(nameof(MaxFrameCount)); }
        }

        #endregion

        /// <summary>
        /// 是否正在保存
        /// </summary>
        public bool IsSaving { get; protected set; } = false;

        /// <summary>
        /// 录制帧队列
        /// </summary>
        public ConcurrentQueue<VideoControlRecordingFrame> RecordingFrameQueue { get; private set; } = new ConcurrentQueue<VideoControlRecordingFrame>();

        /// <summary>
        /// 添加视频帧
        /// </summary>
        /// <param name="frame">视频帧</param>
        public void Append(IVideoFrame frame, object data)
        {
            if (this.IsSaving)
                return;

            VideoControlRecordingFrame recording = new VideoControlRecordingFrame();

            OpenCVStreeamVideoFrame openCv = new OpenCVStreeamVideoFrame();
            openCv.Width = frame.Width;
            openCv.Height = frame.Height;
            openCv.TimeStamp = frame.TimeStamp;
            openCv.DataStream = new SharpDX.DataStream(frame.Length, true, true);
            unsafe
            {
                Buffer.MemoryCopy(frame.DataStream.DataPointer.ToPointer(), openCv.DataStream.DataPointer.ToPointer(), frame.Length, frame.Length);
            }

            recording.VideoFrame = openCv;
            recording.DataFrame = data;

            if (this.RecordingFrameQueue.Count > this.maxFrameCount)
            {
                this.RecordingFrameQueue.TryDequeue(out VideoControlRecordingFrame _);
            }

            this.RecordingFrameQueue.Enqueue(recording);
        }

        /// <summary>
        /// 保存视频
        /// </summary>
        /// <param name="path">视频文件路径</param>
        public void Save(string path, int fps, int width, int height)
        {
            this.IsSaving = true;

            using (VideoWriter writer = new VideoWriter(path, FourCC.MJPG, fps, new OpenCvSharp.Size(width, height)))
            {
                while (this.RecordingFrameQueue.Count > 0)
                {
                    if (!this.RecordingFrameQueue.TryDequeue(out VideoControlRecordingFrame recording))
                    {
                        Task.Delay(10).Wait();

                        continue;
                    }

                    Mat mat = this.Packaging(recording);

                    writer.Write(mat);

                    mat.Dispose();
                    recording.VideoFrame.Dispose();
                }
            }

            this.IsSaving = false;
        }

        /// <summary>
        /// 录制包装
        /// </summary>
        /// <param name="recordingFrame">录制帧</param>
        /// <returns>Mat数据</returns>
        private Mat Packaging(VideoControlRecordingFrame recordingFrame)
        {
            Mat mat = new Mat(recordingFrame.VideoFrame.Height, recordingFrame.VideoFrame.Width, MatType.CV_8UC4, recordingFrame.VideoFrame.DataStream.DataPointer);

            Mat dst = new Mat();
            Cv2.CvtColor(mat, dst, ColorConversionCodes.BGRA2BGR);

            mat.Dispose();

            return dst;
        }
    }
}
