我对Live555进行了一次封装,但是Live555 是单线程的,里面定义的全局变量太多,我封装好dll库后,在客户端调用,因为多个对话框中要使用码流,我就定义了多个对象从设备端接收码流,建立多个连接,但是当一路码流退出,然后在退出另外的一路码流时,库里面出现问题,原因是Live555 里面的全局变量被破坏了!

针对上面问题:我目前的解决办法是将全局的信息隔离:

定义一个结构:

#define CLIENT_STREAM_NUM 4

class ourRTSPClient;

typedef struct  _RtspGlobal
{
 ourRTSPClient *pRtspClient;
 NetSdk *pNetSdk;
}RtspGlobal;

//
RtspGlobal struRtspGlobal[CLIENT_STREAM_NUM];

这样每一路码流对应数组中的一项,就做成多线程的了,在全局的回调函数中,根据RTSPClient*rtspClient的指针和struRtspGloball数组中的指针进行比较,如果相同,就知道是哪个流对应的连接了,比如在continueAfterSETUP函数里面建立sink时,我们可以如下判断:

for (int i=0;i<CLIENT_STREAM_NUM;i++)
  {
   if (struRtspGlobal[i].pNetSdk!=NULL)
   {
    if (struRtspGlobal[i].pRtspClient==rtspClient)
    {
     scs.subsession->sink = CRtpMediaSink::createNew(env, *scs.subsession,
      (RtpMediaSinkCallback)struRtspGlobal[i].pNetSdk->rtspDataCallback,
      (void *)&struRtspGlobal[i],RTPMEDAA_SINK_RECEIVE_BUFFER_SIZE, rtspClient->url());

break;
    }
   }

}

这样使得testRtspClient例子支持到多线程了。

2)Live555 的断网重连问题

1)重连死锁

1.1)重连时如果将解码回调线程放在NetSdk里面,使用两个Event,当接受线程结束时,发送接受线程结束的信号,然后在解码线程里面判断接收线程信号 ,如果有信号,就发送一个退出解码线程,发送一个解码结束的信号;

1.2)当超时重连时,首先Stop码流,然后Restart码流;停止码流时,将eventLoopWatchVariable=1;让数据接收线程顺利退出;同时在stop函数里面等待解码线程结束,

WaitForThreadExit(m_DecodeExitEvent);

这时会造成死锁;因为Live555是单线程的,在超时函数中需要等待本线程的结束,造成死锁;

解决办法:

1)使用单独的心跳线程来实现重连功能或者在回调数据给客户端的的解码线程里面实现重连功能;

2)网络断开判断方法 使用延迟队列来判断,初始化时候调用noteLiveness,然后每次收到Sink的一帧数据时,再次调用noteLiveness,这样如果网络断开,超时后,就能判断出来;在数据接收线程的doEventLoop后面将重连标记置位:

m_bReConnect=true;

3)断网重连的工作不能放在livenessTimeoutTask这个函数里面,不然会造成重连死锁,因为live555是单线程的;只能放在其它的线程里面实现重连;我是放在回调给客户端的解码线程里面实现重连;

void NetSdk::noteLiveness(void* clientData,UsageEnvironment& env) 
{

if (m_ReconnectTime> 0) 
 {
  env.taskScheduler().rescheduleDelayedTask(fLivenessCheckTask,m_ReconnectTime*1000000,(TaskFunc*)livenessTimeoutTask, clientData);
 }

}

void NetSdk::livenessTimeoutTask(void* clientData) {

TRACE("livenessTimeoutTask run\n");
 RtspGlobal *pRtspGlobal=(RtspGlobal *)clientData;
 pRtspGlobal->pNetSdk->fLivenessCheckTask= NULL;
 UsageEnvironment& env = pRtspGlobal->pRtspClient->envir(); // alias

pRtspGlobal->pNetSdk->RestopVideo();

}

重连线程如下:

void NetSdk::DecodeThread(void *arg)
{
 NetSdk *pThis=(NetSdk*)arg;

while (!pThis->m_bQuit)
 {

if (pThis->m_bReConnect)
  {
   //
   pThis->RestartVideo();
   pThis->m_bReConnect=false;

}else
  {
   pThis->ImageDecodeAndShow();
  }

}

Live555 的一个缺陷–例子不能支持多线程(已经修改成支持多线程)的更多相关文章

  1. 阅读DSSS.py 并修改成支持python3.6

    项目地址:https://github.com/stamparm/DSSS 功能:一款小型注入工具 代码如下URL:https://github.com/stamparm/DSSS/blob/mast ...

  2. 百度编辑器UEditor修改成支持物理路径

    一.前言 我虽然工作了2年.有快1年没有做后台的开发了.最近要写个新项目用到富文本编辑器,然后选择用了百度的UEditor.在使用过程中感觉有些不太好.然后就自己手动改一下源码,写得不好请见谅.这只是 ...

  3. C语言多线程的一个简单例子

    多线程的一个简单例子: #include <stdio.h> #include <stdlib.h> #include <string.h> #include &l ...

  4. libcurl的封装,支持同步异步请求,支持多线程下载,支持https

    最近在做一个项目,需要用到http get post等 需求分析需要做到同步和异步,异步请求的返回以可选的回调通知的方式进行. 本人以Linux为例,一步一步的来实现. 配置并且编译libcurl我以 ...

  5. SQL Server Reporting Service(SSRS) 第一篇 我的第一个SSRS例子

    很早就知道SQL SERVER自带的报表工具SSRS,但一直没有用过,最近终于需要在工作中一展身手了,于是我特地按照自己的理解做了以下总结: 1. 安装软件结构 SSRS全称SQL Server Re ...

  6. 一个简单例子:贫血模型or领域模型

    转:一个简单例子:贫血模型or领域模型 贫血模型 我们首先用贫血模型来实现.所谓贫血模型就是模型对象之间存在完整的关联(可能存在多余的关联),但是对象除了get和set方外外几乎就没有其它的方法,整个 ...

  7. 在 Cloudera Data Flow 上运行你的第一个 Flink 例子

    文档编写目的 Cloudera Data Flow(CDF) 作为 Cloudera 一个独立的产品单元,围绕着实时数据采集,实时数据处理和实时数据分析有多个不同的功能模块,如下图所示: 图中 4 个 ...

  8. 一个ioc例子jdk和spring版本导致问题

    今天橘子松在做一个简单例子的时候,出现bug让我久久找了半小时... 天啊 不会吧 错误如下:   java.lang.NoSuchMethodError: org.springframework.a ...

  9. 调用webapi 错误:使用 HTTP 谓词 POST 向虚拟目录发送了一个请求,而默认文档是不支持 GET 或 HEAD 以外的 HTTP 谓词的静态文件。的解决方案

    第一次调用webapi出错如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http:// ...

随机推荐

  1. CentOS7中下载安装Multitail(让你的日志文件变得多彩)

    MultiTail是干啥的? Linux系统下查看日志的一个工具,允许您监视终端中多个窗口中的日志文件和命令输出,着色,过滤和合并. 具体介绍请看官网:https://www.vanheusden.c ...

  2. Kafka 启动报错java.io.IOException: Can't resolve address.

    阿里云上 部署Kafka 启动报错java.io.IOException: Can't resolve address. 本地调试的,报错 需要在本地添加阿里云主机的 host 映射   linux ...

  3. 常见Http状态码大全详解

    HTTP状态码的分类 HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用.HTTP状态码共分为5种类型: 具体如下: 状态码 内容 详细内容 信息告知 - ...

  4. 7.Varnish

    概述 Varnish处理HTTP请求的过程大致分为如下几个步骤:         1> Receive状态:请求处理入口状态,根据VCL规则判断该请求应该Pass或Pipe,还是进入Lookup ...

  5. python人脸对比

    import sys  import ssl  from urllib import request,parse    # client_id 为官网获取的AK, client_secret 为官网获 ...

  6. idea2019 3.3最新版本破解安装教程

    直接给上神秘地址得了:(应该都可以破解) https://www.jianshu.com/p/c7bdc5819d31

  7. scrapy 中没有 crawl 命令

    确保两点: 1.把爬虫.py 复制到 spider 文件夹里 如 执行 scrapy crawl demo.py (spiders 中就要有 demo.py 文件) 2.在项目文件夹内执行命令 在 s ...

  8. Centos7 VNC远程桌面服务安装配置

    1.服务器版本 CentOS Linux release 7.7.1908 (Core) 首先系统安装了GUI界面 # ln -sf /lib/systemd/system/graphical.tar ...

  9. 微信内置浏览器video标签自动全屏的问题

    微信打开h5video视频的时候都会自动全屏播放,有时候影响用户体验 要禁止自动全屏就要加这几个属性 'x5-playsinline':'true', 'webkit-playsinline':'tr ...

  10. 5、mysql的连接查询

    1.内联查询 >inner join 或 join 2.外联查询 (1)左连接 >left outer join 或 left join (2)右连接 >right outer jo ...