Android提供了常见的视频的编码、解码机制。使用Android自带的MediaPlayer、MediaController等类可以很方便的实现视频播放的功能。支持的视频格式有MP4和3GP等。这些多媒体数据可以来自于Android应用的资源文件,也可以来自于外部存储器上的文件,甚至可以是来自于网络上的文件流。

下面来说一下视频播放的几种实现方式:

1、MediaController+VideoView实现方式

这种方式是最简单的实现方式。VideoView继承了SurfaceView同时实现了MediaPlayerControl接口,MediaController则是安卓封装的辅助控制器,带有暂停,播放,停止,进度条等控件。通过VideoView+MediaController可以很轻松的实现视频播放、停止、快进、快退等功能。

布局文件如下:

<?xml version="1.0" encoding="utf-8"?>    

程序代码如下:

public class VideoViewTestActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_video_view_test);        VideoView videoView = (VideoView)findViewById(R.id.videoView);    //加载指定的视频文件        String path = Environment.getExternalStorageDirectory().getPath()+"/20180730.mp4";        videoView.setVideoPath(path);        //创建MediaController对象        MediaController mediaController = new MediaController(this);    //VideoView与MediaController建立关联        videoView.setMediaController(mediaController);    //让VideoView获取焦点        videoView.requestFocus();    }}

使用此实现方式的步骤:

  1. 加载指定的视频文件
  2. 建立VideoView和MediaController之间的关联,这样就不需要自己去控制视频的播放、暂停等。让MediaController控制即可。
  3. VideoView获取焦点。

实现效果图如下:

界面中的快退、播放、快进、时间、进度条等是由MediaController提供的。

2、MediaPlayer+SurfaceView+自定义控制器

虽然VideoView的实现方式很简单,但是由于是自带的封装好的类,所以无论是播放器的大小、位置以及控制都不受我们控制。

这种实现方式步骤如下

  1. 创建MediaPlayer对象,并让它加载指定的视频文件。可以是应用的资源文件本地文件路径、或者URL。
  2. 在界面布局文件中定义SurfaceView组件,并为SurfaceView的SurfaceHolder添加Callback监听器。
  3. 调用MediaPlayer对象的setDisplay(SurfaceHolder sh)将所播放的视频图像输出到指定的SurfaceView组件
  4. 调用MediaPlayer对象的prepareAsync()或prepare()方法装载流媒体文件
  5. 调用MediaPlayer对象的start()stop()和pause()方法来控制视频的播放

在实现第二步之前需要先给surfaceHolder设置一个callbackcallback的3个回调函数如下:

@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}

布局文件如下:

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                

程序代码如下:

public class PlayVideoActivity extends AppCompatActivity implements SurfaceHolder.Callback,        MediaPlayer.OnPreparedListener,        MediaPlayer.OnCompletionListener,        MediaPlayer.OnErrorListener,        MediaPlayer.OnInfoListener, View.OnClickListener,        MediaPlayer.OnSeekCompleteListener,        MediaPlayer.OnVideoSizeChangedListener,        SeekBar.OnSeekBarChangeListener,{    private ImageView playOrPauseIv;    private SurfaceView videoSuf;    private MediaPlayer mPlayer;    private SeekBar mSeekBar;    private String path;    private RelativeLayout rootViewRl;    private LinearLayout controlLl;    private TextView startTime, endTime;    private ImageView forwardButton, backwardButton;    private boolean isShow = false;    public static final int UPDATE_TIME = 0x0001;    public static final int HIDE_CONTROL = 0x0002;    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case UPDATE_TIME:                    updateTime();                    mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 500);                    break;                case HIDE_CONTROL:                    hideControl();                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_play_video);        initViews();        initData();        initSurfaceView();        initPlayer();        initEvent();    }    private void initData() {        path = Environment.getExternalStorageDirectory().getPath() + "/20180730.mp4";//这里写上你的视频地址    }    private void initEvent() {        playOrPauseIv.setOnClickListener(this);        rootViewRl.setOnClickListener(this);        rootViewRl.setOnTouchListener(this);        forwardButton.setOnClickListener(this);        backwardButton.setOnClickListener(this);        mSeekBar.setOnSeekBarChangeListener(this);    }    private void initSurfaceView() {        videoSuf = (SurfaceView) findViewById(R.id.surfaceView);        videoSuf.setZOrderOnTop(false);        videoSuf.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        videoSuf.getHolder().addCallback(this);    }    private void initPlayer() {        mPlayer = new MediaPlayer();        mPlayer.setOnCompletionListener(this);        mPlayer.setOnErrorListener(this);        mPlayer.setOnInfoListener(this);        mPlayer.setOnPreparedListener(this);        mPlayer.setOnSeekCompleteListener(this);        mPlayer.setOnVideoSizeChangedListener(this);        try {            //使用手机本地视频            mPlayer.setDataSource(path);        } catch (Exception e) {            e.printStackTrace();        }    }    private void initViews() {        playOrPauseIv = (ImageView) findViewById(R.id.playOrPause);        startTime = (TextView) findViewById(R.id.tv_start_time);        endTime = (TextView) findViewById(R.id.tv_end_time);        mSeekBar = (SeekBar) findViewById(R.id.tv_progess);        rootViewRl = (RelativeLayout) findViewById(R.id.root_rl);        controlLl = (LinearLayout) findViewById(R.id.control_ll);        forwardButton = (ImageView) findViewById(R.id.tv_forward);        backwardButton = (ImageView) findViewById(R.id.tv_backward);    }    @Override    public void surfaceCreated(SurfaceHolder holder) {        mPlayer.setDisplay(holder);        mPlayer.prepareAsync();    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {    }    @Override    public void onPrepared(MediaPlayer mp) {        startTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getCurrentPosition()));        endTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getDuration()));        mSeekBar.setMax(mp.getDuration());        mSeekBar.setProgress(mp.getCurrentPosition());    }    @Override    public void onCompletion(MediaPlayer mp) {    }    @Override    public boolean onError(MediaPlayer mp, int what, int extra) {        return false;    }    @Override    public boolean onInfo(MediaPlayer mp, int what, int extra) {        return false;    }    private void play() {        if (mPlayer == null) {            return;        }        Log.i("playPath", path);        if (mPlayer.isPlaying()) {            mPlayer.pause();            mHandler.removeMessages(UPDATE_TIME);            mHandler.removeMessages(HIDE_CONTROL);            playOrPauseIv.setVisibility(View.VISIBLE);            playOrPauseIv.setImageResource(android.R.drawable.ic_media_play);        } else {            mPlayer.start();            mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 500);            mHandler.sendEmptyMessageDelayed(HIDE_CONTROL, 5000);            playOrPauseIv.setVisibility(View.INVISIBLE);            playOrPauseIv.setImageResource(android.R.drawable.ic_media_pause);        }    }    @Override    public void onSeekComplete(MediaPlayer mp) {        //TODO    }    @Override    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.tv_backward:                backWard();                break;            case R.id.tv_forward:                forWard();                break;            case R.id.playOrPause:                play();                break;            case R.id.root_rl:                showControl();                break;        }    }    /**     * 更新播放时间     */    private void updateTime() {                        startTime.setText(FormatTimeUtil.formatLongToTimeStr(                          mPlayer.getCurrentPosition()));        mSeekBar.setProgress(mPlayer.getCurrentPosition());    }    /**     * 隐藏进度条     */    private void hideControl() {        isShow = false;        mHandler.removeMessages(UPDATE_TIME);        controlLl.animate().setDuration(300).translationY(controlLl.getHeight());    }    /**     * 显示进度条     */    private void showControl() {        if (isShow) {            play();        }        isShow = true;        mHandler.removeMessages(HIDE_CONTROL);        mHandler.sendEmptyMessage(UPDATE_TIME);        mHandler.sendEmptyMessageDelayed(HIDE_CONTROL, 5000);        controlLl.animate().setDuration(300).translationY(0);    }    /**     * 设置快进10秒方法     */    private void forWard(){        if(mPlayer != null){            int position = mPlayer.getCurrentPosition();            mPlayer.seekTo(position + 10000);        }    }    /**     * 设置快退10秒的方法     */    public void backWard(){        if(mPlayer != null){            int position = mPlayer.getCurrentPosition();            if(position > 10000){                position-=10000;            }else{                position = 0;            }            mPlayer.seekTo(position);        }    }    //OnSeekBarChangeListener    @Override    public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {        if(mPlayer != null && b){             mPlayer.seekTo(progress);        }    }    @Override    public void onStartTrackingTouch(SeekBar seekBar) {    }    @Override    public void onStopTrackingTouch(SeekBar seekBar) {    }}

注意事项:MediaPlayer有prepareprepareAsync两种方法。这两种方法的区别是:prepare方法是将资源同步缓存到内存中,一般加载本地较小的资源可以用这个,如果是较大的资源或者网络资源建议使用prepareAsync方法,异步加载

实现效果如下所示:

3、MediaPlayer+SurfaceView+MediaController

第二种实现方式使用的是自定义控件,MediaPlayer+SurfaceView也可以使用系统自带的MediaController控制器。

使用这个方式实现,布局文件只需一个SurfaceView即可,其他的控件都交给MediaController控制器,布局文件如下:

<?xml version="1.0" encoding="utf-8"?>    

程序代码如下:

public class MediaControllerTestActivity extends Activity implements        MediaController.MediaPlayerControl,        MediaPlayer.OnBufferingUpdateListener,        SurfaceHolder.Callback{    private MediaPlayer mediaPlayer;    private MediaController controller;    private int bufferPercentage = 0;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_media_controller_test);        mediaPlayer = new MediaPlayer();        controller = new MediaController(this);        controller.setAnchorView(findViewById(R.id.root_ll));        initSurfaceView();    }    private void initSurfaceView() {        SurfaceView videoSuf = (SurfaceView) findViewById(R.id.controll_surfaceView);        videoSuf.setZOrderOnTop(false);        videoSuf.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        videoSuf.getHolder().addCallback(this);    }    @Override    protected void onResume() {        super.onResume();        try {            String path = Environment.getExternalStorageDirectory().getPath() + "/20180730.mp4";            mediaPlayer.setDataSource(path);            mediaPlayer.setOnBufferingUpdateListener(this);            //mediaPlayer.prepare();            controller.setMediaPlayer(this);            controller.setEnabled(true);        }catch (IOException e){            e.printStackTrace();        }    }    @Override    protected void onPause() {        super.onPause();        if (mediaPlayer.isPlaying()){            mediaPlayer.stop();        }    }    @Override    protected void onDestroy() {        super.onDestroy();        if (null != mediaPlayer){            mediaPlayer.release();            mediaPlayer = null;        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        controller.show();        return super.onTouchEvent(event);    }    //MediaPlayer    @Override    public void onPointerCaptureChanged(boolean hasCapture) {    }    //MediaPlayerControl    @Override    public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {        bufferPercentage = i;    }    @Override    public void start() {        if (null != mediaPlayer){            mediaPlayer.start();        }    }    @Override    public void pause() {        if (null != mediaPlayer){            mediaPlayer.pause();        }    }    @Override    public int getDuration() {        return mediaPlayer.getDuration();    }    @Override    public int getCurrentPosition() {        return mediaPlayer.getCurrentPosition();    }    @Override    public void seekTo(int i) {        mediaPlayer.seekTo(i);    }    @Override    public boolean isPlaying() {        if (mediaPlayer.isPlaying()){            return true;        }        return false;    }    @Override    public int getBufferPercentage() {        return bufferPercentage;    }    @Override    public boolean canPause() {        return true;    }    @Override    public boolean canSeekBackward() {        return true;    }    @Override    public boolean canSeekForward() {        return true;    }    @Override    public int getAudioSessionId() {        return 0;    }    //SurfaceHolder.callback    @Override    public void surfaceCreated(SurfaceHolder surfaceHolder) {        mediaPlayer.setDisplay(surfaceHolder);        mediaPlayer.prepareAsync();    }    @Override    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {    }    @Override    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {    }}

效果图如下:

更多流媒体资讯,请关注小牛安卓干货铺,将进行不定期推送。

更多相关文章

  1. Android中的资源与国际化
  2. Android自定义实现圆形播放进度条
  3. Android系统做了哪些优化?
  4. android R 文件生成不了
  5. Android(安卓)4.4.2 exfat 移植
  6. Android基础开发之手势识别
  7. 浅谈Java中Collections.sort对List排序的两种方法
  8. NPM 和webpack 的基础使用
  9. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程

随机推荐

  1. Android中socket(tcp|udp),websocket基本
  2. Android(安卓)Camera数据流分析全程记录
  3. Accessibility辅助功能--一念天堂,一念地
  4. AsyncTask研究(以Android(安卓)10.0为准)
  5. android frida 检测_Android逆向之hook框
  6. Android(安卓)Power Management
  7. Android高级开发面试题以及笞案整理
  8. Android(安卓)TextView 属性设置
  9. Android开发新选择:Kotlin
  10. Android(安卓)init.rc