美文网首页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