Fix: skip detection black-screen on single-monitor capture

This commit is contained in:
yuanyuanxiang
2026-06-03 18:53:14 +02:00
parent 99be79b7ae
commit fcd3b13ca8

View File

@@ -150,6 +150,12 @@ public:
int m_GOP; // 关键帧间隔 int m_GOP; // 关键帧间隔
bool m_SendKeyFrame; // 发送关键帧 bool m_SendKeyFrame; // 发送关键帧
std::unique_ptr<VideoEncoderBase> m_encoder; // 编码器ensureEncoder() lazy 创建,走 EncoderFactory 探测 std::unique_ptr<VideoEncoderBase> m_encoder; // 编码器ensureEncoder() lazy 创建,走 EncoderFactory 探测
bool m_bEncoderPrimed = false; // encoder 是否已成功产出过一个包;
// false 时禁止 skip——避免单显示器路径
// 下 m_FirstBuffer 别名到 m_BitmapData_Full
// 且被 GetFirstScreenData 预先填过同帧像素,
// 导致首帧 memcmp 错误命中、跳过 encode、
// 永远不产 IDR → web 黑屏
int m_nScreenCount; // 屏幕数量 int m_nScreenCount; // 屏幕数量
BOOL m_bEnableMultiScreen;// 多显示器支持 BOOL m_bEnableMultiScreen;// 多显示器支持
@@ -949,6 +955,7 @@ public:
} }
*ulNextSendLength = 1 + offset + encoded_size; *ulNextSendLength = 1 + offset + encoded_size;
memcpy(data + offset, encoded_data, encoded_size); memcpy(data + offset, encoded_data, encoded_size);
m_bEncoderPrimed = true; // 与下方 FirstBuffer 同步:自此 skip 安全
break; break;
} }
default: default:
@@ -974,9 +981,14 @@ public:
// 即使逐像素完全一致仍 emit ~5KB/帧的"近 skip P 帧",让空闲流量长期 // 即使逐像素完全一致仍 emit ~5KB/帧的"近 skip P 帧",让空闲流量长期
// 维持 100-200 KB/s每 4s GOP 还叠加一个 IDR。整帧 memcmp BGRA // 维持 100-200 KB/s每 4s GOP 还叠加一个 IDR。整帧 memcmp BGRA
// 找出真无变化帧直接跳过 encode仅发 cursorx264 走这里也省 CPU 无副作用。 // 找出真无变化帧直接跳过 encode仅发 cursorx264 走这里也省 CPU 无副作用。
//
// m_bEncoderPrimed 门encoder 还没产出过任何包时不允许 skip。
// 否则单显示器路径下 m_FirstBuffer 别名到 m_BitmapData_Full
// 而 GetFirstScreenData 已经把同一帧画进去了——首帧 memcmp 会
// 错误命中、永远不会喂 encoder、web 收不到 IDR、黑屏不恢复。
LPBYTE prev = GetFirstBuffer(); LPBYTE prev = GetFirstBuffer();
ULONG bgraSize = m_BitmapInfor_Send->bmiHeader.biSizeImage; ULONG bgraSize = m_BitmapInfor_Send->bmiHeader.biSizeImage;
if (prev && memcmp(nextData, prev, bgraSize) == 0) { if (m_bEncoderPrimed && prev && memcmp(nextData, prev, bgraSize) == 0) {
*ulNextSendLength = 1 + offset; // 仅 cursor无视频负载 *ulNextSendLength = 1 + offset; // 仅 cursor无视频负载
return m_RectBuffer; return m_RectBuffer;
} }
@@ -987,6 +999,7 @@ public:
} }
*ulNextSendLength = 1 + offset + encoded_size; *ulNextSendLength = 1 + offset + encoded_size;
memcpy(data + offset, encoded_data, encoded_size); memcpy(data + offset, encoded_data, encoded_size);
m_bEncoderPrimed = true; // 这一刻起 prev 才有"已编码"语义skip 才安全
// 更新参考帧供下一帧 memcmp。必须在 encode 成功之后更新,否则编码 // 更新参考帧供下一帧 memcmp。必须在 encode 成功之后更新,否则编码
// 失败时下一帧会误以为"已发"而漏发真实变化。 // 失败时下一帧会误以为"已发"而漏发真实变化。
memcpy(prev, nextData, bgraSize); memcpy(prev, nextData, bgraSize);