Ver Fonte

加入ijkplayer支持rtmp播放

詹子聪 há 5 anos atrás
pai
commit
1d6f31a623

+ 6 - 1
app/build.gradle

@@ -118,9 +118,14 @@ dependencies {
     // 文字对齐
     //implementation 'me.codeboy.android:align-text-view:2.3.2'
 
-    //饺子视频播放器
+    // 饺子视频播放器
     //implementation (name: 'jiaozivideoplayer-7.4.2', ext: 'aar')
     implementation 'cn.jzvd:jiaozivideoplayer:7.4.2'
+    // 播放引擎
+    compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
+    compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
+    compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
+    compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
 
     // 右划销毁Activity,另外:sockeqwe/SwipeBack也可以参考
     //implementation 'com.aitangba:swipeback:1.0.3'

+ 7 - 0
app/proguard-rules.pro

@@ -19,3 +19,10 @@
 # If you keep the line number information, uncomment this to
 # hide the original source file name.
 #-renamesourcefileattribute SourceFile
+
+-keep public class cn.jzvd.JZMediaSystem {*; }
+-keep class com.miekir.eden.ui.home.video.** {*; }
+
+-keep class tv.danmaku.ijk.media.player.** {*; }
+-dontwarn tv.danmaku.ijk.media.player.*
+-keep interface tv.danmaku.ijk.media.player.** { *; }

+ 1 - 1
app/src/main/java/com/miekir/eden/net/RetrofitHelper.java

@@ -64,7 +64,7 @@ public class RetrofitHelper {
                 builder.addHeader("token", token)
                         .addHeader("email", email);
             }
-
+            // todo java.net.UnknownHostException: Unable to resolve host "app.icsmabc.cyou": No address associated with hostname
             return chain.proceed(builder.build());
         }
     };

+ 3 - 1
app/src/main/java/com/miekir/eden/ui/home/video/KwyVideoActivity.java

@@ -15,6 +15,7 @@ import com.miekir.eden.net.RetrofitHelper;
 import com.miekir.eden.tool.StringTool;
 import com.miekir.eden.tool.SystemTool;
 import com.miekir.eden.tool.ui.NavigationTool;
+import com.miekir.eden.ui.home.video.media.JZMediaIjk;
 
 import cn.jzvd.JZDataSource;
 import cn.jzvd.Jzvd;
@@ -68,7 +69,8 @@ public class KwyVideoActivity extends Activity {
         });
         mVideoUrl = EdenManager.getInstance().getVideoUrl();
         JzvdStd.setCurrentJzvd(VideoPlayer.CURRENT_JZVD);
-        js_video.setUp(EdenManager.getInstance().getVideoUrl(), mTitle);
+        //js_video.setUp(EdenManager.getInstance().getVideoUrl(), mTitle);
+        js_video.setUp("rtmp://58.200.131.2:1935/livetv/gdtv", mTitle, Jzvd.SCREEN_FULLSCREEN, JZMediaIjk.class);
         js_video.startVideo();
         refresh_video = findViewById(R.id.refresh_video);
         refresh_video.setHeaderView(new MaterialHeaderView(this));

+ 341 - 0
app/src/main/java/com/miekir/eden/ui/home/video/media/JZMediaExo.java

@@ -0,0 +1,341 @@
+package com.miekir.eden.ui.home.video.media;
+
+//import android.content.Context;
+//import android.graphics.SurfaceTexture;
+//import android.net.Uri;
+//import android.os.Handler;
+//import android.os.HandlerThread;
+//import android.util.Log;
+//import android.view.Surface;
+//
+//import com.google.android.exoplayer2.C;
+//import com.google.android.exoplayer2.DefaultLoadControl;
+//import com.google.android.exoplayer2.DefaultRenderersFactory;
+//import com.google.android.exoplayer2.ExoPlaybackException;
+//import com.google.android.exoplayer2.LoadControl;
+//import com.google.android.exoplayer2.PlaybackParameters;
+//import com.google.android.exoplayer2.Player;
+//import com.google.android.exoplayer2.RenderersFactory;
+//import com.google.android.exoplayer2.SimpleExoPlayer;
+//import com.google.android.exoplayer2.Timeline;
+//import com.google.android.exoplayer2.source.MediaSource;
+//import com.google.android.exoplayer2.source.ProgressiveMediaSource;
+//import com.google.android.exoplayer2.source.TrackGroupArray;
+//import com.google.android.exoplayer2.source.hls.HlsMediaSource;
+//import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
+//import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
+//import com.google.android.exoplayer2.trackselection.TrackSelection;
+//import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
+//import com.google.android.exoplayer2.trackselection.TrackSelector;
+//import com.google.android.exoplayer2.upstream.BandwidthMeter;
+//import com.google.android.exoplayer2.upstream.DataSource;
+//import com.google.android.exoplayer2.upstream.DefaultAllocator;
+//import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
+//import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
+//import com.google.android.exoplayer2.util.Util;
+//import com.google.android.exoplayer2.video.VideoListener;
+//
+//import cn.jzvd.JZMediaInterface;
+//import cn.jzvd.Jzvd;
+//import cn.jzvd.demo.R;
+//
+///**
+// * Created by MinhDV on 5/3/18.
+// */
+//public class JZMediaExo extends JZMediaInterface implements Player.EventListener, VideoListener {
+//    private SimpleExoPlayer simpleExoPlayer;
+//    private Runnable callback;
+//    private String TAG = "JZMediaExo";
+//    private long previousSeek = 0;
+//
+//    public JZMediaExo(Jzvd jzvd) {
+//        super(jzvd);
+//    }
+//
+//    @Override
+//    public void start() {
+//        simpleExoPlayer.setPlayWhenReady(true);
+//    }
+//
+//    @Override
+//    public void prepare() {
+//        Log.e(TAG, "prepare");
+//        Context context = jzvd.getContext();
+//
+//        release();
+//        mMediaHandlerThread = new HandlerThread("JZVD");
+//        mMediaHandlerThread.start();
+//        mMediaHandler = new Handler(context.getMainLooper());//主线程还是非主线程,就在这里
+//        handler = new Handler();
+//        mMediaHandler.post(() -> {
+//
+//            TrackSelection.Factory videoTrackSelectionFactory =
+//                    new AdaptiveTrackSelection.Factory();
+//            TrackSelector trackSelector =
+//                    new DefaultTrackSelector(context,videoTrackSelectionFactory);
+//
+//            LoadControl loadControl = new DefaultLoadControl.Builder()
+//                    .setAllocator(new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE))
+//                    .setBufferDurationsMs( 360000, 600000, 1000, 5000)
+//                    .setPrioritizeTimeOverSizeThresholds(false)
+//                    .setTargetBufferBytes(C.LENGTH_UNSET)
+//                    .createDefaultLoadControl();
+//
+//
+//            BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
+//            // 2. Create the player
+//
+//            RenderersFactory renderersFactory = new DefaultRenderersFactory(context);
+//            simpleExoPlayer = new SimpleExoPlayer.Builder(context, renderersFactory)
+//                    .setTrackSelector(trackSelector)
+//                    .setLoadControl(loadControl)
+//                    .setBandwidthMeter(bandwidthMeter)
+//                    .build() ;
+//            // Produces DataSource instances through which media data is loaded.
+//            DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
+//                    Util.getUserAgent(context, context.getResources().getString(R.string.app_name)));
+//
+//            String currUrl = jzvd.jzDataSource.getCurrentUrl().toString();
+//            MediaSource videoSource;
+//            if (currUrl.contains(".m3u8")) {
+//                videoSource = new HlsMediaSource.Factory(dataSourceFactory)
+//                        .createMediaSource(Uri.parse(currUrl));
+//                //addEventListener 这里只有两个参数都要传入值才可以成功设置
+//                // 否者会被断言 Assertions.checkArgument(handler != null && eventListener != null);
+//                // 并且报错  IllegalArgumentException()  所以不需要添加监听器时 注释掉
+//                //      videoSource .addEventListener( handler, null);
+//            } else {
+//                videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
+//                        .createMediaSource(Uri.parse(currUrl));
+//            }
+//            simpleExoPlayer.addVideoListener(this);
+//
+//            Log.e(TAG, "URL Link = " + currUrl);
+//
+//            simpleExoPlayer.addListener(this);
+//            Boolean isLoop = jzvd.jzDataSource.looping;
+//            if (isLoop) {
+//                simpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
+//            } else {
+//                simpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_OFF);
+//            }
+//            simpleExoPlayer.prepare(videoSource);
+//            simpleExoPlayer.setPlayWhenReady(true);
+//            callback = new onBufferingUpdate();
+//
+//            if (jzvd.textureView != null) {
+//                SurfaceTexture surfaceTexture = jzvd.textureView.getSurfaceTexture();
+//                if (surfaceTexture != null) {
+//                    simpleExoPlayer.setVideoSurface(new Surface(surfaceTexture));
+//                }
+//            }
+//        });
+//
+//    }
+//
+//    @Override
+//    public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
+//        handler.post(() -> jzvd.onVideoSizeChanged(width, height));
+//    }
+//
+//    @Override
+//    public void onRenderedFirstFrame() {
+//        Log.e(TAG, "onRenderedFirstFrame");
+//    }
+//
+//    @Override
+//    public void pause() {
+//        simpleExoPlayer.setPlayWhenReady(false);
+//    }
+//
+//    @Override
+//    public boolean isPlaying() {
+//        return simpleExoPlayer.getPlayWhenReady();
+//    }
+//
+//    @Override
+//    public void seekTo(long time) {
+//        if (simpleExoPlayer == null) {
+//            return;
+//        }
+//        if (time != previousSeek) {
+//            if (time >= simpleExoPlayer.getBufferedPosition()) {
+//                jzvd.onStatePreparingPlaying();
+//            }
+//            simpleExoPlayer.seekTo(time);
+//            previousSeek = time;
+//            jzvd.seekToInAdvance = time;
+//
+//        }
+//    }
+//
+//    @Override
+//    public void release() {
+//        if (mMediaHandler != null && mMediaHandlerThread != null && simpleExoPlayer != null) {//不知道有没有妖孽
+//            HandlerThread tmpHandlerThread = mMediaHandlerThread;
+//            SimpleExoPlayer tmpMediaPlayer = simpleExoPlayer;
+//            JZMediaInterface.SAVED_SURFACE = null;
+//
+//            mMediaHandler.post(() -> {
+//                tmpMediaPlayer.release();//release就不能放到主线程里,界面会卡顿
+//                tmpHandlerThread.quit();
+//            });
+//            simpleExoPlayer = null;
+//        }
+//    }
+//
+//    @Override
+//    public long getCurrentPosition() {
+//        if (simpleExoPlayer != null)
+//            return simpleExoPlayer.getCurrentPosition();
+//        else return 0;
+//    }
+//
+//    @Override
+//    public long getDuration() {
+//        if (simpleExoPlayer != null)
+//            return simpleExoPlayer.getDuration();
+//        else return 0;
+//    }
+//
+//    @Override
+//    public void setVolume(float leftVolume, float rightVolume) {
+//        simpleExoPlayer.setVolume(leftVolume);
+//        simpleExoPlayer.setVolume(rightVolume);
+//    }
+//
+//    @Override
+//    public void setSpeed(float speed) {
+//        PlaybackParameters playbackParameters = new PlaybackParameters(speed, 1.0F);
+//        simpleExoPlayer.setPlaybackParameters(playbackParameters);
+//    }
+//
+//    @Override
+//    public void onTimelineChanged(final Timeline timeline, Object manifest, final int reason) {
+//        Log.e(TAG, "onTimelineChanged");
+////        JZMediaPlayer.instance().mainThreadHandler.post(() -> {
+////                if (reason == 0) {
+////
+////                    JzvdMgr.getCurrentJzvd().onInfo(reason, timeline.getPeriodCount());
+////                }
+////        });
+//    }
+//
+//    @Override
+//    public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
+//
+//    }
+//
+//    @Override
+//    public void onLoadingChanged(boolean isLoading) {
+//        Log.e(TAG, "onLoadingChanged");
+//    }
+//
+//    @Override
+//    public void onPlayerStateChanged(final boolean playWhenReady, final int playbackState) {
+//        Log.e(TAG, "onPlayerStateChanged" + playbackState + "/ready=" + String.valueOf(playWhenReady));
+//        handler.post(() -> {
+//            switch (playbackState) {
+//                case Player.STATE_IDLE: {
+//                }
+//                break;
+//                case Player.STATE_BUFFERING: {
+//                    jzvd.onStatePreparingPlaying();
+//                    handler.post(callback);
+//                }
+//                break;
+//                case Player.STATE_READY: {
+//                    if (playWhenReady) {
+//                        jzvd.onStatePlaying();
+//                    } else {
+//                    }
+//                }
+//                break;
+//                case Player.STATE_ENDED: {
+//                    jzvd.onCompletion();
+//                }
+//                break;
+//            }
+//        });
+//    }
+//
+//    @Override
+//    public void onRepeatModeChanged(int repeatMode) {
+//
+//    }
+//
+//    @Override
+//    public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
+//
+//    }
+//
+//    @Override
+//    public void onPlayerError(ExoPlaybackException error) {
+//        Log.e(TAG, "onPlayerError" + error.toString());
+//        handler.post(() -> jzvd.onError(1000, 1000));
+//    }
+//
+//    @Override
+//    public void onPositionDiscontinuity(int reason) {
+//
+//    }
+//
+//    @Override
+//    public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
+//
+//    }
+//
+//    @Override
+//    public void onSeekProcessed() {
+//        handler.post(() -> jzvd.onSeekComplete());
+//    }
+//
+//    @Override
+//    public void setSurface(Surface surface) {
+//        if (simpleExoPlayer != null) {
+//            simpleExoPlayer.setVideoSurface(surface);
+//        } else {
+//            Log.e("AGVideo", "simpleExoPlayer为空");
+//        }
+//    }
+//
+//    @Override
+//    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+//        if (SAVED_SURFACE == null) {
+//            SAVED_SURFACE = surface;
+//            prepare();
+//        } else {
+//            jzvd.textureView.setSurfaceTexture(SAVED_SURFACE);
+//        }
+//    }
+//
+//    @Override
+//    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+//
+//    }
+//
+//    @Override
+//    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+//        return false;
+//    }
+//
+//    @Override
+//    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+//
+//    }
+//
+//    private class onBufferingUpdate implements Runnable {
+//        @Override
+//        public void run() {
+//            if (simpleExoPlayer != null) {
+//                final int percent = simpleExoPlayer.getBufferedPercentage();
+//                handler.post(() -> jzvd.setBufferProgress(percent));
+//                if (percent < 100) {
+//                    handler.postDelayed(callback, 300);
+//                } else {
+//                    handler.removeCallbacks(callback);
+//                }
+//            }
+//        }
+//    }
+//}

+ 226 - 0
app/src/main/java/com/miekir/eden/ui/home/video/media/JZMediaIjk.java

@@ -0,0 +1,226 @@
+package com.miekir.eden.ui.home.video.media;
+
+import android.graphics.SurfaceTexture;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.view.Surface;
+
+import java.io.IOException;
+
+import cn.jzvd.JZMediaInterface;
+import cn.jzvd.Jzvd;
+import tv.danmaku.ijk.media.player.IMediaPlayer;
+import tv.danmaku.ijk.media.player.IjkMediaPlayer;
+import tv.danmaku.ijk.media.player.IjkTimedText;
+
+/**
+ * Created by Nathen on 2017/11/18.
+ * ijk兼容SO库:https://github.com/NamHofstadter/IjkPlayerSos
+ * ijk默认不支持https协议,需要的请自行下载so库
+ */
+
+public class JZMediaIjk extends JZMediaInterface implements IMediaPlayer.OnPreparedListener, IMediaPlayer.OnVideoSizeChangedListener, IMediaPlayer.OnCompletionListener, IMediaPlayer.OnErrorListener, IMediaPlayer.OnInfoListener, IMediaPlayer.OnBufferingUpdateListener, IMediaPlayer.OnSeekCompleteListener, IMediaPlayer.OnTimedTextListener {
+    IjkMediaPlayer ijkMediaPlayer;
+
+    public JZMediaIjk(Jzvd jzvd) {
+        super(jzvd);
+    }
+
+    @Override
+    public void start() {
+        if (ijkMediaPlayer != null) ijkMediaPlayer.start();
+    }
+
+    @Override
+    public void prepare() {
+
+        release();
+        mMediaHandlerThread = new HandlerThread("JZVD");
+        mMediaHandlerThread.start();
+        mMediaHandler = new Handler(mMediaHandlerThread.getLooper());//主线程还是非主线程,就在这里
+        handler = new Handler();
+
+        mMediaHandler.post(() -> {
+
+            ijkMediaPlayer = new IjkMediaPlayer();
+
+            ijkMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            ////1为硬解 0为软解
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
+            //使用opensles把文件从java层拷贝到native层
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
+            //视频格式
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
+            //跳帧处理(-1~120)。CPU处理慢时,进行跳帧处理,保证音视频同步
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
+            //0为一进入就播放,1为进入时不播放
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
+            ////域名检测
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
+            //设置是否开启环路过滤: 0开启,画面质量高,解码开销大,48关闭,画面质量差点,解码开销小
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
+            //最大缓冲大小,单位kb
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 1024 * 1024);
+            //某些视频在SeekTo的时候,会跳回到拖动前的位置,这是因为视频的关键帧的问题,通俗一点就是FFMPEG不兼容,视频压缩过于厉害,seek只支持关键帧,出现这个情况就是原始的视频文件中i 帧比较少
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
+            //是否重连
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", 1);
+            //http重定向https
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1);
+            //设置seekTo能够快速seek到指定位置并播放
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "fastseek");
+            //播放前的探测Size,默认是1M, 改小一点会出画面更快
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 1024 * 10);
+            //1变速变调状态 0变速不变调状态
+            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", 1);
+
+            ijkMediaPlayer.setOnPreparedListener(JZMediaIjk.this);
+            ijkMediaPlayer.setOnVideoSizeChangedListener(JZMediaIjk.this);
+            ijkMediaPlayer.setOnCompletionListener(JZMediaIjk.this);
+            ijkMediaPlayer.setOnErrorListener(JZMediaIjk.this);
+            ijkMediaPlayer.setOnInfoListener(JZMediaIjk.this);
+            ijkMediaPlayer.setOnBufferingUpdateListener(JZMediaIjk.this);
+            ijkMediaPlayer.setOnSeekCompleteListener(JZMediaIjk.this);
+            ijkMediaPlayer.setOnTimedTextListener(JZMediaIjk.this);
+
+            try {
+                ijkMediaPlayer.setDataSource(jzvd.jzDataSource.getCurrentUrl().toString());
+                ijkMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+                ijkMediaPlayer.setScreenOnWhilePlaying(true);
+                ijkMediaPlayer.prepareAsync();
+
+                ijkMediaPlayer.setSurface(new Surface(jzvd.textureView.getSurfaceTexture()));
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        });
+
+    }
+
+    @Override
+    public void pause() {
+        ijkMediaPlayer.pause();
+    }
+
+    @Override
+    public boolean isPlaying() {
+        return ijkMediaPlayer.isPlaying();
+    }
+
+    @Override
+    public void seekTo(long time) {
+        ijkMediaPlayer.seekTo(time);
+    }
+
+    @Override
+    public void release() {
+        if (mMediaHandler != null && mMediaHandlerThread != null && ijkMediaPlayer != null) {//不知道有没有妖孽
+            HandlerThread tmpHandlerThread = mMediaHandlerThread;
+            IjkMediaPlayer tmpMediaPlayer = ijkMediaPlayer;
+            JZMediaInterface.SAVED_SURFACE = null;
+
+            mMediaHandler.post(() -> {
+                tmpMediaPlayer.setSurface(null);
+                tmpMediaPlayer.release();
+                tmpHandlerThread.quit();
+            });
+            ijkMediaPlayer = null;
+        }
+    }
+
+    @Override
+    public long getCurrentPosition() {
+        return ijkMediaPlayer.getCurrentPosition();
+    }
+
+    @Override
+    public long getDuration() {
+        if (ijkMediaPlayer == null) return 0;
+        return ijkMediaPlayer.getDuration();
+    }
+
+    @Override
+    public void setVolume(float leftVolume, float rightVolume) {
+        ijkMediaPlayer.setVolume(leftVolume, rightVolume);
+    }
+
+    @Override
+    public void setSpeed(float speed) {
+        ijkMediaPlayer.setSpeed(speed);
+    }
+
+    @Override
+    public void onPrepared(IMediaPlayer iMediaPlayer) {
+        handler.post(() -> jzvd.onPrepared());
+    }
+
+    @Override
+    public void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3) {
+        handler.post(() -> jzvd.onVideoSizeChanged(iMediaPlayer.getVideoWidth(), iMediaPlayer.getVideoHeight()));
+    }
+
+    @Override
+    public boolean onError(IMediaPlayer iMediaPlayer, final int what, final int extra) {
+        handler.post(() -> jzvd.onError(what, extra));
+        return true;
+    }
+
+    @Override
+    public boolean onInfo(IMediaPlayer iMediaPlayer, final int what, final int extra) {
+        handler.post(() -> jzvd.onInfo(what, extra));
+        return false;
+    }
+
+    @Override
+    public void onBufferingUpdate(IMediaPlayer iMediaPlayer, final int percent) {
+        handler.post(() -> jzvd.setBufferProgress(percent));
+    }
+
+    @Override
+    public void onSeekComplete(IMediaPlayer iMediaPlayer) {
+        handler.post(() -> jzvd.onSeekComplete());
+    }
+
+    @Override
+    public void onTimedText(IMediaPlayer iMediaPlayer, IjkTimedText ijkTimedText) {
+
+    }
+
+    @Override
+    public void setSurface(Surface surface) {
+        ijkMediaPlayer.setSurface(surface);
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        if (SAVED_SURFACE == null) {
+            SAVED_SURFACE = surface;
+            prepare();
+        } else {
+            jzvd.textureView.setSurfaceTexture(SAVED_SURFACE);
+        }
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        return false;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+
+    }
+
+    @Override
+    public void onCompletion(IMediaPlayer iMediaPlayer) {
+        handler.post(() -> jzvd.onCompletion());
+    }
+}