• 高复用率的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

  • 相关阅读:
    C语言第一天
    【PHP学习笔记】Hello,World!
    Photoshop文本位置范围
    快捷套取单色图片
    cesium加载纽约市3dtiles模型
    Python基础——0前言
    Python基础——1基础
    Python基础——2函数
    Python基础——3特性
    Python基础——4高阶函数
  • 原文地址:https://www.cnblogs.com/babosa/p/7518007.html
Copyright © 2020-2023  润新知