目录

效果

项目

使用

代码

下载


效果

项目

使用

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类型的timepstd::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/HTTPstruPlayInfo.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;
}

下载

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/99034.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/99034.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/99034.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows|引用账户被锁定 且暂时无法登录

问题描述尴了个尬&#xff0c;一直认为笔记本锁屏密码记得很牢靠&#xff0c;没想到因为少敲了一个点&#xff08;.&#xff09;&#xff0c;多次输入登陆失败&#xff0c;导致账户被锁定了&#xff0c;提示&#xff1a;引用账户被锁定 且暂时无法登录。然后用手机搜索了一下&a…

系统核心解析:深入操作系统内部机制——进程管理与控制指南(三)【进程优先级/切换/调度】

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨个人…

量子-resistant密码学研究

当亚马逊CloudFront在2025年9月宣布为所有TLS连接默认启用后量子加密支持时&#xff0c;这一举措标志着抗量子密码学从学术研究正式迈入大规模实用部署阶段。与此同时&#xff0c;密码学家们发出警告&#xff1a;一台拥有不到一百万噪声量子比特的计算机&#xff0c;可能在一周…

ARM 架构的存储器模型

ARM 架构的存储器模型 ARM 的存储器模型是一个相对复杂但设计精密的体系&#xff0c;它定义了处理器如何与内存进行交互&#xff0c;包括内存访问的顺序、可见性以及缓存行为等。这对于理解多核编程、并发控制和底层系统性能至关重要。 ARM 架构&#xff0c;特别是 ARMv8 及以后…

机器学习-多层感知机MLP

线性方法->多层感知机&#xff08;MLP&#xff09; 一个全连接&#xff08;线性、dense&#xff09;层有参数W∈Rm∗nW\in\R^{m*n}W∈Rm∗n,b∈Rmb\in\R^mb∈Rm&#xff0c;其用于计算输出yWxb∈RmyWxb\in\R^myWxb∈Rm 线性回归&#xff1a;全连接层有1个输出softmax 回归&a…

PostgreSQL——并行查询

这里写目录标题一、并行查询相关自己置参数二、并行扫描2.1、并行顺序扫描2.2、并行索引扫描2.3、并行index-only扫描2.4、并行bitmap heap扫描三、并行聚合四、多表关联4.1、Nested loop多表关联4.2、Merge join多表关联4.3、Hash join多表关联了解 Oracle 的朋友应该知道 Ora…

智能体赋能金融多模态报告自动化生成:技术原理与实现流程全解析

在金融领域&#xff0c;研报作为决策参考的核心载体&#xff0c;其生成过程往往涉及海量数据采集、多维度分析及专业内容整合&#xff0c;传统人工制作模式不仅耗时耗力&#xff0c;还难以满足实时性与标准化需求。随着人工智能技术的发展&#xff0c;“智能体赋能的金融多模态…

uniapp和vue3项目中引入echarts 、lime-echart(微信小程序、H5等)

目录标题1、获取 lime-echart插件2、安装 echarts3、相关代码4、在线定制5、效果截图1、获取 lime-echart插件 https://gitee.com/liangei/lime-echart 将其中组件和静态资源分别放入当前项目对应的文件夹中&#xff1a; 2、安装 echarts npm install echarts --save具体查…

ZYNQ7020+AD9361裸机驱动验证

1. 程序编译验证 a. 下载源代码 首先需要从GitHub下载相应的源码&#xff0c;打开git bash&#xff0c;然后在mingwin中使用以下命令下载源码。 git clone --recursive https://github.com/MicroPhase/antsdr_standalone.git 注意&#xff1a;在下载源码的时候&#xff0c;使…

Grafana配置连接时候证书与mongosqld启动证书的关系

目录 证书角色说明 1. BI Connector 端的证书 (--sslPEMKeyFile) 2. Grafana 端的证书 (TLS/SSL Client Certificate & Key) 它们之间的关系 配置建议 情况一&#xff1a;只需要服务器验证&#xff08;最常见&#xff09; 情况二&#xff1a;需要双向SSL认证&#x…

解决HTML/JS开发中的常见问题与实用资源

在前端开发过程中&#xff0c;即使是经验丰富的开发者也会遇到各种小问题。本文将聚焦于两个常见问题的解决方案&#xff0c;并推荐一些国内可访问的优质源码学习网站&#xff0c;帮助开发者提升效率。 一、字符编码与乱码问题解决 在HTML和JavaScript开发中&#xff0c;字符编…

SQLI-labs[Part 2]

本篇为SQLI-labs的Write-Up的第二部分包含Level 23- Level 27Level 23 过滤注释符 字符注入拼接语句发现注释符没有生效 应该是被过滤了那只能通过拼接语句来除去后面的影响拼接?id1 or 11?id1%27%20or%20%271%27%271源码中最后的导致语句闭合 Level 24 字符二次注入成功登录…

宋红康 JVM 笔记 Day17|垃圾回收器

一、今日视频区间 P169-P203 二、一句话总结 GC分类与性能指标&#xff1b;不同的垃圾回收器概述&#xff1b;Serial回收器&#xff1a;串行回收&#xff1b;ParNew回收器&#xff1a;并行回收&#xff1b;Parallel回收器&#xff1a;吞吐量优先&#xff1b;CMS回收器&#xff…

[硬件电路-194]:NPN三极管、MOS-N, IGBT比较

NPN三极管、MOS-N&#xff08;N沟道MOS管&#xff09;和IGBT&#xff08;绝缘栅双极型晶体管&#xff09;在电子电路设计中各有其独特的应用场景和优势&#xff0c;以下从工作原理、特性、应用领域三个维度进行比较&#xff1a;工作原理NPN三极管&#xff1a;结构&#xff1a;由…

【代码随想录day 25】 力扣 46. 全排列

视频讲解&#xff1a;https://www.bilibili.com/video/BV19v4y1S79W/?vd_sourcea935eaede74a204ec74fd041b917810c 文档讲解&#xff1a;https://programmercarl.com/0046.%E5%85%A8%E6%8E%92%E5%88%97.html#%E6%80%9D%E8%B7%AF 力扣题目&#xff1a;https://leetcode.cn/prob…

指针(五)后半

1、 qsort 函数1.1、qsort 函数排列结构体在这里&#xff0c;我们创建结构体类型的数组&#xff0c;用于 qsort 函数的传参。#include<stdio.h> #include<stdlib.h> #include<string.h>struct Stu//创建结构体变量 {char name[30];int age; };struct Stu arr…

TDengine 特殊选择函数 MODE() 用户手册

MODE 函数用户手册 函数定义 MODE(expr)功能说明 MODE() 函数返回指定列中出现频率最高的值&#xff08;众数&#xff09;。如果有多个值具有相同的最高频率&#xff0c;系统会返回其中一个值。该函数会忽略 NULL 值。 算法原理 MODE 函数的计算过程如下&#xff1a; 数据…

智能外骨骼技术应用场景及价格可接受区间分析

一、引言 智能外骨骼机器人融合机械、人工智能和传感器技术,增强或恢复人体运动能力。2025年,该技术在医疗康复、工业生产、军事应用和消费市场快速普及。本文分析其应用场景、市场需求、典型产品、价格可接受区间及相关来源,探讨普及的关键因素。 二、主要应用场景及产品…

Vue模板中传递对象或数组时,避免直接使用字面量[]和{}

在 Vue 中&#xff0c;直接在模板中使用 [] 或 {} 作为 prop 值会导致子组件不必要的重新渲染&#xff0c;因为每次父组件渲染时都会创建新的引用。以下是解决方案和最佳实践&#xff1a; 1. 避免在模板中直接使用字面量 <!-- 避免这样写 --> <ChildComponent :items&…

【C++】list容器的模拟实现

目录 1. 节点(list_node) 的结构 2. 哨兵位头节点 3. list容器的成员变量 4. 插入/删除操作 4.1 插入操作&#xff08;insert&#xff09; 4.2 删除操作&#xff08;erase&#xff09; 5. 迭代器的实现 6. 不同迭代器和const容器的限制 7. 重载operator-> 8. 迭代器…