首页 新闻 会员 周边 捐助

ijkplayer 在android 手机上播放rtsp 流视频一定时间后,画面卡住不动了,抛出下面的错误。

0
悬赏园豆:40 [已解决问题] 解决于 2024-11-10 18:52

on-existing SPS 2 referenced in buffering period

Fitz的主页 Fitz | 菜鸟二级 | 园豆:292
提问于:2024-10-12 12:50
< >
分享
最佳答案
0

这个错误一般是说 ijkplayer 在解码 RTSP 流的时候遇到了与视频编码相关的问题,主要是SPS丢失或者错误引用的,RTSP 流的中断或不连续的数据包可能报这个错,这个错误算是比较常见的,有下面几种情况你可以参考一下:

  1. 网络问题,看看RTSP流的服务器稳不稳定,可以试试在本地网络环境上测一下RTSP流
  2. 看看是不是ijkplayer配置参数的问题,试一试这样写:
    IjkMediaPlayer ijkPlayer = new IjkMediaPlayer();
    ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1); // 启用硬件解码
    ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp"); // 强制使用 TCP 传输
    ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 1024 * 512); // 限制缓冲大小
    ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0); // 关闭缓冲避免卡顿
    可以提高稳定性
  3. 有时候这种问题也和版本有关系,试一试更新版本,因为IjkPlayer 是基于 FFmpeg 的项目,可能会存在一些兼容性问题
  4. 在RTSP流的服务器端做一些优化,
    关键帧频率(GOP)调整,这个可以确保 RTSP 流中的关键帧间隔足够短,这样即使数据丢失也可以尽快恢复。
    SPS 和 PPS 重发,一些流媒体服务器可以配置周期性重发 SPS 和 PPS,确保解码器不会丢失这些重要信息。
  5. 用日志调试一下看看,ijkPlayer.setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
  6. 实在找不到问题就换一个播放器试试吧,建议使用 ExoPlayer,它在处理 RTSP 流方面有比较较好的支持
    implementation 'com.google.android.exoplayer:exoplayer-rtsp:2.18.1'
收获园豆:40
五号位 | 小虾三级 |园豆:610 | 2024-10-12 17:33

返回的错误为什么没有被 ijkvideoview.setOnErrorListener() 这个事件监听到?

Fitz | 园豆:292 (菜鸟二级) | 2024-10-15 08:54

@Fitz: 这种情况有很多原因,如果错误是来自解码器、RTSP 传输层或网络中断等是监听不到的。
IjkPlayer 的有些错误,尤其是底层 FFmpeg 或解码器抛出的错误,有可能不能通过 OnErrorListener 回调,而是直接输出到日志或控制台。试试启用更多的日志,看看是不是有底层错误信息:

IjkMediaPlayer ijkPlayer = new IjkMediaPlayer();
ijkPlayer.setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);

然后检查控制台输出,看看有没有有其他详细错误。

监听 info 回调事件:有时错误会以 OnInfoListener 的形式返回。试试这样:

ijkVideoView.setOnInfoListener((mp, what, extra) -> {
    Log.d("IjkPlayer", "Info event: what = " + what + ", extra = " + extra);
    return false;
});

然后就是网络问题了,丢包或连接超时,可能会导致解码器卡住,但不会触发 OnErrorListener。可以试试设置 RTSP 传输和超时:

ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp");
ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", 3000000);  // 设置超时(微秒)
ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
使用 TCP 传输可以减少丢包问题,并通过设置超时让播放器在网络不佳时及时返回错误。

也有可能是底层解码器错误未通过 Java 层回调
IjkPlayer 的一些错误发生在 FFmpeg 解码层,是有可能不会冒泡到 Java 层的 OnErrorListener的,试试直接监听底层 FFmpeg 的消息,使用 IjkMediaPlayer.setOnNativeInvokeListener(),捕获更多底层事件:

ijkPlayer.setOnNativeInvokeListener((what, args) -> {
    Log.d("IjkPlayer", "Native invoke event: what = " + what);
    return false;
});

其他原因有可能是应用被后台杀死或意外中断Android 系统可能因为资源不足或其他原因中断播放,但这些不会触发错误回调。
在 onPause() 和 onResume() 中合理管理播放器,避免意外释放:

@Override
protected void onPause() {
    super.onPause();
    ijkVideoView.pause();
}

@Override
protected void onResume() {
    super.onResume();
    ijkVideoView.start();
}

实在找不到也很简单啊,用全局异常捕获来捕获可能未冒泡的错误:

Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
    Log.e("IjkPlayer", "Uncaught exception: ", throwable);
});

实在找不到就去认真看看日志

五号位 | 园豆:610 (小虾三级) | 2024-10-16 14:34

@五号位: 没有setLogLevel 这个函数,有这个 native_setLogLevel 可以设置

Fitz | 园豆:292 (菜鸟二级) | 2024-11-10 18:51
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册