Unity接入海康相机SDK(保姆级)

这篇具有很好参考价值的文章主要介绍了Unity接入海康相机SDK(保姆级)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Unity接入海康相机SDK(2023/6/21)

1.问题描述:控制海康相机进行操作(远焦、近焦、上下左右移动等)。
2.准备:官网下载SDK:https://open.hikvision.com/#home
选择适合自己平台代码语言开发的SDK下载
unity 海康威视,Unity接入海康相机SDK,unity
Demo里有对应案例可查看
在库文件里除了ClientDemoDll文件 都拖进unityPlugins ,然后有两个重复Dll文件(OpenAL,AudioRender)删除即可
unity 海康威视,Unity接入海康相机SDK,unity
嫌多的,到最后根据用不着的慢慢删除就行
3.开始脚本(两个脚本)
(1)引用Dll的脚本

public class HCNetSDK
{
    #region HCNetSDK.dll function definition
    // function definition
    /* The SDK initialization function */

    // 初始化SDK,调用其他SDK函数的前提
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_Init();

    // 启用日志文件写入接口
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_SetLogToFile(int nLogLevel, IntPtr strLogDir, bool bAutoDel);

    // 返回最后操作的错误码
    [DllImport(@"HCNetSDK.dll")]
    public static extern uint NET_DVR_GetLastError();

    // 释放SDK资源,在程序结束之前调用
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_Cleanup();

    // 登录接口 v40
    [DllImport(@"HCNetSDK.dll")]
    public static extern int NET_DVR_Login_V40(ref NET_DVR_USER_LOGIN_INFO pLoginInfo, ref NET_DVR_DEVICEINFO_V40 lpDeviceInfo);
    
    // 用户注销
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_Logout(int lUserID);

    // 回调函数声明,登录状态回调函数
    public delegate void LoginResultCallBack(int lUserID, uint dwResult, ref NET_DVR_DEVICEINFO_V30 lpDeviceInfo, IntPtr pUser);


    //云台控制
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_PTZControlWithSpeed_Other(int lUserID, int lChannel, uint dwPTZCommand, uint dwStop, uint dwSpeed);

    #endregion

    #region HCNetSDK.dll structure definition

    [StructLayout(LayoutKind.Sequential)]
    public struct NET_DVR_USER_LOGIN_INFO
    {
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_DEV_ADDRESS_MAX_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] sDeviceAddress;
        public byte byUseTransport;
        public ushort wPort;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_LOGIN_USERNAME_MAX_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] sUserName;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_LOGIN_PASSWD_MAX_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] sPassword;
        public LoginResultCallBack cbLoginResult;
        public IntPtr pUser;
        public bool bUseAsynLogin;
        public byte byProxyType; //0:不使用代理,1:使用标准代理,2:使用EHome代理
        public byte byUseUTCTime;    //0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换
        public byte byLoginMode; //0-Private, 1-ISAPI, 2-自适应
        public byte byHttps;    //0-不适用tls,1-使用tls 2-自适应
        public uint iProxyID;    //代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值
        public byte byVerifyMode;  //认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效;    
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 119, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes3;
    }

    public const int NET_DVR_DEV_ADDRESS_MAX_LEN = 129; //device address max length
    public const int NET_DVR_LOGIN_USERNAME_MAX_LEN = 64;   //login username max length
    public const int NET_DVR_LOGIN_PASSWD_MAX_LEN = 64; //login password max length

    public struct NET_DVR_DEVICEINFO_V40
    {
        public NET_DVR_DEVICEINFO_V30 struDeviceV30;
        public byte bySupportLock;        //设备支持锁定功能,该字段由SDK根据设备返回值来赋值的。bySupportLock为1时,dwSurplusLockTime和byRetryLoginTime有效
        public byte byRetryLoginTime;       //剩余可尝试登陆的次数,用户名,密码错误时,此参数有效
        public byte byPasswordLevel;      //admin密码安全等级0-无效,1-默认密码,2-有效密码,3-风险较高的密码。当用户的密码为出厂默认密码(12345)或者风险较高的密码时,上层客户端需要提示用户更改密码。      
        public byte byProxyType;//代理类型,0-不使用代理, 1-使用socks5代理, 2-使用EHome代理
        public uint dwSurplusLockTime;  //剩余时间,单位秒,用户锁定时,此参数有效
        public byte byCharEncodeType;     //字符编码类型(SDK所有接口返回的字符串编码类型,透传接口除外):0- 无字符编码信息(老设备),1- GB2312(简体中文),2- GBK,3- BIG5(繁体中文),4- Shift_JIS(日文),5- EUC-KR(韩文),6- UTF-8,7- ISO8859-1,8- ISO8859-2,9- ISO8859-3,…,依次类推,21- ISO8859-15(西欧) 
        public byte bySupportDev5;//支持v50版本的设备参数获取,设备名称和设备类型名称长度扩展为64字节
        public byte bySupport;  //能力集扩展,位与结果:0- 不支持,1- 支持
                                // bySupport & 0x1:  保留
                                // bySupport & 0x2:  0-不支持变化上报 1-支持变化上报
        public byte byLoginMode; //登录模式 0-Private登录 1-ISAPI登录
        public int dwOEMCode;
        public int iResidualValidity;   //该用户密码剩余有效天数,单位:天,返回负值,表示密码已经超期使用,例如“-3表示密码已经超期使用3天”
        public byte byResidualValidity; // iResidualValidity字段是否有效,0-无效,1-有效
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 243, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes2;
    }

    public const int SERIALNO_LEN = 48;//序列号长度
    public struct NET_DVR_DEVICEINFO_V30
    {
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SERIALNO_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] sSerialNumber;  //序列号
        public byte byAlarmInPortNum;               //报警输入个数
        public byte byAlarmOutPortNum;              //报警输出个数
        public byte byDiskNum;                  //硬盘个数
        public byte byDVRType;                  //设备类型, 1:DVR 2:ATM DVR 3:DVS ......
        public byte byChanNum;                  //模拟通道个数
        public byte byStartChan;                    //起始通道号,例如DVS-1,DVR - 1
        public byte byAudioChanNum;                //语音通道数
        public byte byIPChanNum;                    //最大数字通道个数,低位  
        public byte byZeroChanNum;          //零通道编码个数 //2010-01-16
        public byte byMainProto;            //主码流传输协议类型 0-private, 1-rtsp,2-同时支持private和rtsp
        public byte bySubProto;             //子码流传输协议类型0-private, 1-rtsp,2-同时支持private和rtsp
        public byte bySupport;        //能力,位与结果为0表示不支持,1表示支持,
                                      //bySupport & 0x1, 表示是否支持智能搜索
                                      //bySupport & 0x2, 表示是否支持备份
                                      //bySupport & 0x4, 表示是否支持压缩参数能力获取
                                      //bySupport & 0x8, 表示是否支持多网卡
                                      //bySupport & 0x10, 表示支持远程SADP
                                      //bySupport & 0x20, 表示支持Raid卡功能
                                      //bySupport & 0x40, 表示支持IPSAN 目录查找
                                      //bySupport & 0x80, 表示支持rtp over rtsp
        public byte bySupport1;        // 能力集扩充,位与结果为0表示不支持,1表示支持
                                       //bySupport1 & 0x1, 表示是否支持snmp v30
                                       //bySupport1 & 0x2, 支持区分回放和下载
                                       //bySupport1 & 0x4, 是否支持布防优先级	
                                       //bySupport1 & 0x8, 智能设备是否支持布防时间段扩展
                                       //bySupport1 & 0x10, 表示是否支持多磁盘数(超过33个)
                                       //bySupport1 & 0x20, 表示是否支持rtsp over http	
                                       //bySupport1 & 0x80, 表示是否支持车牌新报警信息2012-9-28, 且还表示是否支持NET_DVR_IPPARACFG_V40结构体
        public byte bySupport2; /*能力,位与结果为0表示不支持,非0表示支持							
							bySupport2 & 0x1, 表示解码器是否支持通过URL取流解码
							bySupport2 & 0x2,  表示支持FTPV40
							bySupport2 & 0x4,  表示支持ANR
							bySupport2 & 0x8,  表示支持CCD的通道参数配置
							bySupport2 & 0x10,  表示支持布防报警回传信息(仅支持抓拍机报警 新老报警结构)
							bySupport2 & 0x20,  表示是否支持单独获取设备状态子项
							bySupport2 & 0x40,  表示是否是码流加密设备*/
        public ushort wDevType;              //设备型号
        public byte bySupport3; //能力集扩展,位与结果为0表示不支持,1表示支持
                                //bySupport3 & 0x1, 表示是否多码流
                                // bySupport3 & 0x4 表示支持按组配置, 具体包含 通道图像参数、报警输入参数、IP报警输入、输出接入参数、
                                // 用户参数、设备工作状态、JPEG抓图、定时和时间抓图、硬盘盘组管理 
                                //bySupport3 & 0x8为1 表示支持使用TCP预览、UDP预览、多播预览中的"延时预览"字段来请求延时预览(后续都将使用这种方式请求延时预览)。而当bySupport3 & 0x8为0时,将使用 "私有延时预览"协议。
                                //bySupport3 & 0x10 表示支持"获取报警主机主要状态(V40)"。
                                //bySupport3 & 0x20 表示是否支持通过DDNS域名解析取流

        public byte byMultiStreamProto;//是否支持多码流,按位表示,0-不支持,1-支持,bit1-码流3,bit2-码流4,bit7-主码流,bit-8子码流
        public byte byStartDChan;       //起始数字通道号,0表示无效
        public byte byStartDTalkChan;   //起始数字对讲通道号,区别于模拟对讲通道号,0表示无效
        public byte byHighDChanNum;     //数字通道个数,高位
        public byte bySupport4;
        public byte byLanguageType;// 支持语种能力,按位表示,每一位0-不支持,1-支持  
                                   //  byLanguageType 等于0 表示 老设备
                                   //  byLanguageType & 0x1表示支持中文
                                   //  byLanguageType & 0x2表示支持英文
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 9, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes2;		//保留
    }

    #endregion
}

(2)控制海康相机的脚本

public class Camera_HK : MonoBehaviour
{
    public Text showMesText;

    private uint iLastErr = 0;
    private int m_lUserID = -1;
    private HCNetSDK.NET_DVR_USER_LOGIN_INFO struLogInfo;
    private HCNetSDK.NET_DVR_DEVICEINFO_V40 DeviceInfo;
    private string str;

    HCNetSDK.LoginResultCallBack LoginCallBack = null;

    public Button up_Button;
    public Button dow_Button;
    public Button lef_Button;
    public Button rig_Button;
    public Button zoomOut_Button;//焦距小
    public Button zoomIn_Button;

    
    Thread thread;
    void Start()
    {

        bool m_bInitSDK = HCNetSDK.NET_DVR_Init();
        if (m_bInitSDK == false)
        {
            Debug.Log("初始化失败!");
            // showMesText.text += "初始化失败!";
            return;
        }
        else
        {
            Debug.Log("初始化成功!");

            // showMesText.text += "初始化成功!";
        }

        LoginCameraHK();      

    }


    #region 按钮事件  

    /// <summary>
    /// 云控制台
    /// </summary>
    /// <param name="登录成功返回的ID"></param>
    /// <param name="默认1"></param>
    /// <param name="平台控制命令"></param>
    /// <param name="开始/停止"></param>
    /// <param name="速度"></param>
    /// <param name="备注"></param>
    private void ControlHead(int lUserID, int lChannel, uint dwPTZCommand, uint dwStop, uint dwSpeed,string remarks="")
    {
        if (HCNetSDK.NET_DVR_PTZControlWithSpeed_Other(lUserID, lChannel, dwPTZCommand, dwStop, dwSpeed))
        {
            Debug.Log("控制云台成功!"+ remarks);
        }
        else
        {
            Debug.Log("控制云台失败...");
            ViewErrorInfo("初始化失败!", HCNetSDK.NET_DVR_GetLastError());
        }
    }
    //Button 按钮  Event Trigger 组件 按下开始做操作 抬起 停止
    public void up_ButtonDownEvent()
    {       
        ControlHead(m_lUserID, 1, 21, 0, 2, "开始上仰");
    }
    public void up_ButtonUpEvent()
    {
        ControlHead(m_lUserID, 1, 21, 1, 2, "关闭上仰");
    }
    
    public void dow_ButtonDownEvent()
    {
        ControlHead(m_lUserID, 1, 22, 0, 2, "开始下俯");
    }

    public void dow_ButtonUpEvent()
    {
        ControlHead(m_lUserID, 1, 22, 1, 2, "关闭下俯");
    }
    
    public void lef_ButtonDownEvent()
    {
        ControlHead(m_lUserID, 1, 23, 0, 2, "开始左转");
    }

    public void lef_ButtonUpEvent()
    {
        ControlHead(m_lUserID, 1, 23, 1, 2, "关闭左转");
    }

    public void rig_ButtonDownEvent()
    {
        ControlHead(m_lUserID, 1, 24, 0, 2, "开始右转");
    }

    public void rig_ButtonUpEvent()
    {
        ControlHead(m_lUserID, 1, 24, 1, 2, "关闭右转");
    }

    public void zoomOut_ButtonDownEvent()
    {
        ControlHead(m_lUserID, 1, 11, 0, 2, "开始焦距变小");
    }

    public void zoomOut_ButtonUpEvent()
    {
        ControlHead(m_lUserID, 1, 11, 1, 2, "关闭焦距变小");
    }
    
    public void zoomIn_ButtonDownEvent()
    {
        ControlHead(m_lUserID, 1, 12, 0, 2, "开始焦距变大");
    }

    public void zoomIn_ButtonUpEvent()
    {
        ControlHead(m_lUserID, 1, 12, 1, 2, "关闭焦距变大");
    }

   
    #endregion
    private void ViewErrorInfo(string errorMessage, uint errorCode)
    {
        Debug.Log(errorMessage + ", 错误代码: " + errorCode);
    }
    public void LoginCameraHK()
    {
        struLogInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();

        if (m_lUserID < 0)
        {
            //从textBox文本框读取字符串,转成byte数组之后,赋值给结构体对象中对应字段
            //设备IP地址或者域名
            byte[] byIP = System.Text.Encoding.Default.GetBytes("192.168.0.201"); //改成自己的
            struLogInfo.sDeviceAddress = new byte[129];
            byIP.CopyTo(struLogInfo.sDeviceAddress, 0);

            //设备用户名
            byte[] byUserName = System.Text.Encoding.Default.GetBytes("admin"); // 改成自己的
            struLogInfo.sUserName = new byte[64];
            byUserName.CopyTo(struLogInfo.sUserName, 0);

            //设备密码
            byte[] byPassword = System.Text.Encoding.Default.GetBytes("q123456.");///改成自己的
            struLogInfo.sPassword = new byte[64];
            byPassword.CopyTo(struLogInfo.sPassword, 0);

            struLogInfo.wPort = ushort.Parse("8000");//设备服务端口号   ///改成自己的  这边注意视频流554 等不是端口 ,端口需要进海康相机自带平台去看一下

            if (LoginCallBack == null)
            {
                LoginCallBack = new HCNetSDK.LoginResultCallBack(cbLoginCallBack);//注册回调函数                    
            }
            struLogInfo.cbLoginResult = LoginCallBack;
            struLogInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是 

            DeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();

            //登录设备 Login the device
            m_lUserID = HCNetSDK.NET_DVR_Login_V40(ref struLogInfo, ref DeviceInfo);



            if (m_lUserID < 0)
            {
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_Login_V40 failed, error code= " + iLastErr; //登录失败,输出错误号\     
                Debug.Log(str);
                // showMesText.text += str;
                return;
            }
            else
            {
                Debug.Log("m_lUserID:" + m_lUserID);
                //登录成功         
                Debug.Log("登陆成功!");
                // showMesText.text += "登陆成功!";
            }
        }
        else
        {
            //注销登录 Logout the device                
            if (!HCNetSDK.NET_DVR_Logout(m_lUserID))
            {
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_Logout failed, error code= " + iLastErr;
                Debug.LogWarning(str);
                return;
            }
            m_lUserID = -1;          

        }



    }

    private void cbLoginCallBack(int lUserID, uint dwResult, ref HCNetSDK.NET_DVR_DEVICEINFO_V30 lpDeviceInfo, IntPtr pUser)
    {
        string strLoginCallBack = "登录设备,lUserID:" + lUserID + ",dwResult:" + dwResult;
        Debug.Log("cbLoginCallBack:" + strLoginCallBack);
        //  showMesText.text += strLoginCallBack;
    }
  
    private void OnApplicationQuit()
    {
        Debug.Log("用户注销...");
        HCNetSDK.NET_DVR_Logout(m_lUserID);
        m_lUserID = -1;
        Debug.Log("SDK资源卸载...");
        HCNetSDK.NET_DVR_Cleanup();
       
    }

再具体可结合海康提供的接口文本去查看
unity 海康威视,Unity接入海康相机SDK,unity
参考文章:Unity3d C# 接入海康威视摄像头SDK实现接口控制功能(如:控制云台) 作者:十幺卜入文章来源地址https://www.toymoban.com/news/detail-599617.html

到了这里,关于Unity接入海康相机SDK(保姆级)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 海康威视监控相机的SDK与opencv调用(非工业相机)

    本篇主要对海康威视的监控相机的SDK回调进行研究,并于opencv结合,保存图像,以供后续其他处理,开发语言为C++ 2.1 海康SDK介绍 海康SDK下载地址 根据自身编译环境,下载对应的SDK,需要注意的是,不要和工业相机SDK相混淆,工业相机好像是MVS是什么玩意儿,现在暂时没研究

    2024年02月04日
    浏览(64)
  • 海康威视工业相机Linux SDK开发指南详细步骤(Ubuntu20.04+单目、双目相机单次、连续拍照)

    由于实验需要使用双目相机同步采集图像,实验室准备的设备是海康威视的工业相机,对其进行二次开发,其中花了大部分时间查找资料,以及代码进行反复调试,最后到达了想要的效果,并写博客记录一下。 首先是资料的查找,我们要注意的是海康威视一共有两个官网,一

    2024年02月16日
    浏览(144)
  • 【项目实践】海康威视工业相机SDK开发小白版入门教程(VS2015+OpenCV4.5.1)

      由于学校要求暑期实习,于是找了一位学长开的公司,接了一个项目,是 对海康威视工业相机(MV_CE200_10GM)进行二次开发,读取其图像并做分析处理。 于是花了一点时间查找的相关资料并记录一些 入门要点 。   想先说说一些 “尝试授人与渔” 的话,也是自己的一

    2024年02月04日
    浏览(52)
  • Unity连接海康威视摄像头 打包后报107或是109的错误 解决方案

    最近在做一个海康威视摄像头的项目,万事俱备,打包G了。在此做一个备忘,先感谢“张富贵”老哥的帖子,原贴关于unity 引用海康威视SDK,打包后不显示问题_张富贵-的博客-CSDN博客_unity打包海康威视摄像头无法播放 解决方案:打包后的文件夹中,找到“文件名_Data-Plugin

    2024年02月15日
    浏览(137)
  • 基于海康SDK实现Python调用海康威视网络摄像头

    本文参考博客,写得很好: Python调用海康威视网络相机之——python调用海康威视C++的SDK Python调用海康威视网络相机C++的SDK 写本文的目的,也是快速复盘,所以没有很详细 保存视频流到本地可参考下一篇:基于海康SDK实现Python保存海康威视网络摄像头拍摄的视频 Windows11 Vis

    2024年02月02日
    浏览(67)
  • vue+js+海康web开发包接入海康威视摄像头

    一、登录海康开放平台下载web开发包,下载需要先登录海康账号,没有的需先注册一个。 海康开放平台web开发包下载地址:https://open.hikvision.com/download/5cda567cf47ae80dd41a54b3?type=10id=4c945d18fa5f49638ce517ec32e24e24 二、将web开发包引入vue项目 下载后解压的包目录如下: 将把webs下的整个

    2024年02月02日
    浏览(60)
  • 基于海康威视的SDK实现二次开发

    因为网上关于海康威视SDK这块的开发资源比较少,自己也是一步一步摸索过来,知道那种痛苦, 所以把自己的一些过来人的经验写出来供大家学习参考 进入海康威视官网 下载你所需要的SDK开发包(这里我就用windows来作为案列) 下载完SDK解压 里面有开发文档和SDK的动态库文

    2024年04月10日
    浏览(45)
  • 【unity接入SDK案例】从0到1 如何接入百度地图SDK到unity中【一】

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 :Unity基础实战 下载入口 下载入口 android studio版本是:2021.2.1.16, 打开后 点击SDK Manager 我们需要更改一下SDK的安装路径 选择自己新建的文

    2024年03月17日
    浏览(46)
  • 【unity接入SDK案例】从0到1 如何接入百度地图SDK到unity中【二】

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 :Unity基础实战 下载入口 下载入口 android studio版本是:2021.2.1.16, 打开后 点击SDK Manager 我们需要更改一下SDK的安装路径 选择自己新建的文

    2024年04月09日
    浏览(49)
  • 海康威视SDK视频录制及强制I帧操作

    使用下面方法可以实现视频录像功能。 该方法有个问题,视频可以录制,但是不能被前端页面直接加载播放,因为视频编码格式问题,虽然可以用FFMPEG工具进行格式转化,但是引入第三方的库,无疑会使代码的维护性降低。 FFMPEG工具 地址 提取码 zc14 使用FFmpeg进行转换的方法

    2023年04月24日
    浏览(80)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包