在海思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的拖累。

 

 

 

版权声明:可自由转载。

相关文章推荐

建立live555海思编码推流服务

因项目需要,这一周弄了一下live555。需求:海思编码——>RTSP server,使用VLC可以访问,类似于网络摄像机的需求。看了一下,live555的架构太复杂了,半桶水的C++水平还真的需要花...

RTSPClient工具EasyRTSPClient支持H.265,支持海思等各种芯片平台

EasyRTSPClient是EasyDarwin开源流媒体团队开发、提供的一套非常稳定、易用、支持重连的RTSPClient工具,接口调用非常简单,再也不用像调用live555那样处理整个RTSP ...

海思Hi3516A开发板RTSP H.265/H.264编码HDMI输入1080P60帧高清

HDMI输入板卡如下: 尺寸如下 板子 100mm x 70mm 资源如下 1.1G Byte/8G Bit DDR 内存 2.32M Byte/256M bit Flash...

RTSP客户端学习(一)——live555库的移植和验证

因为项目原因需要在海思Hi3531平台上实现RTSP客户端,之前没接触过流媒体,作为小白,就记录下学习过程吧。 客户端和服务器端均采用live555,之前尝试过Darwin Stream Ser...

海思hi3516C平台音频输入/输出调试过程

s32Ret =HI_MPI_ADEC_SendStream(s32AdecChn, &stAudioStream, HI_TRUE);         if (s32Ret)         {...

在hi3518EV200模组上用ffmpeg实现rtmp推流直播测试

CPU: 37.6% usr 19.6% sys  0.0% nic 35.5% idle  4.2% io  0.0% irq  2.8% sirq Load average: 7.82 7.31...

移植rtmp到rtsp摄像机的过程记录(sdk2rtmp软件)

srs是Simple Flash media Server的简写。我们用srs+nginx来搭建流服。实现点播、存储和回放功能。安装布署在云服务器上面。 rtmppush是运行在嵌入式ipc(his...

用srs-librtmp写了一个rtmp push程序,将IPC的video data push到srs上。

首先在一台hi3518E+ar0130的摄像机上面测: # ./rtmpmain rtmp://ossrs.net/live/livestream Example for srs-librtmp ...

建议IPC采用RTMP(server+rtmppush)的流媒体框架。

建议IPC采用RTMP(server+rtmppush)的流媒体框架。此技术方案的优势: 1、RTMP协议是标准的。 2、通过服务器中转的方式,完全没有NAT穿透的问题。可以在VPS上面安装srs...

rtsp2rtmp程序,从rtsp摄像机获取流,转换为rtmp push到FMS

软件功能: 1、从rtsp摄像机(rtsp server)获取流,然后转换为rtmp协议,将流推送到FMS(Flash Media Server)上面。 2、支持2000路以上rtsp摄像机(受限...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在海思hi3516C上面做流媒体rtsp server,总是存在延时很大并且VLC播放丢帧
举报原因:
原因补充:

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