5.4.5拉流
拉流功能这里我们使用的是Bilibili开源的IJKplayer框架。再次之前我们介绍过IJKplayer框架编译和它的一些方法,我们知道IJKplayer是一个基于FFmpeg的轻量级Android视频播放器,而FFmpeg是全球领先的多媒体框架之一,它能够解码、编码、转码、流和播放大部分的视频格式。下面我们给大家介绍一下如何集成和开发。
环境配置
我们这里使用在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'
}
播放器使用
依赖集成完之后,我们根据IJKplayer提供的IMediaPlayer类,自定义一个播放器组件,代码如下
public class VideoPlayerIJK extends FrameLayout {
//由IJKplayer提供,用于播放视频,需要给他传入一个surfaceView
private IMediaPlayer mMediaPlayer = null;
//视频文件地址
private String mPath = "";
private SurfaceView surfaceView;
private VideoPlayerListener listener;
private Context mContext;
public VideoPlayerIJK(@NonNull Context context) {
super(context);
initVideoView(context);
}
public VideoPlayerIJK(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initVideoView(context);
}
public VideoPlayerIJK(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
initVideoView(context);
}
private void initVideoView(Context context) {
mContext = context;
setFocusable(true);
}
/**
* 设置视频地址。
* 根据是否第一次播放视频,做不同的操作。
* @param path 视频地址
*/
public void setVideoPath(String path) {
if (TextUtils.equals("", mPath)) {
//如果是第一次播放视频,那就创建一个新的surfaceView
mPath = path;
createSurfaceView();
} else {
//否则就直接load
mPath = path;
load();
}
}
// 新建一个surfaceview
private void createSurfaceView() {
//生成一个新的surface view
surfaceView = new SurfaceView(mContext);
surfaceView.getHolder().addCallback(new LmnSurfaceCallback());
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT
, LayoutParams.MATCH_PARENT, Gravity.CENTER);
surfaceView.setLayoutParams(layoutParams);
this.addView(surfaceView);
}
//surfaceView的监听器
private class LmnSurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//surfaceview创建成功后,加载视频
load();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
//加载视频
private void load() {
//每次都要重新创建IMediaPlayer
createPlayer();
try {
mMediaPlayer.setDataSource(mPath);
} catch (IOException e) {
e.printStackTrace();
}
//给mediaPlayer设置视图
mMediaPlayer.setDisplay(surfaceView.getHolder());
mMediaPlayer.prepareAsync();
}
//创建一个新的player
private void createPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.setDisplay(null);
mMediaPlayer.release();
}
IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
//开启硬解码
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
mMediaPlayer = ijkMediaPlayer;
if (listener != null) {
mMediaPlayer.setOnPreparedListener(listener);
mMediaPlayer.setOnInfoListener(listener);
mMediaPlayer.setOnSeekCompleteListener(listener);
mMediaPlayer.setOnBufferingUpdateListener(listener);
mMediaPlayer.setOnErrorListener(listener);
}
}
public void setListener(VideoPlayerListener listener) {
this.listener = listener;
if (mMediaPlayer != null) {
mMediaPlayer.setOnPreparedListener(listener);
}
}
//开始播放
public void start() {
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
}
//释放播放器
public void release() {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
//暂停播放
public void pause() {
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
}
//停止播放
public void stop() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
}
}
//重新播放
public void reset() {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
}
}
//获取时长
public long getDuration() {
if (mMediaPlayer != null) {
return mMediaPlayer.getDuration();
} else {
return 0;
}
}
//获取当前播放位置
public long getCurrentPosition() {
if (mMediaPlayer != null) {
return mMediaPlayer.getCurrentPosition();
} else {
return 0;
}
}
//跳到指定播放位置
public void seekTo(long l) {
if (mMediaPlayer != null) {
mMediaPlayer.seekTo(l);
}
}
}
自定义完成后,在布局文件中,加入播放器控件,代码如下
<com.troila.live.demo.widget.VideoPlayerIJK
android:id="@+id/videoViewID"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
Activity中注册界面、组件,功能设置代码如下
public class PullActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pull_view);
String urlStr = "RMTP:视频地址";
//加载so文件
try {
IjkMediaPlayer.loadLibrariesOnce(null);
IjkMediaPlayer.native_profileBegin("libijkplayer.so");
} catch (Exception e) {
this.finish();
}
VideoPlayerIJK ijkPlayer = findViewById(R.id.videoViewID);
ijkPlayer.setVideoPath(urlStr);
//播放器设置监听方法
ijkPlayer.setListener(new VideoPlayerListener() {
@Override
public void onBufferingUpdate(IMediaPlayer mp, int percent) {
}
@Override
public void onCompletion(IMediaPlayer mp) {
mp.seekTo(0);
mp.start();
}
@Override
public boolean onError(IMediaPlayer mp, int what, int extra) {
return false;
}
@Override
public boolean onInfo(IMediaPlayer mp, int what, int extra) {
if(what == IMediaPlayer.MEDIA_INFO_BUFFERING_START){
textNoDataID.setVisibility(View.VISIBLE);
ijkPlayer.setVisibility(View.GONE);
Toast.makeText(PullActivity.this,"直播结束",Toast.LENGTH_SHORT).show();
}else if(what == IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START
|| what == IMediaPlayer.MEDIA_INFO_BUFFERING_END){
textNoDataID.setVisibility(View.GONE);
ijkPlayer.setVisibility(View.VISIBLE);
Toast.makeText(PullActivity.this,"直播开始",Toast.LENGTH_SHORT).show();
}
return false;
}
@Override
public void onPrepared(IMediaPlayer mp) {
mp.start();
}
@Override
public void onSeekComplete(IMediaPlayer mp) {
}
@Override
public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) {
//获取到视频的宽和高
}
});
}
@Override
protected void onStop() {
super.onStop();
IjkMediaPlayer.native_profileEnd();
}