Android播放器的三种实现方法

转载自:http://blog.csdn.net/wozuihaole/article/details/60867076

今天来说一下Android中怎么实现视频播放,我主要说三种:

1.MediaPlayer+SurfaceView;

2.VideoView;

3.Vitamio框架。


1.MediaPlayer+SurfaceView这种方法是基础,后面的两种方法其实就是把这种方法封装了一下,使用起来更方便些。

我认为大家基本都会用MediaPlayer这个API,我们都知道MediaPlayer是媒体播放器,可以播放音频,视频其实就是给音频配上影像,而SurfaceView就是给音频配上影像的工具,我们只需要把SurfaceView与MediaPlayer关联起来就行了。

主要代码:

SurfaceHolder holder = SurfaceView.getHolder();
MediaPlayer.setDisplay(holder);//将影像播放控件与媒体播放控件关联起来
我认为之前不知道的代码可能只有这两句。

布局代码:

 效果图

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.video.MainActivity"
    android:layout_margin="10dp"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入文件名称例如:aa.mp4,务必确保文件放在sdcard目录下"/>

    <SurfaceView
        android:id="@+id/sfv"
        android:layout_width="match_parent"
        android:layout_marginTop="10dp"
        android:layout_height="200dp" />

    <SeekBar
        android:id="@+id/sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"/>

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

        <Button
            android:id="@+id/play"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="1"
            android:onClick="play"
            android:text="播放"/>

        <Button
            android:id="@+id/pause"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_marginLeft="10dp"
            android:layout_weight="1"
            android:onClick="pause"
            android:text="暂停"/>

        <Button
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_marginLeft="10dp"
            android:layout_weight="1"
            android:onClick="stop"
            android:text="停止"/>

        <Button
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_marginLeft="10dp"
            android:layout_weight="1"
            android:onClick="replay"
            android:text="重播"/>

    </LinearLayout>

</LinearLayout>

完整代码+注释:

package com.example.video;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 需要注意的是我实验了.mp4,3gp和avi3种格式的视频,在5.1的真机和模拟器上avi格式都是只有声音没有影像,其他两种格式
 * 播放正常。
 */

public class MainActivity extends Activity {

    private SurfaceView sfv;//能够播放图像的控件
    private SeekBar sb;//进度条
    private String path ;//本地文件路径
    private SurfaceHolder holder;
    private MediaPlayer player;//媒体播放器
    private Button Play;//播放按钮
    private Timer timer;//定时器
    private TimerTask task;//定时器任务
    private int position = 0;
    private EditText et;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }

    //初始化控件,并且为进度条和图像控件添加监听
    private void initView() {
        sfv = (SurfaceView) findViewById(R.id.sfv);
        sb = (SeekBar) findViewById(R.id.sb);
        Play = (Button) findViewById(R.id.play);
        et = (EditText) findViewById(R.id.et);
        Play.setEnabled(false);

        holder = sfv.getHolder();
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                //当进度条停止拖动的时候,把媒体播放器的进度跳转到进度条对应的进度
                if (player != null) {
                    player.seekTo(seekBar.getProgress());
                }
            }
        });

        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                //为了避免图像控件还没有创建成功,用户就开始播放视频,造成程序异常,所以在创建成功后才使播放按钮可点击
                Log.d("zhangdi","surfaceCreated");
                Play.setEnabled(true);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                Log.d("zhangdi","surfaceChanged");
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                //当程序没有退出,但不在前台运行时,因为surfaceview很耗费空间,所以会自动销毁,
                // 这样就会出现当你再次点击进程序的时候点击播放按钮,声音继续播放,却没有图像
                //为了避免这种不友好的问题,简单的解决方式就是只要surfaceview销毁,我就把媒体播放器等
                //都销毁掉,这样每次进来都会重新播放,当然更好的做法是在这里再记录一下当前的播放位置,
                //每次点击进来的时候把位置赋给媒体播放器,很简单加个全局变量就行了。
                Log.d("zhangdi","surfaceDestroyed");
                if (player != null) {
                    position = player.getCurrentPosition();
                    stop();
                }
            }
        });
    }

    private void play() {

        Play.setEnabled(false);//在播放时不允许再点击播放按钮

        if (isPause) {//如果是暂停状态下播放,直接start
            isPause = false;
            player.start();
            return;
        }

        path = Environment.getExternalStorageDirectory().getPath()+"/";
        path = path + et.getText().toString();//sdcard的路径加上文件名称是文件全路径
        File file = new File(path);
        if (!file.exists()) {//判断需要播放的文件路径是否存在,不存在退出播放流程
            Toast.makeText(this,"文件路径不存在",Toast.LENGTH_LONG).show();
            return;
        }

        try {
            player = new MediaPlayer();
            player.setDataSource(path);
            player.setDisplay(holder);//将影像播放控件与媒体播放控件关联起来

            player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {//视频播放完成后,释放资源
                    Play.setEnabled(true);
                    stop();
                }
            });

            player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    //媒体播放器就绪后,设置进度条总长度,开启计时器不断更新进度条,播放视频
                    Log.d("zhangdi","onPrepared");
                    sb.setMax(player.getDuration());
                    timer = new Timer();
                    task = new TimerTask() {
                        @Override
                        public void run() {
                            if (player != null) {
                                int time = player.getCurrentPosition();
                                sb.setProgress(time);
                            }
                        }
                    };
                    timer.schedule(task,0,500);
                    sb.setProgress(position);
                    player.seekTo(position);
                    player.start();
                }
            });

            player.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void play(View v) {
        play();
        Log.d("zhangdi",path);
    }

    private boolean isPause;
    private void pause() {
        if (player != null && player.isPlaying()) {
            player.pause();
            isPause = true;
            Play.setEnabled(true);
        }
    }

    public void pause(View v) {
        pause();
    }

    private void replay() {
        isPause = false;
        if (player != null) {
            stop();
            play();
        }
    }

    public void replay(View v) {
        replay();
    }

    private void stop(){
        isPause = false;
        if (player != null) {
            sb.setProgress(0);
            player.stop();
            player.release();
            player = null;
            if (timer != null) {
                timer.cancel();
            }
            Play.setEnabled(true);
        }
    }

    public void stop(View v) {
        stop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stop();
    }
}

2.VideoView 系统自带的视频播放控件,自带进度条、暂停、播放等功能,使用起来十分简单,只需要为控件设置好播放路径,监听是否准备就绪,就绪后直接播放就可以了。

  效果图

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.video.Main2Activity"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/et1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:hint="请输入文件名"/>

        <Button
            android:id="@+id/btn"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="确定"/>
    </LinearLayout>

    <VideoView
        android:id="@+id/video"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layout_marginTop="10dp"/>

</LinearLayout>

完整代码:

package com.example.video;

import android.app.Activity;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.MediaController;
import android.widget.VideoView;

import java.net.URI;

public class Main2Activity extends Activity {

    private VideoView video;
    private EditText et;
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        initView();
    }

    private void initView() {
        et = (EditText) findViewById(R.id.et1);
        video = (VideoView) findViewById(R.id.video);
        btn = (Button) findViewById(R.id.btn);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String path = Environment.getExternalStorageDirectory().getPath()+"/"+et.getText().toString();//获取视频路径
                Uri uri = Uri.parse(path);//将路径转换成uri
                video.setVideoURI(uri);//为视频播放器设置视频路径
                video.setMediaController(new MediaController(Main2Activity.this));//显示控制栏
                video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        video.start();//开始播放视频
                    }
                });
            }
        });
    }
}

3.Vitamio 框架  使用起来和VideoView基本一样,区别在于,我们自己写的和系统自带的控件无法做到所有格式的视频都可以播放,但是这个框架基本可以实现,我用真机测试了mp4,flv,mkv,rmvb,3gp,avi这5中格式的视频,其中只有avi的只有声音没有影像,其他都可以正常播放,不过avi格式无法播放也可能是视频本身有点问题,不过我也没有其他视频了,无法继续测试,如果大家看完文章自己测试的时候可以用,也可以在回复的地方告诉我下,谢了。

vitamio的library下载地址是:https://www.vitamio.org/Download/

效果图与2一样

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.video.Main2Activity"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/et2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:hint="请输入文件名"/>

        <Button
            android:id="@+id/btn1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="确定"/>
    </LinearLayout>

    <io.vov.vitamio.widget.VideoView
        android:id="@+id/video1"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layout_marginTop="10dp"/>

</LinearLayout>

完整代码与2也一样,需要注意的是里面的VideoView是Vitamio中的,不是android.widget中的:

package com.example.video;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.widget.MediaController;
import io.vov.vitamio.widget.VideoView;

public class Main3Activity extends Activity {

    private VideoView video;
    private Button btn;
    private EditText et;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        initView();
    }

    private void initView() {
        video = (VideoView) findViewById(R.id.video1);
        btn = (Button) findViewById(R.id.btn1);
        et = (EditText) findViewById(R.id.et2);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String path = Environment.getExternalStorageDirectory().getPath()+"/"+et.getText().toString();
                Uri uri = Uri.parse(path);
                video.setVideoURI(uri);
                video.setMediaController(new MediaController(Main3Activity.this));

                video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        video.start();
                    }
                });
            }
        });
    }
}

以上三种方法完整案例demo下载地址:下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值