在海思hi3516C上面做流媒体rtsp server,总是存在延时很大并且VLC播放丢帧

原创 2015年11月20日 09:49:07

丢帧是VLC报出来的,如下:

 

我将帧率设置为15,而且是CIF分辨率,局域网传输,不应该有丢帧啊!?我XX

 

查了一整天,各种办法,最后我发现是海思SDK送出来PTS有问题:

pts=pstStream->pstPack[i].u64PTS*90/1000;      //ms*90

干脆换成我自己计算PTS:

gVideoPath[ch].VencOutQue[wp].u64PTS=gVideoPath[ch].seq*gVencIn[ch].pts_tick;

这样就不丢帧了,延时也正常了。

但刚开始时,仍然要丢几帧。

不过仔细听起来,这种做法,声音总是一顿一顿的,不连续。

没有办法,还是得用SDK提供出来timestamp。而且,越播延迟越大,但第一路流1080P就不会,这TMD究竟是什么原因啊?

 

我在海思底层MPP上面配置了三个通道(1080P/720P/QVGA):

   VpssGrp = 0;   VpssChn = 3;

   VencGrp = 0;   VencChn = 0;             //for HD recording

   s32Ret = _COMM_VENC_Start(VencGrp, VencChn, pVideo+0);

   s32Ret = SAMPLE_COMM_VENC_BindVpss(VencGrp, VpssGrp, VpssChn);

   VpssGrp = 0;        VpssChn = 4;

   VencGrp = 1;    VencChn = 1;           //for preview

   s32Ret = _COMM_VENC_Start(VencGrp, VencChn, pVideo+1);

   s32Ret = SAMPLE_COMM_VENC_BindVpss(VencChn, VpssGrp, VpssChn);

   VpssGrp = 0;        VpssChn = 5;

   VencGrp = 2;    VencChn = 2;    //for CIF clip recording

   s32Ret = _COMM_VENC_Start(VencGrp, VencChn, (pVideo+2));

现在的现象就是1080P这个通道是正常的,延迟在2s左右,丢帧也少。720P/QVGA就不行了,延时达到6秒以上,丢帧严重。

下面只有两个办法:

1、 换成wis-streamer。

2、 录像为mp4文件播放,看是否有问题。

我把VpssChn改了一下,不再关联3/4/5,而是关联0,这样的话,延时的问题基本上算是解决了。但是,丢帧的原因始终没有找到。

我去掉audio后,Video就不再丢帧了,看来,这是音视频不同步引发的血案啊!

 

Hi3518平台流媒体服务器的音视频同步问题

 

PTS:Presentation Time Stamp
DTS:Decoding TimeStamp
PCR:Program ClockReference
STC:System TimeClock

 

我也正在研究这一块.说解码才得到的都是不对的.其实是从LIVE555那里得到的.afterGettingFrame里面有一个参数是presentationTime.通过RTSP得到的流的PTS都是由它计算出来的.不过它的单位是us.还是90000.这个要值得注意.ffmpeg解码后只是校准了PTS.PTS真正的源头是RTSP的发送方.只有发送方才有能力告诉你数据采集的PTS从而帮助你进行同步.

RTP规范里,RTP包的TIMESTAMP字段应该指示图像的显示时间,而且时间单位是tick.像视频的话单位就是90K,那一段25fps的视频每增长一帧,时间戳就应该增加3600.但是同样是通过RTSP播实时流,ffplay和vlc对于时间戳的处理是不一样的.如果在ffplay里.它直接把rtp包里的timestamp当作是解码前的pts传入avcodec_decode_video2().ffmpeg进行重排序(如果没有B帧,一般是原样复制到解码后的AVFrame里),然后将它乘以1/90K还原成us的单位,然后直接用来usleep();而vlc的rtsp传输模块用的是live555,live555在我看来多此一举了,它对上层屏蔽了RTP包里的TIMESTAMP.而是直接帮你还原好了.单位就是us.也就是说,afterGettingFrame()函数的pts单位是us.可以直接拿来用usleep了。

// 1s = 90000 time scale , 一帧就应该是  90000/video_frame_rate 个timescale
static uint32_t video_frame_rate = 30;
static uint32_t video_pts_increment = 90000 / video_frame_rate;   //用一秒钟除以帧率,得到每一帧应该耗时是多少,单位是 timescale单位
static uint64_t video_pts = 0;
pts初始值可以是任意的,我一般定为0,后面每一帧加上增量就可以了。
音频pts的计算方法同上,只不过不是通过帧率,而是通过采样率。
uint32_t audio_pts_increment = (90000 * audio_samples_per_frame) / audio_sample_rate;
audio_samples_per_frame这个值对aac和mp3是不同的,aac固定为1024,mp3固定为1152。

>>

用了你的计算方法,音视频可以用VLC同时播放,但是音频过一段时间后就变慢了。
而且越来延时越大,最后音频就没有了。请问知道是什么原因吗?而且这是变帧率,根本不应该这样来计算。

 

A:RFC3984 规定采用 90000 Hz 的时钟,因此如果编码帧频是 30,那么时间戳间隔就该是 90000 / 30 = 3000。audio_timebase =av_q2d(fmtctx->streams[audio_index]->time_base);
video_timebase = av_q2d(fmtctx->streams[video_index]->time_base);
last_video_pts = pts * video_timebase;
last_audio_pts = pts * audio_timebase;
timebase就是单位
audio为基准同步video(算法是如何?),因为audio是固定帧率的,而video是变帧率。只要设置好了 ao 的参数,如sample rate, channels, sample size等, audio驱动就能以正确的速度播放,所以只要程序里write不出大问题的话,这种同步是非常有效的。

 

一 固定帧率

1. 视频时间戳

     pts = inc++*(1000/fps);  其中inc是一个静态的,初始值为0,每次打完时间戳inc加1.

    在ffmpeg,中的代码

    pkt.pts=m_nVideoTimeStamp++ * (m_VCtx->time_base.num * 1000 /m_VCtx->time_base.den);

 2. 音频时间戳

    pts = inc++ *(frame_size * 1000 / sample_rate)

   在ffmpeg中的代码为

   pkt.pts=m_nAudioTimeStamp++ * (m_ACtx->frame_size * 1000 / m_ACtx->sample_rate);

采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。

。正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采样频率,还可以达到DVD的音质

对采样率为44.1kHz的AAC音频进行解码时,一帧的解码时间须控制在23.22毫秒内。

背景知识:

(一个AAC原始帧包含一段时间内1024个采样及相关数据)
分析:

1 AAC

音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率(单位为s)

一帧 1024个 sample。采样率 Samplerate 44100KHz,每秒44100个sample, 所以 根据公式   音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率

当前AAC一帧的播放时间是= 1024*1000000/44100=22.32ms(单位为ms)

2 MP3

 mp3 每帧均为1152个字节, 则:

frame_duration = 1152 * 1000000 /sample_rate

例如:sample_rate= 44100HZ时, 计算出的时长为26.122ms,这就是经常听到的mp3每帧播放时间固定为26ms的由来。

 

二 可变帧率

有很多的采集卡,摄像头,在做采集的时候,明明设置的25FPS,但实际采集数据回调过来,发现并不是40毫秒的间隔,而是50,60,甚至100不等的时间间隔。

这就给编码后打时间戳带来很大的困难。

在libav里,我们的默认编码参数都是:

ptAvEncoder->ptAvStreamVideo->codec->time_base.den = s32Fps;

ptAvEncoder->ptAvStreamVideo->codec->time_base.num = 1;

这样在编码后的时间戳以1递增,只适合于固定帧率。

我们来改一下:

ptAvEncoder->ptAvStreamVideo->codec->time_base.den = s32Fps * 1000;

ptAvEncoder->ptAvStreamVideo->codec->time_base.num = 1* 1000;

这样就把时间戳的scale变成了毫秒,就可以以毫秒为单位进行计算了,如下:

tAvPacket.pts = ((s64)u32TimeStamp * (s64)s32Fps);

u32TimeStamp是从开始记录的时间差值,以毫秒为单位;s32Fps是帧率。

对于音频,mp4文件默认是采样率为tick的,时间戳计算为:

tAvPacket.pts = (AvEncoderAudioInSizeGet(hHandle) * ( (s64)(u32TimeStamp)) / (AvEncoderAudioInSizeGet(hHandle) * 1000 / ptAvEncoder->ptAvStreamAudio->codec->sample_rate);

AvEncoderAudioInSizeGet(hHandle) 每次编码器需要的PCM数据长度。

u32TimeStamp是从开始记录的时间差值,以毫秒为单位。

 ptAvEncoder->ptAvStreamAudio->codec->sample_rate PCM采样率,代表一秒的数据量。

因为乘以了1000,所以也化成了毫秒单位。

 

一般有三种办法
1.以音频为主进行同步
2.以视频为主进行同步
3.以一个外部参考时钟为同步
你可以参考下ffmpeg下的ffplay来做,还有
http://www.dranger.com/ffmpeg/tutorial05.html 和
http://www.dranger.com/ffmpeg/tutorial04.html 
具体如何实现还是要靠自己研究清楚代码后来解决的.

 

同步的方法:

1、 audio pts直接用video的pts,这样的话,播放继续,Video受audio拖累而丢包严重。

2、 video pts直接用audio pts,结果Video播放不动,audio可以继续。

3、 audio pts直接填0,也就是不要,这样播放是最为流畅的,但video偶尔有丢帧,不知道是否受audio的拖累。

 

 

 

版权声明:可自由转载。

RTSP再学习 -- Hi3516A RTSP实例 分析

上一篇文章,讲到了Hi3516A通过RTSP播放H.265视频流的源码。接下来对源码分析一下。这里推荐一个工具,参看:...
  • qq_29350001
  • qq_29350001
  • 2017年10月09日 10:04
  • 1235

live555 交叉编译移植到海思开发板

本文章参考了。http://blog.csdn.net/lawishere/article/details/8182952,写了hi3518的配置说明。特此感谢 1、首先到它的主页下载一个源码包: ...
  • u011563903
  • u011563903
  • 2014年11月26日 23:09
  • 5685

rtsp rtmp http 比较

本篇文档转载:http://www.cnblogs.com/my_life/articles/5593892.html,感谢博主热心的奉献 以下内容为转载内容: http://blog.c...
  • xwjazjx1314
  • xwjazjx1314
  • 2016年12月16日 15:11
  • 4989

VLC播放RTSP视频延迟问题

之前写过一篇关于在Linux平台上编译android平台上VLC播放器源代码的文章,vlc这款播放器非常优秀而且是开源的,它的核心是开源视频编解码库ffmpeg。而且这款播放器还支持RTSP协议,这个...
  • bingqingsuimeng
  • bingqingsuimeng
  • 2016年05月05日 12:56
  • 4425

ffmpeg ffplay播放延时大问题:播放延时参数设置

使用ffplay播放视频源时,rtsp/rtmp等,会有一定的延时,这里我们可以通过设置ffplay播放参数将延时控制到最小。 ffplay.exe -i rtmp://xxxxxxx -ffla...
  • xiejiashu
  • xiejiashu
  • 2016年09月23日 13:32
  • 8128

VLC播放RTSP视频延迟问题 (转)

原帖地址:http://blog.chinaunix.net/uid-26611383-id-3755283.html =======================================...
  • wainiwann
  • wainiwann
  • 2014年09月01日 11:28
  • 2419

判断网络传输h264视频流是否丢包

用RTP可以很方便的判断是否丢包,丢了那些包。 而用UDP如何判断丢包,这个问题不成立。 首先,NAL必须根据网络环境的MTU值再做一次分包或者并包,独立的一个NAL一个包只是一种情况。为了程...
  • a2657222
  • a2657222
  • 2012年08月03日 21:17
  • 4586

Wireshark 抓包分析 RTSP/RTP/RTCP 基本工作过程

整体而言,RTSP 通常工作于可靠的传输协议 TCP 之上,就像 HTTP 那样,用于发起/结束流媒体传输,交换流媒体元信息。RTP 通常工作于 UDP  之上,用于传输实际的流媒体数据,其中的载荷...
  • u013898698
  • u013898698
  • 2017年10月11日 15:54
  • 548

ffmpeg强制使用TCP方式读取rtsp流

ffmpeg强制使用TCP方式处理rtsp流,参考网上资料,得知可以使用如下命令: “ffmpeg -rtsp_transport tcp -i rtsp://admin.......” ...
  • xiejiashu
  • xiejiashu
  • 2016年05月04日 16:07
  • 3520

live555 rtsp流丢包问题

live555使用过程中遇到一个问题,发送低分辨率的码流码流OK,发送高分辨率的码流会丢包,而且丢的大部分都是I帧;        两台设备网线直连测试是OK的;        开始怀疑是交换机的限制...
  • LIFEXX
  • LIFEXX
  • 2016年09月30日 22:47
  • 1740
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在海思hi3516C上面做流媒体rtsp server,总是存在延时很大并且VLC播放丢帧
举报原因:
原因补充:

(最多只允许输入30个字)