Exoplayer: Multiple ExoPlayer instances using one SurfaceHolder

Created on 10 Feb 2016  路  2Comments  路  Source: google/ExoPlayer

Is it possible to create more than one instance of ExoPlayer and use the same SurfaceHolder? I have the use case where I need one player for streaming content, and another for streaming client side ads. Only one player is supposed to play/show at a time, and they are directly on top of each other. Is there any way I can do this with just a single SurfaceHolder? I'm pretty sure it's only the MediaCodec api complaining with this error:

E/MediaCodec: native_window_api_connect returned an error: Invalid argument (-22)
E/MediaCodec: configure failed with err 0xffffffea, resetting...

Followed by an ExoPlayer exception:

E/ExoPlayerImplInternal: Internal track renderer error.
    com.google.android.exoplayer.ExoPlaybackException: com.google.android.exoplayer.MediaCodecTrackRenderer$DecoderInitializationException: Decoder init failed: OMX.qcom.video.decoder.avc, MediaFormat(null, video/avc, -1, -1, 704, 396, -1, 1.0, -1, -1, null, -1, false, 1280, 720)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.notifyAndThrowDecoderInitError(MediaCodecTrackRenderer.java:388)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.maybeInitCodec(MediaCodecTrackRenderer.java:374)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.onInputFormatChanged(MediaCodecTrackRenderer.java:729)
    at com.google.android.exoplayer.MediaCodecVideoTrackRenderer.onInputFormatChanged(MediaCodecVideoTrackRenderer.java:334)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.readFormat(MediaCodecTrackRenderer.java:496)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.doSomeWork(MediaCodecTrackRenderer.java:479)
    at com.google.android.exoplayer.SampleSourceTrackRenderer.doSomeWork(SampleSourceTrackRenderer.java:129)
    at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:431)
    at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:213)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:135)
    at android.os.HandlerThread.run(HandlerThread.java:61)
    at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
    Caused by: com.google.android.exoplayer.MediaCodecTrackRenderer$DecoderInitializationException: Decoder init failed: OMX.qcom.video.decoder.avc, MediaFormat(null, video/avc, -1, -1, 704, 396, -1, 1.0, -1, -1, null, -1, false, 1280, 720)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.maybeInitCodec(MediaCodecTrackRenderer.java:374)聽
    at com.google.android.exoplayer.MediaCodecTrackRenderer.onInputFormatChanged(MediaCodecTrackRenderer.java:729)聽
    at com.google.android.exoplayer.MediaCodecVideoTrackRenderer.onInputFormatChanged(MediaCodecVideoTrackRenderer.java:334)聽
    at com.google.android.exoplayer.MediaCodecTrackRenderer.readFormat(MediaCodecTrackRenderer.java:496)聽
    at com.google.android.exoplayer.MediaCodecTrackRenderer.doSomeWork(MediaCodecTrackRenderer.java:479)聽
    at com.google.android.exoplayer.SampleSourceTrackRenderer.doSomeWork(SampleSourceTrackRenderer.java:129)聽
    at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:431)聽
    at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:213)聽
    at android.os.Handler.dispatchMessage(Handler.java:98)聽
    at android.os.Looper.loop(Looper.java:135)聽
    at android.os.HandlerThread.run(HandlerThread.java:61)聽
    at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)聽
    Caused by: android.media.MediaCodec$CodecException: Error 0xffffffea
    at android.media.MediaCodec.native_configure(Native Method)
    at android.media.MediaCodec.configure(MediaCodec.java:580)
    at com.google.android.exoplayer.MediaCodecVideoTrackRenderer.configureCodec(MediaCodecVideoTrackRenderer.java:328)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.maybeInitCodec(MediaCodecTrackRenderer.java:363)
    at com.google.android.exoplayer.MediaCodecTrackRenderer.onInputFormatChanged(MediaCodecTrackRenderer.java:729)聽
    at com.google.android.exoplayer.MediaCodecVideoTrackRenderer.onInputFormatChanged(MediaCodecVideoTrackRenderer.java:334)聽
    at com.google.android.exoplayer.MediaCodecTrackRenderer.readFormat(MediaCodecTrackRenderer.java:496)聽
    at com.google.android.exoplayer.MediaCodecTrackRenderer.doSomeWork(MediaCodecTrackRenderer.java:479)聽
    at com.google.android.exoplayer.SampleSourceTrackRenderer.doSomeWork(SampleSourceTrackRenderer.java:129)聽
    at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:431)聽
    at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:213)聽
    at android.os.Handler.dispatchMessage(Handler.java:98)聽
    at android.os.Looper.loop(Looper.java:135)聽
    at android.os.HandlerThread.run(HandlerThread.java:61)聽
    at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)

However, when I use two separate SurfaceHolder's, it doesn't complain. Has anyone had any similar issues? Or am I possibly doing something wrong?

Thanks.

question

Most helpful comment

ExoPlayer doesn't know anything about SurfaceHolder; it only knows about Surface directly.

I haven't tried, but it should be possible to have multiple ExoPlayer instances render to the same Surface, provided only one of them is doing so at any point in time. When you want to switch player from A to B, you'll need to clear the surface from A using ExoPlayer.blockingSendMessage and attach it to B using ExoPlayer.sendMessage. Note that the first call needs to be blocking so that you can be sure A really doesn't have access to the surface before you give it to B.

All 2 comments

ExoPlayer doesn't know anything about SurfaceHolder; it only knows about Surface directly.

I haven't tried, but it should be possible to have multiple ExoPlayer instances render to the same Surface, provided only one of them is doing so at any point in time. When you want to switch player from A to B, you'll need to clear the surface from A using ExoPlayer.blockingSendMessage and attach it to B using ExoPlayer.sendMessage. Note that the first call needs to be blocking so that you can be sure A really doesn't have access to the surface before you give it to B.

You're right, this was happening because when I switched players, I was using sendMessage instead of blockingSendMessage, so the surface was still in use when it was trying to make the switch.

Thanks!

Was this page helpful?
0 / 5 - 0 ratings