diff --git a/Fischless.GameCapture/BitBlt/BitBltCapture.cs b/Fischless.GameCapture/BitBlt/BitBltCapture.cs
index bf8eff15..85992d13 100644
--- a/Fischless.GameCapture/BitBlt/BitBltCapture.cs
+++ b/Fischless.GameCapture/BitBlt/BitBltCapture.cs
@@ -92,7 +92,7 @@ public class BitBltCapture : IGameCapture
}
catch (Exception e)
{
- Error.WriteLine("Failed to create bitblt session:{0}", e);
+ Error.WriteLine("[BitBlt]Failed to create session:{0}", e);
return false;
}
finally
@@ -123,27 +123,48 @@ public class BitBltCapture : IGameCapture
}
}
+ Mat? mat = null;
try
{
_lockSlim.EnterReadLock();
- using var mat = _session?.BitBlt();
- if (mat is null || mat.Empty())
+ if (_session is null)
{
- if (_session is not null && !_session.IsInvalid())
- {
- // 有时候会出现截图失败的情况,这时候重置会话
- _needResetSession = true;
- }
-
+ // 没有成功创建会话,直接返回空
return null;
}
+ mat = _session.GetMat();
+
+ if (mat is not null) // 成功执行
+ {
+ if (!mat.Empty()) // 并且获取到了图
+ {
+ _needResetSession = false;
+ return mat;
+ }
+ else // 成功执行但是没有图,可能是截图过快导致的
+ {
+ mat.Dispose();
+ mat = null; // 防止二次释放
+ }
+ }
- var bgrMat = new Mat();
- Cv2.CvtColor(mat, bgrMat, ColorConversionCodes.BGRA2BGR);
- return bgrMat;
+ // 无论没有图还是执行失败都会到这里
+ if (_session is not null && !_session.IsInvalid())
+ {
+ // _session正确但是截图失败,如果持续出现这个问题需要重置会话
+ _needResetSession = true;
+ }
+
+ return null;
}
- catch (Exception)
+ catch (Exception e)
{
+ // 理论这里不应出现异常,除非窗口不存在了或者有什么bug
+ // 出现异常的时候释放内存
+ mat?.Dispose();
+ // 如果持续出现异常则重置会话
+ _needResetSession = true;
+ Error.WriteLine("[BitBlt]Failed to capture image {0}", e);
return null;
}
finally
diff --git a/Fischless.GameCapture/BitBlt/BitBltSession.cs b/Fischless.GameCapture/BitBlt/BitBltSession.cs
index 6d102f71..ff3efee7 100644
--- a/Fischless.GameCapture/BitBlt/BitBltSession.cs
+++ b/Fischless.GameCapture/BitBlt/BitBltSession.cs
@@ -25,8 +25,18 @@ public class BitBltSession : IDisposable
// 旧位图,析构时一起释放掉
private HGDIOBJ _oldBitmap;
public int Width { get; }
+
public int Height { get; }
+ // 用于过滤alpha通道
+ private static readonly Gdi32.BLENDFUNCTION BlendFunction = new()
+ {
+ BlendOp = 0, //Gdi32.BlendOperation.AC_SRC_OVER,
+ BlendFlags = 0,
+ SourceConstantAlpha = 255,
+ AlphaFormat = 0,
+ };
+
private readonly object _lockObject = new object();
@@ -71,9 +81,9 @@ public class BitBltSession : IDisposable
biWidth = Width,
biHeight = -Height, // Top-down image
biPlanes = 1,
- biBitCount = 32,
+ biBitCount = 24,
biCompression = 0, // BI_RGB
- biSizeImage = 0
+ biSizeImage = 0,
}
};
_hBitmap = Gdi32.CreateDIBSection(_hdcDest, bmi, Gdi32.DIBColorMode.DIB_RGB_COLORS, out var bits,
@@ -105,17 +115,27 @@ public class BitBltSession : IDisposable
}
///
- /// 调用bitblt复制并返回新的mat
+ /// 调用GDI复制到缓冲区并返回新的mat
///
- ///
- public Mat? BitBlt()
+ /// MatType.CV_8UC3
+ public Mat? GetMat()
{
lock (_lockObject)
{
- return Gdi32.BitBlt(_hdcDest, 0, 0, Width, Height, _hdcSrc, 0, 0, Gdi32.RasterOperationMode.SRCCOPY) ? Mat.FromPixelData(Height, Width, MatType.CV_8UC4, _bitsPtr) : null;
+ // 直接返回转换后的位图
+ return Gdi32.AlphaBlend(_hdcDest, 0, 0, Width, Height, _hdcSrc, 0, 0, Width, Height, BlendFunction)
+ ? Mat.FromPixelData(Height, Width, MatType.CV_8UC3, _bitsPtr, (Width * 3 + 3) & ~3)
+ : null;
+
+ // 原始宏 ((((biWidth * biBitCount) + 31) & ~31) >> 3) => (biWidth * biBitCount + 3) & ~3) (在总位数是8的倍数时,两者等价)
+ // 对齐 https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
+
+ // 适用于32位(RGBA)
+ // return Gdi32.BitBlt(_hdcDest, 0, 0, Width, Height, _hdcSrc, 0, 0, Gdi32.RasterOperationMode.SRCCOPY ) ? Mat.FromPixelData(Height, Width, MatType.CV_8UC3, _bitsPtr) : null;
}
}
+
///
/// 不是所有的失效情况都能被检测到
///