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

最终效果图如下:
在这里插入图片描述
  说起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: optionalcompile '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, experimentalcompile '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环境变量即可
在这里插入图片描述

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.shcd android/contrib
./compile-ffmpeg.sh clean# 编译 openssl(可选)
./compile-openssl.sh clean
./compile-openssl.sh all# 默认编译arm-v7的so,all代表编译所有平台下的so,我们可以有选择性的编译指定的平台so
./compile-ffmpeg.sh allcd ..
# 默认编译arm-v7的so,all代表编译所有平台下的so,我们可以有选择性的编译指定的平台so
./compile-ijk.sh all

编译成功以后cd到ijkplayer目录下,此时的so是支持https的,直接把对应平台下的so拷贝到项目中的jnilibs去。
在这里插入图片描述

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() {@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {if (mMedialPlayer != null) {mMedialPlayer.setDisplay(holder);}}@Overridepublic 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() {@Overridepublic void onBufferingUpdate(IMediaPlayer iMediaPlayer, int i) {mListener.onBufferingUpdate(iMediaPlayer, i);}});player.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(IMediaPlayer iMediaPlayer) {mListener.onCompletion(iMediaPlayer);}});player.setOnErrorListener(new IMediaPlayer.OnErrorListener() {@Overridepublic boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {return mListener.onError(iMediaPlayer, i, i1);}});player.setOnInfoListener(new IMediaPlayer.OnInfoListener() {@Overridepublic boolean onInfo(IMediaPlayer iMediaPlayer, int i, int i1) {return mListener.onInfo(iMediaPlayer, i, i1);}});player.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(IMediaPlayer iMediaPlayer) {mListener.onPrepared(iMediaPlayer);}});player.setOnVideoSizeChangedListener(new IMediaPlayer.OnVideoSizeChangedListener() {@Overridepublic void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3) {mListener.onVideoSizeChanged(iMediaPlayer, i, i1, i2, i3);}});player.setOnSeekCompleteListener(new IMediaPlayer.OnSeekCompleteListener() {@Overridepublic 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;}@Overridepublic boolean performClick() {return super.performClick();}
}

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

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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部