上一篇文章我们主要讲了视频播放器开发之前需要准备的一个知识,TextureView,用于对图像流的处理。这篇文章开始构建一个基础的视频播放器。

<>一、准备工作


在之前的文章已经说过了,播放器也是一个view,我们要在这个view上播放视频流。所以我们要自定义一个简单的viewgroup,比如继承FrameLayout。还出就是布局简单,其他控件可以往上面添加。大家见过的视频播放器的控制器都是放在视频的上方的。这样就是用FrameLayout布局是最好的。
class SmallVideoPlayer extends FrameLayout
<>二、初始化TextureView


这是一个用于承载显示‘数据流’的View,它不会创建新的窗口来显示内容。它是将内容流直接投放到View中,并且可以和其它普通View一样进行移动,旋转,缩放,动画等变化。
TextureView初始化方式如下,并且我们这个播放器View要实现其监听方法:
class SmallVideoPlayer extends FrameLayout implements
TextureView.SurfaceTextureListener private void initTextureView() { if
(mTextureView == null) { mTextureView = new TextureView(mContext);
mTextureView.setSurfaceTextureListener(this); } }
然后我们把这个TextureView添加到我们的视频播放器的view上,并且设置跟视频播放器View一样大小:
private void addTextureView() { removeView(mTextureView); LayoutParams params
= new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); addView(mTextureView, 0,
params); }
<>三、初始化播放器内核


一个公司想要实现机的播放器内核需要一定的成本,所以大部分公司都选择使用第三方的内核,比如bilibili开源的ijkplayer。ijkplayer是一个基于FFmpeg的轻量级Android/iOS视频播放器。FFmpeg的是全球领先的多媒体框架,能够解码,编码,转码,复用,解复用,流,过滤器和播放大部分的视频格式。它提供了录制、转换以及流化音视频的完整解决方案。这里我们也用它。

在项目module的gradle里面添加依赖:
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.3' implementation
'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.3' implementation
'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.3' implementation
'tv.danmaku.ijk.media:ijkplayer-x86:0.8.3'
编译成功之后我们就可以在代码里面用它了,这个也很简单一般不会出什么问题。ijplayer里面提供了一个IMediaPlayer,我们初始化它即可:
private void initMediaPlayer() { if (mMediaPlayer == null) { mMediaPlayer =
new IjkMediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } }

准备工作都做好了,我们要在什么时候开始播放呢?当然是TextureView准备好之后就可以播放了,TextuerView的draw方法中会调用TextureLayer
layer = getTextureLayer();方法,而getTextureLayer()这个方法中当surface创建成功之后会执行我们实现的接口方法:
if (mListener != null && createNewSurface) {
mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight()); }

从上面代码可以看出当我们设置了mListener,并且创建surface成功之后会为我们回调onSurfaceTextureAvailable方法,并传递给我们一个mSurface及其宽高。那我们在这个方法里播放视频就可以了:
@Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int
width, int height) { if (mSurfaceTexture == null) { mSurfaceTexture = surface;
openMediaPlayer(); } else { mTextureView.setSurfaceTexture(mSurfaceTexture); } }

我们自己创建一个SurfaceTexture对象存储TextureView给我传递的SurfaceTexture对象,然后开启视频播放。如果你自己实现了SurfaceTexture,你也可以用你自己的。
private void openMediaPlayer() { // 屏幕常亮 setKeepScreenOn(true); //
设置dataSource try { mMediaPlayer.setDataSource(mContext.getApplicationContext(),
Uri.parse(mUrl)); if (mSurface == null) { mSurface = new
Surface(mSurfaceTexture); } mMediaPlayer.setSurface(mSurface);
mMediaPlayer.prepareAsync(); } catch (IOException e) { e.printStackTrace(); } }
使用ijplayer播放视频很简单,只要为其设置数据源即可。但是为了能让视频显示出来,也就是能在view上播放出来,我们需要使用Surface。
创建对象private Surface mSurface;,传入刚才存储的SurfaceTexture对象:mSurface = new
Surface(mSurfaceTexture);,然后把这个surface对象传递给播放器即可,最后使用播放器开始播放,注意这个方法是同步的。
完成以上步骤,简单的视频播放器就可以完成了。

代码:
我们把代码进行整理如下:

播放器
public class SmallVideoPlayer extends FrameLayout implements
TextureView.SurfaceTextureListener { private TextureView mTextureView; private
SurfaceTexture mSurfaceTexture; private Surface mSurface; private AudioManager
mAudioManager; private IMediaPlayer mMediaPlayer; private Context mContext;
private String mUrl; public SmallVideoPlayer(@NonNull Context context) {
this(context, null); } public SmallVideoPlayer(@NonNull Context context,
@Nullable AttributeSet attrs) { this(context, attrs, -1); } public
SmallVideoPlayer(@NonNull Context context, @Nullable AttributeSet attrs, int
defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext = context; }
public void setUp(String url) { mUrl = url; } public void start() {
initAudioManager(); initMediaPlayer(); initTextureView(); addTextureView(); }
private void initAudioManager() { if (mAudioManager == null) { mAudioManager =
(AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mAudioManager.requestAudioFocus(new
AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).build()); } else {
mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN); } } } private void initMediaPlayer() { if
(mMediaPlayer == null) { mMediaPlayer = new IjkMediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } } private void
initTextureView() { if (mTextureView == null) { mTextureView = new
TextureView(mContext); mTextureView.setSurfaceTextureListener(this); } }
private void addTextureView() { removeView(mTextureView); LayoutParams params =
new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); addView(mTextureView, 0,
params); } @Override public void onSurfaceTextureAvailable(SurfaceTexture
surface, int width, int height) { if (mSurfaceTexture == null) {
mSurfaceTexture = surface; openMediaPlayer(); } else {
mTextureView.setSurfaceTexture(mSurfaceTexture); } } private void
openMediaPlayer() { // 屏幕常亮 setKeepScreenOn(true); // 设置dataSource try {
mMediaPlayer.setDataSource(mContext.getApplicationContext(), Uri.parse(mUrl)/*,
mHeaders*/); if (mSurface == null) { mSurface = new Surface(mSurfaceTexture); }
mMediaPlayer.setSurface(mSurface); mMediaPlayer.prepareAsync(); } catch
(IOException e) { e.printStackTrace(); } } @Override public void
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { }
@Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return mSurfaceTexture == null; } @Override public void
onSurfaceTextureUpdated(SurfaceTexture surface) { } }
使用布局:
在activity中的布局加上即可
<com.example.ycm.smallvideoplayer.smallvideoplayer.SmallVideoPlayer
android:id="@+id/small_video_player" android:layout_width="match_parent"
android:layout_height="200dp" />
在activity中获取播放器view,然后设置一个视频URL,开启播放即可。
SmallVideoPlayer mSmallVideoPlayer; = findViewById(R.id.small_video_player);
mSmallVideoPlayer.setUp("http://tanzi27niu.cdsb.mobi/wps/wp-content/uploads/2017/05/2017-05-17_17-33-30.mp4");
mSmallVideoPlayer.start();

以上就完成了视频播放器的初体验。其实你会发现这是多么简单啊。实际上来说一个高级开发人员并没有比你高明多少,他们比你多的其实只是经验和思路。所以想要从初中级开发跳跃到高级开发,需要你不断的思考,独立实现业务需求。如果给你一个大模块,你能利用你的知识,和网络获取的资料就能实现,你离高级开发工程师就不远了。

<>推荐阅读

Android进阶:自定义视频播放器开发(上)
<https://blog.csdn.net/weixin_43902172/article/details/89035368>

<>福利

需要相关教学视频及源码,可以点击链接加入群聊【Android技术开发交流】:
https://jq.qq.com/?_wv=1027&k=5PWTvm9,找群管理免费领取一下,欢迎进群一起学习交流
<https://jq.qq.com/?_wv=1027&k=5PWTvm9%EF%BC%8C%E6%89%BE%E7%BE%A4%E7%AE%A1%E7%90%86%E5%85%8D%E8%B4%B9%E9%A2%86%E5%8F%96%E4%B8%80%E4%B8%8B%EF%BC%8C%E6%AC%A2%E8%BF%8E%E8%BF%9B%E7%BE%A4%E4%B8%80%E8%B5%B7%E5%AD%A6%E4%B9%A0%E4%BA%A4%E6%B5%81>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信