NVR开发重要bug总结

本次做摄像头监控主要遇到的问题有2个。

1:丢帧问题。协议采用的是基于rtp的Udp协议。

2:花屏问题。

丢帧问题解决思路:

1:采取双线程机制。

     如果接收和解码在一个线程中,那么会遇到一个问题就是如果解码一个较大的帧,这时发送端发送2个较小的帧。这时就只能保存一个帧,从而出现丢帧的问题。

:2:发送端采取双线程增加缓冲区机制。

     缓冲区采用循环队列的方式。

     一个进程往缓冲区里面放数据,一个进程从缓冲区里面取数据并解码。

     具体实现参考接收端缓冲区。

3:接收端采取双线程增加缓冲区机制。

     缓冲区采用循环队列的方式。

     一个进程往缓冲区里面放数据,一个进程从缓冲区里面取数据并解码。

     每次接收到的rtp数据包为一帧H264数据。(注意,由于一些帧太大,可能会将帧分成若干包,我们需要将包重组为帧。)

设我们得到的一帧数据长度为vsize,得到的数据保存在vdata中。开辟一个全局数组作为缓冲区。假设缓冲区数组为BufQue。我们需要在数组中保存的内容为数据长度vsize和vdata。由于H264数据以字节为单位而vsize为int型,占据4个字节,需要采取一定措施将int型转化为4个字节。方法如下:

         BufQue[head] = numcount & 0xff;//FirstBit;

         head= (head+1)%BUF_SZIE;

         BufQue[head]= (numcount>>8) & 0xff;//SecondBit;

         head= (head+1)%BUF_SZIE;

         BufQue[head]=(numcount>>16) & 0xff;

         head= (head+1)%BUF_SZIE;

         BufQue[head]= (numcount>>24) & 0xff;

         head= (head+1)%BUF_SZIE;

BUF_SZIE为缓冲区的大小。切记:由于缓冲区为循环队列,因此必须有求余操作。

检查缓冲区代码是否正确与是否丢帧的思路:

    缓冲区代码写好以后并不能立即确定缓冲区代码是否正确,并且由于是一帧帧的得到数据,用单步调试太过复杂繁琐并且一不错就得重新调试,并且由于码流在不停发送并不能确定是否丢帧。解决办法就是将调试信息写到文件中去。

解决思路:

First :发送端发送数据是发送一个时间戳,也就是帧发送的顺序。接受端接受到的数据也有一个时间戳,如果接收端接收到的时间戳不连续,即是丢帧。

Second:接收端接受到数据以后在将数据写入缓冲区以前将H264码流保存到文件中设该文件为RecH264.h264.

Third :将从缓冲区里面读出来的数据也保存到文件中。设该文件为DecBuf.h264

Forth:用VLC播放器播放RecH264.h264.,如果没有花屏则证明接收到的数据无误。如果播放RecH264.h264.不花屏而播放DecBuf.h264花屏说明缓冲区代码错误。

Fifth:如果用VLC播放器播放RecH264.h264花屏,检查数据是否发送和发送的每一帧数据是都正确。

注意:如果写文件的时候以a+,ab+,w+等方式打开文件,在写文件的时候会自动将0A转化为0D0A,这时就算发送端发送数据无误,写文件的时候也会出错。解决方式很简单。以wb+方式打开文件,这样0A就不会转化为0D0A了。

 

花屏问题解决思路:

1:检查解码方式是否正确。

     遇到花屏问题首先考虑的是是否丢帧。而丢帧问题的解决办法为增加缓冲区。增加缓冲区以后,如果还是出现花屏,这时候解决问题主要从以下方面着手。

第一:检查缓冲区,方法如上。

第二:解码是否正确。无论是采用FFmpeg解码还是用海思解码还是别的方式解码,必须确定解码是都正确。验证解码是否正确的方式如下:

将解码以后的YUV数据保存,可以自己编写YUV文件播放器也可以用现有软件播放。当然也可以将现有的YUV数据转码成RGB数据进行播放。如果此时不能正常播放则说明是解码出错。

2:针对缓冲区的访问机制。(事件遇到问题,信号量可以完美解决缓冲区互斥访问的问题)

     对于缓冲区我们必须保持互斥访问,然而互斥访问就有一个问题那就是读和写会占据一定的时间,不能同时访问。不用mutex那么采用event会怎么样呢?会缓冲区爆掉,原因也很简单,因为如果解码一个很大的帧,解码需要花相当多的时间,这是同时到来2个event,然而传给解码进程的只有后面一个event,也就是说缓冲区里面有一帧数据没有进行解码,这样越积累愈多,缓冲区就会爆掉。

信号量semaphor可以完美解决以上问题。每往缓冲区里面存一个数据,semaphor就加1.每取一个数据semaphor就减一,只要有数据取进程就可以一直取,没有数据,那么取数据进程就阻塞等待,这样可以解决有的数据没有取走的问题。

3:SDL显示的控制。(每一帧应该怎么播放)

   SDL显示的时候如果用SDL_delay()函数,不是说不行,而是相对不好,因为每帧的解码时间不确定,delay时间不好确定,并且如果帧率改变的话delay的时间就需要重新修改。怎么控制SDL显示呢?可以采取事件或信号量机制。每解码一帧就发送一个事件或信号量,然后SDL就显示一帧图像。如果没有事件或信号量到来,SDL就显示上一幅图像直到下幅解码图像的到来!

 

本次所做的主要测试:

1:考虑到丢帧问题,首先考虑的是udp不可靠传输导致丢帧。考虑使用tcp传输。(实验失败)

由于tcp采取可靠传输,会占据大量带宽。甚至有可能造成网络拥塞。特别是如果多个摄像头同时发送数据时。网络拥塞反而会造成更多的丢帧。

2:客户端采取双线程机制增加缓冲区。(实验成功)

由于开始采取单线程,此时丢帧明显。大概40帧左右丢一帧,采取双线程加缓冲区机制后丢帧现象几乎没有。有时上千帧未丢一帧数据。

3:发送端采取双线程机制增加缓冲区。(实验成功)

发送端同样存在类似的问题。如果发送一个较大的帧,这时到来2个较小的帧,这时只会发送一个帧,这时也会丢帧。同样需要采取双线程加缓冲区机制。

4:SDL显示时增加缓冲区。(实验失败)

当初因为播放使用的是SDL_delay()函数,考虑到delay时间已到,而解码没有完成,这时可能会有一个画面没有播放,导致花屏。因此增加第二个缓冲区,播放和存储交叉进行。后来发现这样做完全没有意义。实现方式参考(SDL显示的控制)。

5:判断接收到的H264和从缓冲区读出来的H264数据是否正确。(实验成功)

实现方式参考(接收端采取双线程增加缓冲区机制)

6:判断解码方式是否正确。(实验成功)。

将解码后的数据保存,这是仍然花屏,而从缓冲区读出来的H264则不花屏说明解码方式错误,重写解码函数。问题解决。

7:接收到的H264数据明明正确,可是用VLC播放居然花屏。(验证H264时产生的问题)

因为window写文件时以a+,ab+,w,w+等方式写文件时会自动将OA转化为0D0A,这就相当于把OA默认的看成换行符。而window下换行符为2个符号即回车和换行。因此保存的文件反而是错的。解决方式是以wb+方式打开文件即可。c++也会有类似问题。

8:接收端接收线程往缓冲区存数据,解码线程从缓冲区取数据并解码。缓冲区会爆掉。(window同步互斥机制使用不当)

参考(针对缓冲区的访问机制)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值