美文网首页Android基础
Android业务需求视频时,如何选择有效的方式实现

Android业务需求视频时,如何选择有效的方式实现

作者: Candy有雪吃 | 来源:发表于2018-08-28 17:04 被阅读3次

现在视频格式有:AVI/VCD/SVCD/DVD/MPG/WMV/ASF/RM/RMVB/FLV/F4V/MOV/QT/MP4/MPEG4/3GP/3G2/MKV/TS/TP/MTS/M2TS/MOD/TOD/SDP/YUV等。

在Android中,一般有下面几种方式来实现视频的播放:

1、利用Intent调用系统自带的播放器或者安装的第三方播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。
2、使用VideoView来播放。在布局文件中使用VideoView结合MediaController来实现对其控制。
3、使用MediaPlayer类和SurfaceView来实现,这种方式很灵活。
4、使用开源框架实现。

一、调用已有播放器

     Uri uri=Uri.parse("***");  
    Intent intent=new Intent(Intent.ACTION_VIEW);  
    intent.setDataAndType(uri,"video/*");  
    startActivity(intent);  

这种方式很简单只要设置好视频路径(可以是本地路径和网络路径),系统就会自动检索手机上已安装的视频播放器来播放。这种方式依赖于选择播放器的支持视频格式,基本会支持所有视频格式。

二、利用VideoView来播放视频(只支持mp4、avi、3gp格式的视频,支持格式单一)

ViewView是系统封装好的SurfaceView,所以特点就是调用简单,但是定制困难,而且同SurfaceView一样,会遇到很多异常情况,推荐一篇文章就是在实际项目中用的VideoView里面记录了很多问题以及解决方法,文章推荐。再推荐一个完整的视频项目开发文章文章推荐

简单的VideoView使用

         /** 
         *初始化videoview播放 
         */  
        public void initVideoView(){  
            //初始化进度条  
            progressBar= (ProgressBar) findViewById(R.id.progressBar);  
            //初始化VideoView  
            videoView= (VideoView) findViewById(R.id.videoView);  
            //初始化videoview控制条  
            mediaController=new MediaController(this);  
            //设置videoview的控制条  
            videoView.setMediaController(mediaController);  
            //设置显示控制条  
            mediaController.show(0);  
            //设置播放完成以后监听  
            videoView.setOnCompletionListener(this);  
            //设置发生错误监听,如果不设置videoview会向用户提示发生错误  
            videoView.setOnErrorListener(this);  
            //设置在视频文件在加载完毕以后的回调函数  
            videoView.setOnPreparedListener(this);  
            //设置videoView的点击监听  
            videoView.setOnTouchListener(this);  
            //设置网络视频路径  
            Uri uri=Uri.parse("***");  
            videoView.setVideoURI(uri);  
            //设置为全屏模式播放  
            setVideoViewLayoutParams(1);  
        }  

三、MediaPlayer+surfaceView是其他方法的基础,其他方法都是对其进行封装的

我们都知道MediaPlayer是媒体播放器,可以播放音频,视频其实就是给音频配上影像,而SurfaceView就是给音频配上影像的工具,我们只需要把SurfaceView与MediaPlayer关联起来就行了。

SurfaceHolder holder = SurfaceView.getHolder();
...
MediaPlayer.setDisplay(holder);//将影像播放控件与媒体播放控件关联起来

简单demo实现

        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("nantang","surfaceCreated");
                Play.setEnabled(true);
            }

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

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

            /**
            *prepare方法是将资源同步缓存到内存中,一般加载本地较小的资源可以用这个,
            *如果是较大的资源或者网络资源建议使用prepareAsync方法,异步加载.
            *但如果想让资源启动,即start()起来,因为在异步中,如果不设置监听直接start的话,
            *是拿不到这个资源,如果让线程睡眠一段时间,则可以取得资源,因为这个时候,
            *异步线程已经取得资源,但不可能使用线程睡眠的方式来获取资源啊.
            *所以就需要设置监听事件setOnPreparedListener();
            *来通知MediaPlayer资源已经获取到了,然后实现onPrepared(MediaPlayer mp)方法.
            *在里面启动MediaPlayer
            */
            player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    //媒体播放器就绪后,设置进度条总长度,开启计时器不断更新进度条,播放视频
                    Log.d("nantang","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();
        }
    }

四、开源框架

1、Vitamio

极其推荐的文章

2、VLC
公司机器人上的播放器就是基于VLC,效果挺好的,不过没具体研究过,后期研究研究。

相关文章

网友评论

    本文标题:Android业务需求视频时,如何选择有效的方式实现

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