|
@@ -10,16 +10,21 @@
|
|
|
#include <cassert>
|
|
#include <cassert>
|
|
|
#include <d3d11.h>
|
|
#include <d3d11.h>
|
|
|
#include <dxgi1_2.h>
|
|
#include <dxgi1_2.h>
|
|
|
|
|
+#include <QDebug>
|
|
|
|
|
+#include <mutex>
|
|
|
|
|
|
|
|
namespace avrecorder {
|
|
namespace avrecorder {
|
|
|
namespace video {
|
|
namespace video {
|
|
|
|
|
|
|
|
// --- DxgiCapturerPrivate 实现 ---
|
|
// --- DxgiCapturerPrivate 实现 ---
|
|
|
bool DxgiCapturerPrivate::Open(int left, int top, int width, int height) {
|
|
bool DxgiCapturerPrivate::Open(int left, int top, int width, int height) {
|
|
|
- Close();
|
|
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(_deviceMutex);
|
|
|
|
|
+ CloseInternal(); // 使用内部方法避免死锁
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hr = S_OK;
|
|
|
_isAttached = false;
|
|
_isAttached = false;
|
|
|
- if (_bInit) return false;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 重置初始化状态,允许重新初始化
|
|
|
|
|
+ _bInit = false;
|
|
|
// Driver types supported
|
|
// Driver types supported
|
|
|
D3D_DRIVER_TYPE DriverTypes[] = {
|
|
D3D_DRIVER_TYPE DriverTypes[] = {
|
|
|
D3D_DRIVER_TYPE_HARDWARE,
|
|
D3D_DRIVER_TYPE_HARDWARE,
|
|
@@ -111,22 +116,39 @@ bool DxgiCapturerPrivate::Open(int left, int top, int width, int height) {
|
|
|
Free(_hDevice, [this]{ _hDevice->Release(); });
|
|
Free(_hDevice, [this]{ _hDevice->Release(); });
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
- // Set ColorSpace
|
|
|
|
|
|
|
+ // Set ColorSpace - 修复RGB到NV12转换的颜色空间设置
|
|
|
D3D11_VIDEO_PROCESSOR_COLOR_SPACE inputColorSpace;
|
|
D3D11_VIDEO_PROCESSOR_COLOR_SPACE inputColorSpace;
|
|
|
- inputColorSpace.Usage = 1;
|
|
|
|
|
- inputColorSpace.RGB_Range = 0;
|
|
|
|
|
- inputColorSpace.YCbCr_Matrix = 1;
|
|
|
|
|
- inputColorSpace.YCbCr_xvYCC = 0;
|
|
|
|
|
- inputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255;
|
|
|
|
|
|
|
+ inputColorSpace.Usage = 0; // 0 = Playback (更适合屏幕捕获)
|
|
|
|
|
+ inputColorSpace.RGB_Range = 0; // 0 = Full range (0-255) for RGB input
|
|
|
|
|
+ inputColorSpace.YCbCr_Matrix = 0; // 对于RGB输入,这个值会被忽略,但设为0 (BT.601)
|
|
|
|
|
+ inputColorSpace.YCbCr_xvYCC = 0; // 0 = Conventional YCbCr
|
|
|
|
|
+ inputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255; // Full range for RGB
|
|
|
|
|
+
|
|
|
D3D11_VIDEO_PROCESSOR_COLOR_SPACE outputColorSpace;
|
|
D3D11_VIDEO_PROCESSOR_COLOR_SPACE outputColorSpace;
|
|
|
- outputColorSpace.Usage = 0;
|
|
|
|
|
- outputColorSpace.RGB_Range = 0;
|
|
|
|
|
- outputColorSpace.YCbCr_Matrix = 1;
|
|
|
|
|
- outputColorSpace.YCbCr_xvYCC = 0;
|
|
|
|
|
- outputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235;
|
|
|
|
|
- _rgbToNv12.Open(_hDevice, _hContext, inputColorSpace, outputColorSpace);
|
|
|
|
|
|
|
+ outputColorSpace.Usage = 0; // 0 = Playback
|
|
|
|
|
+ outputColorSpace.RGB_Range = 0; // 对于YUV输出,这个值会被忽略
|
|
|
|
|
+ outputColorSpace.YCbCr_Matrix = 0; // 0 = BT.601 (标准定义电视)
|
|
|
|
|
+ outputColorSpace.YCbCr_xvYCC = 0; // 0 = Conventional YCbCr
|
|
|
|
|
+ outputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235; // Studio range for YUV output
|
|
|
|
|
+
|
|
|
|
|
+ qDebug() << "DxgiCapturer::Open: Color space settings - Input: Usage=" << inputColorSpace.Usage
|
|
|
|
|
+ << ", RGB_Range=" << inputColorSpace.RGB_Range << ", Nominal_Range=" << inputColorSpace.Nominal_Range
|
|
|
|
|
+ << "; Output: Usage=" << outputColorSpace.Usage << ", YCbCr_Matrix=" << outputColorSpace.YCbCr_Matrix
|
|
|
|
|
+ << ", Nominal_Range=" << outputColorSpace.Nominal_Range;
|
|
|
|
|
+
|
|
|
|
|
+ // 确保RGB到NV12转换器正确初始化
|
|
|
|
|
+ qDebug() << "DxgiCapturer::Open: Initializing RGB to NV12 converter";
|
|
|
|
|
+ if (FAILED(_rgbToNv12.Open(_hDevice, _hContext, inputColorSpace, outputColorSpace))) {
|
|
|
|
|
+ qDebug() << "DxgiCapturer::Open: RGB to NV12 converter initialization failed";
|
|
|
|
|
+ Free(_hDeskDupl, [this]{ _hDeskDupl->Release(); });
|
|
|
|
|
+ Free(_hContext, [this]{ _hContext->Release(); });
|
|
|
|
|
+ Free(_hDevice, [this]{ _hDevice->Release(); });
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ qDebug() << "DxgiCapturer::Open: RGB to NV12 converter initialized successfully";
|
|
|
_nv12Frame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_NV12, width, height);
|
|
_nv12Frame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_NV12, width, height);
|
|
|
_xrgbFrame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_BGR0, width, height);
|
|
_xrgbFrame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_BGR0, width, height);
|
|
|
|
|
+
|
|
|
if (!_nv12Frame) {
|
|
if (!_nv12Frame) {
|
|
|
__DebugPrint("Alloc NV12 frame failed");
|
|
__DebugPrint("Alloc NV12 frame failed");
|
|
|
Free(_hDeskDupl, [this]{ _hDeskDupl->Release(); });
|
|
Free(_hDeskDupl, [this]{ _hDeskDupl->Release(); });
|
|
@@ -149,6 +171,7 @@ bool DxgiCapturerPrivate::Open(int left, int top, int width, int height) {
|
|
|
AVFrame* DxgiCapturerPrivate::GetFrame(
|
|
AVFrame* DxgiCapturerPrivate::GetFrame(
|
|
|
bool shouldDrawCursor, int left, int top, int right, int bottom)
|
|
bool shouldDrawCursor, int left, int top, int right, int bottom)
|
|
|
{
|
|
{
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(_deviceMutex);
|
|
|
if (!_bInit) return nullptr;
|
|
if (!_bInit) return nullptr;
|
|
|
_isCaptureSuccess = false;
|
|
_isCaptureSuccess = false;
|
|
|
IDXGIResource* hDesktopResource = nullptr;
|
|
IDXGIResource* hDesktopResource = nullptr;
|
|
@@ -219,13 +242,23 @@ AVFrame* DxgiCapturerPrivate::GetFrame(
|
|
|
return nullptr;
|
|
return nullptr;
|
|
|
}
|
|
}
|
|
|
_hContext->CopyResource(tmpImage, _gdiImage);
|
|
_hContext->CopyResource(tmpImage, _gdiImage);
|
|
|
- // 首先尝试创建 NV12 纹理
|
|
|
|
|
|
|
+ // 首先尝试创建 NV12 纹理,如果失败则重试一次
|
|
|
AVFrame* frame = nullptr;
|
|
AVFrame* frame = nullptr;
|
|
|
auto tmpFormat = _desc.Format;
|
|
auto tmpFormat = _desc.Format;
|
|
|
_desc.Format = DXGI_FORMAT_NV12;
|
|
_desc.Format = DXGI_FORMAT_NV12;
|
|
|
- if (GenNv12Frame(_hDevice, _hContext, _desc, tmpImage, _nv12Buffers, _nv12Frame, _rgbToNv12)) {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ bool nv12Success = GenNv12Frame(_hDevice, _hContext, _desc, tmpImage, _nv12Buffers, _nv12Frame, _rgbToNv12);
|
|
|
|
|
+ if (!nv12Success) {
|
|
|
|
|
+ qDebug() << "DxgiCapturer::GetFrame: First NV12 conversion failed, retrying...";
|
|
|
|
|
+ // 重试一次NV12转换
|
|
|
|
|
+ nv12Success = GenNv12Frame(_hDevice, _hContext, _desc, tmpImage, _nv12Buffers, _nv12Frame, _rgbToNv12);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (nv12Success) {
|
|
|
frame = _nv12Frame;
|
|
frame = _nv12Frame;
|
|
|
|
|
+ qDebug() << "DxgiCapturer::GetFrame: NV12 conversion successful";
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ qDebug() << "DxgiCapturer::GetFrame: NV12 conversion failed, falling back to RGB";
|
|
|
_desc.Format = tmpFormat;
|
|
_desc.Format = tmpFormat;
|
|
|
GenRgbFrame(_hDevice, _hContext, _desc, _gdiImage, _xrgbBuffers, _xrgbFrame);
|
|
GenRgbFrame(_hDevice, _hContext, _desc, _gdiImage, _xrgbBuffers, _xrgbFrame);
|
|
|
frame = _xrgbFrame;
|
|
frame = _xrgbFrame;
|
|
@@ -283,17 +316,41 @@ bool DxgiCapturer::open(const CaptureTarget& target, int width, int height) {
|
|
|
#endif
|
|
#endif
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void DxgiCapturerPrivate::Close() {
|
|
|
|
|
|
|
+void DxgiCapturerPrivate::CloseInternal() {
|
|
|
if (!_bInit) return;
|
|
if (!_bInit) return;
|
|
|
|
|
+ qDebug() << "DxgiCapturerPrivate::CloseInternal: Starting cleanup";
|
|
|
|
|
+
|
|
|
_bInit = false;
|
|
_bInit = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 清理缓冲区
|
|
|
|
|
+ qDebug() << "DxgiCapturerPrivate::CloseInternal: Clearing buffers";
|
|
|
_nv12Buffers.Clear();
|
|
_nv12Buffers.Clear();
|
|
|
_xrgbBuffers.Clear();
|
|
_xrgbBuffers.Clear();
|
|
|
|
|
+
|
|
|
|
|
+ // 释放D3D转换器
|
|
|
|
|
+ qDebug() << "DxgiCapturerPrivate::CloseInternal: Closing D3D converter";
|
|
|
_rgbToNv12.Close();
|
|
_rgbToNv12.Close();
|
|
|
|
|
+
|
|
|
|
|
+ // 释放帧
|
|
|
|
|
+ qDebug() << "DxgiCapturerPrivate::CloseInternal: Freeing frames";
|
|
|
Free(_nv12Frame, [this] { av_frame_free(&_nv12Frame); });
|
|
Free(_nv12Frame, [this] { av_frame_free(&_nv12Frame); });
|
|
|
Free(_xrgbFrame, [this] { av_frame_free(&_xrgbFrame); });
|
|
Free(_xrgbFrame, [this] { av_frame_free(&_xrgbFrame); });
|
|
|
|
|
+
|
|
|
|
|
+ // 释放DXGI资源
|
|
|
|
|
+ qDebug() << "DxgiCapturerPrivate::CloseInternal: Releasing DXGI resources";
|
|
|
Free(_hDeskDupl, [this] { _hDeskDupl->Release(); });
|
|
Free(_hDeskDupl, [this] { _hDeskDupl->Release(); });
|
|
|
- Free(_hDevice, [this] { _hDevice->Release(); });
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 最后释放D3D设备和上下文
|
|
|
|
|
+ qDebug() << "DxgiCapturerPrivate::CloseInternal: Releasing D3D resources";
|
|
|
Free(_hContext, [this] { _hContext->Release(); });
|
|
Free(_hContext, [this] { _hContext->Release(); });
|
|
|
|
|
+ Free(_hDevice, [this] { _hDevice->Release(); });
|
|
|
|
|
+
|
|
|
|
|
+ qDebug() << "DxgiCapturerPrivate::CloseInternal: Cleanup completed";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void DxgiCapturerPrivate::Close() {
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(_deviceMutex);
|
|
|
|
|
+ CloseInternal();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void DxgiCapturer::close() {
|
|
void DxgiCapturer::close() {
|