You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何切换视频解码器的NewFrame事件委托?

这是个很典型的委托引用和事件订阅的坑,我来帮你理清楚问题所在,以及为什么你的最终方案是可行的:

为什么最初的代码不生效?

当你执行decoder.NewFrame += currentNewFrameDelegate;时,事件订阅的是当时currentNewFrameDelegate指向的playingStarted方法的引用。后续你修改currentNewFrameDelegate = imageReceived;,只是改变了这个变量的指向,但事件列表里保存的还是最初的playingStarted引用,所以每次触发NewFrame时,依然会调用playingStarted,完全不受变量修改的影响。

关于你提到的间接调用方案

你尝试的:

decoder.NewFrame += img => currentNewFrameDelegate?.Invoke(img);

其实这个思路是对的——通过一个固定的lambda作为事件的订阅者,让它去调用当前的委托变量。如果出现“双重调用”,大概率是你没有取消之前订阅的currentNewFrameDelegate(也就是playingStarted),导致事件列表里同时存在原来的委托和这个lambda,所以每次触发会执行两次。如果只订阅这个lambda,然后通过修改currentNewFrameDelegate的指向来切换处理逻辑,这个方案是可以正常工作的,只是相比你的最终方案,每次事件触发多了一层lambda的调用开销,对于实时视频处理来说,可能会有微小的性能影响。

你的最终方案:高效且易维护的正确姿势

你写的这个hookNewFrameEvent函数,完美解决了问题,而且非常适合你的场景:

Action<byte[]> current;
void hookNewFrameEvent(Action<byte[]> x) {
    decoder.NewFrame -= current;
    decoder.NewFrame += x;
    current = x;
}

原理说明:

  1. 每次切换处理逻辑时,先从事件中移除当前正在订阅的委托(保存在current变量里)。
  2. 再将新的处理委托x添加到事件中。
  3. 最后更新current变量,记录当前订阅的委托,方便下次切换时移除。

优势:

  • 性能高效:每次切换只做一次移除和一次添加操作,没有额外的中间调用开销,完全满足视频处理对实时性的要求。
  • 可读性高:所有事件订阅的切换逻辑都集中在这个函数里,你在任何需要切换回playingStarted的地方,只需要调用hookNewFrameEvent(playingStarted)即可,不用重复写-=和+=的代码,避免了代码冗余和出错的可能。

如果你需要初始化时就订阅playingStarted,只需要在构造函数里调用hookNewFrameEvent(playingStarted)就可以了,完全替代你最初的订阅代码。


内容的提问来源于stack exchange,提问作者Larry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:37:55