本文章为原创,转载时请注明出处
Android播放视频
实现Android的视频播放器,通常有以下几种方式:
1、使用自带的播放器,指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。
2、使用VideoView来播放,在布局文件中使用VideoView结合MediaController来实现对其控制。
3、使用MediaPlayer类和SurfaceView来实现,这种方式很灵活。
通过VideoView播放视频的步骤:
1、在界面布局文件中定义VideoView组件,或在程序中创建VideoView组件
2、调用VideoView的如下两个方法来加载指定的视频
setVidePath(String path):加载path文件代表的视频
setVideoURI(Uri uri):加载uri所对应的视频
3、调用VideoView的start()、stop()、psuse()方法来控制视频的播放
4、VideoView通过与MediaController类结合使用,开发者可以不用自己控制播放与暂停
下面针对使用VideoView播放视频时seekTo跳转不准的问题进行解析
使用VideoView
当用户从后台恢复播放时,需要跳转到之前退出的时间点继续播放。
整个控制逻辑大致上是:
在暂停时保存CurrantPosition进度
恢复播放时,调用seekTo方法,传入currantPosition作为参数
但是还是遇到了恢复播放时位置不准的问题,而且甚至有重头开始播放的现象。
问题定位
VideoView的seekTo是异步执行的,会有seek未完成但播放已经开始的现象。需要消除seekTo对恢复播放的影响,应该在seek操作完成的seekComplete回调方法中执行start方法。
VideoView是基于MediaPlayer实现的,但没提供setOnSeekCompleteListener方法
//设置videoview的OnPrepared监听
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//设置MediaPlayer的OnSeekComplete监听
mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
if(isPause){
videoView.start();
isPause = false;
}
}
});
}
});
根本原因
其实seekTo跳转的位置其实并不是参数所带的position,而是离position最近的关键帧。关于视频的关键帧建议大家可以去了解一下相关知识,大致上就是视频播放时需要从一个关键帧的位置开始。
当视频在相应的position位置缺少关键帧的情况下,调用seekTo方法是无法在当前位置开始播放。这时会寻找离指定position最近的关键帧位置开始播放。
解决措施
如何确认是视频源造成的问题,可以采取以下解决措施:
1、替换成满足需求的视频源文件(寻找合格的视频文件)。
2、对视频源文件进行处理,增加其关键帧数量,比如可以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盘。
总结
在深究问题的原因时不可浅尝而止,也不要一味的怀疑是不是代码造成了问题。很多情况下都选择盲目地替换不同的视频组件出实现,而忽略了视频源文件本身的问题。
不积跬步无以至千里,从当下开始就得养成好的习惯,一点一滴的积累经验。厚积薄发,技术由点汇聚成面,总结很重要,后面会开始很多的文章产出。