HarmonyOS鸿蒙Next中ijkplayer播放视频时,将应用设置为全屏也就是关闭状态栏时,视频画面颜色异常

HarmonyOS鸿蒙Next中ijkplayer播放视频时,将应用设置为全屏也就是关闭状态栏时,视频画面颜色异常 我实现的应用,在EntryAbility.ets中开启了沉浸式。cke_3131.png

在使用XComponent组件播放视频时,会动态计算组件宽高:cke_6787.png其中percent是播放视频时计算的宽高比:cke_11662.png

然后我现在有一个按钮,来控制显隐状态栏和导航栏。具体逻辑是:cke_20955.png

现在的问题就是当我设置成全屏时,也就是隐藏状态栏和导航栏时,视频播放画面颜色会异常,异常情况如图所示:cke_408.jpeg

cke_1083.jpeg


更多关于HarmonyOS鸿蒙Next中ijkplayer播放视频时,将应用设置为全屏也就是关闭状态栏时,视频画面颜色异常的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

是不是你的setvideoWH未重新获取最新窗口尺寸?导致 XComponent 宽高计算错误,Surface 渲染区域与实际窗口不匹配。而且ijkplayer 的 Surface 未随窗口变化重置:全屏会触发窗口的 Surface 上下文(如颜色空间、像素格式)变更,但 ijkplayer 仍绑定旧的 Surface,导致颜色格式不兼容。

所以,全屏切换后,强制更新窗口尺寸 + XComponent 宽高,然后重置 ijkplayer 的 Surface(解决颜色格式不匹配):

ts

// 在你的视频播放组件中,添加Surface重置方法
resetIjkplayerSurface() {
  // 1. 先释放ijkplayer当前绑定的Surface
  if (this.ijkPlayer) {
    this.ijkPlayer.releaseSurface(); // 依赖ijkplayer的Surface释放API
  }

  // 2. 重新获取XComponent的最新Surface(全屏后XComponent已更新尺寸)
  const xComponentElement = this.$refs.xcomponentRef as XComponent;
  const newSurface = xComponentElement.getSurface(); // XComponent的Surface对象

  // 3. 将新Surface重新绑定到ijkplayer
  if (newSurface && this.ijkPlayer) {
    this.ijkPlayer.setSurface(newSurface); // 绑定新Surface
    this.ijkPlayer.resetRender(); // 重置渲染上下文(关键:解决颜色偏色)
  }
}

更多关于HarmonyOS鸿蒙Next中ijkplayer播放视频时,将应用设置为全屏也就是关闭状态栏时,视频画面颜色异常的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


ijkplayer三方库IjkMediaPlayer类对象中没有releaseSurface,setSurface,resetRender这些方法。并且就算我按照你的逻辑: this.ijkPlayer?.setContext(this.xcomponentContext, ‘xcomponent’);将对象释放资源后,重新设置XComponent组件的这些信息。播放时画面还是异常的。我使用手机倒是不会有这个问题。但是外接HDMI屏幕就会画面颜色异常。这个可能是外接HDMI屏幕的原因,

哦,那可能是HDMI线或者标准问题,HDMI 支持RGB和YCbCr两种核心色彩格式,手机默认输出的格式如果外接屏不支持,就会出现反色的问题。

鸿蒙Next中ijkplayer全屏播放时视频颜色异常,可能是由于状态栏隐藏后系统未正确处理色彩空间转换。可检查SurfaceView或TextureView的色彩格式配置,确保与视频源匹配。同时确认ijkplayer的渲染管线是否适配鸿蒙的图形合成器,避免因状态栏切换导致YUV到RGB转换错误。

根据您提供的代码和现象描述,全屏时视频颜色异常(如发绿或颜色错乱)通常与图形缓冲区(Surface)的格式或处理方式在全屏状态切换时发生变化有关。在HarmonyOS Next中,XComponentijkplayer 结合使用时,需要特别注意窗口状态变化对渲染表面的影响。

核心问题分析:

  1. Surface格式不匹配:当应用从非全屏切换到全屏(隐藏状态栏/导航栏)时,XComponent 持有的 NativeWindow(对应 Surface)可能被重新配置或属性(如像素格式、色彩空间)发生改变。如果 ijkplayer 内部没有及时适配新的 Surface 属性,会导致解码后的图像数据与 Surface 预期的格式不匹配,从而引发颜色渲染错误。
  2. 渲染上下文未同步:全屏切换可能触发了 XComponent 底层 EGL 上下文或 Surface 的重建。如果 ijkplayer 持有的渲染资源(如 EGLDisplay, EGLSurface)没有随之更新或重新绑定,会导致渲染到错误的缓冲区或使用无效的配置。

排查与解决方向:

1. 检查并显式设置 XComponent 的 Surface 参数XComponent 初始化或全屏切换后,确保传递给 ijkplayerNativeWindow 具有正确的色彩格式。重点关注 OH_NativeWindow_Handle 的属性设置。

  • 在 Native 层(C/C++),通过 OH_NativeWindow_Handle 相关接口(如 OH_NativeWindow_SetBufferColorSpace)检查或设置色彩空间(如 COLOR_SPACE_SRGBCOLOR_SPACE_DISPLAY_P3)。
  • 确保 OH_NativeWindow_GetBufferColorSpace 获取的值与 ijkplayer 解码器输出格式(如 AV_PIX_FMT_NV12, AV_PIX_FMT_RGBA)兼容。

2. 正确处理 XComponent 的生命周期事件 监听 XComponentonSurfaceCreatedonSurfaceChangedonSurfaceDestroyed 事件。在全屏切换时,onSurfaceChanged 很可能会被触发。

  • onSurfaceChanged 回调中,需要重新将新的 NativeWindow 句柄传递给 ijkplayer,并让 ijkplayer 重新初始化渲染环境(如重置 EGL 上下文、重新创建 EGLSurface)。
  • 代码示例框架:
    // ArkTS 侧
    xComponentContext.onSurfaceChanged((id, component, surfaceId, width, height) => {
      // 获取新的 NativeWindow 句柄
      let nativeWindow = xComponentContext.getNativeWindow(surfaceId);
      // 将新的 nativeWindow 传递给 ijkplayer 原生层
      nativeIjkPlayerHandle.onSurfaceChanged(nativeWindow);
    });
    

3. 在 ijkplayer 原生层适配 Surface 变化

  • ijkplayerffplay.c 或相关视频渲染模块(如 opengl 渲染器)中,找到 surface 设置和 egl 初始化的代码。
  • 确保在接收到新的 ANativeWindow(HarmonyOS 中为 OH_NativeWindow_Handle)时,执行以下操作:
    1. 释放旧的 EGLSurfaceEGLContext(如果需要)。
    2. 使用新的 OH_NativeWindow_Handle 重新创建 EGLSurface
    3. 重新设置 egl 的视口(viewport)和投影矩阵,以匹配新的窗口尺寸。
  • 检查 ijkplayer 的像素格式转换(swscale)逻辑,确保其输出格式(如 RGBABGRA)与 EGL 纹理内部格式以及 Surface 的预期格式一致。

4. 验证全屏切换时的窗口属性

  • 在调用 window.getTopWindow().setWindowSystemBarEnable([]) 切换全屏后,可以尝试延迟一小段时间(如 100ms)再触发 ijkplayer 的重绘或 Surface 更新,以确保窗口系统已完成内部状态切换。
  • 检查是否在全屏和非全屏状态下,XComponent 获得的 NativeWindowwidthheight 与预期一致,避免尺寸计算错误导致拉伸和像素格式错位。

总结: 该问题的根源在于全屏切换导致 XComponent 的渲染表面(Surface/NativeWindow)属性或句柄发生变化,而 ijkplayer 未能及时同步并重新配置其渲染管线。解决方案的核心是在全屏状态变化时,准确地将新的 NativeWindow 句柄传递给 ijkplayer,并驱动其内部重新创建 EGL 渲染表面。请重点检查 onSurfaceChanged 回调的处理以及 ijkplayer 原生层中 EGL 环境与 Surface 的绑定逻辑。

回到顶部