由于种种原因,感觉还是调用别人的sdk效果比自己写的要好的多,机缘巧合之下,我用雄迈的sdk进行了二次开发。网上基本没有教程,对c++真的不熟悉,很是吃力。

雄迈的NetSdk的ui界面使用的是MFC开发的,因此我也用了MFC,开发环境:vc2017

下面这个链接下载雄迈的sdk

https://open.jftech.com/#/

下载的是NetSdk

目录

使用MFC

准备工作

MFC界面搭建

 C++代码

存在问题


使用MFC

在vc安装器里面加装MFC,大概2G左右

创建MFC的项目文件,起名字就随便了。

准备工作

在开始之前,在下载的sdk里面把以下文件放到项目根目录

H264Play.dll;       H264Play.h;       H264Play.lib

NetSdk.dll;           NetSdk.lib;       NetSdk.h;

StreamRead.dll

嗨,运行看他报啥错,你就往里面加啥就行了。

MFC界面搭建

简单测试,简单界面

STK二次开发Java sdk 二次开发_windows

 C++代码

// ShowDialog.cpp: 实现文件
//

#include "pch.h"
#include "MFC_XM.h"
#include "ShowDialog.h"
#include "afxdialogex.h"
#include "netsdk.h"
#include <stdio.h>
#include <iostream>
#include <string>
#include "Resource.h"
#include "H264Play.h"
#include <direct.h>
#include <IO.H>
using namespace std;
// ShowDialog 对话框

IMPLEMENT_DYNAMIC(ShowDialog, CDialogEx)

ShowDialog::ShowDialog(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_SHOW_DIALOG, pParent)
{	//播放端口
	_PlaySDKHandle = -1;
	//实时播放句柄NetSdk媒体句柄
	watchHandle = -1;
	//下载选项
	m_bRecord = false;
	//登录句柄
	LoginHandle = 0;
}	

ShowDialog::~ShowDialog()
{
}

void ShowDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(ShowDialog, CDialogEx)
	ON_BN_CLICKED(IDC_BUTTON_OPENCAM, &ShowDialog::OnBnClickedButtonOpencam)
	
	ON_BN_CLICKED(IDC_BUTTON_DOWN, &ShowDialog::OnBnClickedButtonDown)
END_MESSAGE_MAP()




//实时数据回调函数.设置实时监视数据回调,给用户提供设备流出的数据。
int __stdcall RealDataCallBack(long lRealHandle,
	long dwDataType, unsigned char *pBuffer,
	long lbufsize, USEROBJECT dwUser)
{
	ShowDialog *pDataChnl = (ShowDialog*)dwUser;
	H264_PLAY_InputData(pDataChnl->GetPlaySDKHandle(), pBuffer, lbufsize);
	return 1;
}

//
int __stdcall RealDataCallBack_V2(long lRealHandle, const PACKET_INFO_EX *pFrame, USEROBJECT dwUser)
{
	ShowDialog *pDataChnl = (ShowDialog*)dwUser;
	STDH264_PACKET_INFO stdH264Info;

	memset(&stdH264Info, 0, sizeof(STDH264_PACKET_INFO));
	if (pFrame->nPacketType == VIDEO_I_FRAME) {
		pFrame->pPacketBuffer + 16;
		pFrame->dwPacketSize - 16;
		H264_PLAY_InputData(pDataChnl->GetPlaySDKHandle(), (unsigned char*)pFrame->pPacketBuffer, pFrame->dwPacketSize);
	}
	else if (pFrame->nPacketType == VIDEO_P_FRAME)   //P帧
	{
		pFrame->pPacketBuffer + 8;
		pFrame->dwPacketSize - 8;
		H264_PLAY_InputData(pDataChnl->GetPlaySDKHandle(), (unsigned char*)pFrame->pPacketBuffer, pFrame->dwPacketSize);
	}
	return 1;
}



//播放图像回调函数,有啥用啊不知道
void __stdcall pProc(LONG nPort, LPCSTR pBuf, LONG nSize, LONG nWidth, LONG nHeight, LONG nStamp, LONG nType, USEROBJECT nUser)
{

}


 //ShowDialog 消息处理程序




void ShowDialog::OnBnClickedButtonOpencam()
{
//注册设备
	CString  account;//
	CString  password;
	CString  ip;
	CString  port;
	GetDlgItem(IDC_EDIT_ACCOUNT)->GetWindowText(account);
	GetDlgItem(IDC_EDIT_PASSWORD)->GetWindowText(password);
	GetDlgItem(IDC_EDIT_IP)->GetWindowText(ip);
	GetDlgItem(IDC_EDIT_PORT)->GetWindowText(port);
	//设备信息,属于输出参数
	H264_DVR_DEVICEINFO OutDev;
	int nError = 0;
	//重连时间
	H264_DVR_SetConnectTime(3000, 1);
	//获得的是CString 要转换成sdk能用的格式
	//转不成的时候去项目->属性->常规->把字符串集改成多字符串集
	LPTSTR Account = (LPTSTR)(LPCTSTR)account;
	LPTSTR Password = (LPTSTR)(LPCTSTR)password;
	LPTSTR Ip = (LPTSTR)(LPCTSTR)ip;
	//Cstring 转换short
	int Port = atoi((LPCTSTR)port);
	LoginHandle = H264_DVR_Login(Ip, Port, Account, Password, &OutDev, &nError);
	if (LoginHandle <= 0) {
		AfxMessageBox("连接摄像头失败");
	}
	else {
		GetDlgItem(IDC_STATIC_CAM)->SetWindowText("摄像头已连接");
	}
//显示画面
	CRect rect;
	CWnd *pWnd = GetDlgItem(IDC_FRAME);//IDC_picture为picture控件ID

	pWnd->GetClientRect(&rect);//rc为控件的大小。
	int y = rect.Height();
	int x = rect.Width();
	//获取实时播放句柄
	//播放窗口句柄
	HWND hWnd = GetDlgItem(IDC_FRAME)->m_hWnd;
	//HWND myhWnd = (HWND)ui->myVideo->winId();
	//cout << "hWnd" << myhWnd << endl;
	// 播放句柄IDC_FRAME
	H264_DVR_CLIENTINFO playstru;
	playstru.nChannel = 0;//1的时候就报错-11202,说明是主码流预览,或者连接数过多
	playstru.nStream = 0;
	playstru.nMode = 0;
	//playstru.hWnd = hWnd;
	//实时监视句柄
	//long watchHandle = 0; 
	watchHandle = H264_DVR_RealPlay(LoginHandle, &playstru);
	if (watchHandle <= 0) {
		AfxMessageBox("实时句柄获得失败");
	}


	if (_PlaySDKHandle == -1)
	{
		//BYTE byFileHeadBuf;  &byFileHeadBuf
		//获得播放端口
		H264_PLAY_GetPort(&_PlaySDKHandle);
		//打开流数据
		if (H264_PLAY_OpenStream(_PlaySDKHandle, NULL, 0, SOURCE_BUF_MIN * 50))
		{
			//设置信息帧回调
			//H264_PLAY_SetInfoFrameCallBack(_PlaySDKHandle, videoInfoFramCallback, (DWORD)this);
			H264_PLAY_SetStreamOpenMode(_PlaySDKHandle, STREAME_REALTIME);
			//只播放I帧,可降低cpu使用率
			//H264_PLAY_OnlyIFrame(_PlaySDKHandle, true);
			H264_PLAY_SetDisplayCallBack(_PlaySDKHandle, pProc, (USEROBJECT)this);

			H264_PLAY_AdjustFluency(_PlaySDKHandle, 7);

			//H264_DVR_SetRealDataCallBack(watchHandle, RealDataCallBack, (USEROBJECT)this);
			//H264_PLAY_SetDecCallBack(m_nIndex, nProc);
			H264_PLAY_Play(_PlaySDKHandle, hWnd);
			H264_DVR_SetRealDataCallBack_V2(watchHandle, RealDataCallBack_V2, (USEROBJECT)this);
			//第一次调用播放之前要调用H264_PLAY_GetPort, H264_PLAY_OpenStream两个之后才能调用
			//H264_PLAY_InputData这个函数,而这个函数通过H264_DVR_SetRealDataCallBack回调函数获得摄像头的播放通道号
			//应该就相当于用这个把播放通道定义一下,但是他是怎么做到画面刷新的呢
			//H264_DVR_SetRealDataCallBack_V2(watchHandle, RealDataCallBack_V2, (USEROBJECT)this);

			//设置实时显示,这个是有用的,但是设置帧率和画面质量就不对了

		}
	}
}



BOOL ShowDialog::OnInitDialog()
{
	//对话框初始化
	CDialogEx::OnInitDialog();
	GetDlgItem(IDC_EDIT_ACCOUNT)->SetWindowText("admin");
	GetDlgItem(IDC_EDIT_PASSWORD)->SetWindowText("");
	GetDlgItem(IDC_EDIT_IP)->SetWindowText("192.168.0.90");
	GetDlgItem(IDC_EDIT_PORT)->SetWindowText("34567");
	// TODO:  在此添加额外的初始化
		//初始化sdk,这里先这样写吧。最好是改变界面的文本,报错弹窗口
	bool iResult = H264_DVR_Init((fDisConnect)NULL, NULL);
	if (iResult == true) {
		GetDlgItem(IDC_STATIC_SDK)->SetWindowText("sdk就绪");
	}
	else {
		GetDlgItem(IDC_STATIC_SDK)->SetWindowText("sdk未就绪");
	}
	return TRUE;  // return TRUE unless you set the focus to a control
				  // 异常: OCX 属性页应返回 FALSE
}


void ShowDialog::OnBnClickedButtonDown()
{
	// TODO: 在此添加控件通知处理程序代码
		//获取当前窗口播放句柄
	if (watchHandle <= 0)
	{
		AfxMessageBox("下载失败");
	}

	CString  cFilename;

	CTime time = CTime::GetCurrentTime();
	cFilename.Format("%s\\record\\%4d%02d%02d_%02d%02d%02d.h264",
		"c:",
		time.GetYear(),
		time.GetMonth(),
		time.GetDay(),
		time.GetHour(),
		time.GetMinute(),
		time.GetSecond());



	if (-1 == _access("c:\\record", 0))
	{
		CreateDirectory("c:\\record", NULL);
	}
	if (m_bRecord)
	{
		
		if (H264_PLAY_StopDataRecord(_PlaySDKHandle))
		{
			m_bRecord = FALSE;
			AfxMessageBox("Desktop.StopRecordOk");
		}
	}
	else
	{
		CString strFileType(".h264");
		CString strFileName("");
		if (strstr(cFilename, ".h264"))
		{
			strFileType = _T("h264");
		}
		else
		{
			MessageBox("Type Error!");
		}

		int iNum = cFilename.ReverseFind('\\');
		if (-1 == iNum)
		{
			MessageBox("Type1 Error!");
		}
		else
		{
			strFileName = cFilename.Right(cFilename.GetLength() - (iNum + 1));
		}

		CFileDialog dlg(FALSE, strFileType, strFileName, OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY,
			"All File(*.h264;)|*.*||", this);
		dlg.m_ofn.lpstrInitialDir = cFilename.Left(iNum);

		CString strSaveName;
		if (dlg.DoModal() == IDOK)
		{
			cFilename = dlg.GetPathName();
			int nTemp = 0;
			for (;;)
			{
				int nIndex = cFilename.Find('\\', nTemp);
				if (nIndex == -1)
				{
					break;
				}
				CString str = cFilename.Left(nIndex);
				nTemp = nIndex + 1;
				_mkdir(str);
			}
			//H264_PLAY_StartDataRecord(_PlaySDKHandle, cFilename.GetBuffer(0), MEDIA_FILE_NONE)
			//H264_DVR_API bool CALL_METHOD H264_DVR_StartLocalRecord(long lRealHandle,char*szSaveFileName,long type=0);
			//H264_PLAY_API BOOL 	CALLMETHOD 	H264_PLAY_StartDataRecord(LONG nPort,  LPCSTR sFileName, LONG nType);

			LPTSTR adress = (LPTSTR)(LPCTSTR)cFilename.GetBuffer(0);
			//H264_DVR_StartLocalRecord(watchHandle, adress, long(0))

			if (H264_PLAY_StartDataRecord(watchHandle, adress, long(0)))
			{
				m_bRecord = TRUE;
				H264_PLAY_GetStreamOpenMode(_PlaySDKHandle);
				AfxMessageBox("Desktop.StartRecordOk");
			}
			else
			{
				int a = H264_DVR_GetLastError();
				AfxMessageBox("Desktop.StartRecordFail");
			}
		}
	}

}

 基本流程就是:登录设备->获得登录句柄

                           设置实时显示->获得实时显示句柄

                        设置回调函数->设置H264播放

                        H264按照给的句柄播放

下载的功能就在代码后面,不在多说了。

存在问题

朋友们,雄迈没有sdk技术支持,建议用别的

很多设置不能用

他这个是私有h264头,需要自己修改成标准264,不然保存的视频或者源264码流只能用雄迈的软件才能用。

调用二次开发sdk要把
NETSDK.DLL源程序代码文件夹下,就是该文件夹上级路径
还有streamread.dll
更不要忘了在需要调用sdk的地方在程序最前面#include "netsdk.h"

如果MFC读取ID号失败,一般是因为没有#include "Resource.h",且这个里面的id号有重复的冲突。随便改一个别的号就行了。

调用一个.dll文件需要.h文件和.lib文件。如果.h文件找不到函数,可以在项目-属性-连接-输入里面加入.lib文件的名字。多个用  ;   隔开。

综上所述,用大华的sdk了