I'm trying to write a simple TvInputService for Android TV using ExoPlayer. On the emulator everything works fine, but on Sony TV (KDL-43WF804) I get IllegalStateException
from video codec after a few seconds of video playing. What am I doing wrong?
Logs:
D/MtkACodecPlugin: MtkACodecPlugin createAPlugin
D/MtkACodecPlugin: OMX.MTK.VIDEO.DECODER.AVC needRmClient (673)
D/MtkACodecPlugin: OMX.MTK.VIDEO.DECODER.AVC mNeedVdpImgrz (679)
I/OMXClient: IOmx service obtained
D/SurfaceUtils: connecting to surface 0x8e25d808, reason connectToSurface
I/MediaCodec: [OMX.MTK.VIDEO.DECODER.AVC] setting surface generation to 21334017
D/SurfaceUtils: disconnecting from surface 0x8e25d808, reason connectToSurface(reconnect)
D/SurfaceUtils: connecting to surface 0x8e25d808, reason connectToSurface(reconnect)
D/MtkMediaCodecPlugin: [OMX.MTK.VIDEO.DECODER.AVC] set mOutputPath = 0 L(150)
E/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] setPortMode on output to DynamicANWBuffer failed w/ err -1010
I/ACodec: codec does not support config priority (err -1010)
D/MtkACodecPlugin: add usage GRALLOC_USAGE_PATH_VDP0
D/SurfaceUtils: disconnecting from surface 0x8e25d808, reason setNativeWindowSizeFormatAndUsage
D/SurfaceUtils: connecting to surface 0x8e25d808, reason setNativeWindowSizeFormatAndUsage
D/SurfaceUtils: set up nativeWindow 0x8e25d808 for 1920x1088, color 0x7f000103, rotation 0, usage 0x30002900
D/MtkACodecPlugin: MtkACodecPlugin createAPlugin
I/OMXClient: IOmx service obtained
D/MtkMediaCodecPlugin: No surfaceTextureClient, [OMX.google.aac.decoder] set mOutputPath = 1024 L(159)
I/ACodec: codec does not support config priority (err -2147483648)
I/ACodec: codec does not support config operating rate (err -2147483648)
W/v.rudnev.tvlak: Accessing hidden method Landroid/media/AudioTrack$Builder;->setOffloadedPlayback(Z)Landroid/media/AudioTrack$Builder; (dark greylist, linking)
W/v.rudnev.tvlak: Accessing hidden method Landroid/media/AudioTrack$Builder;->setOffloadedPlayback(Z)Landroid/media/AudioTrack$Builder; (dark greylist, linking)
E/Surface: queueBuffer: error queuing buffer to SurfaceTexture, -19
E/ACodec: queueBuffer failed in onOutputBufferDrained: -19
E/ACodec: signalError(omxError 0x80001001, internalError -19)
E/MediaCodec: Codec reported err 0xffffffed, actionCode 0, while in state 6
D/SurfaceUtils: disconnecting from surface 0x8e25d808, reason disconnectFromSurface
E/MediaCodecVideoRenderer: Video codec error
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:115)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:1139)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:780)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:982)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:486)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
E/ExoPlayerImplInternal: Playback error
com.google.android.exoplayer2.ExoPlaybackException: MediaCodecVideoRenderer error, index=0, format=Format(0, null, null, video/avc, avc1.4D4020, 5049176, null, [1920, 1080, 25.0], [-1, -1]), format_supported=YES
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:562)
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.MTK.VIDEO.DECODER.AVC
at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.createDecoderException(MediaCodecVideoRenderer.java:1470)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:799)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:982)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:486)
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:115)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:1139)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:780)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:982)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:486)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
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:188)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.flushCodec(MediaCodecRenderer.java:850)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.flushOrReleaseCodec(MediaCodecRenderer.java:843)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onDisabled(MediaCodecRenderer.java:696)
at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onDisabled(MediaCodecVideoRenderer.java:529)
at com.google.android.exoplayer2.BaseRenderer.disable(BaseRenderer.java:178)
at com.google.android.exoplayer2.ExoPlayerImplInternal.disableRenderer(ExoPlayerImplInternal.java:1642)
at com.google.android.exoplayer2.ExoPlayerImplInternal.resetInternal(ExoPlayerImplInternal.java:1382)
at com.google.android.exoplayer2.ExoPlayerImplInternal.stopInternal(ExoPlayerImplInternal.java:1345)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:578)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6d00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 22 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6c00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 21 to native window
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6700
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 16 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6600
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 15 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6500
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 14 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6400
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 13 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6300
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 12 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6200
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 11 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6100
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 10 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b2a6000
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 9 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b290f00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 8 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b290e00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 7 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b290d00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 6 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b290c00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 5 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b290b00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 4 to native window
D/gralloc: unregister FBM buffer
E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8b290a00
W/ACodec: [OMX.MTK.VIDEO.DECODER.AVC] can not return buffer 3 to native window
D/gralloc: unregister FBM buffer
D/MediaCodec: mState = 0, mHaveKick = 0, L(703)
D/MtkACodecPlugin: MtkACodecPlugin destoryAPlugin
D/gralloc: unregister FBM buffer
I/chatty: uid=10178(dev.rudnev.tvlake) identical 3 lines
D/gralloc: unregister FBM buffer
I/ExoPlayerImpl: Release b6e9764 [ExoPlayerLib/2.16.1] [BRAVIA_ATV3_2K, BRAVIA 2K GB ATV3, Sony, 28] [goog.exo.core, goog.exo.decoder, goog.exo.exoplayer, goog.exo.hls, goog.exo.datasource, goog.exo.extractor]
D/MediaCodec: mState = 0, mHaveKick = 0, L(703)
D/MtkACodecPlugin: MtkACodecPlugin destoryAPlugin
Code:
public class IptvInputService extends TvInputService {
private static final String TAG = "IptvInputService";
@Override
public Session onCreateSession(String inputId) {
return new Session(this);
}
public static class Session extends TvInputService.Session {
private final Context mContext;
private final ExoPlayer mPlayer;
public Session(Context context) {
super(context);
mContext = context;
mPlayer = new ExoPlayer.Builder(context).build();
mPlayer.addListener(new PlayerListener(this));
}
@Override
public void onRelease() {
mPlayer.release();
}
@Override
public boolean onSetSurface(@Nullable Surface surface) {
mPlayer.setVideoSurface(surface);
return true;
}
@Override
public void onSetStreamVolume(float volume) {
mPlayer.setVolume(volume);
}
@Override
public boolean onTune(Uri uri) {
try {
notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
String streamUrl = "https://okkotv-live.cdnvideo.ru/channel/Viasat_Explore_HD.m3u8";
mPlayer.setMediaItem(MediaItem.fromUri(streamUrl));
mPlayer.prepare();
mPlayer.play();
return true;
} catch (Throwable ex) {
notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
Log.e(TAG, "Unable to play stream", ex);
}
return false;
}
@Override
public void onSetCaptionEnabled(boolean b) {
}
}
private static class PlayerListener implements Player.Listener {
private final Session mSession;
public PlayerListener(Session session) {
mSession = session;
}
@Override
public void onRenderedFirstFrame() {
mSession.notifyVideoAvailable();
}
}
}
I figured it out. In my case, this exception is caused by the crash of the system tv application, which owns the Surface
object. The codec goes into the Error
state when the Surface
becomes invalid and at the same moment the ExoPlayer tries to work with the codec's buffers, not knowing that the codec has changed the Executing
state to Error
.
And the reason for the crash of the system tv app was the following exception:
02-10 21:31:39.606 7036 7218 E AndroidRuntime: FATAL EXCEPTION: TvCardUpdater-0
02-10 21:31:39.606 7036 7218 E AndroidRuntime: Process: com.sony.dtv.tvx, PID: 7036
02-10 21:31:39.606 7036 7218 E AndroidRuntime: java.lang.RuntimeException: An error occurred while executing doInBackground()
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at android.os.AsyncTask$3.done(AsyncTask.java:354)
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at java.util.concurrent.FutureTask.run(FutureTask.java:271)
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764)
02-10 21:31:39.606 7036 7218 E AndroidRuntime: Caused by: java.lang.ClassCastException: android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
02-10 21:31:39.606 7036 7218 E AndroidRuntime: at com.sony.dtv.tvx.tvplayer.function.actionmenu.tvcardstate.AppLinkItemCreator.makeStateOfAppLink(AppLinkItemCreator.java:59)
The fix is simple: you need to specify a bitmap for android:banner
in AndroidManifest.xml
instead of a vector image.
Because Sony has its own app instead of Live Channels, the problem only occurred on the physical device and not on the emulator where Live Channels is installed.