目录
效果

项目

使用

PlayDemo.exe <IP> <Port> <Username> <Password>
代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string>
#include <iostream>
#include <Windows.h>
#include <thread>
#include <time.h>
#include <conio.h>
#include <filesystem>
#include <iomanip>
#include <chrono>
#include <sstream>
#include <direct.h>
using namespace std;
#include "PlayM4.h"
#include "HCNetSDK.h"
int times = 0;
LONG lRealPlayHandle;
LONG m_lPort[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };//全局的播放库port号
std::string imgFolder = "img"; // 图片保存文件夹
//播放库硬解码回调
void CALLBACK DisplayCBFun(DISPLAY_INFO_YUV* pstDisplayInfo) {
//每100次保存一次yuv数据
if (times % 100 == 0) {
FILE* fp = NULL;
string ansiString = "example" + to_string(pstDisplayInfo->nPort) + "___" + to_string(times / 100) + ".yuv";
fp = fopen(ansiString.c_str(), "wb");
// 将字符数组写入文件
fwrite(pstDisplayInfo->pBuf, sizeof(char), pstDisplayInfo->nBufLen, fp); // 不包括末尾的空字符
// 关闭文件
fclose(fp);
}
times++;
printf("Buf长度:%d\n画面宽:%d\n画面高:%d\n数据类型:%d\nn播放库句柄:%d\n", pstDisplayInfo->nBufLen, pstDisplayInfo->nWidth, pstDisplayInfo->nHeight, pstDisplayInfo->nType, pstDisplayInfo->nPort);
}
//播放库解码回调
void CALLBACK DecCBFunIm(long nPort, char* pBuf, long nSize, FRAME_INFO* pFrameInfo, void* nUser, void* nReserved2) {
// 获取当前时间(精确到毫秒)
auto now = std::chrono::system_clock::now();
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
auto epoch = now_ms.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
long long milliseconds = value.count();
// 转换为时间结构
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::tm tm = *std::localtime(&time);
// 格式化时间字符串
std::ostringstream oss;
oss << std::put_time(&tm, "%Y%m%d_%H%M%S_") << std::setfill('0') << std::setw(3) << (milliseconds % 1000);
std::string baseName = imgFolder + "/" + oss.str();
// 保存JPEG图片并计算耗时
auto jpgStart = std::chrono::high_resolution_clock::now();
std::string jpgPath = baseName + ".jpg";
BOOL jpgResult = PlayM4_ConvertToJpegFile(pBuf, nSize, pFrameInfo->nWidth, pFrameInfo->nHeight, pFrameInfo->nType, const_cast<char*>(jpgPath.c_str()));
auto jpgEnd = std::chrono::high_resolution_clock::now();
auto jpgDuration = std::chrono::duration_cast<std::chrono::milliseconds>(jpgEnd - jpgStart);
// 保存BMP图片并计算耗时
//auto bmpStart = std::chrono::high_resolution_clock::now();
//std::string bmpPath = baseName + ".bmp";
//BOOL bmpResult = PlayM4_ConvertToBmpFile(pBuf, nSize, pFrameInfo->nWidth, pFrameInfo->nHeight, pFrameInfo->nType, const_cast<char*>(bmpPath.c_str()));
//auto bmpEnd = std::chrono::high_resolution_clock::now();
//auto bmpDuration = std::chrono::duration_cast<std::chrono::milliseconds>(bmpEnd - bmpStart);
// 输出保存结果和时间
if (jpgResult) {
std::cout << "JPEG saved: " << jpgPath << " (Size: " << nSize << " bytes, " << pFrameInfo->nWidth << "x" << pFrameInfo->nHeight << ")" << " 耗时: " << jpgDuration.count() << " ms" << std::endl;
}
else {
std::cout << "Failed to save JPEG. Error code: " << GetLastError() << std::endl;
}
//if (bmpResult) {
// std::cout << "BMP saved: " << bmpPath << " in " << bmpDuration.count() << " ms" << std::endl;
//}
//else {
// std::cout << "Failed to save BMP. Error code: " << GetLastError() << std::endl;
//}
//// 输出总耗时
//auto totalDuration = std::chrono::duration_cast<std::chrono::milliseconds>(bmpEnd - jpgStart);
//std::cout << "Total time for both images: " << totalDuration.count() << " ms" << std::endl;
}
//sdk码流回调
void CALLBACK g_RealDataCallBack_V30(LONG lRealHandle, DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize, void* dwUser)
{
DWORD dRet = 0;
BOOL inData = FALSE;
LONG lPort = -1;
switch (dwDataType)
{
case NET_DVR_SYSHEAD: //系统头
if (!PlayM4_GetPort(&lPort)) //获取播放库未使用的通道号
{
printf("申请播放库资源失败");
break;
}
printf("播放库句柄:%d\n", lPort);
m_lPort[lRealPlayHandle] = lPort; //第一次回调的是系统头,将获取的播放库port号赋值给全局port,下次回调数据时即使用此port号播放
if (dwBufSize > 0) {
//设置实时流播放模式
if (!PlayM4_SetStreamOpenMode(m_lPort[lRealPlayHandle], STREAME_REALTIME))
{
printf("PlayM4_SetStreamOpenMode Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_SetStreamOpenMode Sus!\n");
}
//打开流接口
if (!PlayM4_OpenStream(m_lPort[lRealPlayHandle], pBuffer, dwBufSize, 5 * 1024 * 1024))
{
printf("PlayM4_OpenStream Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_OpenStream Sus!\n");
}
//设置解码模式,第二个参数0为软解码,1为硬解码(硬解码需要硬件支持)
//if (!PlayM4_SetDecodeEngine(m_lPort[lRealPlayHandle], 1))
//{
// printf("PlayM4_SetDecodeEngine Error\n");
// printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
// break;
//}
//else
//{
// printf("PlayM4_SetDecodeEngine Sus!\n");
//}
////设置硬解码回调,若设置为硬解码模式,需要使用该接口设置硬解码回调
//if (!PlayM4_SetDisplayCallBackYUV(m_lPort[lRealPlayHandle], DisplayCBFun, FALSE, NULL))
//{
// printf("PlayM4_SetDisplayCallBackYUV Error\n");
// printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
// break;
//}
//else
//{
// printf("PlayM4_SetDecodeEngine Sus!\n");
//}
//设置解码回调函数 解码显示 回调yuv数据,软解模式下,使用该回调
if (!PlayM4_SetDecCallBackExMend(m_lPort[lRealPlayHandle], DecCBFunIm, NULL, 0, NULL))
{
printf("PlayM4_SetDecCallBackExMend Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_SetDecodeEngine Sus!\n");
}
if (!PlayM4_Play(m_lPort[lRealPlayHandle], NULL)) //播放开始hWnd[lRealHandle]
{
printf("PlayM4_Play Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_SetDecodeEngine Sus!\n");
}
}
break;
case NET_DVR_STREAMDATA: //码流数据
if (dwBufSize > 0 && m_lPort[lRealPlayHandle] != -1)
{
//送数据入播放库
while (!PlayM4_InputData(m_lPort[lRealPlayHandle], pBuffer, dwBufSize))
{
int dwError = PlayM4_GetLastError(m_lPort[lRealPlayHandle]);
printf("播放库句柄ID:%d,错误码:%d\n", m_lPort[lRealPlayHandle], dwError);
if (dwError == 11) //缓冲区满,需要重复送入数据
{
continue;
}
}
}
break;
default: //其他数据
if (dwBufSize > 0 && m_lPort[lRealPlayHandle] != -1)
{
if (!PlayM4_InputData(m_lPort[lRealPlayHandle], pBuffer, dwBufSize))
{
break;
}
}
break;
}
}
//播放库抓图
void getPic() {
int i = 0;
BOOL bFlag = FALSE;
DWORD dwErr = 0;
LONG dwWidth = 0;
LONG dwHeight = 0;
DWORD dwSize = 0;
DWORD dwCapSize = 0;
//抓10张图
while (i++ < 10) {
//获取当前视频文件的分辨率
int bFlag = PlayM4_GetPictureSize(m_lPort[lRealPlayHandle], &dwWidth, &dwHeight);
if (bFlag == FALSE)
{
dwErr = PlayM4_GetLastError(m_lPort[lRealPlayHandle]);
printf("PlayM4_GetPictureSize, error code: %d\n", dwErr);
break;
}
dwSize = dwWidth * dwHeight * 5;
//申请抓图内存
BYTE* m_pCapBuf = NULL;
if (m_pCapBuf == NULL)
{
m_pCapBuf = new BYTE[dwSize];
if (m_pCapBuf == NULL)
{
return;
}
}
//抓图BMP图片
bFlag = PlayM4_GetJPEG(m_lPort[lRealPlayHandle], m_pCapBuf, dwSize, &dwCapSize);
if (bFlag == FALSE)
{
dwErr = PlayM4_GetLastError(m_lPort[lRealPlayHandle]);
printf("PlayM4_GetLastError, error code: %d\n", dwErr);
break;
}
if (bFlag) {
FILE* fp = NULL;
time_t timep;
time(&timep); //获取从1970至今过了多少秒,存入time_t类型的timep
std::string temp_str = std::to_string(timep) + ".jpg";
fp = fopen(temp_str.c_str(), "wb");
// 将字符数组写入文件,文件即为图片文件
fwrite(m_pCapBuf, sizeof(char), dwCapSize, fp); // 不包括末尾的空字符
// 关闭文件
fclose(fp);
}
if (m_pCapBuf != NULL)
{
delete[] m_pCapBuf;
m_pCapBuf = NULL;
}
printf("完成第%d张抓图\n", i);
//等待1秒后进下下一次抓图
Sleep(1000);
}
}
// 检查文件夹是否存在 (C++14兼容方法)
bool folderExists(const std::string& folderPath) {
struct stat info;
return stat(folderPath.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
}
// 创建文件夹 (C++14兼容方法)
bool createFolder(const std::string& folderPath) {
return _mkdir(folderPath.c_str()) == 0;
}
// 检查并创建图片保存文件夹
bool ensureImageFolderExists() {
// 检查文件夹是否存在
if (folderExists(imgFolder)) {
std::cout << "使用图片保存文件夹: " << imgFolder << std::endl;
return true;
}
// 如果不存在,尝试创建文件夹
if (createFolder(imgFolder)) {
std::cout << "创建图片保存文件夹: " << imgFolder << std::endl;
return true;
}
std::cerr << "错误: 无法创建图片保存文件夹" << std::endl;
return false;
}
//*********************************
// 函数入口
//*********************************
int main(int argc, char* argv[])
{
std::string folderPath = "Capture";
if (!CreateDirectoryA(folderPath.c_str(), NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
std::cout << "Failed to create directory: " << folderPath << std::endl;
return 1;
}
}
// 检查参数数量
if (argc != 5) {
printf("Usage: %s <IP> <Port> <Username> <Password>\n", argv[0]);
return 1;
}
// 从参数获取连接信息
const char* deviceAddress = argv[1];
WORD wPort = static_cast<WORD>(atoi(argv[2]));
const char* userName = argv[3];
const char* password = argv[4];
// 检查并创建图片保存文件夹
if (!ensureImageFolderExists()) {
std::cerr << "错误: 无法创建或访问图片保存文件夹,程序将退出" << std::endl;
return -1;
}
//---------------------------------------
// 初始化
NET_DVR_Init();
char ansiStringss[] = "./SdkLog";
NET_DVR_SetLogToFile(3, ansiStringss, TRUE);
//设置连接时间与重连时间
NET_DVR_SetConnectTime(2000, 1);
NET_DVR_SetReconnect(10000, true);
// 注册设备
LONG lUserID;
//登录参数,包括设备地址、登录用户、密码等
NET_DVR_USER_LOGIN_INFO struLoginInfo = { 0 };
struLoginInfo.bUseAsynLogin = 0; //同步登录方式
strncpy(struLoginInfo.sDeviceAddress, deviceAddress, NET_DVR_DEV_ADDRESS_MAX_LEN - 1);//设备IP地址
struLoginInfo.wPort = wPort;//设备服务端口
strncpy(struLoginInfo.sUserName, userName, NAME_LEN - 1); //设备登录用户名
strncpy(struLoginInfo.sPassword, password, NAME_LEN - 1);//设备登录密码
//设备信息, 输出参数
NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = { 0 };
//登录
lUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
if (lUserID < 0)
{
printf("Login failed, error code: %d\n", NET_DVR_GetLastError());
NET_DVR_Cleanup();
return 1;
}
//预览相关参数设置
NET_DVR_PREVIEWINFO struPlayInfo = { 0 };
struPlayInfo.hPlayWnd = NULL; //需要SDK解码时句柄设为有效值,仅取流不解码时可设为空
struPlayInfo.lChannel = 1; //预览通道号
struPlayInfo.dwStreamType = 0; //0-主码流,1-子码流,2-码流3,3-码流4,以此类推
struPlayInfo.dwLinkMode = 0; //0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
struPlayInfo.bBlocked = 1; //0- 非阻塞取流,1- 阻塞取流
//启动预览并设置回调数据流
lRealPlayHandle = NET_DVR_RealPlay_V40(lUserID, &struPlayInfo, g_RealDataCallBack_V30, NULL);//
if (lRealPlayHandle < 0)
{
printf("NET_DVR_RealPlay_V40 error %d\n", NET_DVR_GetLastError());
NET_DVR_Logout(lUserID);
NET_DVR_Cleanup();
return 1;
}
//等待播放库有数据,否则后面无法使用播放库抓图
//Sleep(3000);
// 创建并启动抓图线程
//std::thread t1(getPic);
// 播放库抓图分离线程
//t1.detach();
// 等待按键退出
while (true) {
if (_kbhit()) { // 检测键盘输入
int key = _getch(); // 获取按键
if (key == 27) { // ESC键
printf("ESC pressed, exiting...\n");
break;
}
}
Sleep(100); // 减少CPU占用
}
//关闭预览
NET_DVR_StopRealPlay(lRealPlayHandle);
//释放播放库资源
PlayM4_Stop(m_lPort[lRealPlayHandle]);
//关闭流
PlayM4_CloseStream(m_lPort[lRealPlayHandle]);
//释放播放端口
PlayM4_FreePort(m_lPort[lRealPlayHandle]);
//退出登录
NET_DVR_Logout(lUserID);
//释放sdk资源
NET_DVR_Cleanup();
return 1;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string>
#include <iostream>
#include <Windows.h>
#include <thread>
#include <time.h>
#include <conio.h>
#include <filesystem>
#include <iomanip>
#include <chrono>
#include <sstream>
#include <direct.h>
using namespace std;
#include "PlayM4.h"
#include "HCNetSDK.h"
int times = 0;
LONG lRealPlayHandle;
LONG m_lPort[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };//全局的播放库port号
std::string imgFolder = "img"; // 图片保存文件夹
//播放库硬解码回调
void CALLBACK DisplayCBFun(DISPLAY_INFO_YUV* pstDisplayInfo) {
//每100次保存一次yuv数据
if (times % 100 == 0) {
FILE* fp = NULL;
string ansiString = "example" + to_string(pstDisplayInfo->nPort) + "___" + to_string(times / 100) + ".yuv";
fp = fopen(ansiString.c_str(), "wb");
// 将字符数组写入文件
fwrite(pstDisplayInfo->pBuf, sizeof(char), pstDisplayInfo->nBufLen, fp); // 不包括末尾的空字符
// 关闭文件
fclose(fp);
}
times++;
printf("Buf长度:%d\n画面宽:%d\n画面高:%d\n数据类型:%d\nn播放库句柄:%d\n", pstDisplayInfo->nBufLen, pstDisplayInfo->nWidth, pstDisplayInfo->nHeight, pstDisplayInfo->nType, pstDisplayInfo->nPort);
}
//播放库解码回调
void CALLBACK DecCBFunIm(long nPort, char* pBuf, long nSize, FRAME_INFO* pFrameInfo, void* nUser, void* nReserved2) {
// 获取当前时间(精确到毫秒)
auto now = std::chrono::system_clock::now();
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
auto epoch = now_ms.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
long long milliseconds = value.count();
// 转换为时间结构
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::tm tm = *std::localtime(&time);
// 格式化时间字符串
std::ostringstream oss;
oss << std::put_time(&tm, "%Y%m%d_%H%M%S_") << std::setfill('0') << std::setw(3) << (milliseconds % 1000);
std::string baseName = imgFolder + "/" + oss.str();
// 保存JPEG图片并计算耗时
auto jpgStart = std::chrono::high_resolution_clock::now();
std::string jpgPath = baseName + ".jpg";
BOOL jpgResult = PlayM4_ConvertToJpegFile(pBuf, nSize, pFrameInfo->nWidth, pFrameInfo->nHeight, pFrameInfo->nType, const_cast<char*>(jpgPath.c_str()));
auto jpgEnd = std::chrono::high_resolution_clock::now();
auto jpgDuration = std::chrono::duration_cast<std::chrono::milliseconds>(jpgEnd - jpgStart);
// 保存BMP图片并计算耗时
//auto bmpStart = std::chrono::high_resolution_clock::now();
//std::string bmpPath = baseName + ".bmp";
//BOOL bmpResult = PlayM4_ConvertToBmpFile(pBuf, nSize, pFrameInfo->nWidth, pFrameInfo->nHeight, pFrameInfo->nType, const_cast<char*>(bmpPath.c_str()));
//auto bmpEnd = std::chrono::high_resolution_clock::now();
//auto bmpDuration = std::chrono::duration_cast<std::chrono::milliseconds>(bmpEnd - bmpStart);
// 输出保存结果和时间
if (jpgResult) {
std::cout << "JPEG saved: " << jpgPath << " (Size: " << nSize << " bytes, " << pFrameInfo->nWidth << "x" << pFrameInfo->nHeight << ")" << " 耗时: " << jpgDuration.count() << " ms" << std::endl;
}
else {
std::cout << "Failed to save JPEG. Error code: " << GetLastError() << std::endl;
}
//if (bmpResult) {
// std::cout << "BMP saved: " << bmpPath << " in " << bmpDuration.count() << " ms" << std::endl;
//}
//else {
// std::cout << "Failed to save BMP. Error code: " << GetLastError() << std::endl;
//}
//// 输出总耗时
//auto totalDuration = std::chrono::duration_cast<std::chrono::milliseconds>(bmpEnd - jpgStart);
//std::cout << "Total time for both images: " << totalDuration.count() << " ms" << std::endl;
}
//sdk码流回调
void CALLBACK g_RealDataCallBack_V30(LONG lRealHandle, DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize, void* dwUser)
{
DWORD dRet = 0;
BOOL inData = FALSE;
LONG lPort = -1;
switch (dwDataType)
{
case NET_DVR_SYSHEAD: //系统头
if (!PlayM4_GetPort(&lPort)) //获取播放库未使用的通道号
{
printf("申请播放库资源失败");
break;
}
printf("播放库句柄:%d\n", lPort);
m_lPort[lRealPlayHandle] = lPort; //第一次回调的是系统头,将获取的播放库port号赋值给全局port,下次回调数据时即使用此port号播放
if (dwBufSize > 0) {
//设置实时流播放模式
if (!PlayM4_SetStreamOpenMode(m_lPort[lRealPlayHandle], STREAME_REALTIME))
{
printf("PlayM4_SetStreamOpenMode Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_SetStreamOpenMode Sus!\n");
}
//打开流接口
if (!PlayM4_OpenStream(m_lPort[lRealPlayHandle], pBuffer, dwBufSize, 5 * 1024 * 1024))
{
printf("PlayM4_OpenStream Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_OpenStream Sus!\n");
}
//设置解码模式,第二个参数0为软解码,1为硬解码(硬解码需要硬件支持)
//if (!PlayM4_SetDecodeEngine(m_lPort[lRealPlayHandle], 1))
//{
// printf("PlayM4_SetDecodeEngine Error\n");
// printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
// break;
//}
//else
//{
// printf("PlayM4_SetDecodeEngine Sus!\n");
//}
////设置硬解码回调,若设置为硬解码模式,需要使用该接口设置硬解码回调
//if (!PlayM4_SetDisplayCallBackYUV(m_lPort[lRealPlayHandle], DisplayCBFun, FALSE, NULL))
//{
// printf("PlayM4_SetDisplayCallBackYUV Error\n");
// printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
// break;
//}
//else
//{
// printf("PlayM4_SetDecodeEngine Sus!\n");
//}
//设置解码回调函数 解码显示 回调yuv数据,软解模式下,使用该回调
if (!PlayM4_SetDecCallBackExMend(m_lPort[lRealPlayHandle], DecCBFunIm, NULL, 0, NULL))
{
printf("PlayM4_SetDecCallBackExMend Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_SetDecodeEngine Sus!\n");
}
if (!PlayM4_Play(m_lPort[lRealPlayHandle], NULL)) //播放开始hWnd[lRealHandle]
{
printf("PlayM4_Play Error\n");
printf("GetLastError错误码 :%d\n", PlayM4_GetLastError(m_lPort[lRealPlayHandle]));
break;
}
else
{
printf("PlayM4_SetDecodeEngine Sus!\n");
}
}
break;
case NET_DVR_STREAMDATA: //码流数据
if (dwBufSize > 0 && m_lPort[lRealPlayHandle] != -1)
{
//送数据入播放库
while (!PlayM4_InputData(m_lPort[lRealPlayHandle], pBuffer, dwBufSize))
{
int dwError = PlayM4_GetLastError(m_lPort[lRealPlayHandle]);
printf("播放库句柄ID:%d,错误码:%d\n", m_lPort[lRealPlayHandle], dwError);
if (dwError == 11) //缓冲区满,需要重复送入数据
{
continue;
}
}
}
break;
default: //其他数据
if (dwBufSize > 0 && m_lPort[lRealPlayHandle] != -1)
{
if (!PlayM4_InputData(m_lPort[lRealPlayHandle], pBuffer, dwBufSize))
{
break;
}
}
break;
}
}
//播放库抓图
void getPic() {
int i = 0;
BOOL bFlag = FALSE;
DWORD dwErr = 0;
LONG dwWidth = 0;
LONG dwHeight = 0;
DWORD dwSize = 0;
DWORD dwCapSize = 0;
//抓10张图
while (i++ < 10) {
//获取当前视频文件的分辨率
int bFlag = PlayM4_GetPictureSize(m_lPort[lRealPlayHandle], &dwWidth, &dwHeight);
if (bFlag == FALSE)
{
dwErr = PlayM4_GetLastError(m_lPort[lRealPlayHandle]);
printf("PlayM4_GetPictureSize, error code: %d\n", dwErr);
break;
}
dwSize = dwWidth * dwHeight * 5;
//申请抓图内存
BYTE* m_pCapBuf = NULL;
if (m_pCapBuf == NULL)
{
m_pCapBuf = new BYTE[dwSize];
if (m_pCapBuf == NULL)
{
return;
}
}
//抓图BMP图片
bFlag = PlayM4_GetJPEG(m_lPort[lRealPlayHandle], m_pCapBuf, dwSize, &dwCapSize);
if (bFlag == FALSE)
{
dwErr = PlayM4_GetLastError(m_lPort[lRealPlayHandle]);
printf("PlayM4_GetLastError, error code: %d\n", dwErr);
break;
}
if (bFlag) {
FILE* fp = NULL;
time_t timep;
time(&timep); //获取从1970至今过了多少秒,存入time_t类型的timep
std::string temp_str = std::to_string(timep) + ".jpg";
fp = fopen(temp_str.c_str(), "wb");
// 将字符数组写入文件,文件即为图片文件
fwrite(m_pCapBuf, sizeof(char), dwCapSize, fp); // 不包括末尾的空字符
// 关闭文件
fclose(fp);
}
if (m_pCapBuf != NULL)
{
delete[] m_pCapBuf;
m_pCapBuf = NULL;
}
printf("完成第%d张抓图\n", i);
//等待1秒后进下下一次抓图
Sleep(1000);
}
}
// 检查文件夹是否存在 (C++14兼容方法)
bool folderExists(const std::string& folderPath) {
struct stat info;
return stat(folderPath.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
}
// 创建文件夹 (C++14兼容方法)
bool createFolder(const std::string& folderPath) {
return _mkdir(folderPath.c_str()) == 0;
}
// 检查并创建图片保存文件夹
bool ensureImageFolderExists() {
// 检查文件夹是否存在
if (folderExists(imgFolder)) {
std::cout << "使用图片保存文件夹: " << imgFolder << std::endl;
return true;
}
// 如果不存在,尝试创建文件夹
if (createFolder(imgFolder)) {
std::cout << "创建图片保存文件夹: " << imgFolder << std::endl;
return true;
}
std::cerr << "错误: 无法创建图片保存文件夹" << std::endl;
return false;
}
//*********************************
// 函数入口
//*********************************
int main(int argc, char* argv[])
{
std::string folderPath = "Capture";
if (!CreateDirectoryA(folderPath.c_str(), NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
std::cout << "Failed to create directory: " << folderPath << std::endl;
return 1;
}
}
// 检查参数数量
if (argc != 5) {
printf("Usage: %s <IP> <Port> <Username> <Password>\n", argv[0]);
return 1;
}
// 从参数获取连接信息
const char* deviceAddress = argv[1];
WORD wPort = static_cast<WORD>(atoi(argv[2]));
const char* userName = argv[3];
const char* password = argv[4];
// 检查并创建图片保存文件夹
if (!ensureImageFolderExists()) {
std::cerr << "错误: 无法创建或访问图片保存文件夹,程序将退出" << std::endl;
return -1;
}
//---------------------------------------
// 初始化
NET_DVR_Init();
char ansiStringss[] = "./SdkLog";
NET_DVR_SetLogToFile(3, ansiStringss, TRUE);
//设置连接时间与重连时间
NET_DVR_SetConnectTime(2000, 1);
NET_DVR_SetReconnect(10000, true);
// 注册设备
LONG lUserID;
//登录参数,包括设备地址、登录用户、密码等
NET_DVR_USER_LOGIN_INFO struLoginInfo = { 0 };
struLoginInfo.bUseAsynLogin = 0; //同步登录方式
strncpy(struLoginInfo.sDeviceAddress, deviceAddress, NET_DVR_DEV_ADDRESS_MAX_LEN - 1);//设备IP地址
struLoginInfo.wPort = wPort;//设备服务端口
strncpy(struLoginInfo.sUserName, userName, NAME_LEN - 1); //设备登录用户名
strncpy(struLoginInfo.sPassword, password, NAME_LEN - 1);//设备登录密码
//设备信息, 输出参数
NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = { 0 };
//登录
lUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
if (lUserID < 0)
{
printf("Login failed, error code: %d\n", NET_DVR_GetLastError());
NET_DVR_Cleanup();
return 1;
}
//预览相关参数设置
NET_DVR_PREVIEWINFO struPlayInfo = { 0 };
struPlayInfo.hPlayWnd = NULL; //需要SDK解码时句柄设为有效值,仅取流不解码时可设为空
struPlayInfo.lChannel = 1; //预览通道号
struPlayInfo.dwStreamType = 0; //0-主码流,1-子码流,2-码流3,3-码流4,以此类推
struPlayInfo.dwLinkMode = 0; //0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
struPlayInfo.bBlocked = 1; //0- 非阻塞取流,1- 阻塞取流
//启动预览并设置回调数据流
lRealPlayHandle = NET_DVR_RealPlay_V40(lUserID, &struPlayInfo, g_RealDataCallBack_V30, NULL);//
if (lRealPlayHandle < 0)
{
printf("NET_DVR_RealPlay_V40 error %d\n", NET_DVR_GetLastError());
NET_DVR_Logout(lUserID);
NET_DVR_Cleanup();
return 1;
}
//等待播放库有数据,否则后面无法使用播放库抓图
//Sleep(3000);
// 创建并启动抓图线程
//std::thread t1(getPic);
// 播放库抓图分离线程
//t1.detach();
// 等待按键退出
while (true) {
if (_kbhit()) { // 检测键盘输入
int key = _getch(); // 获取按键
if (key == 27) { // ESC键
printf("ESC pressed, exiting...\n");
break;
}
}
Sleep(100); // 减少CPU占用
}
//关闭预览
NET_DVR_StopRealPlay(lRealPlayHandle);
//释放播放库资源
PlayM4_Stop(m_lPort[lRealPlayHandle]);
//关闭流
PlayM4_CloseStream(m_lPort[lRealPlayHandle]);
//释放播放端口
PlayM4_FreePort(m_lPort[lRealPlayHandle]);
//退出登录
NET_DVR_Logout(lUserID);
//释放sdk资源
NET_DVR_Cleanup();
return 1;
}