您的位置:首页 > 移动开发 > Android开发

MediaPlayer+TextureView全屏播放视频

2017-09-21 19:07 2306 查看
项目需要做一个简单的播放视频功能demo,考虑到需求较简单(实现不超过2min的MP4格式短视频播放),所以就没考虑使用复杂的第三方视频库了。最初敲定使用系统原生的VideoView实现,后来发现不能在列表中使用普通的VideoView
。VideoView 继承自SurfaceView,而SurfaceView并没有UI同步缓冲区。这就导致了在列表滚动的时候,正在播放的视频可能无法跟上滚动的步伐。针对这个问题继续查资料,最终选择使用MediaPlayer+TextureView实现视频播放。相关的资料很多,这里就不细说了。我主要说一下实现全屏播放的实现思路及遇到的问题。

一、在activity中留一个全屏的ViewGroup放置播放器实现全屏

在相应Activity中预留一个放置播放器的宽高都是match_parent的ViewGroup,大小切换就是把播放器添加到本来的小容器和添加到全屏的ViewGroup中来回切换。

全屏时,把从当前视图移除的播放器View即自定义的TextureView重新添加到预留的ViewGroup中,并且设置activity为横屏。

在activity中监听屏幕状态变化:

@Override
public void onConfigurationChanged(Configuration newConfig) {
TestLog.d(TAG, "onConfigurationChanged : fullScreen=" + fullScreen);
super.onConfigurationChanged(newConfig);
if (fullScreen != null && newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE && getVideoContent() != null) {
getVideoContent().setClickable(true);//拦截点击事件
ViewUtils.setVisible(getVideoContent(), View.VISIBLE);
fullScreen.full();
fullScreen = null;
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
ViewUtils.setVisible(getVideoContent(), View.GONE);
}
}

相应的实现点击全屏按钮实现全屏逻辑:

public void clickESC() {
PingbackUtils_3_9_0.pingVideoFullScreen();
if (mAdapter != null) {
final Context context = mAdapter.getContext();
if (context instanceof BaseActivity) {
((BaseActivity) context).setFullScreen(new IFullScreen() {

@Override
public void full() {
handler.addVideo((ViewGroup) ((BaseActivity) context).getRootView(), false);
TestLog.d(TAG,
TestLog.isDebug() ? "clickESC videoInfo.getCurrentPosition()=" + videoInfo.getCurrentPosition() : "");
//handler.seekTo(videoInfo.getCurrentPosition());
handler.fullScreen((BaseActivity) context);//这个要放到addVideo后面,需要是否全屏的状态
}
});

SingleVideoHandler.setOrientation((BaseActivity) context);
}
}
}

退出全屏倒着做就好了,设置会竖屏,将
播放器view
ViewGroup
中移除,重新添加到当前视图。

注意:切换横竖屏时为了避免
Activity
重新走生命周期,需要在
Manifest.xml
activity
标签下添加如下配置:

android:configChanges="orientation|keyboardHidden|screenSize"

到了这里别以为已经万事大吉了,亲自实践发现小屏播放和切换大屏衔接的不好,会出现短暂的黑屏现象。这是因为切换到大屏

时视频view从当前播放视图移除重新添加到大屏视图后,TextureView会重绘,就会重新new一个surfaceTexture,并重新回调onSurfaceTextureAvailable()

方法,这样TextureView的数据通道SurfaceTexture发生了变化,但是mediaPlayer还是持有原来的SurfaceTexture。

解决方法:重写onSurfaceTextureAvailable()、onSurfaceTextureDestroyed(),在从当前视图移除播放器viwe之前保存当前SurfaceTexture,

重新添加到大屏视图时,将之前保存的SurfaceTexture重新设置给当前播放器view。

@Override
public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) {
TestLog.d(TAG, TestLog.isDebug() ? "onSurfaceTextureAvailable:surface=" + surface : "");
TestLog.d(TAG, TestLog.isDebug() ? "onSurfaceTextureAvailable:mSurfaceTexture=" + mSurfaceTexture : "");
if (Utils.hasJellyBeanMR2()) {//如下方法在android4.2会崩溃,所以4.3之后(包括4.3)再使用
if (mSurfaceTexture == null) {
mSurfaceTexture = surface;
TestLog.d(TAG, TestLog.isDebug() ? "after set:mSurfaceTexture=" + mSurfaceTexture : "");
openVideo();
} else {
setSurfaceTexture(mSurfaceTexture);
}
} else {
mSurface = new Surface(surface);
openVideo();
}
}

@Override
public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) {
TestLog.d(TAG, TestLog.isDebug() ? "onSurfaceTextureDestroyed:surface=" + surface : "");
// after we return from this we can't use the surface any more
/*if (mSurface != null) {
mSurface.release();
mSurface = null;
}
if (mMediaController != null) mMediaController.hide();
release(true);
return true;*/
return mSurfaceTexture == null;
}

参考:

VideoView and TextureVideoView on Android

Android视频播放器实现小窗口和全屏状态切换

[Android基础] VideoView
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息