自定义IjkMediaPlayer播放器的基本实现

最终效果图如下:
自定义IjkMediaPlayer播放器的基本实现_第1张图片
  说起Android的播放器,就会想起MediaPlayer,但是MediaPlayer本身的坑太多,连google都推出了ExoPlayer来代替MediaPlayer,如今网上已经开源了许多成熟的功能强大的播放器。比如bilibili的Ijkplayer,google的ExoPlayer,GSYVideoPlayer等。

  下面介绍一下ijkplayer。ijkplayer是一款基于ffplay的轻量级的跨平台的播放器,有类似于MediaPlayer的API,github上有超过23000+个star,ijkplayer底层是c实现的,Android通过jni的方式调用。

ijkplayer地址:https://github.com/bilibili/ijkplayer

一、ijkplayer集成

ijkplayer的集成方式有两种:

1. gradle依赖(默认配置)

# required
allprojects {
    repositories {
        jcenter()
    }
}

dependencies {
    # required, enough for most devices.
    compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
    compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'

    # Other ABIs: optional
    compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
    compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
    compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
    compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'

    # ExoPlayer as IMediaPlayer: optional, experimental
    compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'
}

2.手动编译so,导入或依赖jni代码

如果你需要一些特殊的配置,比如默认ijkplayer是不支持https的,你需要手动配置并编译支持https的so。

2.1 本人用的Mac,需要准备好以下的环境:

1.ndk r10 ndk是向上兼容的,所以版本选择比较低一点的比较好

2.homebrew环境 ,许多软件都可以通过homebrew安装,比如git,homebrew的安装方式:在终端输入

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

3.git,如果安装好了homebrew,就可以直接使用brew install git 命令安装git了

4.nasm/yasm, 直接通过brew install nasm或者 brew install yasm安装, 这个是ffmpeg为了加快编译速度需要使用的。Ps:我在Mac上安装yasm后使用ffmpeg编译还是提示我yasm not found, 不知道怎么解决,最后安装了nasm才解决。

5.ffmpeg,ffmpeg编译so时会用到,这里我是通过brew install ffmpeg方式安装的,

Ps:途中会下载许多的依赖,并且可能会提示报错,比如:

xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun

这个是说无效的路径,找不到这个路径,其实就是没有安装xcode的命令行工具,解决办法就是:打开终端使用:xcode-select --install解决。

还有一个错误:

python3 link Error: An unexpected error occurred during the brew  link step

这是homebrew在安装相应的依赖报的错,原因是我们没有给/usr/local/设置权限。解决办法是
使用命令sudo chown -R $(whoami) /usr/local/python3 然后使用brew link python3重新link一下,最后重新执行brew install ffmpeg即可。

6.编辑bash_profile文件配置环境变量这里配置sdk和ndk环境变量即可
自定义IjkMediaPlayer播放器的基本实现_第2张图片

2.2 手动编译SO

git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.8.8

./init-android.sh

# 如果要添加对https的支持(可选)
./init-android-openssl.sh

cd android/contrib
./compile-ffmpeg.sh clean

# 编译 openssl(可选)
./compile-openssl.sh clean
./compile-openssl.sh all

# 默认编译arm-v7的so,all代表编译所有平台下的so,我们可以有选择性的编译指定的平台so
./compile-ffmpeg.sh all

cd ..
# 默认编译arm-v7的so,all代表编译所有平台下的so,我们可以有选择性的编译指定的平台so
./compile-ijk.sh all

编译成功以后cd到ijkplayer目录下,此时的so是支持https的,直接把对应平台下的so拷贝到项目中的jnilibs去。
自定义IjkMediaPlayer播放器的基本实现_第3张图片

2.3 导入或依赖jni代码

你可以直接这么依赖,版本号要和编译so的分支的版本号一致

compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'

也可以直接把编译生成的ijkplayer-java依赖到项目里去都可以。

二、自定义IjkMediaPlayer

主要封装了一些MediaPlayer常用的方法

public class CusIjkPlayer extends FrameLayout {
    /**
     * 由ijkplayer提供,用于播放视频,需要给他传入一个surfaceView
     */
    private IMediaPlayer mMedialPlayer = null;
    /**
     * 视频文件地址
     */
    private String mPath;
    /**
     * 视频请求header
     */
    private Map mHeader;
    private SurfaceView mSurfaceView;
    private Context mContext;
    private boolean mEnableMediaCodec;
    private AudioManager mAudioManager;
    private AudioFocusHelper mAudioFousHelper;
    private VideoListener mListener;

    public CusIjkPlayer(Context context) {
        this(context, null);
    }

    public CusIjkPlayer(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CusIjkPlayer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        setBackgroundColor(Color.BLACK);
        createSurfaceView();
        mAudioManager = (AudioManager) mContext.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
        mAudioFousHelper = AudioFocusHelper.getInstance(mContext);
    }

    private void createSurfaceView() {
        mSurfaceView = new SurfaceView(mContext);
        mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                if (mMedialPlayer != null) {
                    mMedialPlayer.setDisplay(holder);
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
        });
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER);
        addView(mSurfaceView, 0, layoutParams);
    }

    private IMediaPlayer createPlayer() {
        IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "skip_loop_filter", 1);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "http-detect-range-support", 48);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "min-frames", 100);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
        ijkMediaPlayer.setVolume(1.0f, 1.0f);
        setEnableMediaCodec(ijkMediaPlayer, mEnableMediaCodec);
        return ijkMediaPlayer;
    }

    /**
     * 设置是否开启硬解码
     */
    private void setEnableMediaCodec(IjkMediaPlayer ijkMediaPlayer, boolean isEnable) {
        int value = isEnable ? 1 : 0;
        // 开启硬解码
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", value);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", value);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", value);
    }

    public void setEnableMediaCodec(boolean mEnableMediaCodec) {
        this.mEnableMediaCodec = mEnableMediaCodec;
    }

    private void setListener(IMediaPlayer player) {
        if (mListener != null) {
            player.setOnBufferingUpdateListener(new IMediaPlayer.OnBufferingUpdateListener() {
                @Override
                public void onBufferingUpdate(IMediaPlayer iMediaPlayer, int i) {
                    mListener.onBufferingUpdate(iMediaPlayer, i);
                }
            });
            player.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(IMediaPlayer iMediaPlayer) {
                    mListener.onCompletion(iMediaPlayer);
                }
            });
            player.setOnErrorListener(new IMediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {
                    return mListener.onError(iMediaPlayer, i, i1);
                }
            });
            player.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
                @Override
                public boolean onInfo(IMediaPlayer iMediaPlayer, int i, int i1) {
                    return mListener.onInfo(iMediaPlayer, i, i1);
                }
            });
            player.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(IMediaPlayer iMediaPlayer) {
                    mListener.onPrepared(iMediaPlayer);
                }
            });
            player.setOnVideoSizeChangedListener(new IMediaPlayer.OnVideoSizeChangedListener() {
                @Override
                public void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3) {
                    mListener.onVideoSizeChanged(iMediaPlayer, i, i1, i2, i3);
                }
            });
            player.setOnSeekCompleteListener(new IMediaPlayer.OnSeekCompleteListener() {
                @Override
                public void onSeekComplete(IMediaPlayer iMediaPlayer) {
                    mListener.onSeekComplete(iMediaPlayer);
                }
            });
        }
    }

    public void setVideoListener(final VideoListener videoListener) {
        mListener = videoListener;
    }

    public void setPath(String path) {
        setPath(path, null);
    }

    public void setPath(String path, Map header) {
        mPath = path;
        mHeader = header;
    }

    public void load() throws IOException {
        if (mMedialPlayer != null) {
            mMedialPlayer.stop();
            mMedialPlayer.release();
        }
        mMedialPlayer = createPlayer();
        setListener(mMedialPlayer);
        mMedialPlayer.setDisplay(mSurfaceView.getHolder());
        mMedialPlayer.setDataSource(mContext, Uri.parse(mPath), mHeader);
        mMedialPlayer.prepareAsync();
    }

    public void start() {
        if (mMedialPlayer != null) {
            mMedialPlayer.start();
            mAudioFousHelper.startFocus();
        }
    }

    public void release() {
        if (mMedialPlayer != null) {
            mMedialPlayer.reset();
            mMedialPlayer.release();
            mMedialPlayer = null;
            mAudioFousHelper.stopFocus();
        }
    }

    public void pause() {
        if (mMedialPlayer != null) {
            mMedialPlayer.pause();
        }
    }

    public void stop() {
        if (mMedialPlayer != null) {
            mMedialPlayer.stop();
            mAudioFousHelper.stopFocus();
        }
    }

    public void resume() {
        if (mMedialPlayer != null) {
            mMedialPlayer.start();
        }
    }

    public void reset() {
        if (mMedialPlayer != null) {
            mMedialPlayer.reset();
            mAudioFousHelper.stopFocus();
        }
    }

    public long getDuration() {
        if (mMedialPlayer != null) {
            return mMedialPlayer.getDuration();
        } else {
            return 0;
        }
    }

    public void seekTo(long l) {
        if (mMedialPlayer != null) {
            mMedialPlayer.seekTo(l);
        }
    }

    public boolean isPlaying() {
        if (mMedialPlayer != null) {
            return mMedialPlayer.isPlaying();
        }
        return false;
    }

    public long getCurrentDuration() {
        if (mMedialPlayer != null) {
            return mMedialPlayer.getCurrentPosition();
        }
        return 0;
    }

    public void setVolume(int volume) {
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume / 3, AudioManager.FLAG_PLAY_SOUND);
    }

    public int getVolume() {
        int currentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
        return currentVolume * 3;
    }

    public int getMaxVolume() {
        int currentVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        return currentVolume * 3;
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }
}

github地址:https://github.com/zhoumoumou123year/IjkPlayerDemo

参考链接:
https://www.jianshu.com/p/cb7868a09756
https://www.jianshu.com/p/a57bbdd78798

你可能感兴趣的:(MediaPlayer)