using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.IO;

using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.Threading;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System.Runtime.InteropServices;
namespace UnNomalized_node
{
    class HKVSCamera
    {
        private bool m_bInitSDK = false;
        private bool m_bRecord = false;
        private uint iLastErr = 0;
        private Int32 m_lUserID = -1;
        private Int32 m_lRealHandle = -1;
        private string str1;
        private string str2;
        private Int32 i = 0;
        private Int32 m_lTree = 0;
        private string str;
        private long iSelIndex = 0;
        private uint dwAChanTotalNum = 0;
        private uint dwDChanTotalNum = 0;
        private Int32 m_lPort = -1;
        private IntPtr m_ptrRealHandle;
        private int[] iIPDevID = new int[96];
        private int[] iChannelNum = new int[96];

        private CHCNetSDK.REALDATACALLBACK RealData = null;
        public CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;
        public CHCNetSDK.NET_DVR_IPPARACFG_V40 m_struIpParaCfgV40;
        public CHCNetSDK.NET_DVR_STREAM_MODE m_struStreamMode;
        public CHCNetSDK.NET_DVR_IPCHANINFO m_struChanInfo;
        public CHCNetSDK.NET_DVR_PU_STREAM_URL m_struStreamURL;
        public CHCNetSDK.NET_DVR_IPCHANINFO_V40 m_struChanInfoV40;
        private PlayCtrl.DECCBFUN m_fDisplayFun = null;
      
        [DllImport(@".\transpose_image.dll",
          EntryPoint = "yv12Torgb_transpose",
          CharSet = CharSet.Ansi,
          CallingConvention = CallingConvention.Cdecl)]
        public static extern void yv12Torgb_transpose(IntPtr input, IntPtr output, int height, int width, int size);

        [DllImport(@".\transpose_image.dll",
          EntryPoint = "render",
          CharSet = CharSet.Ansi,
          CallingConvention = CallingConvention.Cdecl)]
        public static extern void render(IntPtr hWnd, IntPtr buf, int height, int width, int size);
        public class Camera_Image
        {
            private IntPtr m_pBuf;
            private int m_width;
            private int m_height;
            private int m_size;
            private object lck=new object();

            
            public Camera_Image()
            {
                m_pBuf = IntPtr.Zero;
                m_width = 0;
                m_height = 0;
                m_size = 0;

            }


            public void updata(IntPtr pBuf, int width, int height,int size)
            {
                lock (lck)
                {
                    m_pBuf = pBuf;
                    m_width = width;
                    m_height = height;
                    m_size = size;
                }
            }
            private unsafe bool transform(IntPtr pBGR24)
            {
                if (m_width < 1 || m_height < 1 || m_pBuf == IntPtr.Zero)
                    return false;
                // 拷贝一份数据转换
                lock (lck)
                {
                    yv12Torgb_transpose(m_pBuf, pBGR24, m_height, m_width, m_size);
                }
                

                return true;
            }
            public void draw_image_to_wnd(IntPtr handle)
            {
                if(handle!=IntPtr.Zero&&m_pBuf!=IntPtr.Zero&&m_height>0&&m_width>0)
                    render(handle, m_pBuf, m_height, m_width, m_size);
            }
            public unsafe Bitmap get_bitmap()
            {

                if (m_width < 1 || m_height < 1 || m_pBuf == IntPtr.Zero)
                    return null;

                //获取转置bmp

                Bitmap image = new Bitmap(m_height, m_width, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                BitmapData bmpData = image.LockBits(new Rectangle(0, 0, m_height, m_width),
                       ImageLockMode.ReadWrite, image.PixelFormat);

                IntPtr desPtr = bmpData.Scan0;

                //DateTime beforDT = System.DateTime.Now;
                transform(desPtr);

                /*DateTime afterDT = System.DateTime.Now;
                TimeSpan ts = afterDT.Subtract(beforDT);
                Console.WriteLine("DateTime总共花费{0}ms.", ts.TotalMilliseconds);*/

                image.UnlockBits(bmpData);
                return image;
            }
        }

        public Camera_Image m_camera_img = new Camera_Image();

        internal static PictureBox PictureBox { set; get; }
        public Camera_Image Camera
        {
            get
            {

                return m_camera_img; 
            }

        }
        public HKVSCamera(PictureBox pictureBox)
        {
            PictureBox = pictureBox;
           
        }
        public void release()
        {
            stopview();
            
        }
      
        public bool init()
        {
            m_bInitSDK = CHCNetSDK.NET_DVR_Init();
            if (m_bInitSDK == false)
            {
                MessageBox.Show("NET_DVR_Init error!");
            }
            return m_bInitSDK;
        }

        //解码回调 视频为YUV数据(YV12)，音频为PCM数据
        private void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2)
        {
          
            // 将pBuf解码后视频输入写入文件中（解码后YUV数据量极大，尤其是高清码流，不建议在回调函数中处理）
            if (pFrameInfo.nType == 3) //#define T_YV12    3
            {
                int m_Width = pFrameInfo.nWidth;
                int m_Height = pFrameInfo.nHeight;
                ///render(PictureBox.Handle, pBuf, m_Height, m_Width, nSize);
                //m_camera_img.updata(pBuf, m_Width, m_Height,nSize);

                //Thread.Sleep(1);
                
               /* */
                // });
            }
        }
        ///把YV12数据转为BGR24数据，我只关心灰度图，因此只取了Y数据，如果想获取彩色图像，考虑计算UV数据

       
        public bool open(string ip,string user,string password,Int16 port)
        {
            if (m_bInitSDK == false)
                return false;
            string DVRIPAddress =ip; //设备IP地址或者域名 Device IP
            Int16 DVRPortNumber = port;//设备服务端口号 Device Port
            string DVRUserName = user;//设备登录用户名 User name to login
            string DVRPassword = password;//设备登录密码 Password to login

            
            //登录设备 Login the device
            m_lUserID = CHCNetSDK.NET_DVR_Login_V30(DVRIPAddress, DVRPortNumber, DVRUserName, DVRPassword, ref DeviceInfo);
            if (m_lUserID < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_Login_V30 failed, error code= " + iLastErr; //登录失败，输出错误号 Failed to login and output the error code
                MessageBox.Show(str);
                return false;
            }
            /*m_fresh_thread = new Thread(transform_function);
            m_fresh_thread.Start();*/
            return true;
        }

        public bool view()
        {
            if (m_lUserID < 0)
            {
                MessageBox.Show("Please login the device firstly!");
                return false;
            }

            if (m_bRecord)
            {
                MessageBox.Show("Please stop recording firstly!");
                return false;
            }

            if (m_lRealHandle < 0)
            {
                CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
                lpPreviewInfo.lChannel = 1;
                //lpPreviewInfo.hPlayWnd = wnd_handle;//预览窗口 live view window
                lpPreviewInfo.dwStreamType = 0;//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
                lpPreviewInfo.dwLinkMode = 0;//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
                lpPreviewInfo.bBlocked = true; //0- 非阻塞取流，1- 阻塞取流
                lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数

                IntPtr pUser = IntPtr.Zero;//用户数据 user data 

                lpPreviewInfo.hPlayWnd = PictureBox.Handle;//预览窗口 live view window
                m_ptrRealHandle = IntPtr.Zero;
                RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数 real-time stream callback function 
                m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, RealData, pUser);

                if (m_lRealHandle < 0)
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_RealPlay_V40 failed, error code= " + iLastErr; //预览失败，输出错误号 failed to start live view, and output the error code.
                    MessageBox.Show(str);
                    return false;
                }
                return true;
            }
            return true;
        }

        public void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)
        {
            //下面数据处理建议使用委托的方式
            //MyDebugInfo AlarmInfo = new MyDebugInfo(DebugInfo);
            switch (dwDataType)
            {
                case CHCNetSDK.NET_DVR_SYSHEAD:     // sys head
                    if (dwBufSize > 0)
                    {
                        if (m_lPort >= 0)
                        {
                            return; //同一路码流不需要多次调用开流接口
                        }

                        //获取播放句柄 Get the port to play
                        if (!PlayCtrl.PlayM4_GetPort(ref m_lPort))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            //----------str = "PlayM4_GetPort failed, error code= " + iLastErr;
                            //  ---------this.BeginInvoke(AlarmInfo, str);
                            break;
                        }

                        //设置流播放模式 Set the stream mode: real-time stream mode
                        if (!PlayCtrl.PlayM4_SetStreamOpenMode(m_lPort, PlayCtrl.STREAME_REALTIME))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            //str = "Set STREAME_REALTIME mode failed, error code= " + iLastErr;
                            //this.BeginInvoke(AlarmInfo, str);
                        }

                        //打开码流，送入头数据 Open stream
                        if (!PlayCtrl.PlayM4_OpenStream(m_lPort, pBuffer, dwBufSize, 2 * 1024 * 1024))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                           // str = "PlayM4_OpenStream failed, error code= " + iLastErr;
                            //this.BeginInvoke(AlarmInfo, str);
                            //break;
                        }


                        //设置显示缓冲区个数 Set the display buffer number
                        if (!PlayCtrl.PlayM4_SetDisplayBuf(m_lPort, 15))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            //str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;
                            //this.BeginInvoke(AlarmInfo, str);
                        }

                        //设置显示模式 Set the display mode
                        if (!PlayCtrl.PlayM4_SetOverlayMode(m_lPort, 0, 0/* COLORREF(0)*/)) //play off screen 
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            //str = "PlayM4_SetOverlayMode failed, error code= " + iLastErr;
                            //this.BeginInvoke(AlarmInfo, str);
                        }

                        //设置解码回调函数，获取解码后音视频原始数据 Set callback function of decoded data
                        m_fDisplayFun = new PlayCtrl.DECCBFUN(DecCallbackFUN);
                        if (!PlayCtrl.PlayM4_SetDecCallBackEx(m_lPort, m_fDisplayFun, IntPtr.Zero, 0))
                        {
                            //this.BeginInvoke(AlarmInfo, "PlayM4_SetDisplayCallBack fail");
                        }

                        //开始解码 Start to play                       
                        if (!PlayCtrl.PlayM4_Play(m_lPort, m_ptrRealHandle))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                            //str = "PlayM4_Play failed, error code= " + iLastErr;
                            //this.BeginInvoke(AlarmInfo, str);
                            break;
                        }
                    }
                    break;
                case CHCNetSDK.NET_DVR_STREAMDATA:     // video stream data
                    if (dwBufSize > 0 && m_lPort != -1)
                    {
                        for (int i = 0; i < 99; i++)
                        {
                            //送入码流数据进行解码 Input the stream data to decode
                            if (!PlayCtrl.PlayM4_InputData(m_lPort, pBuffer, dwBufSize))
                            {
                                iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                                ///str = "PlayM4_InputData failed, error code= " + iLastErr;
                                Thread.Sleep(1);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    break;
                default:
                    if (dwBufSize > 0 && m_lPort != -1)
                    {
                        //送入其他数据 Input the other data
                        for (int i = 0; i < 999; i++)
                        {
                            if (!PlayCtrl.PlayM4_InputData(m_lPort, pBuffer, dwBufSize))
                            {
                                iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                                str = "PlayM4_InputData failed, error code= " + iLastErr;
                                Thread.Sleep(2);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    break;
            }
            Thread.Sleep(1);
        }
        public void stopview()
        {
            if (m_bInitSDK == false)
                return ;
            if (m_lUserID < 0)
                return;
            //停止预览 Stop live view 
            if (!CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle))
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                return;
            }

            if (m_lPort >= 0)
            {
                if (!PlayCtrl.PlayM4_Stop(m_lPort))
                {
                    iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                    
                }
                if (!PlayCtrl.PlayM4_CloseStream(m_lPort))
                {
                    iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                   
                }
                if (!PlayCtrl.PlayM4_FreePort(m_lPort))
                {
                    iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);
                    
                }
                m_lPort = -1;
            }
            m_lRealHandle = -1;

            //注销登录
            if (m_lUserID >= 0)
            {
                CHCNetSDK.NET_DVR_Logout(m_lUserID);
                m_lUserID = -1;
            }

            CHCNetSDK.NET_DVR_Cleanup();

        }
    }
}
