媒体播放器 prepare() 方法上的 IllegalStateException

IllegalStateException on mediaplayer prepare() method

我正在使用 SurfaceViewMediaPlayerRTSP 流式传输视频,而 MJPEG 两种协议都独立工作,即当我仅从 RTSPMJPEG over HTTP 只有。我遇到的问题是当我尝试从 MJPEG 协议切换到其他协议时 prepare() 方法抛出 IllegalStateException

对于 RTSP 流,我使用 MediaPlayer class,因为它默认支持 RTSP 流。对于 MJPEG,我有一个调用 HTTP url 和 returns JPEG 的 AsyncTask,我用它来设置 SurfaceViews SurfaceHolder Canvas。当我尝试解锁 SurfaceHolder Canvas

时,我认为问题出在某个地方

当我尝试将流从 MJPEG 更改为 RTSP 时的第一步:

MjpegThread.isRunning = false;
mediaPlayer.release();
mediaPlayer = null;
setMediaPlayer();

MjpegThread 是发出 HTTP 请求并在停止 AsyncTask 后更新 SurfaceHolderCanvas我调用的 doInBackground 方法结束

surfaceHolder.unlockCanvasAndPost(canvas);

该过程的最后一步是显示 RTSP 流,这是我的代码:

mediaPlayer.setDisplay(vidHolder);
mediaPlayer.setDataSource(OZOptions.RTSP_URL);
mediaPlayer.prepare(); // <- IllegalStateException HERE
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

上面的代码在我最初使用 RTSP 机器人时有效,但在我从 MJPEG 切换到 RTSP 时无效。

unlockCanvasAndPost 用于通过软件渲染到 Surface。 MediaPlayer 想要将帧直接发送到 Surface。由于 Android 的 Surface class 的限制,一旦您执行了软件渲染,您就无法对 Surface 执行任何其他操作。 (如果 Surface 上已经附加了其他东西,您也无法进行软件渲染。)

您没有在问题中显示 logcat 输出,但这是一个很常见的问题。 (这类似于人们询问在播放视频后擦除 SurfaceView Surface 的其他问题,例如 this one。)

您有两个选择:

  1. 使用多个 SurfaceView。将视频播放到一个,将 MJPEG 帧写入另一个,并使非活动的透明。使用 setZOrderMediaOverlay() 将一个放在另一个之上。

  2. 使用 SurfaceView 的两个部分。使用 invalidate()onDraw() 渲染您的 MJPEG,就像 custom View。这类似于 #1 但可能更有效,因为自定义视图可以硬件加速。完成 MJPEG 后,将视图清除为透明以显示表面内容。

您还可以使用单独的自定义视图,并使用 FrameLayout 将其与 SurfaceView 重叠。