Android 视频播放之MediaPlayer+SurfaceView

之前用Android系统提供的视频播放组件VideoView实现了播放视频的功能,当然,Android播放视频不只有一种实现方式,今天就记录另一种播放视频的demo。

点击下载

1、效果图:

这里写图片描述

这里简单一点,就放一张图片吧,视频资源前两天不小心删掉了,也就显示不出来,不过功能是没问题的。

2、分析代码:

主界面SurfaceViewVideoActivity.java:

/**
 * SurfaceViewVideoActivity 2016-10-13
 */
public class SurfaceViewVideoActivity extends Activity implements
        OnClickListener {

    private Button startplay_btn;// 播放
    private Button pauseplay_btn;// 暂停
    private Button restartplay_btn;// 继续播放
    private SurfaceView surfaceview_video;// 播放显示
    private ImageView imageplay;
    private SeekBar seekbar;
    /**
     * 播放路径
     */
    private String pathString;

    /**
     * surfaceView播放控制
     */
    private SurfaceHolder surfaceHolder;

    /**
     * 播放视频
     */
    private MediaPlayer mediaPlayer = null;

    /**
     * 屏幕的宽度和高度
     */
    private int screenWidth, screenHeight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_surfaceviewvideo_activity);
        initView();
        loadData();
    }

    @Override
    public void onClick(View view) {
        // TODO Auto-generated method stub
        switch (view.getId()) {
        case R.id.startplay_btn:
            playVideo(pathString);
            break;

        case R.id.pauseplay_btn:
            mediaPalyPause();
            break;

        case R.id.restartplay_btn:
            mediaPlayRestart();
            break;

        }
    }

    // 加载数据
    @SuppressLint("NewApi")
    private void loadData() {
        imageplay.setVisibility(View.VISIBLE);
        surfaceview_video.setVisibility(View.GONE);
        String path = null;
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            // 存在获取外部文件路径
            path = Environment.getExternalStorageDirectory().getPath();
        } else {
            // 不存在获取内部存储
            path = Environment.getDataDirectory().getPath();
        }
        pathString = path + "/test.mp4";

        Bitmap bitmap = null;
        // 获取视频缩略图
        try {
            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
            retriever.setDataSource(pathString);
            bitmap = retriever.getFrameAtTime();
            if (bitmap != null) {
                imageplay.setImageBitmap(bitmap);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    // 初始化视图
    @SuppressWarnings("deprecation")
    private void initView() {
        startplay_btn = (Button) findViewById(R.id.startplay_btn);
        pauseplay_btn = (Button) findViewById(R.id.pauseplay_btn);
        startplay_btn.setOnClickListener(this);
        pauseplay_btn.setOnClickListener(this);
        surfaceview_video = (SurfaceView) findViewById(R.id.surfaceview_video);
        imageplay = (ImageView) findViewById(R.id.imageplay);
        restartplay_btn = (Button) findViewById(R.id.restartplay_btn);
        restartplay_btn.setOnClickListener(this);
        seekbar = (SeekBar) findViewById(R.id.seekbar);
        // 设置surfaceHolder
        surfaceHolder = surfaceview_video.getHolder();
        // 设置Holder类型,该类型表示surfaceView自己不管理缓存区
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // 设置surface回调
        surfaceHolder.addCallback(new SurfaceCallBack());
        // 设置拖动事件
        seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

            @Override
            public void onStopTrackingTouch(SeekBar arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onStartTrackingTouch(SeekBar arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress,
                    boolean fromUser) {
                // TODO Auto-generated method stub
                if (mediaPlayer != null) {
                    if (progress >= 0) {
                        // 如果是用户手动拖动控件,则设置视频跳转。
                        if (fromUser) {
                            // 设置进度
                            mediaPlayer.seekTo(progress);
                        }
                    }
                }
            }
        });
    }

    // 设置SurfaceView的回调监听
    private class SurfaceCallBack implements SurfaceHolder.Callback {

        @Override
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                int arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void surfaceCreated(SurfaceHolder arg0) {
            // surfaceView被创建

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder arg0) {
            // surfaceView销毁,同时销毁mediaPlayer
            if (mediaPlayer != null) {
                mediaPlayer.release();
                mediaPlayer = null;
            }
        }

    }

    /**
     * 播放视频
     */
    public void playVideo(String path) {
        imageplay.setVisibility(View.GONE);
        surfaceview_video.setVisibility(View.VISIBLE);
        if (mediaPlayer == null) {
            // 初始化MediaPaly
            mediaPlayer = new MediaPlayer();
            // 开始时设置为0
            seekbar.setProgress(0);
            mediaPlayer.seekTo(0);
            // 重置MediaPlay
            mediaPlayer.reset();
            try {
                // 设置视频资源路径
                mediaPlayer.setDataSource(path);
                // 设置媒体加载完成监听
                mediaPlayer.prepareAsync();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // 设置声音效果
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            // 设置播放完成监听
            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer arg0) {
                    // 播放完成
                    if (mediaPlayer != null) {
                        mediaPlayer.release();
                        mediaPlayer = null;
                        // mediaPlayer.seekTo(0);
                    }
                    imageplay.setVisibility(View.VISIBLE);
                    surfaceview_video.setVisibility(View.GONE);
                }
            });
            // 设置媒体加载完成监听
            mediaPlayer.setOnPreparedListener(new OnPreparedListener() {

                @Override
                public void onPrepared(MediaPlayer arg0) {
                    // 开始播放
                    mediaPlayer.start();
                    // 视频显示到屏幕上SurfaceView
                    mediaPlayer.setDisplay(surfaceHolder);
                    // 设置视频播放的大小
                    setDisplayMetrics();
                    // 设置SeekBar的最大进度
                    seekbar.setMax(mediaPlayer.getDuration());
                    // 开启线程 刷新进度条
                    new Thread(runnable).start();
                }
            });
        }
    }

    private Runnable runnable = new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                seekbar.setProgress(mediaPlayer.getCurrentPosition());
            }
        }
    };

    /**
     * 暂停
     */
    private void mediaPalyPause() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }
    }

    /**
     * 继续播放
     */
    public void mediaPlayRestart() {
        if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
            mediaPlayer.start();
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            // 销毁时,如果正在播放,则停止。
            mediaPlayer.stop();
            mediaPlayer = null;
        }
    }

    // 设置video surface窗口的大小
    public void setDisplayMetrics() {
        // 获取屏幕的宽度和高度
        DisplayMetrics displayMetrics = new DisplayMetrics();
        this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        screenWidth = displayMetrics.widthPixels;
        screenHeight = displayMetrics.heightPixels;
        // 获取视频的大小
        // 获取视频的宽度和高度
        int width = mediaPlayer.getVideoWidth();
        int height = mediaPlayer.getVideoHeight();
        if (width > screenWidth || height > screenHeight) {
            // 计算出宽高的倍数
            float vWidth = (float) width / (float) screenWidth;
            float vHeight = (float) height / (float) screenHeight;
            // 获取最大的倍数值,按大数值进行缩放
            float max = Math.max(vWidth, vHeight);
            // 计算出缩放大小,取接近的正值
            width = (int) Math.ceil((float) width / max);
            height = (int) Math.ceil((float) height / max);
        }
        // 设置SurfaceView的大小并居中显示
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                width, height);
        layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        surfaceview_video.setLayoutParams(layoutParams);

        // 全屏
        // RelativeLayout.LayoutParams layoutParams = new
        // RelativeLayout.LayoutParams(screenWidth,
        // screenHeight);
        // layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        // surfaceview_video.setLayoutParams(layoutParams);
    }

}

上面的代码中有几行是可以作为新知识学习的:

Bitmap bitmap = null;
        // 获取视频缩略图
        try {
            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
            retriever.setDataSource(pathString);
            bitmap = retriever.getFrameAtTime();
            if (bitmap != null) {
                imageplay.setImageBitmap(bitmap);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }

这里的功能是截取到视频的第一帧,展示到图片控件上,我们也可以试着获取视频的中间某一部分,指定那一刻时间点,方法为retriever.getFrameAtTime(timeUs)retriever.getFrameAtTime(timeUs, option)

看源码参数介绍:

这里写图片描述

意思是指该时间点的播放帧会被截取到,系统不会保证指定的这个位置position正好是一帧,如果这个位置不正好是播放帧,那么会截取距离此位置最近的一帧用来返回bitmap。时间格式不正确的话,这个参数就会被忽略。这个功能很有用哦,像progressbar拖拽时在其上面出现的每一帧都是对应的progressbar的位置,有很多播放器像搜狐都是用的这个思路吧。

另外,其实MediaPlayer还可以设置声音的效果:

// 设置声音效果
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

这里还有其他效果是可以获取的:

这里写图片描述

警告、音乐、通知、铃声、系统声音等等。

最后有一个记录播放位置的变量,封装到Constants.java里边了:

public class Constants {
    /**
     * 记录播放位置
     */
    public static int playPosition=-1;
}

布局文件 layout_surfaceviewvideo_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/startplay_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="播放" />

        <Button
            android:id="@+id/pauseplay_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="暂停" />

        <Button
            android:id="@+id/restartplay_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="继续播放" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="300dp" >

            <ImageView
                android:id="@+id/imageplay"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="fitXY"
                android:visibility="gone" />

            <SurfaceView
                android:id="@+id/surfaceview_video"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:visibility="gone" />
        </RelativeLayout>

        <SeekBar
            android:id="@+id/seekbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true" />
    </LinearLayout>

</LinearLayout>

上述代码就是实现视频播放的全过程了,简单易学,最后附上源码地址:

点击下载

祝大家学习快乐,每天都能进步一点点!(^__^) 嘻嘻……

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值