实现 Android 的视频播放,通常有以下几种方式

  • 使用自带的播放器,指定 Action ACTION_VIEW Data Uri Type 为其 MIME 类型。
  • 使用 VideoView 来播放,在布局文件中使用 VideoView 结合 MediaController 来实现对其控制。
  • 使用 MediaPlayer 类和 SurfaceView 来实现,这种方式很灵活。
  • 使用 VideoView 播放视频的步骤:

  • 在界面布局文件中定义 VideoView 组件,或在程序中创建 VideoView 组件
  • 调用 VideoView 的如下两个方法来加载指定的视频
  • setVidePath(String path) // 加载 path 文件路径对应的视频 setVideoURI(Uri uri) // 加载 uri 所对应的视频

  • 调用 start()、stop()、pause() 方法来控制视频的播放
  • 通过与 MediaController 类结合使用,开发者可以不用自己控制播放与暂停
  • 调用 seekTo 方法跳转不准的问题

    典型场景:

    当用户从后台恢复播放界面时,需要跳转到之前退出的时间点继续播放原来的视频。其实现逻辑大致上是:

  • 在暂停时保存当前 VideoView currantPosition 进度
  • 恢复播放时,调用 seekTo 方法,传入 currantPosition 作为跳转参数
  • 按照官方提供的 API 来看,这是最合理的使用方式。但在某些情况下,我们会遇到视频恢复播放时进度位置不准的问题,甚至有些会重头开始播放。

    下面就针对使用 VideoView 播放视频时 seekTo 跳转不准的问题进行分析。

    1. 消除方法异步执行的影响

    首先明确一点: VideoView seekTo 方法是异步执行的 ,因此会有 seek 未完成但播放已经开始的现象。需要消除 seekTo 对恢复播放的影响,应该在 seek 操作完成的 seekComplete 回调方法中执行 ViedeoView start 方法。

    Tip: seekComplete 属于 MediaPlayer 类的 OnPreparedListener 监听器的一个回调方法。虽然 VideoView 是基于 MediaPlayer 实现的,但没提供 setOnSeekCompleteListener 设置监听器的方法,所以我们要拿到 VideoView 内部持有 MediaPlayer 对象。

    // 设置 VideoView 的 OnPrepared 监听,拿到 MediaPlayer 对象。
    videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                //设置 MediaPlayer 的 OnSeekComplete 监听
                    mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
                        @Override
                        public void onSeekComplete(MediaPlayer mp) {
                        // seekTo 方法完成时的回调
                            if(isPause){
                                videoView.start();
                                isPause = false;
    复制代码

    2. 消除视频源的问题

    其实 seekTo 跳转的位置其实并不是参数所带的 position ,而是离 position 最近的 视频关键帧

    关于 视频关键帧 建议大家可以去了解一下相关知识,大致上就是视频播放时需要从一个关键帧的位置开始。

    所以当视频在跳转到相应的 position 位置缺少关键帧的情况下,调用 seekTo 方法是无法在当前位置开始播放。这时会寻找离指定 position 最近的关键帧位置开始播放。

    关于视频源造成的问题,可以采取以下解决措施:

  • 替换成满足需求的视频源文件(寻找合格的视频文件)
  • 对视频源文件进行处理,增加其关键帧数量,比如可以1s设置一个关键帧(基于目前已有的视频文件进行处理)。
  • 如果选择第二种方式,要增加视频的关键帧数量,可以推荐大家使用FFmpeg进行增加关键帧的处理工作。 http://ffmpeg.org/

    FFmpeg 工具相关命令行语句: ffmpeg.exe -i "D:\in.mp4" -c:v libx264 -preset superfast -x264opts keyint=25 -acodec copy -f mp4 "D:\out.mp4"

    命令语句大致意思是:在 D 盘路径下把 in.mp4 视频文件每隔 25 帧设置一个关键帧,音轨保持原视频参数,其余使用 FFmpeg 提供的default 值,最后保存为 out.mp4 文件到 D 盘。