You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Rodger-Wang
56aa55773d
字幕小窗改成自绘:pip 包只喂了一块纯黑像素,字幕根本进不去小窗
用户反馈「悬浮弹幕上没有显示翻译内容」,根因在 pub 包 pip 0.0.4:
PipView.m: const int pixel = 0xFF000000; // BGRA 全黑
填满 pixelBuffer → enqueue 进 AVSampleBufferDisplayLayer
小窗显示的就是这一帧纯黑占位。真正的字幕卡片它是靠
insertContentViewIfNeeded 塞进 activeKeyWindow 的,而 PiP 窗口由系统进程托管、
**不在 UIApplication.connectedScenes 的窗口列表里**,那个 keyWindow 永远是
App 自己的窗口。于是字幕落在 App 身上(上一版还因此盖住整个屏幕点不动),
小窗里只可能是黑的。PipView.m 全文件 0 处引用 contentView,可以佐证。
改成自己实现:SubtitlePipController 把 PlayerView 画进 CVPixelBuffer,
逐帧喂给自己的 AVSampleBufferDisplayLayer,再用 sampleBufferDisplayLayer
这一路 content source 起 AVPictureInPictureController。小窗显示的就是它。
Dart 侧不再依赖 pip 包(import 与相关字段一并删除)。
同时回答另外两个问题:
- 大小:PiP 小窗的实际尺寸由用户捏合手势决定,App 无权直接设定。能控的是
**宽高比**(= 画布宽高比),setPipWidthScale 改的是这个,系统会按新形状
重新布局。另外卡片有内容时自动变高、没内容时收成一条,也走同一条路。
- 透明度:**做不到透过小窗看见下面的 App**。iOS 的 PiP 窗口本身不透明,
系统没有开放任何接口。setPipOpacity 只作用于卡片自己的底色(在小窗那块底
之上显得深浅不同)。真要少挡内容只能把小窗做小或拖到别处。
这一条在 Dart 与原生两侧的注释里都写明了,免得以后有人再试一遍。
几处实现要点:
- 心跳定时器每秒补一帧。只在文案变化时推帧的话,长时间没有新帧会让
AVSampleBufferDisplayLayer 被判定停滞并清空,表现是「翻译停一会儿小窗就黑」。
- start() 之前先推一帧:没有任何已入队帧时 AVPictureInPictureController
会判定内容源为空,直接回调 failed。
- 渲染上下文要做一次 y 轴翻转,否则字幕上下颠倒(UIKit 原点左上、CG 左下)。
- renderView 必须挂在真实窗口层级里且尺寸非零,脱离层级的 layer 不被 PiP 采纳。
- 时间轴返回无限区间,让系统按直播流处理,小窗上不出现进度条和快进按钮。
⚠️ 构建注意:给本地 pod 加新文件后必须重跑 pod install,否则文件不进 Pods
工程,报 "Cannot find 'SubtitlePipController' in scope"。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
1 month ago |
| .. |
|
core
|
闹钟改成只在 App 内提示;通话翻译/通话录音挂前台服务;复刻档位日志提到 warn
|
1 month ago |
|
data
|
iOS 多媒体翻译接入 ReplayKit 广播扩展,真正拿系统音频
|
1 month ago |
|
modules
|
字幕小窗改成自绘:pip 包只喂了一块纯黑像素,字幕根本进不去小窗
|
1 month ago |
|
routes
|
收拢积压改动:恒玄 OTA、发版配置拆表、实名认证、芯片厂商/代工厂管理等
|
1 month ago |
|
firebase_options.dart
|
apps/client 首次入库(Flutter 移动端)
|
1 month ago |
|
main.dart
|
apps/client 首次入库(Flutter 移动端)
|
1 month ago |