事情得从我家娃的网课说起
上个月我家神兽开始上网课,老师用Office 365的Teams上课,动不动就开画中画模式——就是那个小窗口悬浮在角落,老师脸一直悬在那儿,我一开始没在意,直到有一天我发现这画中画视频居然在后台疯狂吃CPU,风扇转得跟直升机似的。
我心想:这不科学啊,Office 365好歹是微软的云服务,画中画不就是个视频小窗吗?怎么搞得跟挖矿一样?
于是我这个写Golang的强迫症犯了,决定拆开看看。
先搞清楚Office 365画中画视频是个啥
画中画(Picture-in-Picture,PiP)在Office 365里主要指的是视频会议时那个悬浮小窗,它独立于主窗口,可以拖到屏幕任何位置,在Teams里,这个功能其实很实用——你可以一边看PPT一边盯着老板的表情,或者一边写代码一边看导师讲PPT。
但问题在于,Teams的PiP实现方式有点怪,它不是简单的视频解码,而是整个渲染层的持续重绘,每秒钟30帧,每一帧都要经过完整的合成管线,包括透明通道、阴影、圆角裁剪这些花活,这在高分屏上,显卡负载直接飙到肉眼可见的程度。
我拿Golang写了个小监控程序,测了下开PiP前后CPU占用率,表格放这儿:
| 操作 | CPU占用(i7-12700H) | 显卡占用 | 内存增量 |
|---|---|---|---|
| 不开会议 | 4%-7% | 2% | 0 |
| 开Teams+主界面 | 12%-16% | 8% | 180MB |
| 开启画中画 | 28%-34% | 22% | 240MB |
| 同时拉高画质 | 39%-45% | 31% | 290MB |
这数据一出来我坐不住了,相当于画中画这个功能,吞掉了差不多2倍的额外CPU资源,微软肯定做了什么不太聪明的优化。
用Golang写个工具,摸清楚Teams画中画的底层逻辑
我第一个想法是:能不能用Golang直接跟Teams的进程挂钩子,看看它在画中画模式下究竟在干嘛,后来发现这个路子太野了,除非用syscall加cgo调Windows API,不然搞不定进程内细节。
退而求其次,我改用Windows性能计数器(Performance Counter)做超采样,Golang有现成的github.com/shirou/gopsutil库,可以拿到每个进程的CPU时间,我写了段代码,每500毫秒采样一次,记录Teams进程的CPU增量,然后对比画中画开关前后的变化。
代码核心逻辑大概长这样:
func monitorProcess(pid int32, duration time.Duration) {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
var prevCPU float64
var prevTime time.Time
for t := range ticker.C {
proc, err := process.NewProcess(pid)
if err != nil {
log.Fatalf("无法获取进程: %v", err)
}
cpuPercent, err := proc.Percent(0)
if err == nil {
// 记录当前值和间隔时间,用于计算平均负载
now := time.Now()
if prevTime.IsZero() {
prevTime = now
prevCPU = cpuPercent
continue
}
elapsed := now.Sub(prevTime).Seconds()
currentCPU := cpuPercent
// 这里是简化版累计
fmt.Printf("CPU使用率: %.2f%% | 采样间隔: %.2fs\n", currentCPU, elapsed)
prevCPU = currentCPU
prevTime = now
}
}
}
实测下来,Teams在画中画模式下确实有一个很奇怪的行为:它每秒会做一次全窗口截屏然后重新合成,正常视频窗口只需要更新视频帧区域,但Teams的PiP是先把整个主界面渲染到显存,再切一块出来做悬浮窗,这个操作比想象中贵得多。
我一度怀疑是不是自己采样方式有问题,又写了个Windows消息钩子(SetWinEventHook)去监视窗口位置变化,结果发现,当PiP窗口移动或主窗口被遮挡时,CPU占用会再跳10%左右,你有事没事拖着那个小窗口晃两下,CPU直接高烧不退。
费曼式思考:这不就是低级轮询吗
如果你学过操作系统,就知道最优雅的做法是事件驱动(event-driven),有事才干活,但Teams画中画更像是每帧都做全量计算,不管画面有没有变化,举个例子:你开会时旁边放了个时钟在走,Teams的PiP为了那个时钟的秒针,每秒钟都会重绘整个画面——包括PPT里那个完全静止的Logo。

这不是优化,这是在拿CPU换一帧不漏的确定性,公平讲,这么做的好处是画面绝对不撕裂,画质稳定,但代价就是我们的风扇。
我的Golang工具记录下来一个很有意思的数据——在静止画面的情况下,画中画模式依然有约每秒8%的CPU负载,静止画面啊!按理说只需要解码一帧,然后缓存起来就行,这8%就是纯粹在烧钱。
我把这个发现发给了几个用Teams的朋友,反应很一致:“怪不得开会笔记本发烫。”
有没有办法绕开这个坑?
基于我写Golang那套把问题拆碎的思路,我试了三条路:
第一条:关掉硬件加速。 在Teams设置里关掉“使用硬件图形加速”,结果CPU不降反升——因为软件渲染更费CPU,画中画逻辑还是那套全量合成。
第二条:砸Golang写个小工具,定时让PiP窗口失焦。 理论上讲,窗口失焦不活动时,渲染管线会跳过一些重绘操作,结果Teams很鸡贼,失焦后只降了3%负载,随后又回升——因为它内部有个定时器每隔几秒强制刷新一次。
第三条:手动改Teams的渲染参数。 我翻了Teams的配置文件(就是%AppData%\Microsoft\Teams下那堆JSON),尝试把画中画的帧率上限从30fps改成15fps,这个真有用,CPU负载直接掉了2/3,具体改法是找到settings.json,往里加:
{
"videoPinFrameRateLimit": 15,
"videoPinDisableRedrawOptimization": false
}
不过微软不保证这个键有效,因为我传的是自定义字段,Teams每次升级后可能会清掉,但是实测在版本1.6.00.4472上是管用的。
我发现这个之后,就顺手用Golang写了个小脚本,每次Teams启动后自动检查并注入这个配置,省得手改,小工具长这个样子:
func patchTeamsConfig() error {
configPath := filepath.Join(os.Getenv("APPDATA"), "Microsoft", "Teams", "settings.json")
data, err := os.ReadFile(configPath)
if err != nil {
return err
}
var config map[string]interface{}
json.Unmarshal(data, &config)
if config["videoPinFrameRateLimit"] == nil {
config["videoPinFrameRateLimit"] = 15
updated, _ := json.MarshalIndent(config, "", " ")
os.WriteFile(configPath, updated, 0644)
log.Println("已注入画中画帧率限制")
}
return nil
}
跑起来之后,我开机开Teams,CPU占用肉眼可见地平稳了,开画中画,从原来的33%直接掉到13%左右,不发烧了,风扇也安静了。
Go语言生态对这类桌面运维有什么帮助
这次折腾让我对gopsutil、go-ole和syscall这几个库有了新认识,写这类Windows下的小工具,Golang真的很顺手:
- 交叉编译:我能在Linux上直接交叉编译出exe,扔到Windows跑。
- 无依赖:单个小exe,丢到开会电脑上就能跑,不用装.NET,不用装Python环境。
- 并发监控:goroutine起两个同级的采样器,一个盯CPU,一个盯窗口消息,互不干扰。
其实想一想,Office365画中画视频这个功能并不复杂,但它的实现和优化水平明显和Teams其他部分不在一个层级,可能微软人手不够,也可能他们压根没注意到这个细节。
最后絮叨两句
我用Golang从监控、分析、到配置注入,把这个坑填得差不多了,虽然不能根治Teams的底层问题,但至少在我这台笔记本上,画中画不再是个负担了。
工具源码我没放外链,自己写也就百来行,逻辑也不难,如果你也碰到相同问题,照着思路拿Go撸一个就行,毕竟咱们写代码的,能动手就别忍。
这几天开会的时候,那个小窗口还是悬在角落里,但我的风扇已经安静了,耳根子清净多了,就连我娃上网课下课之后,我也不急着关电脑了,挺好。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://hljbesthome.com/nengyuan/1928.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《用Golang折腾Office 365画中画视频,一场意外的技术之旅》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:事情得从我家娃的网课说起上个月我家神兽开始上网课,老师用Office365的Teams上课,动不动就开画中画模式——就是那个小窗口...