工作中开发视频播放器的项目结束后,总结下之前开发过程中所遇到的一些坑。
1.播放网络视频,onError报错所遇到的what -38;
细节总结:
(1)正因为播放的是网络视频,所以mediaPlayer采用的是 prepareAsync();就会遇到上述问题
而且大部分同一个视频有时候会出错,有时候又不会出现这个错误,也有极少数视频一直出这个错
@Override
public boolean onError(MediaPlayer mp, int what, int extra){
switch (what) {
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
mp.release();
return true;
case -38:
start();
break;
default:
mp.reset();
break;
}
return false;
}
上网找了很多资料,都是没有具体的解决办法,因为这个问题偶尔出现,所以我想既然有时候不出错的话,那干脆获取这个错误后,再反复去执行播放的操作,结果发现问题可以得以解决。
我个人理解的意思是,异步操作的视频,在用prepareAsnc的时候,出现了获取视频元素失败或者其他错误,反复执行,经测试,一般大概3-5次就可以正常播放。
(2) 还是上个问题,使用prepare()就不会出现错误,但是在视频准备前期,UI层会出现巨卡现象,这显然更不符合要求,本来还想自己尝试去封装这个,用另一个线程执行,不过还是觉得官方的更靠谱点。所以才会花心思去研究和推论第一点的尝试。
2.MediaPlayer error (1, -2147483648)
偶尔播放视频,会发现报上述错误信息,尤其是杂牌子的低端手机,查阅资料1其实代表MEDIA_ERROR_UNKNOWN,不过文档对-2147483648(0x80000000)没有做什么说明,实际上它也是代表unknown error的意思。
真正的原因在于,MP4有多种编码格式,例如H.264,H.263等,而Android版本较低的机器只支持部分编码。
可以参考官方的视频编码支持的说明:
后来把不能播放的视频下载到本地,用mediaInfo工具查看编码信息,发现不能播放的是AVC High@L4.1的编码方式,再用格式工厂采取其他方式编码,测试可以播放
3.视频缩放
如果只是简单的视频缩放就不值得拿出来,但是如果牵涉到视频的旋转,再缩放,就有点工作量,我之前的那个项目,有3套旋转和缩放的逻辑处理。这里只拿出最关键的处理代码
水平方向的视频缩放
private void horizontalResize(){
float ra1,ra2;
if (videoHeight > 0 && videoWidth > 0) {
ra1 = (float) videoWidth / videoHeight;
ra2 = (float) surfaceWidth / surfaceHeight;
//宽屏
if(ra1>ra2){
realVideoWidth = surfaceWidth;
realVideoHeight =(int) (realVideoWidth/ra1);
}else{
realVideoHeight = surfaceHeight;
realVideoWidth = (int)(realVideoHeight*ra1);
}
}
mTextureView.setScaleX((float)realVideoWidth/surfaceWidth);
mTextureView.setScaleY((float)realVideoHeight /surfaceHeight);
}
竖直方向的视频缩放
private void verticalResize(){
float ra1,ra2;
if (videoHeight > 0 && videoWidth > 0) {
ra1 = (float) videoHeight/videoWidth;
ra2 = (float) surfaceWidth/surfaceHeight;
//宽屏
if(ra1>ra2){
realVideoWidth = surfaceWidth;
realVideoHeight =(int) (realVideoWidth/ra1);
}else{
realVideoHeight = surfaceHeight;
realVideoWidth = (int)(realVideoHeight*ra1);
}
}
mTextureView.setScaleX((float)realVideoHeight/surfaceWidth);
mTextureView.setScaleY((float)realVideoWidth/surfaceHeight);
}
上述代码还可以优化,但是为了阅读方便,没有处理。
水平方向还好理解,竖直方向的缩放,因为牵涉到旋转,所以原来的视频宽高比也要互换位置,同时渲染的texture的缩放比列也要互换位置,我都用红色标注了。
4.播放器尺寸的修改
onSurfaceTextureSizeChanged
只要对视频的渲染皮肤事件侦听就可以了,然后修改后,再去判断当前的状态是全屏还是非全屏的,这些都还好弄。
就是碰到一些奇怪的现象,有时候播放器的设置,第一次设置后,坐标和尺寸不执行,加了一个延时执行才可以
new Handler().postDelayed(new Runnable() {
public void run() {
//具体代码
}, delayTime);
不知道是渲染机制的问题还是?这块没有深入研究
5.关闭播放器
大家都知道释放播放器的代码是:
this.mediaPlayer.release();
this.mediaPlayer = null;
但是在实际测试的过程中,有时候执行到这步的时候会报空指针错误,google了一些资料,说是清除机制里,这个变量值可能在一些特殊的时机里,会已经被null了,所以再执行就会报错,和系统底层所取的变量值不一致。
解决的方法是:类名.mediaPlayer这种访问方式去执行,可以避免。