demo:新增xor播放支持

sdk:player: texture 播放链优化
This commit is contained in:
2026-04-13 10:09:24 +08:00
parent 103145d5e6
commit 54a78130b1
11 changed files with 876 additions and 59 deletions

View File

@@ -582,7 +582,9 @@ player.play()
- `RTMP` 播放支持 `SurfaceView``TextureView``SurfaceTexture`
- `RTC/WHEP` 播放支持 `SurfaceViewRenderer``TextureView`,以及高级场景下的 `SurfaceTexture`
- 当前版本建议在 **开始播放前** 选定渲染后端;当前 Demo 在首页设置中统一选择,进入页面后不再暴露热切换
- `RTMP/VOD``TextureView / SurfaceTexture` 默认走 **direct output**,优先保证首帧和低延迟
- 当前版本建议在 **开始播放前** 选定渲染后端;运行中如需变更目标,请走 `clearRenderTarget()` + `setRenderView(...)` / `setRenderSurfaceTexture(...)` 的显式重绑流程
- Flutter 场景优先使用 `setRenderSurfaceTexture(...)`,配合 Flutter `Texture` widget 使用;如 UI 层级正确性优先,不建议继续依赖 `Hybrid Composition + SurfaceView`
控制接口:
@@ -599,6 +601,29 @@ player.play()
- `clearRenderTarget()`:解绑当前渲染面,播放会话可继续存活
- `seekBy(deltaMs)`:播放进度跳转(仅在流支持快进/回放时有效)
### 7.3.2 Flutter / SurfaceTexture 接入建议
如果业务侧需要把视频放到 Flutter UI 层下面,并正常叠加按钮、封面、弹层、动画,推荐使用:
- Flutter 侧创建 `TextureRegistry.SurfaceTextureEntry`
- Android 插件层取出 `SurfaceTexture`
- 调用 `setRenderSurfaceTexture(surfaceTexture, width, height)`
- Flutter 页面使用 `Texture(textureId)` 显示视频
示意:
```kotlin
player.setRenderSurfaceTexture(surfaceTexture, width, height)
player.prepareToPlay()
player.play()
```
说明:
- `SurfaceTexture` 生命周期由调用方负责
- 销毁前建议先调用 `clearRenderTarget()` 或直接 `release()`
- 如果页面重建、Texture 重新申请或 Flutter 侧切换 textureId需要重新绑定新的 `SurfaceTexture`
### 7.4 播放回调
```kotlin
@@ -622,6 +647,60 @@ player.delegate = object : SellyLiveVideoPlayerDelegate {
- `Reconnecting`
- `Failed`
首帧语义说明:
- 默认 `DIRECT` 模式下,`onFirstVideoFrameRendered()` 对应 decoder 首帧可用时机
-`TextureView / SurfaceTexture` 且启用了 playback processing 的场景SDK 会等待目标渲染面确认首帧已真正呈现后,再触发 `onFirstVideoFrameRendered()`
- `onFirstAudioFrameRendered()` 仍表示音频首帧可播放时机;在 texture-backed processing 场景中,音频与视频首帧不一定完全同一时刻
### 7.4.1 播放侧帧回调与二次处理
播放器支持一组独立于采集/推流链路的播放侧高级能力:
- `setPlaybackFrameObserver(observer)`:播放侧只读帧回调
- `setPlaybackVideoProcessor(processor)`:播放侧可写纹理处理
当前能力边界:
- 当前仅支持 **texture-backed** 播放目标:`TextureView` / `SurfaceTexture`
- 当前仅支持 `preferredFormat = TEXTURE_2D`
- 当前仅支持 `stage = RENDER_PRE_DISPLAY`
- 当前默认渲染模式为 `DIRECT`
- 只有设置了有效的 observer / processor才会切到 `PROCESSING`
- 如果当前 render target 已经绑定,新增或移除 observer / processor 后,需要 **重绑一次 texture render target** 才会生效
- `RTC/WHEP` 播放当前不支持这套 playback processing当前主要用于 `RTMP/VOD` 播放链
只读 observer 示例:
```kotlin
player.setPlaybackFrameObserver(object : PlaybackFrameObserver {
override val config = PlaybackFrameObserverConfig(
preferredFormat = VideoProcessFormat.TEXTURE_2D,
stage = VideoStage.RENDER_PRE_DISPLAY
)
override fun onTextureFrame(frame: VideoTextureFrame) {
// 读取播放侧纹理帧信息
}
})
```
可写 processor 示例:
```kotlin
player.setPlaybackVideoProcessor(object : PlaybackVideoProcessor {
override val config = PlaybackVideoProcessorConfig(
preferredFormat = VideoProcessFormat.TEXTURE_2D,
mode = VideoProcessMode.READ_WRITE,
stage = VideoStage.RENDER_PRE_DISPLAY
)
override fun processTexture(input: VideoTextureFrame, outputTextureId: Int) {
// 将后处理结果写入 outputTextureId
}
})
```
### 7.5 播放 API 速览(含 Demo 未覆盖)
创建与渲染:
@@ -634,6 +713,8 @@ player.delegate = object : SellyLiveVideoPlayerDelegate {
- `setRenderSurfaceTexture(surfaceTexture, width, height)`:绑定 `SurfaceTexture`(调用方负责 SurfaceTexture 生命周期)
- `clearRenderTarget()`:解绑当前渲染面
- `getRenderView()`:获取当前渲染 View
- `setPlaybackFrameObserver(observer)`:设置播放侧只读 observertexture 路径)
- `setPlaybackVideoProcessor(processor)`:设置播放侧 processortexture 路径)
播放控制:
@@ -655,6 +736,12 @@ player.delegate = object : SellyLiveVideoPlayerDelegate {
- `setRenderView(surfaceView)` / `setRenderView(textureView)`:手动绑定现有 View
- `setRenderSurfaceTexture(surfaceTexture, width, height)`:高级场景使用 `SurfaceTexture`(调用方负责 SurfaceTexture 生命周期)
- `clearRenderTarget()`:解绑当前渲染面但不一定立即销毁播放实例
- `setPlaybackFrameObserver(observer)` / `setPlaybackVideoProcessor(processor)`:点播同样支持 texture-backed playback processing
补充说明:
- 点播在重绑 `TextureView / SurfaceTexture` 后,会自动复用最近一次视频宽高信息,保持正确显示比例
- 如在已有 texture 目标上新增或移除 observer / processor也需要重绑一次 texture render target 才会应用新的渲染模式
因此 Demo 中点播页的 `SurfaceView / TextureView` 选择,也与直播播放页保持一致,均在首页设置中统一生效。
@@ -681,6 +768,10 @@ player.delegate = object : SellyLiveVideoPlayerDelegate {
- 推流前先完成采集预览
- `SurfaceView / TextureView` backend 建议在开始推流或播放前选定
- Flutter 场景优先使用 `setRenderSurfaceTexture(...)`,不要把 `Hybrid Composition + SurfaceView` 当成默认方案
- 普通播放默认保持 `DIRECT`;只有确实需要播放侧帧观察或纹理后处理时,再启用 playback processing
- playback processing 当前仅建议用于 `TextureView / SurfaceTexture + TEXTURE_2D + RENDER_PRE_DISPLAY`
- 变更 texture 路径的 observer / processor 后,显式重绑一次 render target
- `RTC/WHIP` 的美颜、滤镜、水印、观测优先使用 `TEXTURE_2D`
- `I420 / RGBA` 仅在算法必须访问 CPU 像素时再使用
- 完整重写输出的 GPU 处理器设置 `fullRewrite = true`;叠加类处理保留默认值
@@ -723,13 +814,13 @@ SDK 不解析 URL 中的鉴权信息,所有鉴权均通过 `token` 属性完
- 普通原生 Android 页面,优先使用默认 `SurfaceView`,性能最优
- 需要与按钮、封面、弹层等普通 View 正常混排时,优先使用 `TextureView`
- Flutter 场景通过 `setRenderSurfaceTexture()` 接入,`TextureView` 同一套渲染管线
- Flutter 场景通过 `setRenderSurfaceTexture()` 接入,配合 Flutter `Texture` widget 使用
- 当前版本建议在开始推流/播放前选定 backend当前 Demo 在首页设置中统一选择,进入页面后不支持切换
### Q5.1`TextureView` 模式下VOD/RTMP 播放的 `BufferQueueProducer timeout` 日志是什么?
**A**
SDK 内部使用 GL Bridge 将 MediaCodec 硬解输出通过 OpenGL 中转渲染到 TextureView大幅减少此类日志。如在极端场景下仍偶现属于 Android 系统 BufferQueue 机制限制,不影响播放功能。`SurfaceView` 路径不存在此问题
当前 `RTMP/VOD``TextureView / SurfaceTexture` 默认走 direct output以缩短首帧和减少黑屏。极端机型或系统版本下仍可能偶现 `BufferQueueProducer timeout` / `BufferQueue has been abandoned` 之类系统日志;如果不伴随黑屏、花屏、卡死,通常可视为 Android BufferQueue 机制噪声。开启 playback processing 时texture 路径内部会启用额外的处理中转链,日志形态也可能与 direct 模式不同
### Q5.2`attach` 和 `set` 两套 API 的区别?
**A**