current position:Home>Koo video player integrated into the shuttle project

Koo video player integrated into the shuttle project

2022-01-26 23:50:15 Such scenery

Note that this article takes the video playback layer as a plug-in , To facilitate flutter Integrate

1. Configuration plug-ins

Put the existing in the project koo Video player so Copy the library to the specified directory of the project

image.png

hold libflutter.so Copy the file to the folder above

Configure... Under Android directory build.gradle file ( Enable the project to identify so The library files )

android {
    compileSdkVersion 30

    defaultConfig {
        minSdkVersion 16
        ndk{ abiFilters "armeabi-v7a" }// Mainly this sentence 
    }
}
 Copy code 

establish KoolMediaPlayer Helper classes , be used for java The code calls the relevant functions of the player

  1. load so library
public static void loadLibraries() {
    System.loadLibrary("kooffmpeg");
    System.loadLibrary("mediaplayer");
}
 Copy code 
  1. Define common local methods ( Here is to carry out their own packaging , Not yet koolSDK Bring everything in )
//C Method start 
public static final native long nativeInit();
public native float nativeGetSpeed() throws IllegalStateException;
public native long nativeSetup(Object var1) throws IllegalStateException;
public native void nativeSetDataSource(String var1, String[] var2, String[] var3) throws IllegalStateException;
public native void nativePrepare() throws IllegalStateException;
public native void nativePrepareAsync() throws IllegalStateException;
public native void nativeSetSurface(Surface var1, int var2) throws IllegalStateException;
public native int nativeGetVideoWidth() throws IllegalStateException;
public native int nativeGetVideoHeight() throws IllegalStateException;
public native int nativeGetCurrentPosition() throws IllegalStateException, IllegalArgumentException;
public native void nativeSeekTo(int var1) throws IllegalStateException;
public native void nativeSetAudioVolume(int var1) throws IllegalStateException;
public native void nativeSetSpeed(float var1) throws IllegalStateException;
public native void nativeStop() throws IllegalStateException;
public native int nativeGetMediaDuration() throws IllegalStateException;
public native void nativeStart() throws IllegalStateException;
public native void nativeMPause() throws IllegalStateException;
public native void nativeRelease() throws IllegalStateException;
public native void nativeSetNetTimeout(int var1) throws IllegalStateException;
public native void nativeSetCacheEnable(boolean var1) throws IllegalStateException;
public native void nativeSetHwDecEnable(boolean var1, boolean var2) throws IllegalStateException;
public native void nativeReset() throws IllegalStateException;
//------->C Method end 
 Copy code 
  1. java Level call -- There are too many ways , See all the contents of the following class
  2. KoolMediaPlayer The whole content of the class
import android.content.ContentResolver;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;

import org.json.JSONObject;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Calendar;
import java.util.Map;

public class KoolMediaPlayer {
    private static boolean mBrokenLibraries;
    private long mNativeContext;
    private Context mContext;
    private boolean mStayAwake;
    private boolean mScreenOnWhilePlaying;
    protected SurfaceHolder mSurfaceHolder;
    protected Surface mSurface;
    private int mVideoRenderType = 4;
    private PowerManager.WakeLock mWakeLock = null;
    private KoolMediaPlayer.NativeMsgHandler mEventHandler;
    public static void loadLibraries() {
        System.loadLibrary("kooffmpeg");
        System.loadLibrary("mediaplayer");
    }

    public KoolMediaPlayer(Context context) {
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            this.mEventHandler = new KoolMediaPlayer.NativeMsgHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            this.mEventHandler = new KoolMediaPlayer.NativeMsgHandler(this, looper);
        } else {
            this.mEventHandler = null;
        }
        this.mContext=context;
        if (mBrokenLibraries) {
            this.mNativeContext = 0L;
            Log.e("KoolMediaPlayer", "Error in load library!\n");
        } else {
            long nNativeContext = this.nativeSetup(new WeakReference<KoolMediaPlayer>(this));
            if (nNativeContext != this.mNativeContext) {
                Log.e("KoolMediaPlayer", "Error in create native mediaplayer\n");
            }
        }

    }

    //C Method start 
    public static final native long nativeInit();
    public native float nativeGetSpeed() throws IllegalStateException;
    public native long nativeSetup(Object var1) throws IllegalStateException;
    public native void nativeSetDataSource(String var1, String[] var2, String[] var3) throws IllegalStateException;
    public native void nativePrepare() throws IllegalStateException;
    public native void nativePrepareAsync() throws IllegalStateException;
    public native void nativeSetSurface(Surface var1, int var2) throws IllegalStateException;
    public native int nativeGetVideoWidth() throws IllegalStateException;
    public native int nativeGetVideoHeight() throws IllegalStateException;
    public native int nativeGetCurrentPosition() throws IllegalStateException, IllegalArgumentException;
    public native void nativeSeekTo(int var1) throws IllegalStateException;
    public native void nativeSetAudioVolume(int var1) throws IllegalStateException;
    public native void nativeSetSpeed(float var1) throws IllegalStateException;
    public native void nativeStop() throws IllegalStateException;
    public native int nativeGetMediaDuration() throws IllegalStateException;
    public native void nativeStart() throws IllegalStateException;
    public native void nativeMPause() throws IllegalStateException;
    public native void nativeRelease() throws IllegalStateException;
    public native void nativeSetNetTimeout(int var1) throws IllegalStateException;
    public native void nativeSetCacheEnable(boolean var1) throws IllegalStateException;
    public native void nativeSetHwDecEnable(boolean var1, boolean var2) throws IllegalStateException;
    public native void nativeReset() throws IllegalStateException;
    //------->C Method end 


    //setDataSource A series of 
    public void setDataSource(Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        this.setDataSource(mContext, uri, null);
    }

    public void setDataSource(Context context, Uri uri, Map<String, String> headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        ContentResolver resolver = context.getContentResolver();
        String scheme = uri.getScheme();
        if ("file".equals(scheme)) {
            this.setDataSource(uri.getPath());
        } else {
            if ("content".equals(scheme) && "settings".equals(uri.getAuthority())) {
                int type = RingtoneManager.getDefaultType(uri);
                Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
                if (actualUri == null) {
                    throw new FileNotFoundException("Failed to resolve default ringtone");
                }
            }

            this.setDataSource(uri.toString(), headers);
        }
    }

    public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        this.setDataSource((String)path, (String[])null, (String[])null);
    }

    //setDataSource A series of   end

    public void setSurface(Surface surface) {
        if (this.mScreenOnWhilePlaying && surface != null) {
            Log.w("KoolMediaPlayer", "setScreenOnWhilePlaying(true) is ineffective for Surface");
        }

        this.mSurfaceHolder = null;
        this.nativeSetSurface(surface, this.mVideoRenderType);
        this.mSurface = surface;
        this.updateSurfaceScreenOn();
    }
    private void updateSurfaceScreenOn() {
        if (this.mSurfaceHolder != null) {
            this.mSurfaceHolder.setKeepScreenOn(this.mScreenOnWhilePlaying && this.mStayAwake);
        }

    }

    public void setScreenOnWhilePlaying(boolean screenOn) {
        if (this.mScreenOnWhilePlaying != screenOn) {
            if (screenOn && this.mSurfaceHolder == null) {
                Log.w("KoolMediaPlayer", "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
            }

            this.mScreenOnWhilePlaying = screenOn;
            this.updateSurfaceScreenOn();
        }

    }
    public void setAudioStreamType(int type) {
    }

    public void setVolume(int volume) {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeSetAudioVolume(volume);
        }
    }

    public int getDuration() {
        int mediaDuration = 0;
        if (this.isValidNativeObjId(this.mNativeContext)) {
            mediaDuration = this.nativeGetMediaDuration();
        }
        return mediaDuration;
    }

    private boolean isValidNativeObjId(long id) {
        boolean ret = true;
        if (id <= 0L) {
            ret = false;
        }

        return ret;
    }
    public void setHwDecEnable(boolean flag, boolean fastRenderFlag) {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeSetHwDecEnable(flag, fastRenderFlag);
        }

    }
    public void prepare() {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativePrepare();
        }

    }

    public void setNetTimeout(int seconds) {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeSetNetTimeout(seconds);
        }

    }

    public void setCacheEnable(boolean flag) {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeSetCacheEnable(flag);
        }

    }

    public void setSpeed(float speed) {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeSetSpeed(speed);
        }

    }

    public float getSpeed() {
        float speed = 1.0F;
        if (this.isValidNativeObjId(this.mNativeContext)) {
            speed = this.nativeGetSpeed();
        }

        return speed;
    }

    public void prepareAsync() {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativePrepareAsync();
        }

    }

    public void seekTo(int msec) {
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeSeekTo(msec);
        }

    }

    public void stop() {
        this.stayAwake(false);
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeStop();
        }

    }

    private void stayAwake(boolean awake) {
        if (this.mWakeLock != null) {
            if (awake && !this.mWakeLock.isHeld()) {
                this.mWakeLock.acquire();
            } else if (!awake && this.mWakeLock.isHeld()) {
                this.mWakeLock.release();
            }
        }

        this.mStayAwake = awake;
        this.updateSurfaceScreenOn();
    }

    // Get the currently playing position 
    public int getCurrentPosition() {
        int currPosition = 0;
        if (this.isValidNativeObjId(this.mNativeContext)) {
            currPosition = this.nativeGetCurrentPosition();
        }

        return currPosition;
    }

    private static void postEventFromNative(Object mediaplayer, int what, int arg1, int arg2, Object obj) {
        Log.d("------------>postEvent Yes ", "Get event what = " + what + ",arg1 = " + arg1 + ",arg2 = " + arg2);
        KoolMediaPlayer mp = null;

        try {
            mp = (KoolMediaPlayer)((WeakReference)mediaplayer).get();
        } catch (Exception var7) {
            var7.printStackTrace();
        }

        if (mp != null) {
            if (obj != null) {
                Log.i("error", obj.toString());
            }

            if (mp.mEventHandler != null) {
                Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
                mp.mEventHandler.sendMessage(m);
            }

        }
    }

    public void setDataSource(String path, Map<String, String> headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        //TODO  If necessary here , You need to achieve 
        String[] keys = null;
        String[] values = null;
//        if (headers != null) {
//            keys = new String[headers.size()];
//            values = new String[headers.size()];
//            int i = 0;
//            for(Iterator var6 = headers.entrySet().iterator(); var6.hasNext(); ++i) {
//
//                Map.Entry<String, String> entry = (Map.Entry<String, String>)var6.next();
//                keys[i] = (String)entry.getKey();
//                values[i] = (String)entry.getValue();
//            }
//        }

        this.setDataSource(path, keys, values);
    }

    private void setDataSource(String path, String[] keys, String[] values) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        Uri uri = Uri.parse(path);
        String scheme = uri.getScheme();
        if ("file".equals(scheme)) {
            path = uri.getPath();
        } else if (scheme != null) {
            this.nativeSetDataSource(path, keys, values);
            return;
        }

        File file = new File(path);
        if (file.exists()) {
            this.nativeSetDataSource(path, keys, values);
        } else {
            throw new IOException("setDataSource failed.");
        }
    }

    static {
        String errorMsgBrokenLib = "";

        try {
            loadLibraries();
            nativeInit();
        } catch (UnsatisfiedLinkError var2) {
            System.err.println(var2.getMessage());
            mBrokenLibraries = true;
            errorMsgBrokenLib = var2.getMessage();
        } catch (Exception var3) {
            System.err.println(var3.getMessage());
            mBrokenLibraries = true;
            errorMsgBrokenLib = var3.getMessage();
        }

        if (mBrokenLibraries) {
            Log.e("KoolMediaPlayer", errorMsgBrokenLib);
        }

    }

    public void start() {
        this.stayAwake(true);
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeStart();
        }

    }

    public void pause() {
        this.stayAwake(false);
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeMPause();
        }

    }

    public void reset() {
        this.stayAwake(false);
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeReset();
        }

    }

    public void release() {
        this.stayAwake(false);
        this.updateSurfaceScreenOn();
        //TODO
//        this.mOnPreparedListener = null;
//        this.mOnBufferingUpdateListener = null;
//        this.mOnCompletionListener = null;
//        this.mOnSeekCompleteListener = null;
//        this.mOnErrorListener = null;
//        this.mOnInfoListener = null;
//        this.mOnVideoSizeChangedListener = null;
        if (this.isValidNativeObjId(this.mNativeContext)) {
            this.nativeRelease();
        }

    }
public int getVideoWidth() {
        int nVideoWidth = 0;
        if (this.isValidNativeObjId(this.mNativeContext)) {
            nVideoWidth = this.nativeGetVideoWidth();
        }

        return nVideoWidth;
    }

    public int getVideoHeight() {
        int nVideoHeight = 0;
        if (this.isValidNativeObjId(this.mNativeContext)) {
            nVideoHeight = this.nativeGetVideoHeight();
        }

        return nVideoHeight;
    }

    public class NativeMsgHandler extends Handler {
        private KoolMediaPlayer mMediaPlayer;
        private long last_bps_time = 0L;
        private long last_fps_time = 0L;
        private long last_bandwidth_time = 0L;
        private long last_duration_time = 0L;
        private long last_start_buffering_time = 0L;
        private long last_buffering_time = 0L;
        private boolean is_first_frame = true;
        private boolean is_seeking = false;
        private int is_report_buffering = 0;
        public static final int MEDIA_REPORTER_EVENT_FIRST_FRAME_BUFFERING = 1;
        public static final int MEDIA_REPORTER_EVENT_SEEKING_BUFFERING = 2;
        public static final int MEDIA_REPORTER_EVENT_NORNAL_BUFFERING = 3;

        public NativeMsgHandler(KoolMediaPlayer mp, Looper looper) {
            super(looper);
            this.mMediaPlayer = mp;
        }

        public void sendInfoData(int arg1, int arg2, Object obj, JSONObject eventData) {
            String eventName = "";
            Calendar cal = Calendar.getInstance();
            if (eventData != null) {
                short event;
                try {
                    switch(arg1) {
                        case 701:
                            if (this.is_first_frame) {
                                this.is_report_buffering = 1;
                            } else if (this.is_seeking) {
                                this.is_report_buffering = 2;
                            } else {
                                this.is_report_buffering = 3;
                            }

                            if (cal.getTimeInMillis() > this.last_buffering_time + 10000L) {
                                this.last_start_buffering_time = cal.getTimeInMillis();
                                return;
                            }
                        case 702:
                            if (cal.getTimeInMillis() <= this.last_buffering_time + 10000L) {
                                return;
                            }

                            event = 2201;
                            if (this.is_report_buffering == 1) {
                                eventName = "first_buffering_end";
                            } else if (this.is_report_buffering == 2) {
                                eventName = "seeking_buffering_end";
                            } else {
                                eventName = "buffering_end";
                            }

                            eventData.put("elapsed_time", arg2);
                            this.last_buffering_time = cal.getTimeInMillis();
                            break;
                        case 703:
                            if (cal.getTimeInMillis() <= this.last_bandwidth_time + 60000L) {
                                return;
                            }

                            event = 2202;
                            eventName = "bandwidth";
                            eventData.put("bandwidth", arg2);
                            this.last_bandwidth_time = cal.getTimeInMillis();
                            break;
                        case 704:
                            if (cal.getTimeInMillis() <= this.last_duration_time + 60000L) {
                                return;
                            }

                            event = 2203;
                            eventName = "buffering_duration";
                            eventData.put("buffer_duration", arg2);
                            this.last_duration_time = cal.getTimeInMillis();
                            break;
                        case 705:
                            event = 2206;
                            eventName = "tv_info";
                            break;
                        case 706:
                            event = 2204;
                            eventName = "buffering_timeout";
                            break;
                        case 707:
                            event = 2205;
                            eventName = "buffering_maxfreq";
                            break;
                        case 708:
                            event = 2207;
                            eventName = "dns_time";
                            eventData.put("dns_time", arg2);
                            break;
                        case 1000:
                            event = 2300;
                            eventName = "demuxer_time";
                            eventData.put("avg_time", arg2);
                            break;
                        case 1001:
                            event = 2301;
                            eventName = "auddec_time";
                            eventData.put("avg_time", arg2);
                            break;
                        case 1002:
                            event = 2302;
                            eventName = "viddec_time";
                            eventData.put("avg_time", arg2);
                            break;
                        case 1003:
                            event = 2303;
                            eventName = "audfil_time";
                            eventData.put("avg_time", arg2);
                            break;
                        case 1004:
                            event = 2304;
                            eventName = "vidfil_time";
                            eventData.put("avg_time", arg2);
                            break;
                        case 1015:
                            event = 2305;
                            eventName = "audren_time";
                            eventData.put("avg_time", arg2);
                            break;
                        case 1016:
                            event = 2306;
                            eventName = "vidren_time";
                            eventData.put("avg_time", arg2);
                            break;
                        case 2000:
                            event = 2100;
                            eventName = "first_audio_time";
                            eventData.put("first_frame_time", arg2);
                            break;
                        case 2001:
                            this.is_first_frame = false;
                            event = 2101;
                            eventName = "first_video_time";
                            eventData.put("first_frame_time", arg2);
                            break;
                        case 2002:
                            if (cal.getTimeInMillis() <= this.last_fps_time + 30000L) {
                                return;
                            }

                            event = 2102;
                            eventName = "fps";
                            eventData.put("fps", arg2);
                            this.last_fps_time = cal.getTimeInMillis();
                            break;
                        case 2100:
                            event = 2106;
                            eventName = "dec_info";
                            eventData.put("is_hw_decode", 1);
                            eventData.put("codec_id", arg2);
                            break;
                        case 2101:
                            event = 2106;
                            eventName = "dec_info";
                            eventData.put("is_hw_decode", 0);
                            eventData.put("codec_id", arg2);
                            break;
                        case 3000:
                            if (cal.getTimeInMillis() <= this.last_bps_time + 60000L) {
                                return;
                            }

                            event = 2103;
                            eventName = "bps";
                            eventData.put("bps", arg2);
                            this.last_bps_time = cal.getTimeInMillis();
                            break;
                        case 4000:
                            event = 2400;
                            eventName = "mark_enable";
                            eventData.put("mark_enable", arg2);
                            break;
                        case 4001:
                            event = 2401;
                            eventName = "mark_time";
                            eventData.put("mark_time", arg2);
                            break;
                        case 4100:
                            event = 2500;
                            eventName = "screenshot";
                            eventData.put("screenshot", arg2);
                            break;
                        default:
                            if (arg1 >= 0) {
                                return;
                            }

                            event = 2800;
                            eventName = "errorinfo";
                            eventData.put("code1", arg1);
                            eventData.put("code2", arg2);
                            if (obj != null) {
                                eventData.put("desc", obj);
                            }
                    }
                } catch (Exception var9) {
                    var9.printStackTrace();
                    return;
                }

//                if (KoolMediaPlayer.this.mKoolMediaReporter != null) {
//                    int ret = KoolMediaPlayer.this.mKoolMediaReporter.sendMessage(event, eventName, eventData);
//                    if (ret != 0) {
//                        Log.e("KoolMediaPlayer", "SendMessage error " + ret);
//                    }
//                }

            }
        }

        public void sendStatisticalMessage(int what, int arg1, int arg2, Object obj) {
            int event = 0;
            String eventName = "";
            JSONObject eventData = new JSONObject();
            Calendar cal = Calendar.getInstance();
            if (true) {
                try {
                    switch(what) {
                        case 0:
                            break;
                        case 1:
                            event = 2003;
                            eventName = "prepared";
                            eventData.put("elapsed_time", arg1);
                            break;
                        case 2:
                            this.is_seeking = false;
                            event = 2011;
                            eventName = "complete";
                            break;
                        case 3:
                            if (cal.getTimeInMillis() <= this.last_duration_time + 10000L) {
                                return;
                            }

                            event = 2203;
                            eventName = "buffering_update";
                            eventData.put("buffer_duration", arg1);
                            this.last_duration_time = cal.getTimeInMillis();
                            break;
                        case 4:
                            event = 2007;
                            eventName = "seek_complete";
                            break;
                        case 6:
                            event = 2004;
                            eventName = "started";
                            eventData.put("elapsed_time", arg1);
                            break;
                        case 7:
                            event = 2005;
                            eventName = "pause";
                            break;
                        case 8:
                            event = 2008;
                            eventName = "stopped";
                            break;
                        case 10:
                            event = 2009;
                            eventName = "release";
                            break;
                        case 11:
                            event = 2010;
                            eventName = "reset";
                            break;
                        case 12:
                            event = 2000;
                            eventName = "initialize";
                            break;
                        case 13:
                            this.is_first_frame = true;
                            event = 2001;
                            eventName = "set_url";
                            break;
                        case 14:
                            event = 2002;
                            eventName = "prepare";
                            break;
                        case 15:
                            this.is_seeking = true;
                            event = 2006;
                            eventName = "seek";
                            eventData.put("seek_time", arg1);
                            break;
                        case 16:
                            event = 2104;
                            eventName = "speedx";
                            eventData.put("speedx", arg1);
                            break;
                        case 17:
                            event = 2105;
                            eventName = "volumex";
                            eventData.put("volumex", arg1);
                            break;
                        case 100:
                            event = -1;
                            eventName = "error";
                            eventData.put("module", arg1);
                            eventData.put("code", arg2);
                            if (obj != null) {
                                eventData.put("desc", obj);
                            }
                            break;
                        case 200:
                            this.sendInfoData(arg1, arg2, obj, eventData);
                            return;
                        default:
                            Log.e("KoolMediaPlayer", "unrecognized message");
                            return;
                    }
                } catch (Exception var10) {
                    var10.printStackTrace();
                    return;
                }

//                if (mKoolMediaReporter != null) {
//                    int ret = mKoolMediaReporter.sendMessage(event, eventName, eventData);
//                    if (ret != 0) {
//                        Log.e("KoolMediaPlayer", "SendMessage error " + ret + eventName + eventData);
//                    }
//                }

            }
        }

        public void handleMessage(Message msg) {
            this.sendStatisticalMessage(msg.what, msg.arg1, msg.arg2, msg.obj);
            switch(msg.what) {
                case 0:
                    Log.d("KoolMediaPlayer", "Media NOP Message!");
                    break;
                case 1:
                    Log.d("KoolMediaPlayer", "MediaPrepared!");
                    mMediaPlayer.start();
                    mMediaPlayer.setSpeed(2f);
                    break;
                case 2:
                    Log.d("KoolMediaPlayer", "MediaCompleted!");
//                    MediaPlayer.OnCompletionListener onCompletionListener = KoolMediaPlayer.this.mOnCompletionListener;
//                    if (onCompletionListener != null) {
//                        onCompletionListener.onCompletion(this.mMediaPlayer);
//                    }
                    break;
                case 3:
                    Log.d("KoolMediaPlayer", "MediaBuffering percent = " + msg.arg1 + "%\n");
//                    MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = KoolMediaPlayer.this.mOnBufferingUpdateListener;
//                    if (onBufferingUpdateListener != null) {
//                        onBufferingUpdateListener.onBufferingUpdate(this.mMediaPlayer, msg.arg1);
//                    }
                    break;
                case 4:
                    Log.d("KoolMediaPlayer", "Media Player Seek Completed!\n");
//                    MediaPlayer.OnSeekCompleteListener onSeekCompleteListener = KoolMediaPlayer.this.mOnSeekCompleteListener;
//                    if (onSeekCompleteListener != null) {
//                        onSeekCompleteListener.onSeekComplete(this.mMediaPlayer);
//                    }
                    break;
                case 5:
                    Log.d("KoolMediaPlayer", "Media Player video size changed!\n");
//                    if (KoolMediaPlayer.this.mOnVideoSizeChangedListener != null) {
//                        KoolMediaPlayer.this.mOnVideoSizeChangedListener.onVideoSizeChanged(this.mMediaPlayer, msg.arg1, msg.arg2);
//                    }
                    break;
                case 6:
                    Log.d("KoolMediaPlayer", "Media Player status started");
                    break;
                case 7:
                    Log.d("KoolMediaPlayer", "Media Player status paused");
                    break;
                case 8:
                    Log.d("KoolMediaPlayer", "Media Player status stopped!");
                    break;
                case 9:
                    Log.d("KoolMediaPlayer", "Media Player skipped!");
                    break;
                case 10:
                    Log.d("KoolMediaPlayer", "Media Player release!");
                    break;
                case 99:
                    Log.d("KoolMediaPlayer", "Media Player timed text!");
                    break;
                case 100:
                    Log.d("KoolMediaPlayer", "Media Player error, what = " + msg.arg1 + ",arg = " + msg.arg2);
//                    OnErrorListener onErrorListener = KoolMediaPlayer.this.mOnErrorListener;
//                    if (onErrorListener != null) {
//                        onErrorListener.onError(this.mMediaPlayer, msg.arg1, msg.arg2, msg.obj);
//                    }
                    break;
                case 200:
                    Log.d("KoolMediaPlayer", "Media Player info, what = " + msg.arg1 + "arg1 = " + msg.arg2);
//                    OnInfoListener onInfoListener = KoolMediaPlayer.this.mOnInfoListener;
//                    if (onInfoListener != null) {
//                        onInfoListener.onInfo(this.mMediaPlayer, msg.arg1, msg.arg2);
//                    }
                    break;
                case 201:
                    Log.d("KoolMediaPlayer", "Media Player subtitle data!");
                    break;
                case 202:
                    Log.d("KoolMediaPlayer", "Media Player meta data!");
                    break;
                default:
                    Log.e("KoolMediaPlayer", "Unknown message type " + msg.what);
                    return;
            }

        }
    }
}
 Copy code 

establish PlayerPlugin

When flutter When the client calls the Android layer code , this plugin be responsible for 1, Corresponding call ,2, establish SurfaceTextureEntry 3, Receive the transmitted address of the video to be played , And complete the playback operation 4, Put the corresponding texture id Send it back to flutter layer . In order to flutter Control

Code

import android.media.AudioManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Surface;

import androidx.annotation.NonNull;

import org.koolearn.mediaplayer.KoolMediaPlayer;

import java.io.IOException;
import java.util.logging.LogRecord;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.view.TextureRegistry;

/** Playertest1Plugin */
public class Playertest1Plugin implements FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;
  private KoolMediaPlayer mPlayer;
  private FlutterPlugin.FlutterPluginBinding mFlutterPluginBinding;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPlugin.FlutterPluginBinding binding) {
    mFlutterPluginBinding = binding;
    mPlayer = new KoolMediaPlayer(binding.getApplicationContext());
    channel = new MethodChannel(binding.getBinaryMessenger(), "playertest");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
    if (call.method.equals("getTextureId")) {
//      val textures: TextureRegistry = this.registrarFor("video").textures()
      TextureRegistry.SurfaceTextureEntry textureEntry = mFlutterPluginBinding.getTextureRegistry().createSurfaceTexture();
      final Surface surface = new Surface(textureEntry.surfaceTexture());
      mPlayer.setSurface(surface);
//      AudioManager am = (AudioManager)mFlutterPluginBinding.getSystemService("audio");
//      am.requestAudioFocus(this.mOnAudioFocusChangeListener, 3, 1);
      this.mPlayer.setHwDecEnable(true, true);
      this.mPlayer.setAudioStreamType(3);
      try {
//        mPlayer.setDataSource(Uri.parse("http://tanzi27niu.cdsb.mobi/wps/wp-content/uploads/2017/05/2017-05-17_17-33-30.mp4"));
//        mPlayer.setDataSource(Uri.parse("http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8"));
        mPlayer.setDataSource(Uri.parse("http://10.155.41.114/videoname/video_name.m3u8"));
      } catch (IOException e) {
        e.printStackTrace();
      }
      mPlayer.setCacheEnable(true);
      mPlayer.prepareAsync();
//      Handler h=new Handler(Looper.getMainLooper());
//      h.postDelayed(new Runnable() {
//        @Override
//        public void run() {
//          mPlayer.getVideoWidth();
//          mPlayer.getVideoHeight();
//          mPlayer.setSpeed(1);
//          mPlayer.start();
//        }
//      },5000);
//      mPlayer.setSpeed(3);
      result.success(textureEntry.id());
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPlugin.FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
    mPlayer.reset();
    mPlayer.release();
  }
}
 Copy code 

2. To configure demo engineering

1.Manifest Increase network permissions

<uses-permission android:name="android.permission.INTERNET"/>
 Copy code 

2.android In the catalog build Add to file ndk To configure android->defaultConfig-> increase ndk{ abiFilters "armeabi-v7a" }

3. The use of plug-in

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:playertest1/playertest1.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _textureId = -1;

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    int textureId;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      textureId = await Playertest1.getTextureId;
    } on PlatformException {
      textureId = -1;
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;
    setState(() {
      _textureId = textureId;
    });
  }

  @override
  Widget build(BuildContext context) {
    print("_textureId = $_textureId");
    return Container(
      padding: EdgeInsets.only(bottom: 600),
      child: Texture(textureId: _textureId),
      width: 400,
      height: 300,
    );
    return Texture(textureId: _textureId);
  }
}
 Copy code 

3. Problems encountered and solutions

  1. abi problem , player abiarmv7a yes 32 Bit ,flutter What is offered is 64 Bit .

Solution : When testing the project , I found that when I packed it, I actually flutter Yes, there is 32 position flutter What is generated is just that it is removed every time it runs , At this point, we just need to manually copy32 Bit flutter.so Package to project jni Just come in the folder . 2. flutter Add so Problems with library configuration flutter Add so The library must be strictly configured , For details, please refer to my demo The relevant configuration inside . 3. The problem of package name signature When creating local method auxiliary classes, we must be consistent with c The package names defined in the library are the same , Method signature must also correspond to . Otherwise... Cannot be called correctly so Methods defined in the library .

4. remaining problems

M3U8 Some resources are playing at an abnormal speed , After adjusting the speed, it can play normally , At present, the reason is unknown .mp4 Can play normally .

So far our koo Transplant the player to flutter In the project demo Already completed ,demo It can be played normally m3u8 and mp4 video . As for subsequent specific use , We need to improve the details later .

demo Address

If necessary, you can send demo Download and run the project in . See the effect . Point me, please.

Important reference articles :

To talk about Flutter External texture

m3u8 Address of the test

copyright notice
author[Such scenery],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/01/202201262350133617.html

Random recommended