基於EasyDarwin框架實現EasyNVR H5無插件直播流媒體服務器方案


在之前的一篇博客《web無插件播放RTSP攝像機方案,拒絕插件,擁抱H5!》中,描述了實現一套H5無插件直播方案的各個組件的參考建議,又在博客《EasyNVR H5流媒體服務器方案架構設計之視頻能力平台》中對整體的架構設計思路做了總結,做高內聚、低耦合的視頻能力平台,不涉足業務部分!那么今天,我們來公開一下EasyNVR到底是如何實現這些功能的;

一、程序框架

熟悉EasyDarwin的同學都知道,EasyDarwin作為老牌的功能框架,在很多領域是非常能夠滿足開發者需求的,尤其是在安防領域,綜合其架構和性能,性價比極高,尤其是在網絡、多線程線程池、模塊化設計等方面,熟悉之后,可以衍生出很多功能類型的服務,這里將要描述的EasyNVR就是其框架產物之一:EasyNVR based on EasyDarwin,底層網絡事件模型完全沿用EasyDarwin,只對其HTTPSession、Module部分做二次開發,包括HTTP協議、Json的協議棧都完全復用EasyDarwin的HTTPProtocol類和EasyProtocol框架,非常方便;

EasyDarwin

二、模塊設計

EasyNVR一共設計了兩個Module:EasyNVRModule和EasyCMSModule:

  • EasyNVRModule的主要工作就是做EasyNVR通道管理的功能,進行攝像機源與推流的銜接,EasyNVRModule總管理多個EasyNVRChannel,一路EasyNVRChannel就是一個設備源,EasyNVRChannel繼承自Darwin框架的Task類,這樣每一個EasyNVRChannel就可以獨立進行Task、Timeout、Event等多種功能了,這樣就能非常方便地實現:設備在線監測、設備定時快照、設備直播流獲取等多種功能,每一個EasyNVRChannel的所有輸出都共享一個RTSPSource源,這樣就能保證一路流媒體數據輸入,多種協議(JPEG、RTMP、HLS)輸出了!

  • EasyCMSModule是EasyNVR為了擴展雲平台對接功能擴展的,與具體平台進行協議交互用到的,這個部分可以完全參考EasyDarwin的EasyCMSModule:https://github.com/EasyDarwin/EasyDarwin/tree/master/EasyDarwin/APIModules,對外的對接方法根據協議而定,這里就不多描述了;

EasyNVR

三、接口調用

在博客《基於EasyNVR二次開發實現自己的攝像機IPC/NVR無插件化直播解決方案》中,我們大概描述了EasyNVR是如何進行接口設計的,在代碼實現上,我們直接復用了EasyDarwin的HTTPSession功能,實現基於http+json的接口協議,例如獲取廣場視頻列表部分,我們在讀取到請求后,直接從EasyNVRModule獲取列表清單,反饋給客戶端:

QTSS_Error HTTPSession::execNetMsgCSGetChannelsRESTful(const char* queryString)
{
    if(QTSServerInterface::GetServer()->GetPrefs()->liveStreamingAuth())
    {
        if (!isAuthenticate()) 
            return EASY_ERROR_CLIENT_UNAUTHORIZED;
    }

    QTSS_Error theErr;

    QTSS_RoleParams params;
    params.easyNVRChannelsParams.inChannels = NULL;

    theErr = EasyNVRUtil::CallDispatch(Easy_NVRGetChannels_Role, QTSSModule::kGetChannelsRole, params);

    EasyProtocolACK rsp(MSG_SC_SERVER_GET_CHANNELS_ACK);
    EasyJsonValue header, body;

    header[EASY_TAG_VERSION] = EASY_PROTOCOL_VERSION;
    header[EASY_TAG_CSEQ] = 1;
    header[EASY_TAG_ERROR_NUM] = EASY_ERROR_SUCCESS_OK;
    header[EASY_TAG_ERROR_STRING] = EasyProtocol::GetErrorString(EASY_ERROR_SUCCESS_OK);

    if (theErr == QTSS_NoErr)
    {
        std::map<int, EasyNVRChannel*>* pChannels = static_cast<std::map<int, EasyNVRChannel*>*>(params.easyNVRChannelsParams.inChannels);
        if (!pChannels)     return QTSS_BadArgument;

        Json::Value* proot = rsp.GetRoot();
        int i = 0;
        std::map<int, EasyNVRChannel*>::iterator it = (*pChannels).begin();
        while (it != (*pChannels).end())
        {
            CameraInfo* item = it->second->GetChannelInfo();
            if (item->enable != 0)
            {
                Json::Value value;
                value[EASY_TAG_CHANNEL] = item->id;
                //value[EASY_TAG_ENABLE] = item->enable;
                value[EASY_TAG_ONLINE] = item->online;
                value[EASY_TAG_NAME] = item->name;
                value[EASY_TAG_SNAP_URL] = item->snap.empty() ? "" : item->snap;
                value[EASY_TAG_ERROR_STRING] = item->lasterror.empty() ? "" : item->lasterror;

                (*proot)[EASY_TAG_ROOT][EASY_TAG_BODY][EASY_TAG_CHANNELS].append(value);
                ++i;
            }
            ++it;
        }

        body[EASY_TAG_CHANNEL_COUNT] = EasyUtil::Int2String(i);
    }

    rsp.SetHead(header);
    rsp.SetBody(body);

    string msg = rsp.GetMsg();
    this->SendHTTPPacket(msg, false, false);

    return QTSS_NoErr;
}

諸如此類,按照這種方式實現每一個http接口功能即可實現完整一套的http接口功能,對外進行能力輸出!

四、配套組件

在《web無插件播放RTSP攝像機方案,拒絕插件,擁抱H5!》中描述了很多組件:live555、ffmpeg、librtmp、faac等等,基於這些組件可以非常好地幫助您實現這些功能,但是這些組件都會存在不成熟或者不易使用的問題,EasyDarwin社區的開發者也實現了一系列此類功能的功能組件,例如:

EasyRTSPClient:類似於live555的RTSPClient功能組件,進行RTSP拉流;

EasyAACEncoder:AAC轉碼,將各種類型的安防音頻格式轉碼成標准H5需要的AAC格式,開源項目地址:https://github.com/EasyDarwin/EasyAACEncoder

EasyRTMP:RTMP推流工具,能非常好地實現推流,重連,數據緩沖,過濾等等功能;

五、細節亮點

  • 按需直播

EasyNVR獨特設計了一套按需直播的方案,也就是可以配置EasyNVR的通道只有在有人看的時候,才會從攝像機設備源取流到EasyNVR流媒體服務器進行直播,當沒有客戶端觀看的時候,直接切斷與源的連接,只做常態的設備狀態監測和快照功能,降低帶寬和服務器的壓力;

具體實現:客戶端頁面需要不斷向EasyNVR發送心跳包,保持具體某一個通道的流狀態,當超時時間內某通道沒有獲得心跳包,那么就認為該通道無人觀看,即停止從設備拉流!

  • token認證

EasyNVR實現了一套authToken驗證機制,客戶端調用登陸接口后,客戶端會獲取到一個token,在本次操作的過程中,只要在http cookies中攜帶token,即可操作EasyNVR其余接口,如果不攜帶token或者攜帶的token已經過期,EasyNVR會返回401,這樣客戶端需要重新調用EasyNVR登陸接口獲取新的token!

  • 占位設計

我們經常在做服務器時會遇到內外網映射的問題,當外網客戶端請求一個通過端口映射出來的內網服務器時,內網服務器往往不知道其所在的公網的IP地址,如果每次都是通過配置IP的方式,一方面是很麻煩,另一方面,很多網絡路由規則會限制內網的客戶端不能請求該內網所在的公網的IP,也就是內網的客戶端不能請求自己的公網IP的對外服務,內網的只能通過內網路由,而且內網請求內網IP就獲取到的是內網的直播流地址也是很合理的需求,於是,我們設計了一套占位方案,比如客戶端請求一個RTMP的直播地址,我們返回給客戶端的地址是:rtmp://{host}:10935/hls/channel_1,那么客戶端再根據自己請求到EasyNVR的host IP,替換{host}占位符,就實現了,內網用內網的IP,公網用公網的IP了!

關於EasyNVR

EasyNVR能夠通過簡單的網絡攝像機通道配置,將傳統監控行業里面的高清網絡攝像機IP Camera、NVR等具有RTSP協議輸出的設備接入到EasyNVR,EasyNVR能夠將這些視頻源的音視頻數據進行拉取,轉換為RTMP/HLS,進行全平台終端H5直播(Web、Android、iOS),並且EasyNVR能夠將視頻源的直播數據對接到第三方CDN網絡,實現互聯網級別的直播分發;

詳細說明:http://www.easydarwin.org/easynvr/

獲取更多信息

郵件:support@easydarwin.org

WEB:www.EasyDarwin.org

Copyright © EasyDarwin.org 2012-2017

EasyDarwin


免責聲明!

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



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