EasyPlayer-RTSP-Android安卓RTSP播放器低延迟播放延时优化策略

EasyPlayer-RTSP-Android播放器是一款专门针对RTSP协议进行过优化的流媒体播放器,其中我们引以为傲的两个技术优势就是起播速度快和播放延迟低。最近我们遇到一些需求,其对延迟要求非常苛刻,于是我们再把代码捡起来,针对之前的播放策略进行再优化,果然又发现一些可以更改和调优的地方,于是又对性能进行了一次压榨,再一次降低了延迟:

提高解码线程的优先级

一个不容忽视且容易被人忽略的事实,就是安卓层在一些低优先级的线程上面,线程休眠时间要比sleep时间要长,比如下面一段代码,在一个线程优先级为BACKGROUND的线程里,我们sleep 100毫秒,然后打印实际上线程暂停的时间。

new Thread(new Runnable() {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
long millis = System.currentTimeMillis();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG,"thread sleep :" + (System.currentTimeMillis() - millis));
}
}).start();

然后打印输出如下内容:

thread sleep :102

可见优先级对线程的睡眠时间影响很大,我们这里需要严格控制休眠时间,所以我们需要将线程优先级设置高一些,设置成Audio级别:

Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);

对于音频播放,使用AudioTrack的非阻塞模式写入

EasyPlayer在渲染视频轨和音频轨的时候,是分别在不同的线程进行的,但是由于有音视频同步策略,如果某一个线程速度慢了,那另外一个线程就也会放慢下来等待它,而音频渲染就是这样一个容易"慢下来"的线程!

音频数据是由AudioTrack来进行渲染的,我们将PCM数据由AudioTrack的write接口写入,就可以播放出声音,但是这个write函数是阻塞的,假设某段时间由于网络抖动,没有音频数据过来,过会又突然来了一大块数据,把这些数据都write到AudioTrack,会阻塞一段时间,这样就会导致不可避免的延迟!

Android 6.0 AudioTrack提供了一个非阻塞的写入方式,我们在6.0以上的安卓系统,使用非阻塞方式写入,这样大块数据也能很快写入音频设备,就不会因此而导致延迟了。

优化追帧策略

视频是有一个个视频帧组成的帧序列。每个视频帧代表了一个时间点的采样,我们收到视频帧同时会得到其所在的时间信息,即视频时间戳。通过时间戳可计算出视频帧之间的时间间隔。播放时,我们需要根据这个时间间隔T来Sleep,这样播放时才能保证流畅性。可通过下面的代码来计算出T:

// 睡眠时间=当前时间戳-上一帧的时间戳-解码时间
long sleepTime = frameInfo.stamp - previousStampUs - decodeSpend * 1000;
if (sleepTime > 100000) { // 睡眠时间超过100毫秒了,可能时间戳异常。设置为100毫秒。
Log.w(TAG, "sleep time.too long:" + sleepTime);
sleepTime = 100000;
}

上面说了,由于网络抖动,可能一段时间内都没有收到媒体数据,过一会又突然来了一大块数据。这时候已经有延迟产生了!那怎么办呢?我们可以让播放器稍微快速点播放,通过控制视频线程的Sleep时间T便可实现,当缓冲区内缓存帧数比较大时,可以以一定比例降低T,这样播放器便可更快地消耗掉缓存帧数,将已经存在的延迟逐步追上。

如下面的代码所示,我们对当前的的Sleep时间进行修正:

if (sleepTime > 0) {
// 计算当前视频队列的缓冲时间。
long cache = mNewestStample - frameInfo.stamp;
// 根据缓冲时间计算一个新的睡眠时间。
sleepTime = fixSleepTime(sleepTime, cache, 50000);
if (sleepTime > 0) {
Thread.sleep(sleepTime / 1000);
}
}

fixSleepTime函数用来修正睡眠时间。思路就是根据当前队列的缓冲和一个固定的延迟时间,调整睡眠时间。其代码如下,第一个参数表示修正前的睡眠时间T,第二个参数表示当前缓冲时长Cache,第三个参数表示当前设置的缓冲时长Delay,单位都是微秒:

    private static final long fixSleepTime(long sleepTimeUs, long totalTimestampDifferUs, long delayUs) {
if (totalTimestampDifferUs < 0l) { // 修正参数异常
Log.w(TAG, String.format("totalTimestampDifferUs is:%d, this should not be happen.", totalTimestampDifferUs));
totalTimestampDifferUs = 0;
}
double dValue = ((double) (delayUs - totalTimestampDifferUs)) / 1000000d;
double radio = Math.exp(dValue);
double r = sleepTimeUs * radio + 0.5f;
Log.i(TAG, String.format("%d,%d,%d->%d", sleepTimeUs, totalTimestampDifferUs, delayUs, (int) r));
return (long) r;
}

这个函数的思路是根据自然指数在x小于0时y小于1,大于0但无限趋近于0,使用这个值乘以睡眠时间,得出新的睡眠时间。

x为允许的缓存时间Delay减去缓冲区的时间Cache。

  • 当Cache大于Delay时,x小于0,y小于1,这时睡眠时间会变小,播放器加速播放。
  • 当Cache等于Delay时,x为0,y等于1,这时睡眠时间不变。
  • 当Cache小于Delay时,x大于0,y大于1.这样修正的睡眠时间会变大。这时播放器会降低播放速度。

总结

通过这个机制,播放器会在播放的过程中通过调节睡眠时间,将当前的缓存时间逐步趋向用户设置的缓冲值。我们可更改这个缓冲值Delay,Delay越大,缓冲越大,播放越流畅;Delay越小,缓冲越小,延迟就越低。

关于EasyPlayer流媒体播放器

An elegant, simple, fast android RTSP/RTMP/HLS/HTTP Player.EasyPlayer support RTSP(RTP over TCP/UDP)version & Pro version,cover all kinds of streaming media!EasyPlayer是一款精炼、高效、稳定的流媒体播放器,分为RTSP版、RTMP版和Pro版三个版本,支持各种各样的流媒体音视频协议和文件的播放,在安防、互联网、教育、录播、IPTV等多个领域大放异彩,广泛应用!

EasyPlayer:https://github.com/EasyDSS/EasyPlayer

点击链接加入群【EasyPlayer】:544917793

获取更多信息

邮件:support@easydarwin.org

EasyDarwin开源流媒体服务器:www.EasyDarwin.org

EasyDSS商用流媒体解决方案:www.EasyDSS.com

EasyNVR无插件直播方案:www.EasyNVR.com

Copyright © EasyDarwin Team 2012-2018

EasyPlayer-RTSP-Android安卓播放器播放RTSP延迟优化策略,极低延时!的更多相关文章

  1. 使用vlc播放器做rtsp流媒体服务器

    可参考: 使用vlc播放器播放rtsp视频 web网页中使用vlc插件播放相机rtsp流视频 使用vlc进行二次开发做自己的播放器 首先需要安装vlc播放器,下载及安装步骤略 使用vlc播放器做rts ...

  2. 使用vlc播放器播放rtsp流视频

    可参考: 使用vlc播放器做rtsp服务器 web网页中使用vlc插件播放相机rtsp流视频 使用vlc进行二次开发做自己的播放器 首先需要安装vlc播放器,下载及安装步骤略 使用vlc播放器播放rt ...

  3. 如何实现Windows平台RTMP播放器/RTSP播放器播放窗口添加OSD文字叠加

    好多开发者在做Windows平台特别是单屏多画面显示时,希望像监控摄像机一样,可以在播放画面添加OSD台标,以实现字符叠加效果,大多开发者可很轻松的实现以上效果,针对此,本文以大牛直播SDK (Git ...

  4. 【转】C# 视频监控系列(12):H264播放器——播放录像文件

    原文地址:http://www.cnblogs.com/over140/archive/2009/03/23/1419643.html?spm=5176.100239.blogcont51182.16 ...

  5. EasyPlayer RTSP播放器对RTSP播放地址url的通用兼容修改意见

    问题反馈 最近在线上遇到一位老朋友咨询关于EasyPlayer播放器的事情,大概现象就是分别用EasyPlayer和vlc播放大华摄像机的RTSP流,流地址是:rtsp://admin:admin12 ...

  6. .net C# 网页播放器 支持多种格式 媒体播放器 播放器 代码

    .avi格式代码片断如下:<object id='video' width='400' height='200' border='0' classid='clsid:CFCDAA03-8BE4- ...

  7. 第十一篇、HTML5隐藏播放器播放背景音乐

    html5添加网页背景音乐  一个客户要求给网站添加一个背景音乐,我用的是html5添加网页背景音乐的代码,在此记录一下以后有用. html5方法一:<audio autoplay=" ...

  8. flv网页播放器播放失败

    在IIS6.0上发布网站时,在路径正确的情况下,网页flv播放器还是无法播放flv视频的解决方法. 1.打开IIS6.0管理器,打开发布的网站,点击打开属性窗口. 2.在HTTP头选项里找到MIME类 ...

  9. java调用本地播放器播放视频文件。调用本地播放器不能播放指定文件的说明。

    public class OpenExe extends HttpServlet { //打开本地播放器并播放视频 public static void openExe(String file) { ...

随机推荐

  1. HDFS主要节点解说(一)节点功能

    1 HDFS体系结构简单介绍及优缺点 1.1体系结构简单介绍  HDFS是一个主/从(Mater/Slave)体系结构.从终于用户的角度来看,它就像传统的文件系统一样,能够通过文件夹路径对文件运行CR ...

  2. iOS开发-在Swift里使用AFNetworking方法

    在OC里使用惯了AFNetworking,比较喜欢这一个第三方库,在别的途径里得知可以在Swift里使用AFNetworking.但是那个时候我不知道具体的操作是怎样的,于是我只能去百度.GOOGLE ...

  3. Centos下Subversion 服务器安装配置

    1.安装 # yum install subversion 2. svn配置 建立svn版本库目录可建多个:2.1 新建文件夹: # mkdir -p /opt/svndata/repos 2.2 建 ...

  4. 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程

    反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑)   背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...

  5. AngularJs学习笔记(2)——ng-include

    编写html文档的时候,为了实现代码模块化,增加复杂页面的代码可读性和可维护性,我们常常会想到将代码分散写入不同的HTML文件 angularJS里面的ng-include指令结合ng-control ...

  6. 灾备用Oracle语句备查

    Oracle常用Sql . 查看数据库的归档模式及闪回是否启用            select log_mode,open_mode,flashback_on .查看实例状态        sel ...

  7. 使用CSS3实现响应式标题全屏居中和站点前端性能

    要实现标题全屏居中(同一时候在垂直和水平方向居中).有若干种方法,包含使用弹性布局.表格单元.绝对定位和自己主动外边距等. 全屏居中 当中眼下比較流行也比較easy理解的方法是使用绝对定位+偏移实现. ...

  8. 实现html锚点的两种方式

    1,a标签+name属性. 2,使用标签的id属性:

  9. spring boot中 使用http请求

    因为项目需求,需要两个系统之间进行通信,经过一番调研,决定使用http请求. 服务端没有什么好说的,本来就是使用web 页面进行访问的,所以spring boot启动后,controller层的接口就 ...

  10. 矩阵中的路径 剑指offer65题

    include "stdafx.h" #include<vector> #include<algorithm> #include<string> ...