美文网首页多媒体开发程序员Android开发
音视频系列之——Android各种视频播放器使用

音视频系列之——Android各种视频播放器使用

作者: 奔跑吧李博 | 来源:发表于2017-12-04 16:39 被阅读254次

    视频播放器在App是很常见的,有哪些视频播放器呢?具体情况该用哪款呢?这里我总结了常用的视屏播放Videoview、mediaplayer+surfaceview、vitamio、jcplayer的使用方法并写了各自的播放示例。

    代码在这里面
    项目目录:

    目录

    用到的视频地址:

    http://rbv01.ku6.com/omtSn0z_PTREtneb3GRtGg.mp4
    http://rbv01.ku6.com/7lut5JlEO-v6a8K3X9xBNg.mp4
    https://key003.ku6.com/movie/1af61f05352547bc8468a40ba2d29a1d.mp4
    https://key002.ku6.com/xy/d7b3278e106341908664638ac5e92802.mp4
    
    Android自带播放器VideoView

    播放效果:


    giphy.gif

    常用方法:

    videoView.start(); //开始播放
    videoView.pause(); //暂停
    videoView.stopPlayback(); //停止播放
    videoView.isPlaying(); //获取是否在播放状态
    videoView.setVideoURI(Uri uri); //设置视频播放uri
    videoView.setVideoPath(String path); //设置视频播放路径
    videoView.seekTo(int msec); //跳转到设置时间
    videoView.getCurrentPosition(); //获取当前播放时间
    videoView.getDuration(); //获取该视频播放时长
    videoView.setMediaController(MediaController controller); //设置播放控制器
    videoView.setOnPreparedListener(MediaPlayer.OnPreparedListener listener); //加载完成监听
    videoView.setOnCompletionListener(MediaPlayer.OnCompletionListener listener); //设置播放完成监听
    videoView.setOnErrorListener(MediaPlayer.OnErrorListener listener); //播放失败监听

    代码:

    import android.media.MediaPlayer;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.MediaController;
    import android.widget.VideoView;
    
    public class VideoViewActivity extends AppCompatActivity {
        private VideoView videoView;
        public final String videoUrl = "http://rbv01.ku6.com/omtSn0z_PTREtneb3GRtGg.mp4";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_video_view);
    
            init();
        }
    
        private void init(){
            videoView = (VideoView) findViewById(R.id.videoview);
            videoView.setVideoPath(videoUrl);
            videoView.setMediaController(new MediaController(this));
            videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    videoView.start();
                }
            });
            videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    videoView.start();
                }
            });
    
        }
    }
    
    

    自定义Mediaplayer+Surfaceview播放器:

    播放效果:


    giphy.gif

    Mediaplayer状态图:


    Mediaplayer状态图

    使用方式:

    surfaceView.getHolder().addCallback(new HolderCallBack());
    mediaPlayer.setDataSource(mediaUrl);
    mediaPlayer.setDisplay(surfaceView.getHolder());
    mediaPlayer.prepareAsync();
    mediaPlayer.setOnPreparedListener(OnPreparedListener listener);
    mediaPlayer.start();

    代码实现:

    播放器类:

    import android.annotation.TargetApi;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.graphics.Bitmap;
    import android.media.MediaMetadataRetriever;
    import android.media.MediaPlayer;
    import android.os.Build;
    import android.os.Handler;
    import android.os.Message;
    import android.view.LayoutInflater;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.SeekBar;
    import android.widget.TextView;
    import com.example.videoplayers.R;
    import java.io.IOException;
    import java.util.HashMap;
    
    public class PlayVideo {
        private Context context;
        private View videoView;
        public MediaPlayer mediaPlayer;
        private boolean isDisplay = true;
        private ProgressBroadCast progressBroadCast;
        private SurfaceView surfaceView;
        private Button btPlay;
        private SeekBar seekBar;
        private TextView tvTime;
        private ImageView ivCover;
        private LinearLayout relaVideo,llLoading;
        /** 视频播放资源地址 */
        private String mediaUrl;
        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if(null != msg){
                    ivCover.setImageBitmap((Bitmap) msg.obj);
                }
            }
        };
    
        public PlayVideo(Context context,String mediaUrl){
            this.context = context;
            this.mediaUrl = mediaUrl;
            videoView = LayoutInflater.from(context).inflate(R.layout.custom_videoplayer,null);
            initView(videoView);
            event();
        }
    
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        private void initView(View view){
            surfaceView = (SurfaceView) view.findViewById(R.id.surfaceview);
            btPlay = (Button) view.findViewById(R.id.btn_play);
            seekBar = (SeekBar) view.findViewById(R.id.play_seekbar);
            tvTime = (TextView) view.findViewById(R.id.tv_video_time);
            relaVideo = (LinearLayout) view.findViewById(R.id.rela_video);
            llLoading = (LinearLayout) view.findViewById(R.id.ll_video_loading);
            ivCover = (ImageView) view.findViewById(R.id.iv_videoplayer_cover);
            MyClickListener listener = new MyClickListener();
            surfaceView.setOnClickListener(listener);
            btPlay.setOnClickListener(listener);
    
            progressBroadCast = new ProgressBroadCast();
            context.registerReceiver(progressBroadCast, new IntentFilter("play"));
            surfaceView.getHolder().setKeepScreenOn(true);
            surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            surfaceView.getHolder().addCallback(new HolderCallBack());
    
            avaterThread();
        }
    
        private void event() {
            //seekbar调节进度
            seekBar.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 seekBar2) {
                    if(null != mediaPlayer)
                        mediaPlayer.seekTo(seekBar2.getProgress());
                }
            });
        }
    
        public View getVideoView(){
            return videoView;
        }
    
        public BroadcastReceiver getReceiver(){
            return progressBroadCast;
        }
    
        private void avaterThread(){
            new Thread(){
                @Override
                public void run() {
                    MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
                    if(Build.VERSION.SDK_INT >= 14){    //需加入api判断,不然会报IllegalArgumentException
                        mediaMetadataRetriever.setDataSource(mediaUrl,new HashMap<String, String>());
                    }else{
                        mediaMetadataRetriever.setDataSource(mediaUrl);
                    }
                    Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(1000,MediaMetadataRetriever.OPTION_CLOSEST);
                    Message message = new Message();
                    message.obj = bitmap;
                    mHandler.sendMessage(message);
                }
            }.start();
        }
    
            class MyClickListener implements View.OnClickListener {
    
                @Override
                public void onClick(View v) {
                    switch (v.getId()) {
                        case R.id.surfaceview:
                            if (isDisplay) {
                                relaVideo.setVisibility(View.GONE);
                            } else {
                                relaVideo.setVisibility(View.VISIBLE);
                            }
                            isDisplay = !isDisplay;
                            break;
                        case R.id.btn_play:
                            if (mediaPlayer == null) {
                                netWorkState();
                            } else {
                                //播放和暂停切换
                                if (mediaPlayer.isPlaying()) {
                                    mediaPlayer.pause();
                                    btPlay.setBackgroundResource(R.mipmap.video_btn_pause);
                                } else {
                                    mediaPlayer.start();
                                    ivCover.setVisibility(View.GONE);
                                    new ProgressThread().start();
                                    btPlay.setBackgroundResource(R.mipmap.video_btn_start);
                                }
                            }
                            break;
                    }
                }
            }
    
                /**
                 * 播放视频,先判断网络,是流量就要提示用户
                 */
                private void netWorkState() {
                    mediaPlayer = new MediaPlayer();
                    new PrepareThread().start();
                    llLoading.setVisibility(View.VISIBLE);
    
                }
    
                class HolderCallBack implements SurfaceHolder.Callback {
    
                    @Override
                    public void surfaceCreated(SurfaceHolder holder) {
    
                    }
    
                    @Override
                    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
                    }
    
                    @Override
                    public void surfaceDestroyed(SurfaceHolder holder) {
    
                    }
                }
    
                class MyPrepareListener implements MediaPlayer.OnPreparedListener {
    
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        if (null != mediaPlayer) {
                            llLoading.setVisibility(View.GONE);
                            mediaPlayer.start();
                            new ProgressThread().start();
                        }
                    }
                }
    
                class PrepareThread extends Thread {
                    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
                    @Override
                    public void run() {
                        super.run();
                        try {
                            mediaPlayer.reset();
                            mediaPlayer.setDataSource(mediaUrl);
                            mediaPlayer.setDisplay(surfaceView.getHolder());
                            mediaPlayer.prepareAsync();
                            mediaPlayer.setOnPreparedListener(new MyPrepareListener());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
    
                /**
                 * 时间进度广播
                 */
                public class ProgressBroadCast extends BroadcastReceiver {
    
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        int curPosition = intent.getIntExtra("position", 0);
                        int maxLen = intent.getIntExtra("max", 0);
                        seekBar.setProgress(curPosition);
                        seekBar.setMax(maxLen);
    
                        setTime(curPosition, maxLen);
                    }
    
                    /**
                     * 秒转化为00:00形式
                     * @param curPosition
                     * @param maxLen
                     */
                    private void setTime(int curPosition, int maxLen) {
                        int cm = curPosition / 1000 / 60;
                        int cs = curPosition / 1000 % 60;
                        int mm = maxLen / 1000 / 60;
                        int ms = maxLen / 1000 % 60;
                        StringBuilder builder = new StringBuilder();
                        builder.append(cm / 10).append(cm % 10).append(":")
                                .append(cs / 10).append(cs % 10).append("/")
                                .append(mm / 10).append(mm % 10).append(":")
                                .append(ms / 10).append(ms % 10);
                        tvTime.setText(builder.toString());
                    }
    
                }
    
                /**
                 * 发送播放进度线程
                 */
                class ProgressThread extends Thread {
                    @Override
                    public void run() {
                        while (null != mediaPlayer && mediaPlayer.isPlaying()) {
                            int currentProgress = mediaPlayer.getCurrentPosition();
                            int maxLen = mediaPlayer.getDuration();
                            //每隔一秒发送一次播放进度
                            Intent progressIntent = new Intent("play");
                            progressIntent.putExtra("position", currentProgress);
                            progressIntent.putExtra("max", maxLen);
                            context.sendBroadcast(progressIntent);
                            try {
                                sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
    
    }
    
    

    MediaPlayerActivity代码:

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.RelativeLayout;
    import com.example.videoplayers.R;
    
    public class MediaPlayerActivity extends AppCompatActivity {
        private RelativeLayout rlPlayer;
        private final String url = "http://rbv01.ku6.com/7lut5JlEO-v6a8K3X9xBNg.mp4";
        private PlayVideo playVideo;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_media_player);
    
            init();
        }
    
        private void init() {
            rlPlayer = (RelativeLayout) findViewById(R.id.rl_player);
            playVideo = new PlayVideo(this,url);
            rlPlayer.addView(playVideo.getVideoView());
        }
    
        @Override
        public void onDestroy() {    //退出停止视频播放
            super.onDestroy();
            try {
                if (null != playVideo) {
                    playVideo.mediaPlayer.release();
                    playVideo.mediaPlayer = null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void onStop() {
            super.onStop();
    
            unregisterReceiver(playVideo.getReceiver());
        }
    }
    

    Vitamio播放器:

    播放效果:


    giphy.gif

    库下载地址: https://github.com/yixia/VitamioBundleStudio

    常用方法(与原生的Videoview使用方法极其类似):

    videoView.setVideoPath(String path);
    videoView.setMediaController(MediaController controller);
    videoView.start();
    videoView.pause();
    videoView.isPlaying();
    videoView.seekTo(long time);
    videoView.getDuration();
    videoView.stopPlayback();
    videoView.getCurrentPosition();
    videoView.setOnPreparedListener(MediaPlayer.OnPreparedListener listener);
    videoView.setOnCompletionListener(MediaPlayer.OnCompletionListener listener);
    videoView.setOnInfoListener(MediaPlayer.OnInfoListener listener);
    videoView.setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener);

    控件引用:
    <io.vov.vitamio.widget.VideoView
    android:id="@+id/videoview"
    android:layout_width="match_parent"
    android:layout_height="200dp"/>

    代码实现:(加入缓冲状态和缓冲网速)

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    import com.example.videoplayers.R;
    import io.vov.vitamio.MediaPlayer;
    import io.vov.vitamio.Vitamio;
    import io.vov.vitamio.widget.MediaController;
    import io.vov.vitamio.widget.VideoView;
    
    public class VitamioPlayerActivity extends AppCompatActivity {
        private VideoView videoView;
        private TextView tvBuffer,tvNet;
        private String videoUrl = "https://key003.ku6.com/movie/1af61f05352547bc8468a40ba2d29a1d.mp4";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_vitamio_player);
    
            init();
    
        }
    
        private void init() {
            videoView = (VideoView) findViewById(R.id.videoview);
            tvBuffer = (TextView) findViewById(R.id.tv_buffer);
            tvNet = (TextView) findViewById(R.id.tv_net);
    
            if (Vitamio.isInitialized(this)) {
                videoView.setVideoPath(videoUrl);
                videoView.setMediaController(new MediaController(this));
                videoView.start();
            }
    
            videoView.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
                @Override
                public void onBufferingUpdate(MediaPlayer mp, int percent) {
                    tvBuffer.setText("已缓冲:" + percent + "%");
                }
            });
    
            videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                @Override
                public boolean onInfo(MediaPlayer mp, int what, int extra) {
                    switch (what) {
                        //开始缓冲
                        case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                            tvBuffer.setVisibility(View.VISIBLE);
                            tvNet.setVisibility(View.VISIBLE);
                            mp.pause();
                            break;
                        //缓冲结束
                        case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                            tvBuffer.setVisibility(View.GONE);
                            tvNet.setVisibility(View.GONE);
                            mp.start();
                            break;
                        //正在缓冲
                        case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:
                            tvNet.setText("网速:" + extra + "kb/s");
                            break;
                    }
                    return true;
                }
            });
    
        }
    }
    
    
    (节操)JCVideoPlayer:

    个人认为这是使用最简单且功能最完善的播放器,播放效果:


    播放效果

    特点:
    1.自带全屏播放放和浮层小窗口播放
    2.可以完全自定义UI
    3.手势修改进度和音量
    4.重力感应自动全屏
    5.支持https和rtsp

    引入库:

        compile 'fm.jiecao:jiecaovideoplayer:5.5.4'
    

    使用控件:

        <fm.jiecao.jcvideoplayer_lib.JCVideoPlayerStandard
            android:id="@+id/playerstandard"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    

    使用类:

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import com.example.videoplayers.R;
    import fm.jiecao.jcvideoplayer_lib.JCVideoPlayerStandard;
    
    public class JcPlayerActivity extends AppCompatActivity {
        private JCVideoPlayerStandard playerStandard;
        private String videoUrl = "https://key002.ku6.com/xy/d7b3278e106341908664638ac5e92802.mp4";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_jc_player);
    
            init();
        }
    
        private void init() {
            playerStandard = (JCVideoPlayerStandard) findViewById(R.id.playerstandard);
            playerStandard.setUp(videoUrl,JCVideoPlayerStandard.SCREEN_LAYOUT_NORMAL,"追龙");
            playerStandard.startVideo();
        }
    }
    

    以上是Android常用视频播放器,根据需求是仅仅要预览功能还是要各种操作引用哪款播放器。由于篇幅原因,功能强大的ijkplayer没加入到本篇博客,写完后会在此加入链接。哎呀妈呀,终于敲完了。

    相关文章

      网友评论

        本文标题:音视频系列之——Android各种视频播放器使用

        本文链接:https://www.haomeiwen.com/subject/dtrabxtx.html