Android进阶:十一、视频播放器初体验

上一篇文章我们主要讲了视频播放器开发之前需要准备的一直个知识,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();

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

下一期,我会为大家梳理播放器更多的情况,甚至为视频播放器添加一个控制器
喜欢本文章,或者我的系列性文章的话,欢迎关注我

原文地址:https://blog.51cto.com/14295695/2391268

时间: 2024-08-29 10:02:52

Android进阶:十一、视频播放器初体验的相关文章

Android进阶 自定义视频播放器

随着快手,抖音,西瓜视频等视频APP的崛起,视频播放已经成为主流,此时作为Android研发的你,想要提高自己的能力还不知道怎么开发视频播放器怎么行?所以今天就带着大家一起开发一个简易播放器:SmallVideoPlayer 一.需求分析 我们观察一个视频播放器,可以看到视频播放器除了正在播放的视频还有很多控件,比如播放按钮,暂停按钮,播放进度条,播放计时器等.这么多控件显然无法播放视频,但是他们都在控制视频的播放.由此可见视频播放器可以分为两层,一层为视频播放器控制层,一层为真正的视频播放层.

android多媒体(视频播放器)

##视频处理 一丶VideoView控件 点击创建一个播放器并播放视频 /**     * 播放视频     * @param view     */    public void play(View view){                vv.setVideoPath(path);        vv.start();        vv.seekTo(currentPositon);//从停的位置开始播放    }    /**     * 暂停播放     * @param view

【Android开发经验】Android Studio1.0正式版初体验——常用功能使用指南

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 上一篇文章中,我们把Android Studio的平台都搭建起来了,这一篇文章,将介绍Android Studio的一些常用的功能介绍.下面要介绍的功能是最常用的,但是肯定不全,如果你有什么其他的疑问,可以给我留言,解决之后我会告诉你. 1.如何导入Eclipse项目创建的项目 我们之前的项目基本都是Eclipse创建的,如果我现在想用Android Studio来管理,我们应该怎么做呢? 首先,在Ecl

android防反编译技术初体验——混淆

这几天做项目要做混淆,所以搜集资料学习了下,这次主要记录混淆的步骤,如有需要改正和完善的地方,还麻烦能够指出,大家共同进步o(* ̄▽ ̄*)ブ 1.项目防反编译技术步骤: a) 加密. b) 混淆. c) 加壳(加固); 2.加密:对信息进行摘要计算,然后摘要值用私钥进行验签,重要数据使用rsa非对称加密: 3.混淆:Android Studio开发工具自身集成了Java语言的ProGuard技术,对java代码有压缩.优化.混淆.预检的功能,AcFlash项目的Android端使用了ProGua

【Android开发经验】Android Studio1.0正式版初体验——Mac/Window双平台安装指南

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 自从谷歌在2013年的I/O大会上推出Android Studio(下称AS)之后, 测试版一直在不断更新,我也一直在关注着这款开发工具的动态.在前几天谷歌终于发布了AS的正式版,并且鼓励Android开发者从Eclipse转向这款新的开发工具.对于国内的开发者来说,由于使用习惯和团队工作的关系,可能短期内不会转向AS,但是从长远来看,我感觉AS一定会取代Eclipse的,因为Eclipse的占用内存大.

处女男学Android(十一)---Gallery、ViewPager和ViewPager+Fragment实现的Tab导航

一.前言 有阵子没更新博客了,主要是最近公司接了个P2P的金融借贷项目没人做,被拉去写服务端,所以迟迟没时间继续学习大安卓,想了想自己的安卓水平和公司的专业安卓璟博比起来依旧差距挺大,于是乎我要加把劲赶上才行,所以继续翻开李刚疯狂讲义系列,看到Gallery这个控件了,大致功能是横向滚动查看列表项,再仔细看了一下居然过时了,官方推荐用ViewPager来替代,还没学就过时了,有点不爽,干脆新的旧的一起学习一下,也好进行一下比较吧.废话不多说,首先是已经过时的Gallery. 二.画廊视图Gall

Android进阶:自定义视频播放器开发(下)

上一篇文章我们主要讲了视频播放器开发之前需要准备的一个知识,TextureView,用于对图像流的处理.这篇文章开始构建一个基础的视频播放器. 一.准备工作 在之前的文章已经说过了,播放器也是一个view,我们要在这个view上播放视频流.所以我们要自定义一个简单的viewgroup,比如继承FrameLayout.还出就是布局简单,其他控件可以往上面添加.大家见过的视频播放器的控制器都是放在视频的上方的.这样就是用FrameLayout布局是最好的. class SmallVideoPlaye

Android进阶:自定义视频播放器开发(上)

随着快手,抖音,西瓜视频等视频APP的崛起,视频播放已经成为主流,此时作为Android研发的你,想要提高自己的能力还不知道怎么开发视频播放器怎么行?所以今天就带着大家一起开发一个简易播放器:SmallVideoPlayer 需求分析 我们观察一个视频播放器,可以看到视频播放器除了正在播放的视频还有很多控件,比如播放按钮,暂停按钮,播放进度条,播放计时器等.这么多控件显然无法播放视频,但是他们都在控制视频的播放.由此可见视频播放器可以分为两层,一层为视频播放器控制层,一层为真正的视频播放层. 所

Android Studio 初体验

Google在I/O2013大会上公布了Android新的开发工具Android Studio,趁周末时间做了一下尝试.有须要的能够 在http://developer.android.com/sdk/installing/studio.html下载,当前版本号是V0.1.官方解释:Android Studio is a new Android development environment based on IntelliJ IDEA. Similar to Eclipse with the