Qt音視頻開發17-海康sdk解碼


一、前言

在視頻監控行業領域,海康當之無愧是老大,穩坐第一的寶座很多年了,近期需要將視頻監控系統改成采用海康sdk的內核,於是特意去查閱了sdk的使用手冊,sdk相關的文檔和文件可以直接官網下載到,而且是經常更新的,目前提供了windows和linux上的,win上的sdk還是更新比較快而且完整的,但是在linux上的就不得不吐槽下了,很舊很舊的版本,不要看打包文件很新,其實里面的內容是很老的,不知道為啥官方不也同步更新linux上的sdk,也許現在linux上的需求還不是很多吧,但是隨着國產化的大力推進,估計不久的將來linux上的也會慢慢的完善起來的,說不定官方早就有了此計划,還有一種個人的猜測是linux上的開發包估計官方自己內部用的新的,可能打算自己做linux上的各種客戶端吧。

官方的sdk手冊做的還是非常詳細的,而且還給到了VC/JAVA/C#等語言的demo代碼,這點肯定值的表揚的,一個產品持續賣得很好,肯定有他深層次的原因,除了產品本身質量過硬以外,周邊的服務也是必須要跟上的。由於本人習慣用Qt來做開發,所以直接編譯了VC的demo,一步到位跑起來了,界面相對來說簡單丑陋了點,但是要的大部分的功能還是有的,可能很多按鈕也沒擺擺整齊呢,管他呢,我們要的就是功能,演示如何使用對應的方法函數等,至於界面美化這塊,盡量交給專業的UI妹子吧,沒有UI妹子那就自己搞點qss樣式表弄上去湊合着用吧,界面的美化核心主要就兩點:布局+配色。

官方把他們常用的大類設備的sdk都封裝到一起了,一個頭文件老大了,光HCNetSDK.h這個頭文件都47451行,我的乖乖,估計是為了方便用戶使用,都放到一個頭文件里面了,其實這些sdk不光只是支持攝像機,NVR/CVR等設備也都是支持的,兼容性比價好,用同一個sdk都可以,官方只是對一個大類的都統一起來了,不同大類的硬件產品之間的sdk還是有點區別出入,比如現在流行的人臉識別、紅外測溫等,那都是新增加的硬件和功能,但是總體接口和使用流程上都大體一致。

解碼處理流程:

  1. 調用NET_DVR_Init初始化sdk,一個項目中只需要初始化一次。
  2. 調用NET_DVR_SetConnectTime、NET_DVR_SetReconnect設置連接時間與重連時間。
  3. 填充NET_DVR_PREVIEWINFO結構體數據用來登錄。
  4. 調用NET_DVR_Login_V30登錄設備。
  5. 調用NET_DVR_RealPlay_V40播放視頻。
  6. 調用NET_DVR_StopRealPlay停止播放。
  7. 調用NET_DVR_Logout登出設備。

二、功能特點

  1. 支持播放視頻流和本地MP4文件。
  2. 支持句柄和回調兩種模式。
  3. 多線程顯示圖像,不卡主界面。
  4. 自動重連網絡攝像頭。
  5. 可設置邊框大小即偏移量和邊框顏色。
  6. 可設置是否繪制OSD標簽即標簽文本或圖片和標簽位置。
  7. 可設置兩種OSD位置和風格。
  8. 可設置是否保存到文件以及文件名。
  9. 可直接拖曳文件到haikangwidget控件播放。
  10. 支持h264/h265視頻流。
  11. 可暫停播放和繼續播放。
  12. 支持存儲單個視頻文件和定時存儲視頻文件。
  13. 自定義頂部懸浮條,發送單擊信號通知,可設置是否啟用。
  14. 可設置畫面拉伸填充或者等比例填充。
  15. 可設置解碼是速度優先、質量優先、均衡處理。
  16. 可對視頻進行截圖(原始圖片)和截屏(視頻窗體)。
  17. 錄像文件存儲為MP4文件。
  18. 支持焦距控制、雲台控制。
  19. 可定制功能。

三、效果圖

四、相關站點

  1. 國內站點:https://gitee.com/feiyangqingyun/QWidgetDemo
  2. 國際站點:https://github.com/feiyangqingyun/QWidgetDemo
  3. 個人主頁:https://blog.csdn.net/feiyangqingyun
  4. 知乎主頁:https://www.zhihu.com/people/feiyangqingyun/
  5. 體驗地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652

五、核心代碼

bool HaiKangThread::playRtsp()
{
    bool ok = false;
    QString ip, userName, userPwd;
    int port, streamType;
    getInfo(ip, port, streamType, userName, userPwd);

    //登錄設備
    NET_DVR_DEVICEINFO_V30 deviceInfo;
    long userid = NET_DVR_Login_V30(ip.toUtf8().data(), port, userName.toUtf8().data(), userPwd.toUtf8().data(), &deviceInfo);
    if (userid >= 0) {
        qDebug() << TIMEMS << "登錄海康設備成功" << userid << deviceInfo.sSerialNumber;
        //這里還需要拿到視頻流的寬高
        //qDebug() << TIMEMS << url << "videoWidth:" << videoWidth << "videoHeight:" << videoHeight;

        //以下參數具體見對應頭文件說明
        NET_DVR_PREVIEWINFO previewInfo;
        previewInfo.lChannel = 1;
        previewInfo.dwStreamType = streamType;
        previewInfo.dwLinkMode = (transport == "tcp" ? 0 : 1);
        previewInfo.bBlocked = 0;
        previewInfo.byProtoType = 1;
        previewInfo.byPreviewMode = 0;
        previewInfo.dwDisplayBufNum = 15;

        //回調則可以拿到音視頻數據,否則就直接句柄播放
        if (callback) {
            hand = NET_DVR_RealPlay_V40(userid, &previewInfo, RealDataCallBack, this);
        } else {
            previewInfo.hPlayWnd = (HWND)playWidget->winId();
            hand = NET_DVR_RealPlay_V40(userid, &previewInfo, NULL, NULL);
        }

        if (hand >= 0) {
            ok = true;
            qDebug() << TIMEMS << "打開視頻數據成功" << url << "碼流" << streamType;
        } else {
            qDebug() << TIMEMS << "打開視頻數據失敗" << url << NET_DVR_GetLastError();
        }
    } else {
        qDebug() << TIMEMS << "登錄海康設備失敗" << NET_DVR_GetLastError();
    }

    return ok;
}

bool HaiKangThread::playLocal()
{
    //轉碼以便支持中文路徑
    QTextCodec *codec = QTextCodec::codecForName("gb2312");
    QByteArray data = codec->fromUnicode(url);

    PlayM4_GetPort(&port);
    bool ok = PlayM4_OpenFile(port, data.data());
    if (ok) {
        //設置文件播放完畢回調函數
        PlayM4_SetFileEndCallback(port, FileEndCallback, this);

        //回調則可以拿到音視頻數據,否則就直接句柄播放
        if (callback) {
            PlayM4_SetDecCallBackMend(port, DecCallBack, (quser)this);
            PlayM4_Play(port, NULL);
        } else {
            PlayM4_Play(port, (HWND)playWidget->winId());
        }

        //同時播放聲音
        PlayM4_PlaySound(port);

        //倒放
        //PlayM4_ReversePlay(port);

        //快進播放,多次調用速度更快
        //PlayM4_Fast(port);
        //PlayM4_Fast(port);

        ok = true;
        qDebug() << TIMEMS << "打開視頻文件成功" << url;
    } else {
        qDebug() << TIMEMS << "打開視頻文件失敗" << url << PlayM4_GetLastError(port);
    }

    return ok;
}

bool HaiKangThread::init()
{
    //判斷該攝像機是否能聯通
    if (checkConn && isRtsp) {
        if (!checkUrl(url, checkTime)) {
            return false;
        }
    }

    if (playWidget == NULL) {
        return false;
    }

    //視頻流和本地文件分別處理
    bool ok = false;
    if (isRtsp) {
        ok = playRtsp();
    } else {
        ok = playLocal();
    }

    if (!ok) {
        return false;
    }

    //設置保存文件
    this->initSave();
    return true;
}

void HaiKangThread::free()
{
    if (isRtsp) {
        //停止播放+登出設備
        NET_DVR_StopRealPlay(hand);
        NET_DVR_Logout(hand);
        hand = -1;
    } else {
        //停止播放+關閉文件+釋放端口
        PlayM4_Stop(port);
        PlayM4_StopSound();
        PlayM4_CloseFile(port);
        PlayM4_FreePort(port);
        port = -1;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM