Ijkplayer: 请问下做RTSP直播,在局域网环境,1080p、30fps的视频流。现在通过设置相关option参数,延时在300-350ms。怎么做进一步优化,达到100ms左右延时呢

Created on 21 May 2018  ·  49Comments  ·  Source: bilibili/ijkplayer

Most helpful comment

  VideoOptionModel videoOptionMode01 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "fast", 1);//不额外优化
    VideoOptionModel videoOptionMode02 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 200);//10240
    VideoOptionModel videoOptionMode03 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1);
    //pause output until enough packets have been read after stalling
    VideoOptionModel videoOptionMode04 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0);//是否开启缓冲
    //drop frames when cpu is too slow:0-120
    VideoOptionModel videoOptionMode05 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);//丢帧,默认是1
    //automatically start playing on prepared
    VideoOptionModel videoOptionMode06 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1);
    VideoOptionModel videoOptionMode07 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);//默认值48
    //0:代表关闭;1:代表开启
    VideoOptionModel videoOptionMode08 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);//开启硬解
    VideoOptionModel videoOptionMode09 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);//自动旋屏
    VideoOptionModel videoOptionMode10 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0);//处理分辨率变化
    //max buffer size should be pre-read:默认为15*1024*1024
    VideoOptionModel videoOptionMode11 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 0);//最大缓存数
    VideoOptionModel videoOptionMode12 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 2);//默认最小帧数2
    VideoOptionModel videoOptionMode13 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", 30);//最大缓存时长
    //input buffer:don't limit the input buffer size (useful with realtime streams)
    VideoOptionModel videoOptionMode14 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", 1);//是否限制输入缓存数
    VideoOptionModel videoOptionMode15 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "nobuffer");

// VideoOptionModel videoOptionMode16 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp");//tcp传输数据
VideoOptionModel videoOptionMode17 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzedmaxduration", 100);//分析码流时长:默认1024*1000

备注:这是Android配置,ios参数类似

All 49 comments

首先能不能请问300-350ms是怎样设置参数的。。。

probesize设置小点
infbuf设为1不限制输入缓存
fflags设为nobuffer
max_cached_duration设置小点
packet-buffering设为0
start-on-prepared设为1
备注:局域网环境测试

问下这个问题有解决吗,我也遇到这个问题

做到了130ms,还得继续优化。。。

能看看你的option参数配置吗

@xufuji456 请问怎么配置或者修改达到130ms?

@xufuji456 朋友,你好,请问你的优化直播延时选项是否可以告知,我会有偿感谢的。

  VideoOptionModel videoOptionMode01 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "fast", 1);//不额外优化
    VideoOptionModel videoOptionMode02 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 200);//10240
    VideoOptionModel videoOptionMode03 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1);
    //pause output until enough packets have been read after stalling
    VideoOptionModel videoOptionMode04 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0);//是否开启缓冲
    //drop frames when cpu is too slow:0-120
    VideoOptionModel videoOptionMode05 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);//丢帧,默认是1
    //automatically start playing on prepared
    VideoOptionModel videoOptionMode06 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1);
    VideoOptionModel videoOptionMode07 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);//默认值48
    //0:代表关闭;1:代表开启
    VideoOptionModel videoOptionMode08 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);//开启硬解
    VideoOptionModel videoOptionMode09 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);//自动旋屏
    VideoOptionModel videoOptionMode10 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0);//处理分辨率变化
    //max buffer size should be pre-read:默认为15*1024*1024
    VideoOptionModel videoOptionMode11 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 0);//最大缓存数
    VideoOptionModel videoOptionMode12 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 2);//默认最小帧数2
    VideoOptionModel videoOptionMode13 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", 30);//最大缓存时长
    //input buffer:don't limit the input buffer size (useful with realtime streams)
    VideoOptionModel videoOptionMode14 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", 1);//是否限制输入缓存数
    VideoOptionModel videoOptionMode15 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "nobuffer");

// VideoOptionModel videoOptionMode16 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp");//tcp传输数据
VideoOptionModel videoOptionMode17 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzedmaxduration", 100);//分析码流时长:默认1024*1000

备注:这是Android配置,ios参数类似

@zhengchengbin610 感谢就不用了,大家相互学习而已

@xufuji456 感谢的回复,max_cached_duration 这个选项是需要自己去按照网络文章加进去吧? 交个朋友,这是我的QQ:471102531

max_cached_duration是自己加的,用来控制音视频缓存队列

我试了你给我的配置选项,但是还是有480ms的延时,不知什么了,我是局域网播放rtsp 流,请问有什么建议吗?

总延时=采集+编码(缓冲)+发送+传输+接收+解码(缓冲)+播放,你先确认下采集编码端有多少延时

@xufuji456 明白,我确认一下,不过我测试的流没有音频,然后我disable 掉了音频流的播放

@xufuji456 我用了一个其他的app 测试同一个流,延时在300ms左右,我的目标也就是300-350之间,但是我用ijkplayer的延时 一直保持在480ms 左右,感觉一直稳定在480ms,换了你的配置也是这样。对ijkplayer 还有什么修改优化的方法吗?

你换成硬解码试下
//0:代表关闭;1:代表开启
VideoOptionModel videoOptionMode08 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);//开启硬解

@xufuji456 是的,这个是否硬解码的选项 也有打开试过,基本没有什么变化,估计瓶颈延时不在解码部分,你是否可以给我修改的版本呢?

@zhengchengbin610 打开硬解后,可以降低 CPU 的使用率,可以让 CPU 做其他的事情,直播是因为码率一般不高,所以不明显,实际上是要好一些的

@Supecomer 你说的了解,只是针对目前延时一直在480ms的问题上,用硬解码不太明显,当然CPU肯定低了,对于整个APP性能是有提升的,关于延时问题你有什么建议吗

max_cached_duration是自己加的,用来控制音视频缓存队列

你好,我现在也是在局域网环境的推流,现在设置option后延迟在300ms左右,想进一步优化延迟,请问你添加max_cached_duration的逻辑能说下吗?非常感谢

判断音视频缓存队列时间戳是否大于max_cached_duration,如果大于,就丢视频帧,要注意的是整个GOP都需要丢,否则会花屏

你先把编译环境搭建好,建议在ubuntu环境编译。
具体修改可参考博客:https://www.jianshu.com/p/d6a5d8756eec

你先把编译环境搭建好,建议在ubuntu环境编译。
具体修改可参考博客:https://www.jianshu.com/p/d6a5d8756eec

已经处理好了,谢谢

我设置上面的参数后,在局域网中还是有2秒的延迟呢?

max_cached_duration是自己加的,用来控制音视频缓存队列

你好,我现在也是在局域网环境的推流,现在设置option后延迟在300ms左右,想进一步优化延迟,请问你添加max_cached_duration的逻辑能说下吗?非常感谢

您好,我设置上面的参数后还是有2秒的延迟呢,我就用了一个无线路由器,么有接网线测试的

1、你确认下推流端延时多少,用其他播放器拉流播放对比
2、确认下推流的码率、分辨率、帧率怎么样的

@xufuji456 关于基于ijkplayer低延时300ms以内优化方法,是否可以交流,有偿的,感谢

@zhengchengbin610 你那边直播的参数是怎么样的呢,分辨率、码率、帧率这些。
另外,这个300ms是在局域网测试的,外网环境具有不确定性

_No description provided._

你好 ,怎么看log 确认是延迟300-500ms

_No description provided._

你好 ,怎么看log 确认是延迟300-500ms
@cg19910712 打开秒表,然后拍照对比推流端和拉流端的时差

@xufuji456 大神你这个FFmpegAndroid里面的Onlive里面的so库 虽然能到达90ms 但是stop的时候没有发送teardown 来停止服务器发送rtsp

你先把编译环境搭建好,建议在ubuntu环境编译。
具体修改可参考博客:https://www.jianshu.com/p/d6a5d8756eec

您好,请问您编译的so库可以分享一下吗?

在开始播放器开始加载视频源的时候打开一个线程,用来监听时间变化,在setOnPreparedListener的onPrepared方法中,打印出准备了多长时间。在setOnInfoListener的onInfo方法中通知MEDIA_INFO_VIDEO_RENDERING_START时打印开始播放的时间。

------------------ 原始邮件 ------------------
发件人: "吃苹果的猫"notifications@github.com;
发送时间: 2019年7月22日(星期一) 中午11:38
收件人: "bilibili/ijkplayer"ijkplayer@noreply.github.com;
抄送: "724699262"l724699262@vip.qq.com;"Comment"comment@noreply.github.com;
主题: Re: [bilibili/ijkplayer] 请问下做RTSP直播,在局域网环境,1080p、30fps的视频流。现在通过设置相关option参数,延时在300-350ms。怎么做进一步优化,达到100ms左右延时呢 (#4267)

请问你们是怎么获取到延时时间的呢


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

(Android平台) 请教下大家,网络波动的时候,或者RTSP服务器断开的时候,你们是如何捕捉到这个事件的?就是说没有一个错误回调的方法,我这边有设置 ijkMediaPlayer.setOnErrorListener(new IMediaPlayer.OnErrorListener() { 但是没有作用,什么打印都没有。希望有大神指点下,谢谢!

(Android平台) 请教下大家,网络波动的时候,或者RTSP服务器断开的时候,你们是如何捕捉到这个事件的?就是说没有一个错误回调的方法,我这边有设置 ijkMediaPlayer.setOnErrorListener(new IMediaPlayer.OnErrorListener() { 但是没有作用,什么打印都没有。希望有大神指点下,谢谢!

和Android平台应该没关系,ffmpeg拉流,本质离不开av_read_frame,RTSP-Server断开或者网络出错,av_read_frame会返回错误码,用av_err2str可以查出具体原因。

@xufuji456 大神你这个FFmpegAndroid里面的Onlive里面的so库 虽然能到达90ms 但是stop的时候没有发送teardown 来停止服务器发送rtsp

setup、teardown、play这些命令应该是推流端发送的,拉流端是接收命令进行处理

你先把编译环境搭建好,建议在ubuntu环境编译。
具体修改可参考博客:https://www.jianshu.com/p/d6a5d8756eec

您好,请问您编译的so库可以分享一下吗?

在这里有 https://github.com/xufuji456/FFmpegAndroid

@xufuji456 大神你这个FFmpegAndroid里面的Onlive里面的so库 虽然能到达90ms 但是stop的时候没有发送teardown 来停止服务器发送rtsp

setup、teardown、play这些命令应该是推流端发送的,拉流端是接收命令进行处理

退出拉流的时候,确实应该要发送 teardown 吧。 我用vlc拉rtsp然后退出的时候,vlc 是有发送 teardwon指令给到服务器端的,但是用这个就没有发送teardwon 指令

(Android平台) 请教下大家,网络波动的时候,或者RTSP服务器断开的时候,你们是如何捕捉到这个事件的?就是说没有一个错误回调的方法,我这边有设置 ijkMediaPlayer.setOnErrorListener(new IMediaPlayer.OnErrorListener() { 但是没有作用,什么打印都没有。希望有大神指点下,谢谢!

和Android平台应该没关系,ffmpeg拉流,本质离不开av_read_frame,RTSP-Server断开或者网络出错,av_read_frame会返回错误码,用av_err2str可以查出具体原因。

ijkplayer 有接口可以直接操作 av_read_frame 吗? av_err2str 这个在哪里可以查呢?

(Android平台) 请教下大家,网络波动的时候,或者RTSP服务器断开的时候,你们是如何捕捉到这个事件的?就是说没有一个错误回调的方法,我这边有设置 ijkMediaPlayer.setOnErrorListener(new IMediaPlayer.OnErrorListener() { 但是没有作用,什么打印都没有。希望有大神指点下,谢谢!

和Android平台应该没关系,ffmpeg拉流,本质离不开av_read_frame,RTSP-Server断开或者网络出错,av_read_frame会返回错误码,用av_err2str可以查出具体原因。

ijkplayer 有接口可以直接操作 av_read_frame 吗? av_err2str 这个在哪里可以查呢?

没直接操作av_read_frame的,这个在ff_ffplay.c读线程里面。
如果is->eof,在ffp_toggle_buffering是有实现通知的ffp_notify_msg2。
如果网络出错,也有匹配好几个错误码,下面的if(pb_error){..}
然后线程就被挂起等待,再次唤醒进入continue,回到循环开头,可能有加了暂停、abort之类的标志,然后退出循环了。
看了下,EOF好像返回的是BUFFERRING_END之类的标志,可能是在状态的监听里面。pb_error应该才回调到你说的OnErrorListener。这部分没仔细看。你可以在av_read_frame返回小于0的条件下加个
av_log(ffp, AV_LOG_ERROR, "av_read_frame error: %s\n", av_err2str(ret)); 重新编译看看在你的环境下,网络出错,断服务器返回什么错误,就比较容易追溯到回调的位置。

`
ret = av_read_frame(ic, pkt);
if (ret < 0) {
int pb_eof = 0;
int pb_error = 0;
if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
ffp_check_buffering_l(ffp);
pb_eof = 1;
// check error later
}
if (ic->pb && ic->pb->error) {
pb_eof = 1;
pb_error = ic->pb->error;
}
if (ret == AVERROR_EXIT) {
pb_eof = 1;
pb_error = AVERROR_EXIT;
}

        if (pb_eof) {
            if (is->video_stream >= 0)
                packet_queue_put_nullpacket(&is->videoq, is->video_stream);
            if (is->audio_stream >= 0)
                packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
            if (is->subtitle_stream >= 0)
                packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
            is->eof = 1;
        }
        if (pb_error) {
            if (is->video_stream >= 0)
                packet_queue_put_nullpacket(&is->videoq, is->video_stream);
            if (is->audio_stream >= 0)
                packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
            if (is->subtitle_stream >= 0)
                packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
            is->eof = 1;
            ffp->error = pb_error;
            av_log(ffp, AV_LOG_ERROR, "av_read_frame error: %s\n", ffp_get_error_string(ffp->error));
            // break;
        } else {
            ffp->error = 0;
        }
        if (is->eof) {
            ffp_toggle_buffering(ffp, 0);
            SDL_Delay(100);
        }
        SDL_LockMutex(wait_mutex);
        SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
        SDL_UnlockMutex(wait_mutex);
        ffp_statistic_l(ffp);
        continue;
    } else {
        is->eof = 0;
    }

`

(Android平台) 请教下大家,网络波动的时候,或者RTSP服务器断开的时候,你们是如何捕捉到这个事件的?就是说没有一个错误回调的方法,我这边有设置 ijkMediaPlayer.setOnErrorListener(new IMediaPlayer.OnErrorListener() { 但是没有作用,什么打印都没有。希望有大神指点下,谢谢!

和Android平台应该没关系,ffmpeg拉流,本质离不开av_read_frame,RTSP-Server断开或者网络出错,av_read_frame会返回错误码,用av_err2str可以查出具体原因。

ijkplayer 有接口可以直接操作 av_read_frame 吗? av_err2str 这个在哪里可以查呢?

没直接操作av_read_frame的,这个在ff_ffplay.c读线程里面。
如果is->eof,在ffp_toggle_buffering是有实现通知的ffp_notify_msg2。
如果网络出错,也有匹配好几个错误码,下面的if(pb_error){..}
然后线程就被挂起等待,再次唤醒进入continue,回到循环开头,可能有加了暂停、abort之类的标志,然后退出循环了。
看了下,EOF好像返回的是BUFFERRING_END之类的标志,可能是在状态的监听里面。pb_error应该才回调到你说的OnErrorListener。这部分没仔细看。你可以在av_read_frame返回小于0的条件下加个
av_log(ffp, AV_LOG_ERROR, "av_read_frame error: %s\n", av_err2str(ret)); 重新编译看看在你的环境下,网络出错,断服务器返回什么错误,就比较容易追溯到回调的位置。

`
ret = av_read_frame(ic, pkt);
if (ret < 0) {
int pb_eof = 0;
int pb_error = 0;
if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
ffp_check_buffering_l(ffp);
pb_eof = 1;
// check error later
}
if (ic->pb && ic->pb->error) {
pb_eof = 1;
pb_error = ic->pb->error;
}
if (ret == AVERROR_EXIT) {
pb_eof = 1;
pb_error = AVERROR_EXIT;
}

        if (pb_eof) {
            if (is->video_stream >= 0)
                packet_queue_put_nullpacket(&is->videoq, is->video_stream);
            if (is->audio_stream >= 0)
                packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
            if (is->subtitle_stream >= 0)
                packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
            is->eof = 1;
        }
        if (pb_error) {
            if (is->video_stream >= 0)
                packet_queue_put_nullpacket(&is->videoq, is->video_stream);
            if (is->audio_stream >= 0)
                packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
            if (is->subtitle_stream >= 0)
                packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
            is->eof = 1;
            ffp->error = pb_error;
            av_log(ffp, AV_LOG_ERROR, "av_read_frame error: %s\n", ffp_get_error_string(ffp->error));
            // break;
        } else {
            ffp->error = 0;
        }
        if (is->eof) {
            ffp_toggle_buffering(ffp, 0);
            SDL_Delay(100);
        }
        SDL_LockMutex(wait_mutex);
        SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
        SDL_UnlockMutex(wait_mutex);
        ffp_statistic_l(ffp);
        continue;
    } else {
        is->eof = 0;
    }

`

嗯,按照你说的加了打印,断开服务器之后,返回的错误是 end of file
image
这个是对应 ijkplayer 的哪个回调呢?

做到了130ms,还得继续优化。。。

做到了130ms,还得继续优化。。。

@xufuji456 能告知做到130ms的option的设置参数吗?

我在html5,最低做到了270ms。
就再下不去了。
楼请的130,是ijkplayer,不是H5的。
到130估计也很难下了。

我尝试使用rtsp局域网,最低到80ms。
但是些都不好在HTMl5上面使用。

最大时延是在: 播放器端; 流到了后要解码。这是软解的可能至少要50ms的时延了。

乐播投屏可以在1080p做到wifi 40ms延时,他们是如何实现的呢?(局域网)

乐播投屏可以在1080p做到wifi 40ms延时,他们是如何实现的呢?(局域网)

猜测并不是1080P,只是分辨率达到了1920*1080. 1080P是逐行扫描,直播或者低延时的高清,可能都比较困难。
码率不足,造成显示上面打折。
还有,你的40ms是如何测试的?RTSP Lan网络测试最快测到80ms。

如果 知道乐投是1080P,麻烦告知。

乐播投屏可以在1080p做到wifi 40ms延时,他们是如何实现的呢?(局域网)

猜测并不是1080P,只是分辨率达到了1920*1080. 1080P是逐行扫描,直播或者低延时的高清,可能都比较困难。
码率不足,造成显示上面打折。
还有,你的40ms是如何测试的?RTSP Lan网络测试最快测到80ms。

如果 知道乐投是1080P,麻烦告知。

分辨率确实是1920x1080,延时利用的秒表,让投屏端显示秒表。然后把接收端和投屏端放在一起,用另一个设备拍照。上面显示的差值即为延迟。乐播投屏和接收端都可以在网上下到,很容易验证。
我现在想做一个基于rtsp的投屏,查了查目前的github,能跑通的就是libstreaming,但他是投的照相机,苦于codec不是很熟,不知道从何改起,把数据源变成屏幕

目前市面上产品以80ms延时为主,偶尔出现40ms,局域网传输,不考虑网络抖动和网络延时。
采用h265编解码,提高压缩率,降低传输延时,自定义传输层协议。

@xufuji456 请问怎么配置或者修改达到130ms?

如果不嫌多个库的话,可以使用live555 来连接rtsp流,,,github上可以找到一个live55helper,是把live555进行一次封装,很好用..使用liv555出来的数据直接就是h265或者265的裸流,给ffmpeg直接解码就行..这样在我的环境下(摄像头->H3516a编码->live555->ffmpeg软解->opengl渲染)效率解码综合下来能有180ms..我打印过日志从live555出来的数据到软解完4-6ms,主要延迟还是在摄像头编码板.pc端的,仅供参考

Was this page helpful?
0 / 5 - 0 ratings