流媒体方案

首先看下项目需求:
   1.最多同时支持16路音视频同时显示。
   2.窗口模式,全屏,1窗口,4窗口,9窗口,16窗口。
   3.播放控制,开始播放,停止播放,开启音频,停止音频,云台控制,Camera管理。
 
 下面谈谈设计方案:
 
 1.总体设计,按照码流数据流向,可以将系统分成三层:
 
  网络层,负责码流的接收,数据的解包,以及网络故障的处理。
   解码显示层,网络层将数据解包后提交给解码层,解码层负责码流解码和图像显示。
   UI层,负责响应消息并进行处理。
 
  处理原则:层与层之间尽量独立,比如网络层发现网络故障后,进行以下处理:
 
  1.通知UI网络故障。
   2.自行进行网络重连。
   3.故障恢复后通往UI层网络故障恢复。
 
  期间并不需要通知解码显示层暂停解码显示。解码显示层收不到网络层提交的码流,自然会暂停解码
 
 1.线程模型
 
  先前的时候我的实现方式是,针对每一个播放窗口开一个线程,在这个线程中进行码流接收,然后进行解码显示。后来发现有诸多问题,其中最严重的就是解码耗时过长导致发送端经常出现发送超时的情形。
 
  现在的实现方式是针对以上各层实现三类线程:
  
   网络数据接收线程:负责网络数据接收,网络连接建立。由于最大只有16路码流数据,使用select进行多路复用足够满足我的需求。网络层还负责对码流数据进行解包和校验,测试证明进行数据解包和校验并不影响网络层的数据接收实时性。
 
  解码显示线程:负责数据的解码和显示,开始我分别使用Semaphore和Event进行线程同步,这样造成了诸多不便,首先程序退出时需要SetEvent唤醒解码线程,暂停和开始播放也需要进行特殊处理,后来我采用最简洁明了的方式:用一个Sleep(1)解决了诸多同步上的问题。
while(!bExit)
{
if(bPlay)
 {
   if(有数据)
 解码显示一帧数据;
  else
 Sleep(1);
 }
 }
    UI线程,主要负责消息响应,UI线程在任何时候都不能阻塞,比如登陆操作直接提交给网络层,网络层收到登陆响应后再通知UI。
 
   2.数据模型
 
   网络层收到数据经解码后得到一帧一帧数据,由于每帧数据长度非常大(I帧比P帧长的多),定义一个固定长度的缓冲区存放一帧数据不是很好的做法。使用链表则会不断的分配和释放内存,造成内存碎片。使用循环缓冲区会增加一次数据拷贝。为此我对循环缓冲区进行扩展:
   
    每次写入一帧数据,写入一帧数据之前先写入该帧数据的长度。
    如果到了缓冲区的末尾,无法容纳一帧完整的数据,直接跳到缓冲区的开始位置写入数据。当然需要进行一些特殊处理。
 
   3.其他方面:
    使用Directshow框架可以方便解码显示,Directshow采用DirectDraw进行图像显示,效率有明显的提升。
    Directshow的窗口模式比无窗口模式要容易控制,比如针对某个窗口进行显示和隐藏。
    全屏播放的最好方法是:先将窗口最大化,置顶,然后隐藏窗口的标题栏,边框,窗口上的其他控件,取消全屏进行逆操作即可。
 
   4.实现难点
 
   我觉得最难得是音视频同步,因为接收的是实时码流,对时延要求较高,不能使用较大的缓冲,所以造成诸多问题,解决这些问题发了我相当大一部分时间,这个留作下回再做讨论吧。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值