视频播放器VideoView

作者: 键盘上的麒麟臂 | 来源:发表于2019-08-19 20:04 被阅读9次

    android原生的两个视频播放器MediaPlayer和VideoView,VideoView内部是封装MediaPlayer,我之前开发时用的是VideoView,用完之后第一感受是更建议直接使用MediaPlayer。写这篇文章主要就是为了记录VideoView一些坑。

    一.VideoView常用方法

    VideoView的方法算得上比较少。
    setVideoURI和setVideoPath 是设置视频的路径。
    setMediaController 是设置MediaController,也就是设置播放器的导航栏。
    setOnPreparedListener 监听在媒体文件加载并准备就绪时的回调
    setOnCompletionListener 监听播放完成后的回调
    setOnErrorListener 监听错误的回调
    setOnInfoListener 监听信息事件的回调
    pause和start 是暂停和开始
    getDuration 获取视频时长
    getCurrentPosition 获取当前视频播放到的节点
    seekTo 设置视频跳到某个节点
    以上这些是比较能常用到的方法,还有一些其他方法用到的时候可以看源码,代码量不是很多,都是最终调用MediaPlayer的方法。

    如果要播放一个视频,可以这样做

    videoView = findViewById(......);
    videoView.setVideoURI(uri);
    videoView.setOnPreparedListener (......);
    videoView.setOnCompletionListener (......);
    videoView.setOnErrorListener (......);
    videoView.setOnInfoListener (......);
    videoView.start();
    

    我觉得使用起来还是挺简单的,就没必要详细去说明,主要就是为了记录一下,碰到的问题。

    二.使用时碰到的问题

    1.getDuration 获取广告的时长为0

    直接使用getDuration会获取不到广告的时长,要在setOnPreparedListener的回调用获取才能获取到广告的时长。

    2.切换到后台再切回来无法正常播放

    例如在播放到一半的时候返回桌面,再点击应用进入,会发现视频无法继续播放。这是因为切换出去的时候内存会被释放掉。所以需要在切换出去的时候记录播放的点,切换回来的时候接着播放。

        @Override
        protected void onPause() {
            super.onPause();
            stopProgress = videoView.getCurrentPosition();
            videoView.pause();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            videoView.resume();
        }
    

    注意这里调用resume()是因为切出去的时候被释放掉了,所以要重新创建,看resume的源码就知道里面做了什么操作。
    然后在监听setOnPreparedListener 的方法中再开始播放,因为这种情况会再次给这个监听一个回调。

                videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        mediaPlayer = mp;
                            new Handler(Looper.getMainLooper()).post(new Runnable() {
                                @Override
                                public void run() {
                                   videoView.seekTo((int) stopProgress);
                                   videoView.start();
                                }
                            });
                        }
                });
    

    注意,如果之前有获取过videoview的MediaPlayer,这里如果继续使用之前的会有问题,所以mediaPlayer = mp;重新再获取一次。

    3.seekTo跳转播放点会有偏差

    比如说你调用seekTo(20),结果播放的点不是从20开始,而且会从0开始。
    我在网上寻找这个问题,发现有人说这个问题是因为seekTo不会跳到传入的点,而是接近它的关键帧(这个东西是不是叫关键帧,我也不清楚)。
    于是我就按照这个方法去查找视频的关键帧来进行测试。
    (1)用ffmpeg查看关键帧
    知道有个工具叫ffmpeg,它能够获取到视频的信息,下载之后是这样


    我是windows的
    然后cmd输入命令查看
    ffprobe -show_frames test.mp4 >test.txt
    

    就会把这个test视频的信息打印到test.txt里面,然后搜索key_frame=1,可以大概找出下图这样的信息


    像我这找到一个点是在19.08。 这时如果我调用seekTo(20),它实际会跳到19.08这个点,这个是实测过的。
    (2)解决seekto的问题
    上面只是一个扩展,扩展如何抓i帧,看归看,最终我们还是必须解决问题。我目前知道的解决方法是,在Api26以上android已经修复这个问题,不会再去找关键帧,比如说seekTo(20),就真的是在20播放,而不是19.08。至于低版本的,目前我也没有什么办法,就是说如果想要解决这个问题,完全可以换个框架,用三方的,但这就偏离了我这文章的主题,所以我这里是针对videoview的。
    那个Api26高版本解决了,但是,这个解决了是用的MediaPlayer的方法
    mediaPlayer.seekTo((int) stopProgress, MediaPlayer.SEEK_CLOSEST);
    

    但是我针对的是videoview,我们都知道videoview是封装了mediaPlayer的操作,上面的方法是有两个参数的,但是即便在api28的版本上,videoview的seekTo也没有两个参数的方法,简单来说就是谷歌修复了里面的东西,但没有管封装的那层的代码,所以我们可以这样做,在 setOnPreparedListener方法中能获取到MediaPlayer对象

                            new Handler(Looper.getMainLooper()).post(new Runnable() {
                                @Override
                                public void run() {
                                    if (Build.VERSION.SDK_INT >= 26) {
                                        // 高版本能直接暂停播放
                                        videoView.seekTo((int) stopProgress);
                                        mediaPlayer.seekTo((int) stopProgress, MediaPlayer.SEEK_CLOSEST);
                                    }
                                    videoView.start();
                                }
                            });
    

    这里只对高版本做处理,低版本不管。

    这篇文章就主要讲这些,主要是videoview使用挺简单的,没什么好讲,而坑确实挺多了,我就是想写篇文章记录下使用videoview遇到的坑,而如果是专门做视频肯定是不会使用videoview的,都是自己开发的控件。

    相关文章

      网友评论

        本文标题:视频播放器VideoView

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