网购一网络摄像机,准备用于无人车,文档只有例程没有详细的SDK使用,看了一下例程,先搞明白了实时预览的代码。摄像机支持标准协议,这种网络摄像机使用都差不多。
例程是支撑多画面多设备的,使用对话框中嵌入formview子对话框的方式实现,先说SDK引入:
VS 建立一个基于对话框的项目,选择在静态库中使用MFC,在生产菜单-->配置管理器中将平台改为x64;修改项目属性C/C++中代码生成为多线程调试(/MTd);然后将下载的SDK包Include以及子文件夹路径添加到附加包含目录;将SDK包Lib 路径添加到附加库目录;在链接器的输入中附加依赖项XNetSDK.lib;将字符集改为使用多字节字符集。
在stdafx.h头文件中加入库头文件以及设备信息结构:
#include "XNetSDK.h"
#include "XNetSDKSyn.h"
#include "XPlaySDK.h"
typedef struct DeviceInfo
{
char szIPAddress[64]; //Device ip
int nDevicePort; //Device port
char szUserName[64]; //Device user name
char szPassword[64]; //Device password
XSDK_HANDLE hLoginID; //Login handle
int nChannelNum; //Device channel number
}DeviceInfo;
创建一建一个fromview格式对话框,例如ID为IDD_DIALOG_VIDWO_WND;创建对话框类(如CVideoWnd);加入实时播放函数及关闭函数(如需要其他功能再引入其他函数,这里只实现单画面实时预览):
XSDK_HANDLE OnRealPlay(XSDK_HANDLE hLogin, int nChannel);
afx_msg void OnCloseVideo();
函数定义及回调函数定义:
int RealPlayMediaCallBack(XSDK_HANDLE hMedia, int nDataType, int nDataLen, int nParam2, int nParam3, const char* szString, void* pData, int64 pDataInfo, int nSeq, void* pUserData, void* pMsg)
{
CVideoWnd* pThis = (CVideoWnd*)pUserData;
if (EUIMSG_AUDIO_DATA == nDataType)
{
XSDK_HANDLE _tPlayer = pThis->OnGetTalkHandle();
//将采集到的音频发送到设备端
if (_tPlayer > 0 )
{
XSDK_SendTalkData(_tPlayer, (const char*)pData, nDataLen);
}
}
return 0;
}
XSDK_HANDLE CVideoWnd::OnRealPlay(XSDK_HANDLE hLogin, int nChannel)
{
OnCloseVideo();
if (hLogin > 0)
{
SXMediaRealPlayReq param = { 0 };
param.nChannel = nChannel; // 通道号(必填)
param.nStreamType = _nStreamType; // 码流类型(必填)
param.result.pUserData = NULL; // 用户参数(选填)
param.nRequestType = EXSDK_DATA_FORMATE_FRAME; // 源数据输出(选填),详见nRequestType说明
param.hShowWindows = this->m_hWnd; // 显示窗口(选填)(暂时支持Window)
param.nDecodeType = DECODE_RESULT_NULL; // 解码结果(选填),详见nDecodeType说明
param.result = RealPlayMediaCallBack; // 结果回调(必填)
_hPlayer = XSDK_MediaRealPlay(hLogin, ¶m);
if (_hPlayer > 0)
{
_hLoginHandle = hLogin;
_nCurChannel = nChannel;
_nCurPlayState = State_Is_Playing;
}
}
return _hPlayer;
}
void CVideoWnd::OnCloseVideo()
{
if (_hPlayer > 0)
{
XSDK_MediaStop(_hPlayer);
}
_hPlayer = 0;
_nCurPlayState = State_Not_Play;
Invalidate();
}
主对话框中加入加入SDK初始化函数、连接设备函数、实时播放函数及关闭函数:
public:
//XNetSDK Function
void InitSDK();
//Device sdk handle
XSDK_HANDLE OnLoginDevice(SXSDKLoginParam* pDevice);
void OnLogoutDevice(XSDK_HANDLE hLogin);
int OnRealPlay(XSDK_HANDLE hLogin, int nChannel);
void OnCloseVideoAll();
函数实现:
int CALLBACK Main_MessageCallBack(XSDK_HANDLE hDevice, int nMsgId, int nParam1, int nParam2, int nParam3, const char* szString, void* pObject, int64 lParam, int nSeq, void* pUserData, void* pMsg)
{
return 1;
}
void CtestvideoDlg::InitSDK()
{
SXSDKInitParam initParam = { 0 };
initParam.mainMsgCallBack = Main_MessageCallBack;
XSDK_Init(&initParam);
}
XSDK_HANDLE CtestvideoDlg::OnLoginDevice(SXSDKLoginParam* pDevice)
{
XSDK_HANDLE hLoginID = 0;
if (pDevice)
{
hLoginID = XSDK_DevLoginSyn(pDevice, 5000);
if (hLoginID <= 0)
{
const char* szLoginError = XSDK_StrError(hLoginID);
CString ss;
ss.Format(_T("%s%s") "Login fail", szLoginError);
AfxMessageBox(ss, MB_ICONERROR);
}
}
return hLoginID;
}
void CtestvideoDlg::OnLogoutDevice(XSDK_HANDLE hLogin)
{
if (hLogin > 0)
{
XSDK_DevLogout(hLogin);
}
}
int CtestvideoDlg::OnRealPlay(XSDK_HANDLE hLogin, int nChannel)
{
XSDK_HANDLE hPlayer = 0;
int nWindIndex = 0;
if (nWindIndex < 0)
{
nWindIndex = 0;
}
hPlayer = _cVideoWnd[nWindIndex].OnRealPlay(hLogin, nChannel);
return hPlayer;
}
void CtestvideoDlg::OnCloseVideoAll()
{
for(int i = 0;i < MAX_WIND_NUM;i++)
{
_cVideoWnd[i].OnCloseVideo();
}
}
初始化主对话框中加入
_cVideoWnd.Create(CVideoWnd::IDD, this);//创建视频子对话框窗口
_cVideoWnd.ShowWindow(SW_HIDE);
CRect _rWindArea; //Play Window area
_rWindArea.top=5;
_rWindArea.bottom=485;
_rWindArea.left=5;
_rWindArea.right=645;
_cVideoWnd.MoveWindow(_rWindArea);
_cVideoWnd.ShowWindow(SW_SHOW);
InitSDK();
然后使用IP地址及用户名密码可连接摄像机播放视频:
SXSDKLoginParam* pDevice = new SXSDKLoginParam;
pDevice->nCnnType=EDEV_CNN_TYPE_IP_DNS;
pDevice->nDevPort=34567;
strcpy(pDevice->sDevId,"192.168.*.*");
strcpy(pDevice->sPassword,"***");
strcpy(pDevice->sUserName,"****");
XSDK_HANDLE hLoginID;
hLoginID=OnLoginDevice(pDevice);
OnRealPlay(hLoginID, 0);
上述代码为子视频窗口方式,适合多画面播放,如果需要多画面创建多个子窗口就行,如果不需要多画面,也可以直接在如Picture控件中播放,如加入控件ID:IDC_PIC,主对话框代码只需要加入回调函数及改写OnRealPlay函数如下:
int RealPlayMediaCallBack(XSDK_HANDLE hMedia, int nDataType, int nDataLen, int nParam2, int nParam3, const char* szString, void* pData, int64 pDataInfo, int nSeq, void* pUserData, void* pMsg)
{
CVideoWnd* pThis = (CVideoWnd*)pUserData;
if (EUIMSG_AUDIO_DATA == nDataType)
{
XSDK_HANDLE _tPlayer = pThis->OnGetTalkHandle();
//将采集到的音频发送到设备端
if (_tPlayer > 0 )
{
XSDK_SendTalkData(_tPlayer, (const char*)pData, nDataLen);
}
}
return 0;
}
int CtestvideoDlg::OnRealPlay(XSDK_HANDLE hLogin, int nChannel)
{
OnCloseVideo();
_nStreamType=0;
HWND PichWnd=::GetDlgItem(this->m_hWnd,IDC_PIC);
if (hLogin > 0)
{
SXMediaRealPlayReq param = { 0 };
param.nChannel = nChannel; // 通道号(必填)
param.nStreamType = _nStreamType; // 码流类型(必填)
param.result.pUserData = NULL; // 用户参数(选填)
param.nRequestType = EXSDK_DATA_FORMATE_FRAME; // 源数据输出(选填),详见nRequestType说明
param.hShowWindows = PichWnd; // 显示窗口(选填)(暂时支持Window)
param.nDecodeType = DECODE_RESULT_NULL; // 解码结果(选填),详见nDecodeType说明
param.result = RealPlayMediaCallBack; // 结果回调(必填)
_hPlayer = XSDK_MediaRealPlay(hLogin, ¶m);
if (_hPlayer > 0)
{
_hLoginHandle = hLogin;
_nCurChannel = nChannel;
_nCurPlayState = State_Is_Playing;
}
}
return _hPlayer;
}
连接及播代码与使用子窗体一样。
代码运行环境不一样,可能需要ucrtbased.dll及vcruntime140d.dll,网上下载后拷入运行文件夹就行,注意动态库文件版本,有的会报错。
SDK下载链接XNetSDK_V1.0.4.0_2022-09-29