zoukankan      html  css  js  c++  java
  • 高复用率的RTSPClient组件EasyRTSPClient设计流程概述

    EasyRTSPClient 设计过程

    概述

    EasyRTSPClient 基于live555构建而成. 今天讲讲EasyRTSPClient的设计过程

    EasyRTSPClient,主要包括以下部分:
    1. 创建live555对象, 连接相机和收流
    2. 解析收到的视频分辨率
    3. 将SDP、音视频流、分辨率及其它相关信息通过回调函数进行回调
    4. 回调连接、断线状态
    5. 根据参数执行是否重连

    创建live555对象,连接相机和收流

    网上很多介绍的都是使用testRTSPClient来做客户端, 这个是没有问题的,但有一点需要注意的是demo中的代码,都是阻塞式的,如下:

    env->taskScheduler().doEventLoop(&eventLoopWatchVariable);
    

    这样就在主线程中阻塞了, 如果我需要它退出,该怎样实现呢?
    有两种方法,目的是相同的,实现方式略有不同罢了:
    1. 外部改变eventLoopWatchVariable的值为1
    2. 通过BasicTaskScheduler0::doEventLoop(char* watchVariable)的实现可以看出, 这里实际上是进行一个无限循环. 当 watchVariable的值不为0时就退出. 所以我们可以自己创建一个线程,在线程内部实现调用 pTaskScheduler0->SingleStep(0), 即可实现对该线程的自由控制; 相当于1个线程对应1路到摄像机的取流;

    解析视频分辨率

    解析分辨率主要是sps_pps.h .c实现,是从VLC中提取出来的相关代码, 可正常解析H264,H265的分辨率;

    回调SDP, 音视频流,分辨率及其它相关信息

    在Live555的continueAfterDESCRIBE的回调函数中, 解析出SDP信息进行回调
    void continueAfterDESCRIBE(RTSPClient* rtspClient, int resultCode, char* resultString)

    if (NULL != sdpDescription)
    {
        if (NULL != pClient)        pClient->SetSDP(sdpDescription, (int)strlen(sdpDescription));
    
        char *sprop_parameter_sets = strstr(sdpDescription, "sprop-parameter-sets=");
        if (NULL != sprop_parameter_sets)
        {
            AnalysisH264SPSPPS(pClient, sprop_parameter_sets+21);
        }
        else
        {
            sprop_parameter_sets = strstr(sdpDescription, "sprop-sps=");
            if (NULL != sprop_parameter_sets)
            {
                AnalysisH265SPSPPS(pClient, sprop_parameter_sets);
            }
        }
    
        //回调出媒体信息
        MediaSubsessionIterator iter(*scs.session);
        MediaSubsession* subsession;
        while ((subsession = iter.next()) != NULL) 
        {
            if (strcmp(subsession->mediumName(), "video") == 0)
            {
                if (strcmp(subsession->codecName(), "H264") == 0)
                {
                    mediainfo.videoCodec = VIDEO_CODEC_H264;
                }
                else if (strcmp(subsession->codecName(), "H265") == 0)
                {
                    mediainfo.videoCodec = VIDEO_CODEC_H265;
                }
                else if (strcmp(subsession->codecName(), "MP4V-ES") == 0)
                {
                    mediainfo.videoCodec = VIDEO_CODEC_MPEG4;
                }
                else if (strcmp(subsession->codecName(), "JPEG") == 0)
                {
                    mediainfo.videoCodec = VIDEO_CODEC_MJPEG;
                }
                mediainfo.videoFps = (float)subsession->videoFPS();
                mediainfo.videoWidth = pClient->params.width;
                mediainfo.videoHeight = pClient->params.height;
            }
    
            if (strcmp(subsession->mediumName(), "audio") == 0)
            {
    
            }
        }
    
        if (NULL != clientObj && NULL !=clientObj->callback)
        {
            RTSPClientCallBack pRtspCallback = (RTSPClientCallBack )clientObj->callback;
            if (NULL != pRtspCallback)
            {
                pRtspCallback(clientObj->channelInfo.id, (int *)clientObj->userPtr, MEDIA_TYPE_CODEC_INFO, (char*)&mediainfo, NULL);
            }
        }
    }
    

    回调连接、断线状态

    断线状态的检测, 这里使用了一个时间对比的方式. 即用当前时间减去上一次获取到音视频流的时间,如果大于指定时长,则认为断线;

    根据参数执行是否重连

    检查重连参数,如果需要重连,则销毁当前的所有对象,再创建新的对象, 继续开始新的循环

    if (NULL != pClient->rtspClient)
    {
        Medium::close(pClient->rtspClient);
        pClient->rtspClient = NULL;
    }
    if (NULL != pClient->env)
    {
        pClient->env->reclaim();
        pClient->env = NULL;
    }
    if (NULL != pClient->scheduler)
    {
        delete pClient->scheduler;
        pClient->scheduler = NULL;
    }
    
    if (NULL != pClient->auth)
    {
        delete pClient->auth;
        pClient->auth = NULL;
    }
    
    if (NULL == pClient->scheduler)     pClient->scheduler = BasicTaskScheduler::createNew();
    if (NULL == pClient->scheduler)     break;
    if (NULL == pClient->env)           pClient->env = BasicUsageEnvironment::createNew(*pClient->scheduler);
    if (NULL == pClient->env)           break;
    
    if (NULL == pClient->rtspClient)    pClient->rtspClient = LiveRTSPClient::createNew(*pClient->env, pClient->channelInfo.url, RTSP_CLIENT_VERBOSITY_LEVEL, RTSP_CLIENT_NAME, 0, (void *)pClient);
    if (NULL == pClient->rtspClient)    break;
    

    今天主要概述了EasyRTSPClient的设计流程, 下一篇将开始着重讲解具体实现细节;

    以下是我写的基于live555的两个应用:

    关于EasyRTSPClient

    EasyRTSPClient是一套非常稳定、易用、支持重连的RTSPClient工具,SDK形式提供,接口调用非常简单,再也不用像调用live555那样处理整个RTSP OPTIONS/DESCRIBE/SETUP/PLAY的复杂流程,担心内存释放的问题了,全平台支持(包括Windows/Linux 32&64,ARM各平台,Android,iOS),支持RTP Over TCP/UDP,支持断线重连,连续维护与迭代超过5年,能够接入市面上99%以上的IPC,调用简单且成熟稳定!

    关于EasyIPCamera

    EasyIPCamera是一套非常稳定、易用、支持多种平台(包括Windows/Linux 32&64,Android,ARM hisiv100/hisiv200/hisiv400等平台)的RTSP Server组件,适用于IPCamera、内网RTSP服务等小型RTSP流媒体服务器,接口调用非常简单成熟,无需关注RTSPServer中关于客户端监听接入、音视频多路复用、RTSP具体流程、RTP打包与发送等相关问题,支持多种音视频格式,再也不用像调用live555 RTSPServer那样处理整个RTSP OPTIONS/DESCRIBE/SETUP/PLAY/RTP/RTCP的复杂流程和担心内存释放的问题了!

    获取更多信息

    邮件:support@easydarwin.org

    WEB:www.EasyDarwin.org

    Copyright © EasyDarwin.org 2012-2017

    EasyDarwin

  • 相关阅读:
    我爱java系列之---【微服务间的认证—Feign拦截器】
    我爱java系列之---【设置权限的三种解决方案】
    581. Shortest Unsorted Continuous Subarray
    129. Sum Root to Leaf Numbers
    513. Find Bottom Left Tree Value
    515. Find Largest Value in Each Tree Row
    155. Min Stack max stack Maxpop O(1) 操作
    painting house
    Minimum Adjustment Cost
    k Sum
  • 原文地址:https://www.cnblogs.com/babosa/p/9217765.html
Copyright © 2011-2022 走看看