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
相关产品推荐
相关产品推荐

