1

Im using a SurfaceView and MediaPlayer to stream video from RTSP and MJPEG both protocols work independently that is when I stream from RTSP only or MJPEG over HTTP only. The problem Im having is when I try to switch from MJPEG protocol to the other thats when the prepare() method throws an IllegalStateException.

For RTSP streaming I use the MediaPlayer class since it supports RTSP streaming by default. For MJPEG I have an AsyncTask that calls an HTTP url and returns the JPEG which I use to set draw on the SurfaceViews SurfaceHolder Canvas. I think that the problem is somewhere when Im trying to unlock the SurfaceHolder Canvas

The first step when I try to change the stream from MJPEG to RTSP:

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

The MjpegThread is the AsyncTask that makes HTTP requests and updates the SurfaceHolders Canvas after stopping the AsyncTask at the end of the doInBackground method I call

surfaceHolder.unlockCanvasAndPost(canvas);

The last step in the process is displaying the RTSP stream heres my code:

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

The code above works when I initially use RTSP bot not when I switch from MJPEG to RTSP.

Arlind Hajredinaj
  • 8,380
  • 3
  • 30
  • 45

1 Answers1

1

unlockCanvasAndPost is used for rendering to a Surface with software. MediaPlayer wants to send frames directly to the Surface. Due to a limitation of Android's Surface class, once you have performed software rendering you cannot do anything else with the Surface. (You also can't do software rendering if something else is already attached to the Surface.)

You didn't show logcat output in your question, but this is a pretty common problem. (This is similar to other questions where people asked about erasing a SurfaceView Surface after playing video, e.g. this one.)

You have a couple of options:

  1. Use more than one SurfaceView. Play video into one, write MJPEG frames into the other, and make the inactive one transparent. Use setZOrderMediaOverlay() to position one over the other.

  2. Use both parts of the SurfaceView. Render your MJPEG using invalidate() and onDraw(), like a custom View. This is similar to #1 but probably more efficient, as custom Views can be hardware-accelerated. When you're done with MJPEG you clear the View to transparent to show the Surface contents.

You can also use a separate custom View and overlap it with the SurfaceView using a FrameLayout.

Community
  • 1
  • 1
fadden
  • 51,356
  • 5
  • 116
  • 166
  • Great you gave me more in detail on how surfaceview works. But why is it that sometimes when the Thread stops before I try to switch to mediaplayer then I change it to mediaplayer it works. Im just sure that for some reason the surface view isnt being properly unlocked In my code when switching from My thread and MediaPlayer. – Arlind Hajredinaj Oct 03 '15 at 07:33