学校网站做几级等保/网络服务投诉平台
相信不少人做过在游戏登陆前做播放视频的需求,最近我也碰到了这个需求,就先在android上面做测试,正好查到cocos2dx
有videoplayer这个类,想来用用。可是呢,cocos2dx
依然是那种脾气,总不会给你一马平川,于是碰到各种问题,诸如播放视频完成后奔溃啊,看不见视频,又或者是软件切入后台再切入前台就看不见视频了,各种问题,查阅google和百度,总没有令人满意和能解决bug的方法,想着自己来研究下,最终还是把安卓版本的videoplayer给搞定了,下面把我碰到的一些问题和解决过程写出来,给需要的同学借鉴一下。
首先,本人用的是cocos2dx
3.1.1,这个版本videoplayer首先来说个问题就是播放结束后会奔溃,无奈对android开发了解不透彻,据说后来3.10版本没有这个问题,后来对比几个java文件发现了一个地方的问题。
cocos2dx 3.1.1 (Cocos2dxVideoView.java)
private MediaPlayer.OnCompletionListener
mCompletionListener =
new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mCurrentState = STATE_PLAYBACK_COMPLETED;
mTargetState = STATE_PLAYBACK_COMPLETED;
mp.release();
if
(mOnVideoEventListener != null) {
mOnVideoEventListener.onVideoEvent(mViewTag,EVENT_COMPLETED);
}
}
};
cocos2dx 3.10(Cocos2dxVideoView.java)
private MediaPlayer.OnCompletionListener
mCompletionListener =
new MediaPlayer.OnCompletionListener()
{
public void onCompletion(MediaPlayer mp)
{
mCurrentState =
STATE_PLAYBACK_COMPLETED;
mTargetState =
STATE_PLAYBACK_COMPLETED;
release(true);
if (mOnVideoEventListener != null) {
mOnVideoEventListener.onVideoEvent(mViewTag,EVENT_COMPLETED);
}
}
};
对比2处红色的代码块,就是这个地方导致的问题,改正即可。至于为什么会造成奔溃,大家可以对照着Cocos2dxVideoView.java这个文件里面的release方法来看就知道了,如果这个地方实施了mp.release(),对mediaplayer作释放处理,之后,再次触发了surfaceDestory方法,于是里面执行了一次release方法,又会对mediaplayer做二次release处理,然后可能就奔溃了。
private void release(boolean cleartargetstate) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
if
(cleartargetstate) {
mTargetState
= STATE_IDLE;
}
}
}
OK,一个问题解决了,下面来解决另一个问题,为什么切入到后台再切入前台就看不见视频了呢,这个问题其实有2个bug都会造成这个问题,我们先来说第一个bug。
Cocos2dxVideView是继承至SurfaceView这个组件的,我了解下来这个组件就是如果隐藏了,就会被销毁,然后我用adt连真机调试了下,果然如此,大家在看代码时候注意一个回调对象:
SurfaceHolder.Callback mSHCallback = new
SurfaceHolder.Callback()
这个里面有三个回调方法
surfaceChanged,surfaceCreated,surfaceDestroyed,在播放视频时候,游戏切入到后台,就会触发surfaceDestroyed的回调,mediaplayer就会被删掉了,再把游戏切入到当前执行,首先会触发surfaceCreated回调,重新创建了一个新的mediaplayer对象,然后又会触发surfaceChanged回调。问题就在这个时候了,我们先来看看surfaceChanged方法里面的代码:
public void surfaceChanged(SurfaceHolder holder, int format,
int w, int h) {
boolean
isValidState = (mTargetState == STATE_PLAYING);
boolean hasValidSize = (mVideoWidth == w
&& mVideoHeight == h);
if (mMediaPlayer != null &&
isValidState && hasValidSize) {
if (mSeekWhenPrepared != 0)
{
seekTo(mSeekWhenPrepared);
}
start();
}
}
看看红色粗体这段代码,当isValidState为true时,下面的start(),才会执行。可是,这时候mTargetState的状态是STATE_IDLE.......所以,不是看不见视频,那压根就没播放啊
。
我的解决方案是,新增一个isComplete的boolean变量,来记录当切入到后台时候,是否视频没有播放完。
public void surfaceDestroyed(SurfaceHolder holder) {
// after we return from this we can't use
the surface any more
if(mCurrentState == STATE_PLAYING)
{
isComplete =
mMediaPlayer.getCurrentPosition() ==
mMediaPlayer.getDuration();
}
mSurfaceHolder =
null;
release(true);
}
isComplete的意思就是如果当前播放进度不等于视频总长度,说明没有播放完成。
然后我们来修改surfaceChanged:
public void surfaceChanged(SurfaceHolder holder, int format,
int w, int h)
{
boolean isValidState = (mTargetState ==
STATE_PLAYING) || !isComplete;
boolean hasValidSize = (mVideoWidth == w
&& mVideoHeight == h);
if (mMediaPlayer != null &&
isValidState && hasValidSize)
{
if (mSeekWhenPrepared != 0) {
seekTo(mSeekWhenPrepared);
}
start();
}
}
当再次切入到前台,如果没播放完isComplete就为false,这样start()就能执行到了,再次播放视频成功!这里插一句,其实surfaceChanged里面start方法只是为了修改mCurrentState的状态为STATE_PLAYING,然后在mPreparedListener这个监听方法里面,才是真正执行start。
我前面说了有两个bug,现在解决掉一个了,另一个是什么?另一个bug就是fixSize。
我们来看看fixSize有关的地方(因为我是从cocos2dx
3.1.1代码改过来的,3.2以后的朋友门可能代码和我不同,大家看看思路就行了,根据需求更改代码)
public void setVideoRect(int left,int top,int maxWidth,int
maxHeight) {
mViewLeft = left;
mViewTop = top;
mViewWidth =
maxWidth;
mViewHeight =
maxHeight;
if (mVideoWidth !=
0 && mVideoHeight != 0)
{
fixSize();
}
}
public void onPrepared(MediaPlayer mp)
{
........
if (mVideoWidth != 0 &&
mVideoHeight != 0) {
fixSize();
}
......
}
大家看到我标红字的地方了么,问题就在这里,因为我调试下来发现,有时候mVideoWidth和mVideoHeight两个值都是0!!!,那都是0了还怎么fixSize。我们再回过头来看看fixSize,
public void fixSize() {
if (mVideoWidth ==
0 || mVideoHeight == 0) {
mVisibleLeft =
mViewLeft;
mVisibleTop =
mViewTop;
mVisibleWidth =
mVideoWidth;
mVisibleHeight =
mVideoHeight;
} else if (mViewWidth != 0 &&
mViewHeight != 0) {
.....
}
}
这里面有对2个是0值的处理方式啊,你在外面加一个过滤算什么事啊?所以我们把外面if (mVideoWidth != 0 &&
mVideoHeight != 0)给注销掉就可以杜绝这个情况了。
但是,我还发现了一个细节,不知道大家有没有发现,如果你是用apk安装器安装完的游戏,在apk安装器里面去打开这个软件,就会有个问题,再切换到后台再切入前台又看不见视频了.........你这不忽悠人么,你不是说就2个bug么~~
,然后我就搜索了下,发现原来这个是安卓的通病,我们在Cocos2dxActivity的onCreate里面加上一段代码
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if ((getIntent().getFlags() &
Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0)
{
finish();
return;
}
。。。。
}
就能解决了,至于是什么原因呢,我还没有去深入研究,有懂的哥们希望能告诉我,感激不敬!!
至此视频播放的问题差不多都解决了。希望能给各位朋友借鉴以下,也许还有不足之处,大家多多点评,谢谢!