Sfoglia il codice sorgente

V0.7
1、添加了使用动态加载的方式调用hk动态库
2、修改了环形队列

Apple 1 mese fa
parent
commit
65011956a6

+ 327 - 0
CPlayer/HKSDKAPI/hksdkapi.cpp

@@ -0,0 +1,327 @@
+#include "hksdkapi.h"
+
+#include "LHQLogAPI.h"
+
+#include <QString>
+#include <QLibrary>
+
+
+
+/* ========================================================================
+ * ************************* 定义海康的SDK接口 *****************************
+ * ======================================================================== */
+
+/* 网络登陆相关的函数指针 */
+using pNet_DEV_Init = bool(*)();
+using pNET_DVR_Cleanup = bool(*)();
+using pNET_DVR_SetConnectTime = bool(*)(DWORD dwWaitTime, DWORD dwTryTimes);
+using pNET_DVR_SetReconnect = bool(*)(DWORD dwInterval, BOOL bEnableRecon);
+using pNET_DVR_Login_V40 = LONG(*)(LPNET_DVR_USER_LOGIN_INFO pLoginInfo,LPNET_DVR_DEVICEINFO_V40 lpDeviceInfo);
+using pNET_DVR_Logout = BOOL(*)(LONG lUserID);
+using pNET_DVR_GetLastError = DWORD(*)();
+
+using pNET_DVR_RealPlay_V40 = LONG(*)(LONG lUserID, LPNET_DVR_PREVIEWINFO lpPreviewInfo, REALDATACALLBACK fRealDataCallBack_V30, void* pUser);
+using pNET_DVR_StopRealPlay = bool(*)(LONG lRealHandle);
+
+
+/* 播放相关的函数指针 */
+using pPlayM4_GetPort = BOOL(*)(LONG* nPort);
+using pPlayM4_FreePort = BOOL(*)(LONG nPort);
+using pPlayM4_Stop = BOOL(*)(LONG nPort);
+using pPlayM4_OpenStream = BOOL(*)(LONG nPort,PBYTE pFileHeadBuf,DWORD nSize,DWORD nBufPoolSize);
+using pPlayM4_CloseStream = BOOL(*)(LONG nPort);
+using pPlayM4_SetDecCallBackMend = BOOL(*)(LONG nPort, void (CALLBACK* DecCBFun)(long nPort, char * pBuf, long nSize, FRAME_INFO * pFrameInfo, void* nUser,void* nReserved2), void* nUser);
+using pPlayM4_Play = BOOL(*)(LONG nPort, HWND hWnd);
+using pPlayM4_PlaySound = BOOL(*)(LONG nPort);
+using pPlayM4_InputData = BOOL(*)(LONG nPort,PBYTE pBuf,DWORD nSize);
+using pPlayM4_GetLastError = DWORD(*)(LONG nPort);
+
+
+/* 网络登录相关的函数指针 */
+pNet_DEV_Init g_NET_DVR_Init = nullptr;
+pNET_DVR_Cleanup g_NET_DVR_Cleanup = nullptr;
+pNET_DVR_SetConnectTime g_NET_DVR_SetConnectTime = nullptr;
+pNET_DVR_SetReconnect g_NET_DVR_SetReconnect = nullptr;
+pNET_DVR_Login_V40 g_NET_DVR_Login_V40 = nullptr;
+pNET_DVR_Logout g_NET_DVR_Logout = nullptr;
+pNET_DVR_GetLastError g_NET_DVR_GetLastError = nullptr;
+
+pNET_DVR_RealPlay_V40 g_NET_DVR_RealPlay_V40 = nullptr;
+pNET_DVR_StopRealPlay g_NET_DVR_StopRealPlay = nullptr;
+
+/* 播放相关的函数指针 */
+pPlayM4_GetPort g_PlayM4_GetPort = nullptr;
+pPlayM4_FreePort g_PlayM4_FreePort = nullptr;
+pPlayM4_Stop g_PlayM4_Stop = nullptr;
+pPlayM4_OpenStream g_PlayM4_OpenStream = nullptr;
+pPlayM4_CloseStream g_PlayM4_CloseStream = nullptr;
+pPlayM4_SetDecCallBackMend g_PlayM4_SetDecCallBackMend = nullptr;
+pPlayM4_Play g_PlayM4_Play = nullptr;
+pPlayM4_PlaySound g_PlayM4_PlaySound = nullptr;
+pPlayM4_InputData g_PlayM4_InputData = nullptr;
+pPlayM4_GetLastError g_PlayM4_GetLastError = nullptr;
+
+
+/* ========================================================================
+ * ****************************** API函数 **********************************
+ * ======================================================================== */
+/* 加载动态库 */
+bool load_HKSDK_Library(QString libPath)
+{
+    if(libPath.isEmpty())
+    {
+        return false;
+    }
+    /* 加载网络动态库 */
+#if defined(Q_OS_WIN)
+    QString libNetPath = libPath + "/HCNetSDK.dll";
+    QString libPlayPath = libPath + "/PlayCtrl.dll";
+#elif defined(Q_OS_LINUX)
+    QString libNetPath = libPath + "/libhcnetsdk.so";
+    QString libPlayPath = libPath + "/libPlayCtrl.so";
+#endif
+
+    QLibrary libNet(libNetPath);
+    if(!libNet.load())
+    {
+        LH_WRITE_ERROR(QString("load 《HCNetSDK》 library failed, path: %1").arg(libPath));
+        return false;
+    }
+    g_NET_DVR_Init = (pNet_DEV_Init)libNet.resolve("NET_DVR_Init");
+    g_NET_DVR_Cleanup = (pNET_DVR_Cleanup)libNet.resolve("NET_DVR_Cleanup");
+    g_NET_DVR_SetConnectTime = (pNET_DVR_SetConnectTime)libNet.resolve("NET_DVR_SetConnectTime");
+    g_NET_DVR_SetReconnect = (pNET_DVR_SetReconnect)libNet.resolve("NET_DVR_SetReconnect");
+    g_NET_DVR_Login_V40 = (pNET_DVR_Login_V40)libNet.resolve("NET_DVR_Login_V40");
+    g_NET_DVR_Logout = (pNET_DVR_Logout)libNet.resolve("NET_DVR_Logout");
+    g_NET_DVR_GetLastError = (pNET_DVR_GetLastError)libNet.resolve("NET_DVR_GetLastError");
+    g_NET_DVR_RealPlay_V40 = (pNET_DVR_RealPlay_V40)libNet.resolve("NET_DVR_RealPlay_V40");
+    g_NET_DVR_StopRealPlay = (pNET_DVR_StopRealPlay)libNet.resolve("NET_DVR_StopRealPlay");
+
+    if(g_NET_DVR_Init == nullptr || g_NET_DVR_Cleanup == nullptr || g_NET_DVR_SetConnectTime == nullptr || 
+        g_NET_DVR_SetReconnect == nullptr || g_NET_DVR_Login_V40 == nullptr || g_NET_DVR_Logout == nullptr ||
+        g_NET_DVR_GetLastError == nullptr || g_NET_DVR_RealPlay_V40 == nullptr || g_NET_DVR_StopRealPlay == nullptr)
+    {
+        LH_WRITE_ERROR("load HCNetSDK library failed, resolve function failed!");
+        return false;
+    }
+
+    /* 加载播放动态库 */
+    QLibrary libPlayM4(libPlayPath);
+    if(!libPlayM4.load())
+    {
+        LH_WRITE_ERROR(QString("load 《PlayCtrl》 library failed, path: %1").arg(libPath));
+        return false;
+    }
+
+    g_PlayM4_GetPort = (pPlayM4_GetPort)libPlayM4.resolve("PlayM4_GetPort");
+    g_PlayM4_FreePort = (pPlayM4_FreePort)libPlayM4.resolve("PlayM4_FreePort");
+    g_PlayM4_Stop = (pPlayM4_Stop)libPlayM4.resolve("PlayM4_Stop");
+    g_PlayM4_OpenStream = (pPlayM4_OpenStream)libPlayM4.resolve("PlayM4_OpenStream");
+    g_PlayM4_CloseStream = (pPlayM4_CloseStream)libPlayM4.resolve("PlayM4_CloseStream");
+    g_PlayM4_SetDecCallBackMend = (pPlayM4_SetDecCallBackMend)libPlayM4.resolve("PlayM4_SetDecCallBackMend");
+    g_PlayM4_Play = (pPlayM4_Play)libPlayM4.resolve("PlayM4_Play");
+    g_PlayM4_PlaySound = (pPlayM4_PlaySound)libPlayM4.resolve("PlayM4_PlaySound");
+    g_PlayM4_InputData = (pPlayM4_InputData)libPlayM4.resolve("PlayM4_InputData");
+    g_PlayM4_GetLastError = (pPlayM4_GetLastError)libPlayM4.resolve("PlayM4_GetLastError");
+
+    if(g_PlayM4_GetPort == nullptr || g_PlayM4_FreePort == nullptr || g_PlayM4_Stop == nullptr || 
+        g_PlayM4_OpenStream == nullptr || g_PlayM4_CloseStream == nullptr || g_PlayM4_SetDecCallBackMend == nullptr ||
+        g_PlayM4_Play == nullptr || g_PlayM4_PlaySound == nullptr || g_PlayM4_InputData == nullptr || g_PlayM4_GetLastError == nullptr)
+    {
+        LH_WRITE_ERROR("load PlayCtrl library failed, resolve function failed!");
+        return false;
+    }
+
+    return true;
+}
+
+
+bool NET_DVR_Init()
+{
+    if(g_NET_DVR_Init == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_Init is nullptr");
+        return false;
+    }
+    return g_NET_DVR_Init();
+}
+
+bool NET_DVR_Cleanup()
+{
+    if(g_NET_DVR_Cleanup == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_Cleanup is nullptr");
+        return false;
+    }
+    return g_NET_DVR_Cleanup();
+}
+
+bool NET_DVR_SetConnectTime(DWORD dwWaitTime, DWORD dwTryTimes)
+{
+    if(g_NET_DVR_SetConnectTime == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_SetConnectTime is nullptr");
+        return false;
+    }
+    return g_NET_DVR_SetConnectTime(dwWaitTime, dwTryTimes);
+}
+
+bool NET_DVR_SetReconnect(DWORD dwInterval, BOOL bEnableRecon)
+{
+    if(g_NET_DVR_SetReconnect == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_SetReconnect is nullptr");
+        return false;
+    }
+    return g_NET_DVR_SetReconnect(dwInterval, bEnableRecon);
+}
+
+LONG NET_DVR_Login_V40(LPNET_DVR_USER_LOGIN_INFO pLoginInfo,LPNET_DVR_DEVICEINFO_V40 lpDeviceInfo)
+{
+    if(g_NET_DVR_Login_V40 == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_Login_V40 is nullptr");
+        return -1;
+    }
+    return g_NET_DVR_Login_V40(pLoginInfo, lpDeviceInfo);
+}
+
+bool NET_DVR_Logout(LONG lUserID)
+{
+    if(g_NET_DVR_Logout == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_Logout is nullptr");
+        return false;
+    }
+    return g_NET_DVR_Logout(lUserID);
+}
+
+DWORD NET_DVR_GetLastError()
+{
+    if(g_NET_DVR_GetLastError == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_GetLastError is nullptr");
+        return -1;
+    }
+    return g_NET_DVR_GetLastError();
+}
+
+LONG NET_DVR_RealPlay_V40(LONG lUserID, LPNET_DVR_PREVIEWINFO lpPreviewInfo, REALDATACALLBACK fRealDataCallBack_V30, void* pUser)
+{
+    if(g_NET_DVR_RealPlay_V40 == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_RealPlay_V40 is nullptr");
+        return -1;
+    }
+    return g_NET_DVR_RealPlay_V40(lUserID, lpPreviewInfo, fRealDataCallBack_V30, pUser);
+}
+
+bool NET_DVR_StopRealPlay(LONG lRealHandle)
+{
+    if(g_NET_DVR_StopRealPlay == nullptr)
+    {
+        LH_WRITE_ERROR("NET_DVR_StopRealPlay is nullptr");
+        return false;
+    }
+    return g_NET_DVR_StopRealPlay(lRealHandle);
+}
+
+bool PlayM4_GetPort(LONG* nPort)
+{
+    if(g_PlayM4_GetPort == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_GetPort is nullptr");
+        return false;
+    }
+    return g_PlayM4_GetPort(nPort);
+}
+
+bool PlayM4_FreePort(LONG nPort)
+{
+    if(g_PlayM4_FreePort == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_FreePort is nullptr");
+        return false;
+    }
+    return g_PlayM4_FreePort(nPort);
+}
+
+bool PlayM4_Stop(LONG nPort)
+{
+    if(g_PlayM4_Stop == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_Stop is nullptr");
+        return false;
+    }
+    return g_PlayM4_Stop(nPort);
+}
+
+bool PlayM4_OpenStream(LONG nPort,PBYTE pFileHeadBuf,DWORD nSize,DWORD nBufPoolSize)
+{
+    if(g_PlayM4_OpenStream == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_OpenStream is nullptr");
+        return false;
+    }
+    return g_PlayM4_OpenStream(nPort, pFileHeadBuf, nSize, nBufPoolSize);
+}
+
+bool PlayM4_CloseStream(LONG nPort)
+{
+    if(g_PlayM4_CloseStream == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_CloseStream is nullptr");
+        return false;
+    }
+    return g_PlayM4_CloseStream(nPort);
+}
+
+bool PlayM4_SetDecCallBackMend(LONG nPort, void (CALLBACK* DecCBFun)(long nPort, char * pBuf, long nSize, FRAME_INFO * pFrameInfo, void* nUser,void* nReserved2), void* nUser)
+{
+    if(g_PlayM4_SetDecCallBackMend == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_SetDecCallBackMend is nullptr");
+        return false;
+    }
+    return g_PlayM4_SetDecCallBackMend(nPort, DecCBFun, nUser);
+}
+
+bool PlayM4_Play(LONG nPort, HWND hWnd)
+{
+    if(g_PlayM4_Play == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_Play is nullptr");
+        return false;
+    }
+    return g_PlayM4_Play(nPort, hWnd);
+}
+
+bool PlayM4_PlaySound(LONG nPort)
+{
+    if(g_PlayM4_PlaySound == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_PlaySound is nullptr");
+        return false;
+    }
+    return g_PlayM4_PlaySound(nPort);
+}
+
+bool PlayM4_InputData(LONG nPort,PBYTE pBuf,DWORD nSize)
+{
+    if(g_PlayM4_InputData == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_InputData is nullptr");
+        return false;
+    }
+    return g_PlayM4_InputData(nPort, pBuf, nSize);
+}
+
+DWORD PlayM4_GetLastError(LONG nPort)
+{
+    if(g_PlayM4_GetLastError == nullptr)
+    {
+        LH_WRITE_ERROR("PlayM4_GetLastError is nullptr");
+        return -1;
+    }
+    return g_PlayM4_GetLastError(nPort);
+}

+ 44 - 0
CPlayer/HKSDKAPI/hksdkapi.h

@@ -0,0 +1,44 @@
+#ifndef HKSDKAPI_H
+#define HKSDKAPI_H
+
+#include "hksdkdefine.h"
+
+class QString;
+
+
+/* ========================================================================
+ * ************************* 海康SDK的一些宏定义 ***************************
+ * ======================================================================== */
+
+
+
+/* 加载动态库 */
+bool load_HKSDK_Library(QString libPath);
+
+/* 海康SDK Net API */
+bool NET_DVR_Init();
+bool NET_DVR_Cleanup();
+bool NET_DVR_SetConnectTime(DWORD dwWaitTime = 3000, DWORD dwTryTimes = 3);
+bool NET_DVR_SetReconnect(DWORD dwInterval = 30000, BOOL bEnableRecon = true);
+LONG NET_DVR_Login_V40(LPNET_DVR_USER_LOGIN_INFO pLoginInfo, LPNET_DVR_DEVICEINFO_V40 lpDeviceInfo);
+bool NET_DVR_Logout(LONG lUserID);
+DWORD NET_DVR_GetLastError();
+
+LONG NET_DVR_RealPlay_V40(LONG lUserID, LPNET_DVR_PREVIEWINFO lpPreviewInfo, REALDATACALLBACK fRealDataCallBack_V30, void* pUser);
+bool NET_DVR_StopRealPlay(LONG lRealHandle);
+
+
+/* 播放器 PlayM4 API */
+bool PlayM4_GetPort(LONG* nPort);
+bool PlayM4_FreePort(LONG nPort);
+bool PlayM4_Stop(LONG nPort);
+bool PlayM4_OpenStream(LONG nPort, PBYTE pFileHeadBuf, DWORD nSize, DWORD nBufPoolSize);
+bool PlayM4_CloseStream(LONG nPort);
+bool PlayM4_SetDecCallBackMend(LONG nPort, void (CALLBACK* DecCBFun)(long nPort, char* pBuf, long nSize, FRAME_INFO* pFrameInfo, void* nUser, void* nReserved2), void* nUser);
+bool PlayM4_Play(LONG nPort, HWND hWnd);
+bool PlayM4_PlaySound(LONG nPort);
+bool PlayM4_InputData(LONG nPort, PBYTE pBuf, DWORD nSize);
+DWORD PlayM4_GetLastError(LONG nPort);
+
+
+#endif /* HKSDKAPI_H */

+ 380 - 0
CPlayer/HKSDKAPI/hksdkdefine.h

@@ -0,0 +1,380 @@
+#ifndef HKSDKDEFINE_H
+#define HKSDKDEFINE_H
+
+
+#if (defined(_WIN32)) //windows
+
+#include <Windows.h>
+    #define NET_DVR_API  extern "C" __declspec(dllimport)
+    typedef  unsigned __int64   UINT64;
+    typedef  signed   __int64   INT64;
+#elif defined(__linux__) || defined(__APPLE__) //linux
+    #define  BOOL  int
+    typedef  unsigned int       DWORD;
+    typedef  unsigned short     WORD;
+    typedef  unsigned short     USHORT;
+    typedef  short              SHORT;
+    typedef  int                LONG;
+    typedef  unsigned char      BYTE;
+    typedef  unsigned int       UINT;
+    typedef  void*              LPVOID;
+    typedef  void*              HANDLE;
+    typedef  unsigned int*      LPDWORD; 
+    typedef  unsigned long long UINT64;
+    typedef  signed long long   INT64;
+
+    #ifndef TRUE
+        #define TRUE  1
+    #endif
+    #ifndef FALSE
+        #define FALSE 0
+    #endif
+    #ifndef NULL
+        #define NULL 0
+    #endif
+
+    #define __stdcall 
+    #define CALLBACK  
+
+    #define NET_DVR_API extern "C"
+    typedef unsigned int   COLORKEY;
+    typedef unsigned int   COLORREF;
+
+    #ifndef __HWND_defined
+        #define __HWND_defined
+        #if defined(__APPLE__) || defined(ANDROID)
+            typedef void* HWND;
+        #elif defined(__linux__)
+            typedef unsigned int HWND;
+        #else
+            typedef void* HWND;
+        #endif
+    #endif
+
+    #ifndef __HDC_defined
+        #define __HDC_defined
+        #if defined(__linux__)
+            typedef struct __DC
+            {
+                void*   surface;        //SDL Surface
+                HWND    hWnd;           //HDC window handle
+            }DC;
+            typedef DC* HDC;
+        #else
+            typedef void* HDC;
+        #endif
+    #endif
+
+    typedef struct tagInitInfo
+    {
+        int uWidth; 
+        int uHeight; 
+    }INITINFO; 
+#endif
+
+/* ========================================================================
+ * ********************** 海康SDK网络相关的宏定义 ***************************
+ * ======================================================================== */
+
+
+/* =============================== 宏定义 ==================================== */
+
+#define SERIALNO_LEN            48      //序列号长度
+
+#define STREAM_ID_LEN   32      //流ID长度
+
+/* =============================== 结构体定义 ==================================== */
+
+//NET_DVR_Login_V30()参数结构
+typedef struct
+{
+    BYTE sSerialNumber[SERIALNO_LEN];  //序列号
+    BYTE byAlarmInPortNum;                //报警输入个数
+    BYTE byAlarmOutPortNum;                //报警输出个数
+    BYTE byDiskNum;                    //硬盘个数
+    BYTE byDVRType;                    //设备类型, 1:DVR 2:ATM DVR 3:DVS ......
+    BYTE byChanNum;                    //模拟通道个数
+    BYTE byStartChan;                    //起始通道号,例如DVS-1,DVR - 1
+    BYTE byAudioChanNum;                //语音通道数
+    BYTE byIPChanNum;                    //最大数字通道个数,低位  
+    BYTE byZeroChanNum;            //零通道编码个数 //2010-01-16
+    BYTE byMainProto;            //主码流传输协议类型 0-private, 1-rtsp,2-同时支持private和rtsp
+    BYTE bySubProto;                //子码流传输协议类型0-private, 1-rtsp,2-同时支持private和rtsp
+    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
+    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结构体
+    BYTE bySupport2; /*能力,位与结果为0表示不支持,非0表示支持                            
+                     bySupport2 & 0x1, 表示解码器是否支持通过URL取流解码
+                     bySupport2 & 0x2,  表示支持FTPV40
+                     bySupport2 & 0x4,  表示支持ANR
+                     bySupport2 & 0x8,  表示支持CCD的通道参数配置
+                     bySupport2 & 0x10,  表示支持布防报警回传信息(仅支持抓拍机报警 新老报警结构)
+                     bySupport2 & 0x20,  表示是否支持单独获取设备状态子项
+    bySupport2 & 0x40,  表示是否是码流加密设备*/
+    WORD wDevType;              //设备型号
+    BYTE bySupport3; //能力集扩展,位与结果为0表示不支持,1表示支持
+    //bySupport3 & 0x1, 表示是否支持批量配置多码流参数
+    // bySupport3 & 0x4 表示支持按组配置, 具体包含 通道图像参数、报警输入参数、IP报警输入、输出接入参数、
+    // 用户参数、设备工作状态、JPEG抓图、定时和时间抓图、硬盘盘组管理 
+    //bySupport3 & 0x8为1 表示支持使用TCP预览、UDP预览、多播预览中的"延时预览"字段来请求延时预览(后续都将使用这种方式请求延时预览)。而当bySupport3 & 0x8为0时,将使用 "私有延时预览"协议。
+    //bySupport3 & 0x10 表示支持"获取报警主机主要状态(V40)"。
+    //bySupport3 & 0x20 表示是否支持通过DDNS域名解析取流
+    
+    BYTE byMultiStreamProto;//是否支持多码流,按位表示,0-不支持,1-支持,bit1-码流3,bit2-码流4,bit7-主码流,bit-8子码流
+    BYTE byStartDChan;        //起始数字通道号,0表示无效
+    BYTE byStartDTalkChan;    //起始数字对讲通道号,区别于模拟对讲通道号,0表示无效
+    BYTE byHighDChanNum;        //数字通道个数,高位
+    BYTE bySupport4;        //能力集扩展,位与结果为0表示不支持,1表示支持
+    //bySupport4 & 0x02 表示是否支持NetSDK透传接口(NET_DVR_STDXMLConfig)透传表单格式
+    //bySupport4 & 0x4表示是否支持拼控统一接口
+    //bySupport4 & 0x80 支持设备上传中心报警使能。表示判断调用接口是 NET_DVR_PDC_RULE_CFG_V42还是 NET_DVR_PDC_RULE_CFG_V41
+    BYTE byLanguageType;// 支持语种能力,按位表示,每一位0-不支持,1-支持  
+    //  byLanguageType 等于0 表示 老设备
+    //  byLanguageType & 0x1表示支持中文
+    //  byLanguageType & 0x2表示支持英文
+    BYTE byVoiceInChanNum;   //音频输入通道数 
+    BYTE byStartVoiceInChanNo; //音频输入起始通道号 0表示无效
+    BYTE  bySupport5;  //按位表示,0-不支持,1-支持,bit0-支持多码流
+    //bySupport5 &0x01表示支持wEventTypeEx ,兼容dwEventType 的事件类型(支持行为事件扩展)--先占住,防止冲突
+    //bySupport5 &0x04表示是否支持使用扩展的场景模式接口
+    /*
+       bySupport5 &0x08 设备返回该值表示是否支持计划录像类型V40接口协议(DVR_SET_RECORDCFG_V40/ DVR_GET_RECORDCFG_V40)(在该协议中设备支持类型类型13的配置)
+       之前的部分发布的设备,支持录像类型13,则配置录像类型13。如果不支持,统一转换成录像类型3兼容处理。SDK通过命令探测处理)
+       bySupport5 &0x10 设备返回改值表示支持超过255个预置点
+    */
+    BYTE  bySupport6;   //能力,按位表示,0-不支持,1-支持
+    //bySupport6 0x1  表示设备是否支持压缩 
+    //bySupport6 0x2 表示是否支持流ID方式配置流来源扩展命令,DVR_SET_STREAM_SRC_INFO_V40
+    //bySupport6 0x4 表示是否支持事件搜索V40接口
+    //bySupport6 0x8 表示是否支持扩展智能侦测配置命令
+    //bySupport6 0x40表示图片查询结果V40扩展
+    BYTE  byMirrorChanNum;    //镜像通道个数,<录播主机中用于表示导播通道>
+    WORD wStartMirrorChanNo;  //起始镜像通道号
+    BYTE bySupport7;   //能力,按位表示,0-不支持,1-支持
+    // bySupport7 & 0x1  表示设备是否支持 INTER_VCA_RULECFG_V42 扩展
+    // bySupport7 & 0x2  表示设备是否支持 IPC HVT 模式扩展
+    // bySupport7 & 0x04  表示设备是否支持 返回锁定时间
+    // bySupport7 & 0x08  表示设置云台PTZ位置时,是否支持带通道号
+    // bySupport7 & 0x10  表示设备是否支持双系统升级备份
+    // bySupport7 & 0x20  表示设备是否支持 OSD字符叠加 V50
+    // bySupport7 & 0x40  表示设备是否支持 主从(从摄像机)
+    // bySupport7 & 0x80  表示设备是否支持 报文加密
+    BYTE  byRes2;        //保留
+}NET_DVR_DEVICEINFO_V30, *LPNET_DVR_DEVICEINFO_V30;
+
+typedef struct tagNET_DVR_DEVICEINFO_V40
+{
+    NET_DVR_DEVICEINFO_V30 struDeviceV30;
+    BYTE  bySupportLock;        //设备支持锁定功能,该字段由SDK根据设备返回值来赋值的。bySupportLock为1时,dwSurplusLockTime和byRetryLoginTime有效
+    BYTE  byRetryLoginTime;        //剩余可尝试登陆的次数,用户名,密码错误时,此参数有效
+    BYTE  byPasswordLevel;      //admin密码安全等级
+    //0-无效,1-默认密码,2-有效密码,3-风险较高的密码。当用户的密码为出厂默认密码(12345)或者风险较高的密码时,上层客户端需要提示用户更改密码。
+    //4-管理员创建一个普通用户为其设置密码,该普通用户正确登录设备后要提示“请修改初始登录密码”,未修改的情况下,用户每次登入都会进行提醒;
+    //5-当普通用户的密码被管理员修改,该普通用户再次正确登录设备后,需要提示“请重新设置登录密码”,未修改的情况下,用户每次登入都会进行提醒;
+    //6-管理员创建一个安装商/操作员用户为其设置密码,该用户正确登录设备后要提示“请修改初始登录密码”,未修改的情况下,无法进行除修改本身密码外的其他操作;
+    BYTE  byProxyType;  //代理类型,0-不使用代理, 1-使用socks5代理, 2-使用EHome代理
+    DWORD dwSurplusLockTime;    //剩余时间,单位秒,用户锁定时,此参数有效
+    BYTE  byCharEncodeType;     //字符编码类型0-无字符编码信息(老设备),1-GB2312(简体中文),2-GBK,3-BIG5(繁体中文),4-Shift_JIS(日文),5-EUC-KR(韩文),6-UTF-8,7-21:ISO8859-1---15(西欧),22-Hebrew(希伯来语)
+    BYTE  bySupportDev5;//支持v50版本的设备参数获取,设备名称和设备类型名称长度扩展为64字节
+    BYTE  bySupport;  //能力集扩展,位与结果:0- 不支持,1- 支持
+    // bySupport & 0x1:  保留
+    // bySupport & 0x2:  0-不支持变化上报 1-支持变化上报
+    BYTE  byLoginMode; //登录模式 0-Private登录 1-ISAPI登录
+    DWORD dwOEMCode;
+    int iResidualValidity;   //该用户密码剩余有效天数,单位:天,返回负值,表示密码已经超期使用,例如“-3表示密码已经超期使用3天”
+    BYTE  byResidualValidity; // iResidualValidity字段是否有效,0-无效,1-有效
+    BYTE  bySingleStartDTalkChan;	//独立音轨接入的设备,起始接入通道号,0-为保留字节,无实际含义,音轨通道号不能从0开始
+    BYTE  bySingleDTalkChanNums;	//独立音轨接入的设备的通道总数,0-表示不支持
+    BYTE  byPassWordResetLevel; //0-无效,1-管理员创建一个非管理员用户为其设置密码,该非管理员用户正确登录设备后要提示“请修改初始登录密码”,未修改的情况下,用户每次登入都会进行提醒;2-当非管理员用户的密码被管理员修改,该非管理员用户再次正确登录设备后,需要提示“请重新设置登录密码”,未修改的情况下,用户每次登入都会进行提醒。
+    BYTE  bySupportStreamEncrypt;  //能力集扩展,位与结果:0- 不支持,1- 支持 bySupportStreamEncrypt & 0x1:表示是否支持RTP/TLS取流 bySupportStreamEncrypt & 0x2:  表示是否支持SRTP/UDP取流 bySupportStreamEncrypt & 0x4:  表示是否支持SRTP/MULTICAST取流
+    BYTE  byMarketType;//0-无效(未知类型),1-经销型,2-行业型
+    BYTE  byTLSCap; //0-无效;byTLSCap & 0x1:  表示是否支持TLS链路预览;byTLSCap & 0x2:  表示是否支持TLS链路回放;byTLSCap & 0x4:  表示是否支持TLS链路下载;
+    BYTE  byRes2[237];
+}NET_DVR_DEVICEINFO_V40, *LPNET_DVR_DEVICEINFO_V40;
+
+
+
+typedef void (CALLBACK *fLoginResultCallBack) (LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo , void* pUser);
+
+#define NET_DVR_DEV_ADDRESS_MAX_LEN 129
+#define NET_DVR_LOGIN_USERNAME_MAX_LEN 64
+#define NET_DVR_LOGIN_PASSWD_MAX_LEN 64
+
+typedef struct  
+{
+    char sDeviceAddress[NET_DVR_DEV_ADDRESS_MAX_LEN];
+    BYTE byUseTransport;    //是否启用能力集透传,0--不启用透传,默认,1--启用透传
+    WORD wPort;
+    char sUserName[NET_DVR_LOGIN_USERNAME_MAX_LEN];
+    char sPassword[NET_DVR_LOGIN_PASSWD_MAX_LEN];
+    fLoginResultCallBack cbLoginResult;
+    void *pUser;
+    BOOL bUseAsynLogin;
+    BYTE byProxyType; //0:不使用代理,1:使用标准代理,2:使用EHome代理
+    BYTE byUseUTCTime;    //0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换
+    BYTE byLoginMode; //0-Private 1-ISAPI 2-自适应
+    BYTE byHttps;    //0-不适用tls,1-使用tls 2-自适应
+    LONG iProxyID;    //代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值
+    BYTE byVerifyMode;  //认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效;
+    BYTE byRes3[119];
+}NET_DVR_USER_LOGIN_INFO,*LPNET_DVR_USER_LOGIN_INFO;
+
+//预览V40接口
+typedef struct tagNET_DVR_PREVIEWINFO
+{
+    LONG lChannel;//通道号
+    DWORD dwStreamType;    // 码流类型,0-主码流,1-子码流,2-码流3,3-码流4, 4-码流5,5-码流6,7-码流7,8-码流8,9-码流9,10-码流10
+    DWORD dwLinkMode;// 0:TCP方式,1:UDP方式,2:多播方式,3 - RTP方式,4-RTP/RTSP,5-RSTP/HTTP ,6- HRUDP(可靠传输) ,7-RTSP/HTTPS
+    HWND hPlayWnd;//播放窗口的句柄,为NULL表示不播放图象
+    DWORD bBlocked;  //0-非阻塞取流, 1-阻塞取流, 如果阻塞SDK内部connect失败将会有5s的超时才能够返回,不适合于轮询取流操作.
+    DWORD bPassbackRecord; //0-不启用录像回传,1启用录像回传
+    BYTE byPreviewMode;//预览模式,0-正常预览,1-延迟预览
+    BYTE byStreamID[STREAM_ID_LEN/*32*/];//流ID,lChannel为0xffffffff时启用此参数
+    BYTE byProtoType; //应用层取流协议,0-私有协议,1-RTSP协议,2-SRTP码流加密(对应此结构体中dwLinkMode 字段,支持如下方式, 为1,表示udp传输方式,信令走TLS加密,码流走SRTP加密,为2,表示多播传输方式,信令走TLS加密,码流走SRTP加密)
+    BYTE byRes1;
+    BYTE byVideoCodingType; //码流数据编解码类型 0-通用编码数据 1-热成像探测器产生的原始数据(温度数据的加密信息,通过去加密运算,将原始数据算出真实的温度值)
+    DWORD dwDisplayBufNum; //播放库播放缓冲区最大缓冲帧数,范围1-50,置0时默认为1 
+    BYTE byNPQMode;	//NPQ是直连模式,还是过流媒体 0-直连 1-过流媒体
+    BYTE byRecvMetaData;  //是否接收metadata数据,设备是否支持该功能通过GET /ISAPI/System/capabilities 中DeviceCap.SysCap.isSupportMetadata是否存在且为true
+    BYTE byDataType;    //数据类型,0-码流数据,1-音频数据
+    BYTE byRes[213];
+}NET_DVR_PREVIEWINFO, *LPNET_DVR_PREVIEWINFO;
+
+typedef void (CALLBACK *REALDATACALLBACK) (LONG lPlayHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void* pUser);
+
+/*************操作异常类型(消息方式, 回调方式(保留))****************/
+#define EXCEPTION_EXCHANGE                0x8000    //用户交互时异常
+#define EXCEPTION_AUDIOEXCHANGE            0x8001    //语音对讲异常
+#define EXCEPTION_ALARM                    0x8002    //报警异常
+#define EXCEPTION_PREVIEW                0x8003    //网络预览异常
+#define EXCEPTION_SERIAL                0x8004    //透明通道异常
+#define EXCEPTION_RECONNECT                0x8005    //预览时重连
+#define EXCEPTION_ALARMRECONNECT        0x8006    //报警时重连
+#define EXCEPTION_SERIALRECONNECT        0x8007    //透明通道重连
+#define SERIAL_RECONNECTSUCCESS         0x8008    //透明通道重连成功
+#define EXCEPTION_PLAYBACK                0x8010    //回放异常
+#define EXCEPTION_DISKFMT                0x8011    //硬盘格式化
+#define EXCEPTION_PASSIVEDECODE         0x8012  //被动解码异常
+#define EXCEPTION_EMAILTEST             0x8013  //邮件测试异常    
+#define EXCEPTION_BACKUP                0x8014  //备份异常
+#define PREVIEW_RECONNECTSUCCESS        0x8015  //预览时重连成功
+#define ALARM_RECONNECTSUCCESS          0x8016  //报警时重连成功
+#define RESUME_EXCHANGE                    0x8017    //用户交互恢复
+#define NETWORK_FLOWTEST_EXCEPTION      0x8018  //网络流量检测异常
+#define EXCEPTION_PICPREVIEWRECONNECT    0x8019    //图片预览重连
+#define PICPREVIEW_RECONNECTSUCCESS        0x8020    //图片预览重连成功
+#define EXCEPTION_PICPREVIEW            0x8021    //图片预览异常
+#define    EXCEPTION_MAX_ALARM_INFO        0x8022    //报警信息缓存已达上限
+#define    EXCEPTION_LOST_ALARM            0x8023  //报警丢失
+#define EXCEPTION_PASSIVETRANSRECONNECT 0x8024  //被动转码重连
+#define PASSIVETRANS_RECONNECTSUCCESS   0x8025  //被动转码重连成功
+#define EXCEPTION_PASSIVETRANS          0x8026  //被动转码异常
+#define SUCCESS_PUSHDEVLOGON            0x8030  //推模式设备注册成功
+#define EXCEPTION_RELOGIN                0x8040    //用户重登陆
+#define RELOGIN_SUCCESS                    0x8041    //用户重登陆成功
+#define EXCEPTION_PASSIVEDECODE_RECONNNECT  0x8042  //被动解码重连
+#define EXCEPTION_CLUSTER_CS_ARMFAILED      0x8043  //集群报警异常
+
+#define EXCEPTION_RELOGIN_FAILED                0x8044   //重登陆失败,停止重登陆
+#define EXCEPTION_PREVIEW_RECONNECT_CLOSED      0x8045   //关闭预览重连功能
+#define EXCEPTION_ALARM_RECONNECT_CLOSED        0x8046   //关闭报警重连功能
+#define EXCEPTION_SERIAL_RECONNECT_CLOSED       0x8047   //关闭透明通道重连功能
+#define EXCEPTION_PIC_RECONNECT_CLOSED          0x8048   //关闭回显重连功能
+#define EXCEPTION_PASSIVE_DECODE_RECONNECT_CLOSED 0x8049 //关闭被动解码重连功能
+#define EXCEPTION_PASSIVE_TRANS_RECONNECT_CLOSED 0x804a  //关闭被动转码重连功能 
+#define EXCEPTION_VIDEO_DOWNLOAD 0x804b // [add] by yangzheng 2019/11/09 录像下载异常
+
+/********************预览回调函数*********************/
+#define NET_DVR_SYSHEAD            1    //系统头数据
+#define NET_DVR_STREAMDATA        2    //视频流数据(包括复合流和音视频分开的视频流数据)
+#define NET_DVR_AUDIOSTREAMDATA    3    //音频流数据
+#define NET_DVR_STD_VIDEODATA    4    //标准视频流数据
+#define NET_DVR_STD_AUDIODATA    5    //标准音频流数据
+#define NET_DVR_SDP             6   //SDP信息(Rstp传输时有效)
+#define NET_DVR_CHANGE_FORWARD  10  //码流改变为正放  
+#define NET_DVR_CHANGE_REVERSE  11  //码流改变为倒放
+#define NET_DVR_PLAYBACK_ALLFILEEND      12  //回放文件结束标记
+#define NET_DVR_VOD_DRAW_FRAME      13  //回放抽帧码流
+#define NET_DVR_VOD_DRAW_DATA       14  //拖动平滑码流
+#define NET_DVR_HLS_INDEX_DATA      15  //HLS索引数据
+#define NET_DVR_PLAYBACK_NEW_POS    16  //回放重置(按时间定位命令NET_DVR_PLAYSETTIME和NET_DVR_PLAYSETTIME_V50接口返回成功后,还需要等待收到该回调类型后才可认为操作成功)
+#define NET_DVR_METADATA_DATA       107  //Metadata数据
+#define NET_DVR_PRIVATE_DATA    112 //私有数据,包括智能信息
+
+
+/* ========================================================================
+ * ********************** 海康SDK播放相关的宏定义 ***************************
+ * ======================================================================== */
+
+//Frame Info
+typedef struct{
+    long nWidth;
+    long nHeight;
+    long nStamp;
+    long nType;
+    long nFrameRate;
+    DWORD dwFrameNum;
+}FRAME_INFO;
+
+//Error code
+#define  PLAYM4_NOERROR                         0   //no error
+#define  PLAYM4_PARA_OVER                       1   //input parameter is invalid;
+#define  PLAYM4_ORDER_ERROR                     2   //The order of the function to be called is error.
+#define  PLAYM4_TIMER_ERROR                     3   //Create multimedia clock failed;
+#define  PLAYM4_DEC_VIDEO_ERROR                 4   //Decode video data failed.
+#define  PLAYM4_DEC_AUDIO_ERROR                 5   //Decode audio data failed.
+#define  PLAYM4_ALLOC_MEMORY_ERROR              6   //Allocate memory failed.
+#define  PLAYM4_OPEN_FILE_ERROR                 7   //Open the file failed.
+#define  PLAYM4_CREATE_OBJ_ERROR                8   //Create thread or event failed
+#define  PLAYM4_CREATE_DDRAW_ERROR              9   //Create DirectDraw object failed.
+#define  PLAYM4_CREATE_OFFSCREEN_ERROR          10  //failed when creating off-screen surface.
+#define  PLAYM4_BUF_OVER                        11  //buffer is overflow
+#define  PLAYM4_CREATE_SOUND_ERROR              12  //failed when creating audio device.	
+#define  PLAYM4_SET_VOLUME_ERROR                13  //Set volume failed
+#define  PLAYM4_SUPPORT_FILE_ONLY               14  //The function only support play file.
+#define  PLAYM4_SUPPORT_STREAM_ONLY             15  //The function only support play stream.
+#define  PLAYM4_SYS_NOT_SUPPORT                 16  //System not support.
+#define  PLAYM4_FILEHEADER_UNKNOWN              17  //No file header.
+#define  PLAYM4_VERSION_INCORRECT               18  //The version of decoder and encoder is not adapted.  
+#define  PLAYM4_INIT_DECODER_ERROR              19  //Initialize decoder failed.
+#define  PLAYM4_CHECK_FILE_ERROR                20  //The file data is unknown.
+#define  PLAYM4_INIT_TIMER_ERROR                21  //Initialize multimedia clock failed.
+#define  PLAYM4_BLT_ERROR                       22  //Blt failed.
+#define  PLAYM4_UPDATE_ERROR                    23  //Update failed.
+#define  PLAYM4_OPEN_FILE_ERROR_MULTI           24  //openfile error, streamtype is multi
+#define  PLAYM4_OPEN_FILE_ERROR_VIDEO           25  //openfile error, streamtype is video
+#define  PLAYM4_JPEG_COMPRESS_ERROR             26  //JPEG compress error
+#define  PLAYM4_EXTRACT_NOT_SUPPORT             27  //Don't support the version of this file.
+#define  PLAYM4_EXTRACT_DATA_ERROR              28  //extract video data failed.
+#define  PLAYM4_SECRET_KEY_ERROR                29  //Secret key is error //add 20071218
+#define  PLAYM4_DECODE_KEYFRAME_ERROR           30  //add by hy 20090318
+#define  PLAYM4_NEED_MORE_DATA                  31  //add by hy 20100617
+#define  PLAYM4_INVALID_PORT                    32  //add by cj 20100913
+#define  PLAYM4_NOT_FIND                        33  //add by cj 20110428
+#define  PLAYM4_NEED_LARGER_BUFFER              34  //add by pzj 20130528
+#define  PLAYM4_FAIL_UNKNOWN                    99  //Fail, but the reason is unknown;	
+
+
+//frame type
+#define T_AUDIO16	101
+#define T_AUDIO8	100
+#define T_UYVY		1
+#define T_YV12		3
+#define T_RGB32		7
+
+
+#endif /* HKSDKDEFINE_H */

+ 237 - 0
CPlayer/Player/PlayerGLWidget - 副本.cpp_

@@ -0,0 +1,237 @@
+#include "PlayerGLWidget.h"
+#include <QOpenGLFunctions> // 添加此行
+
+#include "LHQLogAPI.h"
+
+PlayerGLWidget::PlayerGLWidget(QWidget *parent) : QOpenGLWidget(parent)
+{
+    // QString imagePath = QApplication::applicationDirPath() + "/0.jpg";
+    // QImage image(imagePath);
+    // Image_YUV420 yuv420;
+    // convertQImageToYUV420(image, yuv420);
+    // /* 显示图片  */
+    // updateFrame(yuv420);
+}
+
+PlayerGLWidget::~PlayerGLWidget()
+{
+
+}
+
+/* 设置一张图片,用于显示默认的图片 */
+void PlayerGLWidget::setImage(const QImage& image)
+{
+    Image_YUV420 yuv420;
+    convertQImageToYUV420(image, yuv420);
+    /* 显示图片  */
+    updateFrame(yuv420);
+}
+
+/* 刷新一帧 */
+void PlayerGLWidget::updateFrame(Image_YUV420& image)
+{
+    m_yData = std::move(image.yData);
+    m_uData = std::move(image.uData);
+    m_vData = std::move(image.vData);
+    m_imageSize = QSize(image.width, image.height);
+
+    update();
+}
+
+/* 刷新一帧QImage */
+void PlayerGLWidget::updateFrame(Image_QImage& image)
+{
+    LH_WRITE_LOG("图片宽度: " + QString::number(image.image.width()) + "图片高度: " + QString::number(image.image.height()));
+    convertQImageToYUV420(image.image, m_YUV420);
+    m_yData = m_YUV420.yData;
+    m_uData = m_YUV420.uData;
+    m_vData = m_YUV420.vData;
+    m_imageSize = QSize(m_YUV420.width, m_YUV420.height);
+
+    update();
+}
+
+void PlayerGLWidget::convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420)
+{
+    int width = image.width();
+    int height = image.height();
+    int ySize = width * height;
+    int uvSize = ySize / 4 + 1;
+
+    yuv420.width = width;
+    yuv420.height = height;
+
+    yuv420.yData.resize(ySize);
+    yuv420.uData.resize(uvSize);
+    yuv420.vData.resize(uvSize);
+
+    for (int y = 0; y < height; ++y) {
+        for (int x = 0; x < width; ++x) {
+            QColor color = image.pixelColor(x, y);
+            int r = color.red();
+            int g = color.green();
+            int b = color.blue();
+
+            int yIndex = y * width + x;
+            yuv420.yData[yIndex] = static_cast<unsigned char>((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
+
+            if (y % 2 == 0 && x % 2 == 0) {
+                int uvIndex = (y / 2) * (width / 2) + (x / 2);
+                yuv420.uData[uvIndex] = static_cast<unsigned char>((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128);
+                yuv420.vData[uvIndex] = static_cast<unsigned char>((0.439 * r) - (0.368 * g) - (0.071 * b) + 128);
+            }
+        }
+    }
+}
+
+void PlayerGLWidget::initializeGL()
+{
+    initializeOpenGLFunctions(); // 确保初始化 OpenGL 函数
+
+    // 创建并编译顶点着色器
+    const char* vertexShaderSource = R"(
+        #version 330 core
+        layout(location = 0) in vec3 aPos;
+        layout(location = 1) in vec2 aTexCoord;
+        out vec2 TexCoord;
+        void main()
+        {
+            gl_Position = vec4(aPos, 1.0);
+            TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y); // 翻转纹理坐标
+        }
+    )";
+    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
+    glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
+    glCompileShader(vertexShader);
+
+    // 创建并编译片段着色器
+    const char* fragmentShaderSource = R"(
+        #version 330 core
+        out vec4 FragColor;
+        in vec2 TexCoord;
+        uniform sampler2D textureY;
+        uniform sampler2D textureU;
+        uniform sampler2D textureV;
+        void main()
+        {
+            float y = texture(textureY, TexCoord).r;
+            float u = texture(textureU, TexCoord).r - 0.5;
+            float v = texture(textureV, TexCoord).r - 0.5;
+            float r = y + 1.402 * v;
+            float g = y - 0.344 * u - 0.714 * v;
+            float b = y + 1.772 * u;
+            FragColor = vec4(r, g, b, 1.0);
+        }
+    )";
+    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
+    glCompileShader(fragmentShader);
+
+    // 链接着色器程序
+    shaderProgram = glCreateProgram();
+    glAttachShader(shaderProgram, vertexShader); // 确保传递的是程序对象和着色器对象
+    glAttachShader(shaderProgram, fragmentShader); // 确保传递的是程序对象和着色器对象
+    glLinkProgram(shaderProgram);
+
+    // 删除着色器对象
+    glDeleteShader(vertexShader);
+    glDeleteShader(fragmentShader);
+
+    // 创建纹理
+    glGenTextures(1, &textureIdY_);
+    glGenTextures(1, &textureIdU_);
+    glGenTextures(1, &textureIdV_);
+
+    glBindTexture(GL_TEXTURE_2D, textureIdY_);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    glBindTexture(GL_TEXTURE_2D, textureIdU_);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    glBindTexture(GL_TEXTURE_2D, textureIdV_);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    // 设置顶点数据和缓冲
+    float vertices[] = {
+        // positions          // texture coords
+        -1.0f, -1.0f, 0.0f,  0.0f, 0.0f,
+         1.0f, -1.0f, 0.0f,  1.0f, 0.0f,
+         1.0f,  1.0f, 0.0f,  1.0f, 1.0f,
+        -1.0f,  1.0f, 0.0f,  0.0f, 1.0f
+    };
+    unsigned int indices[] = {
+        0, 1, 2,
+        2, 3, 0
+    };
+
+    glGenVertexArrays(1, &VAO);
+    glGenBuffers(1, &VBO);
+    glGenBuffers(1, &EBO);
+
+    glBindVertexArray(VAO);
+
+    glBindBuffer(GL_ARRAY_BUFFER, VBO);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
+
+    // 位置属性
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
+    glEnableVertexAttribArray(0);
+    // 纹理坐标属性
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
+    glEnableVertexAttribArray(1);
+
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+void PlayerGLWidget::resizeGL(int w, int h)
+{
+    Ortho2DSize_.setWidth(w);
+    Ortho2DSize_.setHeight(h);
+    glViewport(0, 0, w, h);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, Ortho2DSize_.width(), Ortho2DSize_.height(), 0, -1, 1);
+    glMatrixMode(GL_MODELVIEW);
+}
+
+void PlayerGLWidget::paintGL()
+{
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    if (m_yData.isEmpty() || m_uData.isEmpty() || m_vData.isEmpty()) {
+        return;
+    }
+
+    // 使用着色器程序
+    glUseProgram(shaderProgram);
+
+    // 更新纹理数据
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, textureIdY_);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width(), m_imageSize.height(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_yData.data());
+
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, textureIdU_);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width() / 2, m_imageSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uData.data());
+
+    glActiveTexture(GL_TEXTURE2);
+    glBindTexture(GL_TEXTURE_2D, textureIdV_);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width() / 2, m_imageSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_vData.data());
+
+    // 设置纹理单元
+    glUniform1i(glGetUniformLocation(shaderProgram, "textureY"), 0);
+    glUniform1i(glGetUniformLocation(shaderProgram, "textureU"), 1);
+    glUniform1i(glGetUniformLocation(shaderProgram, "textureV"), 2);
+
+    // 绘制四边形
+    glBindVertexArray(VAO);
+    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
+    glBindVertexArray(0);
+}

+ 64 - 0
CPlayer/Player/PlayerGLWidget - 副本.h_

@@ -0,0 +1,64 @@
+#ifndef PLAYEROPENGLWIDGET_H
+#define PLAYEROPENGLWIDGET_H
+
+
+#include <QOpenGLWidget>
+// #include <QOpenGLFunctions> // 添加此行
+#include <QOpenGLFunctions_3_3_Core> // 添加此行
+#include <QOpenGLTexture>
+#include "PlayerGlobalInfo.h"
+
+/**
+ * @brief 
+ * 
+ */
+
+
+class PlayerGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core // 修改此行
+{
+    Q_OBJECT
+public:
+    explicit PlayerGLWidget(QWidget *parent = nullptr);
+    ~PlayerGLWidget();
+
+    /* 设置一张图片,用于显示默认的图片 */
+    void setImage(const QImage& image);
+
+    /* 刷新一帧 */
+    void updateFrame(Image_YUV420& image);
+    /* 刷新一帧QImage */
+    void updateFrame(Image_QImage& image);
+
+
+private:
+    /* 转换成YUV420 */
+    void convertQImageToYUV420(const QImage& image, Image_YUV420& yuv420);
+
+protected:
+    void initializeGL() override;
+    void resizeGL(int w, int h) override;
+    void paintGL() override;
+
+private:
+
+    Image_QImage m_image;
+    Image_YUV420 m_YUV420;
+
+    QByteArray m_yData;
+    QByteArray m_uData;
+    QByteArray m_vData;
+    QSize m_imageSize;
+
+    QOpenGLTexture* textureY_;
+    QOpenGLTexture* textureU_;
+    QOpenGLTexture* textureV_;
+    GLuint textureIdY_;
+    GLuint textureIdU_;
+    GLuint textureIdV_;
+    QSize Ortho2DSize_;
+    
+    GLuint shaderProgram;
+    GLuint VAO, VBO, EBO;
+};
+
+#endif /* PLAYEROPENGLWIDGET_H */

+ 4 - 2
CPlayer/Player/PlayerGLWidget.cpp

@@ -208,6 +208,8 @@ void PlayerGLWidget::paintGL()
     if (m_yData.isEmpty() || m_uData.isEmpty() || m_vData.isEmpty()) {
         return;
     }
+    int uvWidth = m_imageSize.width() / 2;
+    int uvHeight = m_imageSize.height() / 2;
 
     // 使用着色器程序
     glUseProgram(shaderProgram);
@@ -219,11 +221,11 @@ void PlayerGLWidget::paintGL()
 
     glActiveTexture(GL_TEXTURE1);
     glBindTexture(GL_TEXTURE_2D, textureIdU_);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width() / 2, m_imageSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uData.data());
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uData.data());
 
     glActiveTexture(GL_TEXTURE2);
     glBindTexture(GL_TEXTURE_2D, textureIdV_);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_imageSize.width() / 2, m_imageSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_vData.data());
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvWidth, uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_vData.data());
 
     // 设置纹理单元
     glUniform1i(glGetUniformLocation(shaderProgram, "textureY"), 0);

+ 9 - 1
CPlayer/cameraplayer.cpp

@@ -2,6 +2,7 @@
 
 #include <QThread>
 #include <QDebug>
+#include <QApplication>
 
 #include "LHQLogAPI.h"
 #include "Transcode.h"
@@ -11,6 +12,13 @@ CameraPlayer::CameraPlayer(QObject *parent) : QObject(parent)
 {
     // qDebug() << "主线程ID:" << QThread::currentThreadId();
 
+    /* 加载海康的SDK */
+    QString appPath = QApplication::applicationDirPath();
+    if(load_HKSDK_Library(appPath))
+    {
+        LH_WRITE_LOG("加载海康SDK成功!");
+    }
+
     // m_imageQueue = new RingQueue<Image_YUV420*>(10);
     m_imageQueue.setQueueCapacity(10);
     m_imageQueue.setDefaultValue(nullptr);
@@ -46,7 +54,7 @@ CameraPlayer::~CameraPlayer()
     if(m_transCode != nullptr)
     {
         delete m_transCode;
-        m_transCode == nullptr;
+        m_transCode = nullptr;
     }
 }
 

+ 4 - 2
CPlayer/cameraplayer.h

@@ -4,8 +4,10 @@
 #include <QObject>
 #include <QTimer>
 
-#include "PlayM4.h"
-#include "HCNetSDK.h"
+// #include "PlayM4.h"
+// #include "HCNetSDK.h"
+#include "hksdkapi.h"
+
 #include "RingQueue.hpp"
 #include "PlayerGlobalInfo.h"
 #include "PlayerGLWidget.h"

+ 13 - 12
CPlayer/common/RingQueue/RingQueue.hpp

@@ -62,11 +62,11 @@ public:
 
     /* 获取对立第一个数据,获取完立刻出队
      * 如果队列为空,会阻塞住,直到有数据为止 */
-    T&& front_pop();
+    T front_pop();
     /* 非阻塞方式获取第一个值,并出队 */
     bool front_pop_NoBlock(T& t);
     /* 非阻塞方式获取第一个值,并出队,如果队列为空,会返回设置的默认值 */
-    T&& front_pop_NoBlock();
+    T front_pop_NoBlock();
     
     /* 设置队列大小 */
     void setQueueCapacity(long size);
@@ -353,7 +353,7 @@ T RingQueue<T>::front_NoBlock()
 /* 获取对立第一个数据,获取完立刻出队
  * 如果队列为空,会阻塞住,直到有数据为止 */
 template<typename T>
-T&& RingQueue<T>::front_pop()
+T RingQueue<T>::front_pop()
 {
     T ret = m_defaultValue;
     {
@@ -361,9 +361,10 @@ T&& RingQueue<T>::front_pop()
         m_cond_NoEmpty.wait(lock, [this](){
             return (!isEmpty() || m_isExit);
         });
+        /* 是否退出 */
         if(m_isExit)
         {
-            return std::move(ret);
+            return ret;
         }
         ret = std::move(m_queue[m_front]);
         m_front = (m_front + 1) % m_capacity;
@@ -374,7 +375,7 @@ T&& RingQueue<T>::front_pop()
         }
     }
     m_cond_NoFull.notify_all();
-    return std::move(ret);
+    return ret;
 }
 
 /* 非阻塞方式获取第一个值,并出队 */
@@ -401,17 +402,17 @@ bool RingQueue<T>::front_pop_NoBlock(T& t)
 
 /* 非阻塞方式获取第一个值,并出队 */
 template<typename T>
-T&& RingQueue<T>::front_pop_NoBlock()
+T RingQueue<T>::front_pop_NoBlock()
 {
     T ret = m_defaultValue;
     {
         std::unique_lock<std::mutex> lock(m_mutex);
-        m_cond_NoEmpty.wait(lock, [this](){
-            return (!isEmpty() || m_isExit);
-        });
-        if(m_isExit)
+        // m_cond_NoEmpty.wait(lock, [this](){
+        //     return (!isEmpty() || m_isExit);
+        // });
+        if(isEmpty())
         {
-            return std::move(ret);
+            return ret;
         }
         ret = std::move(m_queue[m_front]);
         m_front = (m_front + 1) % m_capacity;
@@ -422,7 +423,7 @@ T&& RingQueue<T>::front_pop_NoBlock()
         }
     }
     m_cond_NoFull.notify_all();
-    return std::move(ret);
+    return ret;
 }
 
 

+ 5 - 3
show1/CMakeLists.txt

@@ -13,6 +13,7 @@ file(GLOB LOCAL_SRC
     # ${CMAKE_SOURCE_DIR}/CPlayer/VideoPlayer/*.cpp
     ${CMAKE_SOURCE_DIR}/CPlayer/Player/*.cpp
     ${CMAKE_SOURCE_DIR}/CPlayer/transcode/*.cpp
+    ${CMAKE_SOURCE_DIR}/CPlayer/HKSDKAPI/*.cpp
 
     ${CMAKE_SOURCE_DIR}/External/module/Logs/*.cpp
     
@@ -34,6 +35,7 @@ target_include_directories(${execName} PRIVATE
     ${CMAKE_SOURCE_DIR}/CPlayer/common/RingQueue
     ${CMAKE_SOURCE_DIR}/CPlayer/Player
     ${CMAKE_SOURCE_DIR}/CPlayer/transcode
+    ${CMAKE_SOURCE_DIR}/CPlayer/HKSDKAPI
 
     ${CMAKE_SOURCE_DIR}/libs/include
 
@@ -60,9 +62,9 @@ target_link_libraries(${execName} PRIVATE
 #链接海康摄像机库,区分Windows和Linux
 if(CMAKE_SYSTEM_NAME MATCHES "Windows")
     target_link_libraries(${execName} PRIVATE
-        HCCore.lib
-        HCNetSDK.lib
-        PlayCtrl.lib
+        # HCCore.lib
+        # HCNetSDK.lib
+        # PlayCtrl.lib
     )
     #链接OpenGL库
     target_link_libraries(${execName} PRIVATE

+ 3 - 1
show1/widget.cpp

@@ -59,8 +59,10 @@ void widget::initCameraPlayer()
     /* 创建摄像机播放器 */
     m_cameraPlayer = new CameraPlayer;
 
-    QString imagePath = QApplication::applicationDirPath() + "/0.jpg";
+    QString imagePath = QApplication::applicationDirPath() + "/2.png";
     QImage image(imagePath);
+    // QImage image(1653, 899, QImage::Format_RGB888);
+    // QImage image(640, 480, QImage::Format_RGB888);
     m_cameraPlayer->setImage(image);
 
     m_cameraPlayer->initCamera("192.1.2.73", 8000, "admin", "LH123456");