ExoPlayer icon indicating copy to clipboard operation
ExoPlayer copied to clipboard

MediaCodecVideoRenderer error

Open Turalllb opened this issue 4 years ago • 5 comments

Hello! I have an android tv device named yu43cv9632. I tried adding it to exceptions but it didn't help.

private static boolean evaluateDeviceNeedsSetOutputSurfaceWorkaround() {
    if (Util.SDK_INT <= 28) {
      // Workaround for MiTV and MiBox devices which have been observed broken up to API 28.
      // https://github.com/google/ExoPlayer/issues/5169,
      // https://github.com/google/ExoPlayer/issues/6899.
      // https://github.com/google/ExoPlayer/issues/8014.
      // https://github.com/google/ExoPlayer/issues/8329.
      switch (Util.DEVICE) {
        case "dangal":
        case "dangalUHD":
        case "dangalFHD":
        case "magnolia":
        case "machuca":
        case "once":
        case "oneday":
        case "YU43CV9632.HV430QUBF11":
          return true;
        default:
          break; // Do nothing.
      }
    }

I have a ViewGroup that the PlayerView is placed in. ExoPlayer.prepare () starts exoPlayer.setMediaSource (mediaSource).

Then he learns that he should show ads in the ViewGroup, add a View on top of the PlayerView that allows you to play ads, pause exoPlayer. And then some devices break. I want to understand how I should properly handle the situation. Is it correct to do release () and how to resume playback after it?

As you can see, the logic is that there is a container in which the PlayerView is placed and a link to this container is passed to the advertising SDK, which adds its PlayerView to this container. No OnPause is called on the activity or fragment. And it works great, except for some devices.

I looked at many answers on similar questions and often talk about problems with the decoder, but my video plays fine, if I do not try to add another instance of PlayerView from the advertising sdk with which another instance of the player works on top.

ExoPlayerImplInternal: Playback error
      com.google.android.exoplayer2.ExoPlaybackException: MediaCodecVideoRenderer error, index=0, format=Format(f4-v1-x3, null, null, video/avc, avc1.640032, 3500427, null, [1920, 1080, 25.0], [-1, -1]), format_supported=YES
        at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:555)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:193)
        at android.os.HandlerThread.run(HandlerThread.java:65)
     Caused by: com.google.android.exoplayer2.video.MediaCodecVideoDecoderException: Decoder failed: OMX.MS.AVC.Decoder
        at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.createDecoderException(MediaCodecVideoRenderer.java:1403)
        at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:869)
        at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:945)
        at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:478)
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.os.HandlerThread.run(HandlerThread.java:65) 
     Caused by: java.lang.IllegalStateException
        at android.media.MediaCodec.native_dequeueInputBuffer(Native Method)
        at android.media.MediaCodec.dequeueInputBuffer(MediaCodec.java:2635)
        at com.google.android.exoplayer2.mediacodec.SynchronousMediaCodecAdapter.dequeueInputBufferIndex(SynchronousMediaCodecAdapter.java:93)
        at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:1214)
        at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:850)
        at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:945) 
        at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:478) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.os.HandlerThread.run(HandlerThread.java:65) 
2021-05-26 14:29:15.863 27352-28559/com.ctcmediagroup.videomore E/ExoPlayerImplInternal: Disable failed.
      java.lang.IllegalStateException
        at android.media.MediaCodec.native_flush(Native Method)
        at android.media.MediaCodec.flush(MediaCodec.java:2131)
        at com.google.android.exoplayer2.mediacodec.SynchronousMediaCodecAdapter.flush(SynchronousMediaCodecAdapter.java:160)
        at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.flushCodec(MediaCodecRenderer.java:917)
        at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.flushOrReleaseCodec(MediaCodecRenderer.java:910)
        at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onDisabled(MediaCodecRenderer.java:765)
        at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onDisabled(MediaCodecVideoRenderer.java:483)
        at com.google.android.exoplayer2.BaseRenderer.disable(BaseRenderer.java:176)
        at com.google.android.exoplayer2.ExoPlayerImplInternal.disableRenderer(ExoPlayerImplInternal.java:1609)
        at com.google.android.exoplayer2.ExoPlayerImplInternal.resetInternal(ExoPlayerImplInternal.java:1351)
        at com.google.android.exoplayer2.ExoPlayerImplInternal.stopInternal(ExoPlayerImplInternal.java:1314)
        at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:571)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:193)
        at android.os.HandlerThread.run(HandlerThread.java:65)

Turalllb avatar May 26 '21 13:05 Turalllb

found this in the documentation: "It’s important to release the player when it’s no longer needed, so as to free up limited resources such as video decoders for use by other applications. This can be done by calling ExoPlayer.release."

I conducted an experiment and realized that the first player breaks when the second starts broadcasting, the first player for some reason starts executing mediaCodecFlush and the native code breaks. I don't understand what Flush means, please explain.

The experiment showed that if I wait until the advertisement ends and call prepare, then my player will come to life. I don't want to release it, because restarting it takes time. What do you think about my decision and what did you know about system decors? Thank you

Turalllb avatar May 27 '21 11:05 Turalllb

but my video plays fine, if I do not try to add another instance of PlayerView from the advertising sdk with which another instance of the player works on top.

I think the problem is that some devices do not let you instantiate multiple decoder instances of the same type. Like your experiment confirms, playing a second video in parallel that requires the same decoder instance makes the app break.

I don't want to release it, because restarting it takes time. What do you think about my decision and what did you know about system decors?

Looks like you need to do that to avoid a crash on some devices? While I appreciate that you probably do not want this it is required to avoid the crash in the setup with multiple players.

What ad SDK are you using? If you are using IMA then you may want to user the IMA extension for playing adds. It plays with a single player and avoids rebufferings when transitioning from content to add and back: https://github.com/google/ExoPlayer/tree/release-v2/extensions/ima

marcbaechinger avatar Jun 01 '21 11:06 marcbaechinger

@marcbaechinger,

What ad SDK are you using? If you are using IMA then you may want to user the IMA extension for playing adds. It plays with a single player and avoids rebufferings when transitioning from content to add and back: https://github.com/google/ExoPlayer/tree/release-v2/extensions/ima

We use a self-written adsdk, not a third-party solution, and yes, it's bad that this is a separate player, but I know why this decision was made.

Looks like to need to do that to avoid a crash on some devices? While I appreciate that you probably do not want this it is required to avoid the crash in the setup with multiple players.

Yes, I do not want the release of the player and I just catch an exception, wait for the ad to end and do prepare () on a new one. As a result, I am not a release player. I guessed before that after I realized that on some devices there is one copy of the video decoder.

Turalllb avatar Jun 01 '21 12:06 Turalllb

Maybe you can try to call setEnableDecoderFallback(true) while creating the ExoPlayer object, it will try to find the available media codec from all the available codec list. If you don't call setEnableDecoderFallback(true), the enableDecoderFallback is false, it will only use the first availabel codec, and it is fail to init in some devices.

val exoPlayer = ExoPlayer.Builder(this)
            .setRenderersFactory(DefaultRenderersFactory(this).setEnableDecoderFallback(true)).build()
// source code
private void maybeInitCodecWithFallback(...) {

  if (availableCodecInfos == null) {
    try {
      List<MediaCodecInfo> allAvailableCodecInfos = getAvailableCodecInfos(mediaCryptoRequiresSecureDecoder);
      availableCodecInfos = new ArrayDeque<>();
      if (enableDecoderFallback) {
        availableCodecInfos.addAll(allAvailableCodecInfos);
      } else if (!allAvailableCodecInfos.isEmpty()) {
        availableCodecInfos.add(allAvailableCodecInfos.get(0));
      }
      ...
  }

  ...

  while (codec == null) {
    MediaCodecInfo codecInfo = availableCodecInfos.peekFirst();
    if (!shouldInitCodec(codecInfo)) {
      return;
    }
    try {
      initCodec(codecInfo, crypto);
    } catch (Exception e) {
      ...
    }
  }

  availableCodecInfos = null;
}

Ygowell avatar Nov 11 '22 09:11 Ygowell

not work, that not using software decoder

sudhanshugairola avatar Nov 07 '23 12:11 sudhanshugairola