You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用用SurfaceView+Kotlin播放指定RTSP流遇prepare失败求助

解决Android中SurfaceView播放RTSP流时prepare()报错status=0x64的问题

你遇到的java.io.IOException: Prepare failed.: status=0x64错误,本质是Android原生MediaPlayer在处理RTSP流时的兼容性或配置问题。下面我一步步帮你排查和解决:

先搞懂错误原因

status=0x64对应的是MediaPlayer的MEDIA_ERROR_TIMED_OUT或者RTSP连接层面的失败,常见诱因包括:

  • 网络权限未配置或明文流量被限制
  • 原生MediaPlayer不支持当前RTSP流的编码格式(比如H.265/HEVC就不在原生支持列表里)
  • RTSP链接的认证参数未被正确解析
  • 设备网络环境无法正常连接到RTSP服务器

分步解决方案

1. 先把基础配置拉满

首先确保你的AndroidManifest.xml里配置了必要的权限和网络策略:

<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Android 9+允许明文流量(RTSP默认是明文) -->
<application
    ...
    android:usesCleartextTraffic="true">
    ...
</application>

如果你的targetSdk是30+,还要注意在运行时动态申请网络权限(虽然大部分场景下INTERNET是正常权限,但有些定制ROM可能需要)。

2. 用ExoPlayer替代原生MediaPlayer(推荐)

Android原生MediaPlayer对RTSP的支持非常有限,尤其是带认证的复杂流或者非标准编码的流。Google官方的ExoPlayer是更好的选择,它对RTSP的兼容性强很多。

下面是Kotlin结合SurfaceView的ExoPlayer实现代码:

import android.os.Bundle
import android.view.SurfaceHolder
import androidx.appcompat.app.AppCompatActivity
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.source.RtspMediaSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource

class RtspPlayerActivity : AppCompatActivity(), SurfaceHolder.Callback {
    private lateinit var player: ExoPlayer
    private lateinit var surfaceHolder: SurfaceHolder

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rtsp_player)
        
        val surfaceView = findViewById<android.view.SurfaceView>(R.id.surfaceView)
        surfaceHolder = surfaceView.holder
        surfaceHolder.addCallback(this)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // 初始化ExoPlayer
        player = ExoPlayer.Builder(this).build()
        // 设置Surface
        player.setVideoSurfaceHolder(holder)
        
        // 构建RTSP媒体源
        val rtspUrl = "rtsp://192.168.8.73/cdb6e5a0-23af-40e8-8da8-54a21af9cba3/cdb6e5a0-23af-40e8-8da8-54a21af9cba3_vs1?token=cdb6e5a0-23af-40e8-8da8-54a21af9cba3^LVEBAMPZOTDGU|admin|1522055956266|0|0^50^26^26^1522315156^3394fa4fd8888fcca38c10bcf5fa74748b5b58a1&username=admin"
        
        val dataSourceFactory = DefaultHttpDataSource.Factory()
        // 如果需要处理认证,可以在这里添加请求头
        // dataSourceFactory.setDefaultRequestProperties(mapOf("Authorization" to "xxx"))
        
        val mediaSource = RtspMediaSource.Factory(dataSourceFactory)
            .createMediaSource(MediaItem.fromUri(rtspUrl))
        
        // 准备并播放
        player.setMediaSource(mediaSource)
        player.prepare()
        player.play()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        // 可以在这里处理视频尺寸变化
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // 释放资源
        player.release()
    }
}

别忘了在build.gradle里添加ExoPlayer的依赖:

implementation "com.google.android.exoplayer:exoplayer-core:2.19.1"
implementation "com.google.android.exoplayer:exoplayer-rtsp:2.19.1"

(版本号可以用最新的,去Google官网查就行)

3. 如果坚持用原生MediaPlayer的修正尝试

如果你一定要用原生MediaPlayer,试试手动设置Surface和处理认证:

import android.media.MediaPlayer
import android.os.Bundle
import android.view.SurfaceHolder
import androidx.appcompat.app.AppCompatActivity

class NativeRtspPlayerActivity : AppCompatActivity(), SurfaceHolder.Callback, MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener {
    private var mediaPlayer: MediaPlayer? = null
    private lateinit var surfaceHolder: SurfaceHolder

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rtsp_player)
        
        val surfaceView = findViewById<android.view.SurfaceView>(R.id.surfaceView)
        surfaceHolder = surfaceView.holder
        surfaceHolder.addCallback(this)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        mediaPlayer = MediaPlayer().apply {
            setSurface(holder.surface)
            setOnPreparedListener(this@NativeRtspPlayerActivity)
            setOnErrorListener(this@NativeRtspPlayerActivity)
            setDataSource("rtsp://192.168.8.73/cdb6e5a0-23af-40e8-8da8-54a21af9cba3/cdb6e5a0-23af-40e8-8da8-54a21af9cba3_vs1?token=cdb6e5a0-23af-40e8-8da8-54a21af9cba3^LVEBAMPZOTDGU|admin|1522055956266|0|0^50^26^26^1522315156^3394fa4fd8888fcca38c10bcf5fa74748b5b58a1&username=admin")
            prepareAsync() // 用异步prepare避免阻塞主线程
        }
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        mediaPlayer?.release()
        mediaPlayer = null
    }

    override fun onPrepared(mp: MediaPlayer) {
        mp.start()
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // 这里可以打印错误信息,比如what和extra的值,方便排查
        return true
    }
}

但要注意,原生MediaPlayer对RTSP的认证支持很弱,如果你的链接里的token需要特殊处理,原生可能搞不定,还是优先用ExoPlayer。

额外排查点

  • 先在电脑上用VLC播放器测试你的RTSP链接是否能正常播放,排除流本身的问题
  • 确认设备和RTSP服务器在同一个局域网(你的链接是192.168开头的局域网地址)
  • 如果是Android 10+,检查是否有后台限制导致网络连接被切断

内容的提问来源于stack exchange,提问作者nicolas asinovich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:01:58