音视频开发框架主要是ijkplayer、VLC、ExoPlayer和其他付费三方库这几种,本项目采用的是ijkplayer,学习难度低。
首先是ijkplayer的引入,为了支持更多格式,这里使用了GSYVideoPlayer的so包
allprojects {
repositories {
jcenter()
maven { url 'https://jitpack.io' }
maven { url "https://maven.aliyun.com/repository/public" }
}
}
//必须
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
//更多ijk的编码支持(mpeg,rtsp, concat、crypto协议)
implementation 'com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-ex_so:v8.2.0-release-jitpack'
混淆
-keep class tv.danmaku.ijk.media.player.** {*;}
-keep class tv.danmaku.ijk.media.player.IjkMediaPlayer{*;}
-keep class tv.danmaku.ijk.media.player.ffmpeg.FFmpegApi{*;}
1.搭建基类
为了方便以后扩展使用,这里搭建视频基类
public abstract class BaseVideoPlayer extends FrameLayout {
public BaseVideoPlayer(@NonNull Context context) {
this(context, null);
}
public BaseVideoPlayer(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseVideoPlayer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
}
}
初始化SurfaceView并添加到布局中
private Context mContext;
private SurfaceView mSurfaceView;
private void init(Context context) {
mContext = context;
setBackgroundColor(Color.BLACK);
createSurfaceView();
}
private void createSurfaceView() {
mSurfaceView = new SurfaceView(mContext);
mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
});
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT
, Gravity.CENTER);
addView(mSurfaceView, 0, layoutParams);
}
设置播放链接并加载
/**
* 由ijkplayer提供,用于播放视频,需要给他传入一个surfaceView
*/
private IMediaPlayer mMediaPlayer = null;
/**
* 视频请求header
*/
private Map<String, String> mHeader;
public void setPathLoad(String path) throws IOException {
setPathLoad(path, null);
}
public void setPathLoad(String path, Map<String, String> header) throws IOException {
mHeader = header;
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
mMediaPlayer = createPlayer();
setListener(mMediaPlayer);
mMediaPlayer.setDisplay(mSurfaceView.getHolder());
mMediaPlayer.setDataSource(mContext, Uri.parse(path), mHeader);
mMediaPlayer.prepareAsync();
}
由子类实现IMediaPlayer
public abstract IMediaPlayer createPlayer();
设置事件回调方法
private void setListener(IMediaPlayer player) {
//在视频预处理完成后被调用。此时视频的宽度、高度、宽高比信息已经获取到,此时可调用seekTo让视频从指定位置开始播放。
player.setOnPreparedListener(iMediaPlayer -> {
if (videoListener != null) {
videoListener.onPrepared(iMediaPlayer);
}
});
player.setOnVideoSizeChangedListener((iMediaPlayer, i, i1, i2, i3) -> {
if (videoListener != null) {
videoListener.onVideoSizeChanged(iMediaPlayer, i, i1, i2, i3);
}
});
player.setOnCompletionListener(iMediaPlayer -> {
if (videoCompletionListener != null) {
videoCompletionListener.onCompletion(iMediaPlayer);
}
});
}
/**
* 设置自己的player回调
*/
public void setVideoListener(VideoListener listener) {
videoListener = listener;
}
/**
* 设置播放完毕回调
*/
public void setVideoCompletionListener(VideoCompletionListener videoCompletionListener) {
this.videoCompletionListener = videoCompletionListener;
}
private VideoListener videoListener;
public interface VideoListener {
void onPrepared(IMediaPlayer iMediaPlayer);
void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3);
}
private VideoCompletionListener videoCompletionListener;
public interface VideoCompletionListener {
void onCompletion(IMediaPlayer iMediaPlayer);
}
在SurfaceV