美文网首页
视频播放器滑动黑屏问题处理

视频播放器滑动黑屏问题处理

作者: fyg | 来源:发表于2020-07-20 19:14 被阅读0次

我们的董事长在某方面也真是舍得花钱,先后请了柳岩,于震,曾志伟,杨坤等各大艺人来为公司做宣传。
先来二段我们公司抖音直播带货的视频

杨坤.gif 曾志伟.gif

进入正题

公司临时加的需求要做类似【抖音直播上下翻页滑动切换直播】效果,按排一个同事从网上找找有没有现有的轮子,同事找到了如下文章,,没多想直接就拿来集成了用的 fragment +Viewpager来实现。

仿抖音系列之翻页上下滑切换视频(一)

提测后发现了较多问题

1,ViewPager会 缓存1个(首次) 或2个(滑动1个后)Fragment,每个Fragment中都有一个播放器和IM的实例,当上下翻页后,播放器和IM实例并没有即时销毁问题,只有当滑过到第三个Fragment后,第一个Fragment中的播放器和IM实例才销毁。 1,导致IM 统计实时在线人数不准确问题,,2,导致用户还没有进入下个直播间时,主播用户会收到 xxx来到直播间的提示。3,导致用户数的礼物数统计有问题。

2,页面重后台进入前台时,缓存的Fragment 都会执行 onResume方法,由于每个Fragment中都维护了一个播放器,而播放器和IM实例的生命周期状态委托给fragent生命周期, 导致onResume方法执行后,页面播放器都会重新开始播放,IM也会重新调用进入某某直播间。(解决方法是在fragment中的onUserVisible中增加falg,onResume时判断falg是否是显示状态,如果是重新走生命周期方法,如果不是return ;)

3,没有及时销毁问题

4,容易导入OOM的发生

5,管理维护起来繁琐,IM 问题(通知消息混乱,退出聊天室不即时,)

二期就已这样的方式上线了。

三期加了送礼物功能,,针对二期这个ViewPager优化问题,我提供了一个思路和Demo交由另外的一个同事来做了。大致思路是 复用ViewPager的 上下滑动事件,问题动态的往ViewPage里添加和移除 播放器和IM组件。

这样做的好处,思路清楚,管理 维护方便,,不需要处理多缓存实例的情况。

从github 找到了如下Demo 供同事参考:

仿映客viewPager上下滑动切换直播 InkeVerticalViewPagerLive

一星期过后,问同事优化的成果,同事说集成的有问题,【播放器在上下滑动过程中会出现 黑屏】如下图 ,并问我有没有遇到过SufaceView 黑屏的问题,,我说没有,他给我演示了一下运行的效果后,我说把你开发的分支名发给我,我看一下 。

播放器黑屏处理1.gif

开始研究测试,

1,第一步猜测是mVerticalVP.setPageTransforme中的代码导致的,注释后运行程序发现不行有黑屏的问题。

mVerticalVP.setPageTransformer(false) { page, position ->
            if (!mScrollInit && (position != 0.0f && position != 1.0f)) {
                mVideoPlayer?.let {
                    it.snapShot()
//                    it.visibility = View.GONE
                }
                mScrollInit = true
            } else if (position == 1.0f || position == 0.0f) {
                mVideoPlayer?.let {
//                    it.visibility = View.VISIBLE
                }
                mReplaceImg.visibility = View.GONE

            }
            val viewGroup = page as ViewGroup
            if (position < 0 && viewGroup.id != mCurrentItem) {
                val mRoomContainer = viewGroup.findViewById<View>(R.id.room_container)
                if (mRoomContainer != null && mRoomContainer.parent != null && mRoomContainer.parent is ViewGroup) {
                    (mRoomContainer as ViewGroup).removeView(mRoomContainer)
                }
            }
            if (position == 0.0f && viewGroup.id == mCurrentItem && mCurrentItem != mCurrentRoomId) {
                mScrollState = if (mCurrentItem > mCurrentRoomId) 2 else 1
                mRoomContainer?.let {
                    if (it.parent != null && it.parent is ViewGroup) {
                        (it.parent as ViewGroup).removeView(it)
                        mReplaceImg.visibility = View.GONE
                    }
                }
                releaseResource(mVideoPlayer)
                loadLiveVideo(viewGroup, mCurrentItem)

            }
        }

2, 从程序的现象来看,由于ViewPager中每个Fragment只是一个直播的背景图,而上下滑动时 播放器的内容会导致黑屏,,所以直接看的 阿里播放器AliyunVodPlayerView的源码,,首先找 这个类中 和View 添加和 移除,挂载的方法,,并没有发现异常,偶然间看到了SurfaceView 这个类,这个类的 getHolder 方法可以添加相应的回调,感觉是这个出的问题,,经过打断点调试,发现,上下滑动ViewPager时,这个SurfaceHolder.Callback会 频繁的调用 surfaceCreated ,surfaceChanged,surfaceDestroyed 方法,,,上下滑动ViewPager为什么会导致SurfaceHolder.Callback 调用呢?

此时有两个解决方法,1 是 SurfaceHolder.Callback 回调中不处理直接return ,但是没有找到判断条件,应该何时return , 2,第二个方法就是 不让SurfaceHolder.Callback回调,,第一种办法,没想到思路 ,,就开始研究第二种, , ViewPager 上下滑动为什么会导致SurfaceHolder.Callback回调? 而采用之前的 ViewPager +Fragment 的方式之前就没有出现过这个问题呢? 带着疑问开始看ViewPager的源码,

项目中使用的是 fr.castorflex.android.verticalviewpager.VerticalViewPager 类,查看该类的代码后,

首页想到的是在 这个类的 onInterceptTouchEvent 、onTouchEvent,方法的 MotionEvent.ACTION_MOVE 中添加断点, onLayout 中添加断点, 然后开始滑动界面,观察现象,,发现 当放行一个断点后,如果界面 黑屏,说明,,确实调用了某些方法,导致 SurfaceHolder.Callback 回调了,而我现在要做的就是找到那行代码(不调用那行代码),,,然后通过不断的打断点,用排除法缩小范围。由于项目是通过gradle 引用 的是第三VerticalViewPager,所以直接把第三方的代码得copy到了项目里,这样也方法我打断点和 注释代码。

通过这种打断点的方法,最终发现了那个方法 ,如下代码


VerticalViewPager类
这个方法的作用是设置 ViewPager中的子View 是否开启硬件加速功能。  当开启后会有副作用。

private void enableLayers(boolean enable) {
    final int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        final int layerType = enable ?
                ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE;
        ViewCompat.setLayerType(getChildAt(i), layerType, null);
    }
}


ViewCompat类

@Deprecated
  public static void setLayerType(View view, int layerType, Paint paint) {
   view.setLayerType(layerType, paint);
  }


view.setLayerType(layerType, paint);  方法是用来设置View 硬件加速的,


注释该行代码即可:如下图:

viewpager_bug.png

昨天测试的时候,由于只开了一个直播,,

当有多个直播时,上下滑动后,由于播放器只是调用了stop和从父布局增加和移除,当进入下个直播后,播放器会显示上个直播的画面一段时间,,当请求视频地址接口返回来并开始播放后,播放器界面才会显示当前直播间的画面。

为了解决这个问题,

第一种思路 是 stop后,清空SufaceView中的内容,并设置内容为透明,,但尝试后发现行不通 【SurfaceView清空画布】

第二种思路是 当调用 播放器的stop后, 设置播放器为 it.visibility = View.INVISIBLE,

playerView?.let {
            if (it.parent != null && it.parent is ViewGroup) {
                (it.parent as ViewGroup).removeView(it)
                it.onStop()
                it.visibility = View.INVISIBLE
            }
        }

当 播放器开始播放第一帧后, 设置播放器为 it.visibility = View.VISIBLE ,就可以解决这个问题,

mVideoPlayer?.let {
            it.setVideoScalingMode(IPlayer.ScaleMode.SCALE_ASPECT_FILL)
            it.setControlBarCanShow(false)
            it.setOnPreparedListener {}
            it.setOnFirstFrameStartListener(object:IPlayer.OnRenderingStartListener{
                override fun onRenderingStart() {
                    it.visibility = View.VISIBLE
                }
            })
            it.setOnErrorListener {
                IPlayer.OnErrorListener {
                    TODO("最后添加")
                }
            }
        }

注意 在 播放器的 setOnPreparedListener 方法中设置是有问题的,因为 setOnPreparedListener 是即将开始播放的方法,这个方法执行时, 播放器还未开始播放呢, 还是会有上述问题。

最终效果如下图:

播放器黑屏处理2.gif
参考

Android setLayerType 硬件加速问题

Android自定义View(八) -- 硬件加速

硬件加速 setlayertype

简述SurfaceView及常见问题

硬件加速
【转】观看视频时启用硬件加速有什么用?如果关闭硬件加速又有什么区别呢?

观看视频时启用硬件加速有什么用?如果关闭硬件加速又有什么区别呢?...

硬件加速是用显卡的GPU解码视频,几乎不占用CPU。在播放高清视频时CPU不给力就会卡,不卡也会占用率很高。开启硬件加速是让显卡分担了CPU的解码工作,所以你可以再开别的程序也不会卡。

硬件加速是用来降低视频解码时候CPU负载的,如果CPU性能不够强,看高清视频没有硬件加速的时候就卡了

硬件加速的优点与缺点


硬件加速的优点与缺点
硬件加速能使用GPU来加速2D图像的渲染速度,但是硬件加速并不能完全支持所有的渲染操作,

针对自定义的View,硬件加速可能导致渲染出现错误。

如果有自定义的View,需要在硬件加速的设备上进行测试,如果出现渲染的问题,需要关闭硬件加速

仿映客viewPager上下滑动切换直播 InkeVerticalViewPagerLive

杨充 仿抖音上下滑动分页视频

VerticalViewPager

相关文章

网友评论

      本文标题:视频播放器滑动黑屏问题处理

      本文链接:https://www.haomeiwen.com/subject/udwykktx.html