我在切换源(和视频组件)时遇到问题,但表面仍然显示旧帧,但我需要黑屏。
什么对我有用,所有操作都在渲染器(impl.GLSurfaceView.Renderer)类中完成:
- 创建
AtomicBoolean,初始值为false(示例中又名stopRendering);
- 清除表面的功能(通过 OpenGL):
private void clearSurface() {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
}
- 然后函数清除和停止渲染(我在切换播放器
VideoComponent时调用它):
public void clearAndStopRendering() {
stopRendering.set(true);
glSurface.requestRender();
}
- 当帧准备好时恢复帧渲染:
@Override
public void onVideoFrameAboutToBeRendered(long presentationTimeUs, long releaseTimeNs, @NonNull Format format, @Nullable MediaFormat mediaFormat) {
if (stopRendering.compareAndSet(true, false)) {
glSurface.requestRender();
}
}
我的onDrawFrame 的样子:
@Override
public void onDrawFrame(GL10 gl) {
// some initialization code, related to my work
if (stopRendering.get()) {
clearSurface();
return;
}
// Drawing ...
}
我在GLSurfaceView 中的代码,我正在触发清除:
public void setVideoComponent(@Nullable Player.VideoComponent newVideoComponent) {
if (newVideoComponent == videoComponent) {
return;
}
if (videoComponent != null) {
// clearing old VideoComponent
renderer.clearAndStopRendering();
}
videoComponent = newVideoComponent;
// setup new VideoComponent
}
所以,我实现了什么:每次VideoComponent 更改(通过自定义PlayerView,其中包括我的GLSurfaceView)时,都会渲染黑屏,然后在视频帧准备好后渲染它,而不是旧框架。
P.S. BTW 第二种变体,如果您像我一样使用自定义 PlayerView,您可以这样做:
class MyGlPlayerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : PlayerView(context, attrs), MyPlayerView {
private lateinit var glSurfaceView: MyGLSurfaceView
override fun onFinishInflate() {
super.onFinishInflate()
val contentFrame = findViewById<FrameLayout>(R.id.exo_content_frame)
glSurfaceView = MyGLSurfaceView(context, false);
contentFrame.addView(glSurfaceView, 0)
setShutterBackgroundColor(Color.BLACK)
}
override fun setPlayer(player: Player?) {
glSurfaceView.setVideoComponent(player?.videoComponent)
super.setPlayer(player)
}