Sfoglia il codice sorgente

修复一些潜在的问题

zhuizhu 7 mesi fa
parent
commit
66eca2cfc0

+ 75 - 18
AvRecorder/capturer/video/DxgiCapturer.cpp

@@ -10,16 +10,21 @@
 #include <cassert>
 #include <d3d11.h>
 #include <dxgi1_2.h>
+#include <QDebug>
+#include <mutex>
 
 namespace avrecorder {
 namespace video {
 
 // --- DxgiCapturerPrivate 实现 ---
 bool DxgiCapturerPrivate::Open(int left, int top, int width, int height) {
-    Close();
+    std::lock_guard<std::mutex> lock(_deviceMutex);
+    CloseInternal(); // 使用内部方法避免死锁
     HRESULT hr = S_OK;
     _isAttached = false;
-    if (_bInit) return false;
+    
+    // 重置初始化状态,允许重新初始化
+    _bInit = false;
     // Driver types supported
     D3D_DRIVER_TYPE DriverTypes[] = {
         D3D_DRIVER_TYPE_HARDWARE,
@@ -111,22 +116,39 @@ bool DxgiCapturerPrivate::Open(int left, int top, int width, int height) {
         Free(_hDevice, [this]{ _hDevice->Release(); });
         return false;
     }
-    // Set ColorSpace
+    // Set ColorSpace - 修复RGB到NV12转换的颜色空间设置
     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;
-    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);
     _xrgbFrame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_BGR0, width, height);
+
     if (!_nv12Frame) {
         __DebugPrint("Alloc NV12 frame failed");
         Free(_hDeskDupl, [this]{ _hDeskDupl->Release(); });
@@ -149,6 +171,7 @@ bool DxgiCapturerPrivate::Open(int left, int top, int width, int height) {
 AVFrame* DxgiCapturerPrivate::GetFrame(
     bool shouldDrawCursor, int left, int top, int right, int bottom)
 {
+    std::lock_guard<std::mutex> lock(_deviceMutex);
     if (!_bInit) return nullptr;
     _isCaptureSuccess = false;
     IDXGIResource* hDesktopResource = nullptr;
@@ -219,13 +242,23 @@ AVFrame* DxgiCapturerPrivate::GetFrame(
             return nullptr;
         }
         _hContext->CopyResource(tmpImage, _gdiImage);
-        // 首先尝试创建 NV12 纹理
+        // 首先尝试创建 NV12 纹理,如果失败则重试一次
         AVFrame* frame = nullptr;
         auto tmpFormat = _desc.Format;
         _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;
+            qDebug() << "DxgiCapturer::GetFrame: NV12 conversion successful";
         } else {
+            qDebug() << "DxgiCapturer::GetFrame: NV12 conversion failed, falling back to RGB";
             _desc.Format = tmpFormat;
             GenRgbFrame(_hDevice, _hContext, _desc, _gdiImage, _xrgbBuffers, _xrgbFrame);
             frame = _xrgbFrame;
@@ -283,17 +316,41 @@ bool DxgiCapturer::open(const CaptureTarget& target, int width, int height) {
 #endif
 }
 
-void DxgiCapturerPrivate::Close() {
+void DxgiCapturerPrivate::CloseInternal() {
     if (!_bInit) return;
+    qDebug() << "DxgiCapturerPrivate::CloseInternal: Starting cleanup";
+    
     _bInit = false;
+    
+    // 清理缓冲区
+    qDebug() << "DxgiCapturerPrivate::CloseInternal: Clearing buffers";
     _nv12Buffers.Clear();
     _xrgbBuffers.Clear();
+    
+    // 释放D3D转换器
+    qDebug() << "DxgiCapturerPrivate::CloseInternal: Closing D3D converter";
     _rgbToNv12.Close();
+    
+    // 释放帧
+    qDebug() << "DxgiCapturerPrivate::CloseInternal: Freeing frames";
     Free(_nv12Frame, [this] { av_frame_free(&_nv12Frame); });
     Free(_xrgbFrame, [this] { av_frame_free(&_xrgbFrame); });
+    
+    // 释放DXGI资源
+    qDebug() << "DxgiCapturerPrivate::CloseInternal: Releasing DXGI resources";
     Free(_hDeskDupl, [this] { _hDeskDupl->Release(); });
-    Free(_hDevice, [this] { _hDevice->Release(); });
+    
+    // 最后释放D3D设备和上下文
+    qDebug() << "DxgiCapturerPrivate::CloseInternal: Releasing D3D resources";
     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() {

+ 3 - 0
AvRecorder/capturer/video/DxgiCapturer.h

@@ -7,6 +7,7 @@
 #include "d3d/convert.h"
 #include <d3d11.h>
 #include <dxgi1_2.h>
+#include <mutex>
 
 namespace avrecorder {
 namespace video {
@@ -17,6 +18,7 @@ public:
     ~DxgiCapturerPrivate() = default;
     bool Open(int left, int top, int width, int height);
     void Close();
+    void CloseInternal(); // 内部清理方法,不使用锁
     AVFrame* GetFrame(bool drawCursor, int left, int top, int right, int bottom);
     bool _bInit = false;
     bool _isCaptureSuccess = false;
@@ -32,6 +34,7 @@ public:
     BufferFiller _xrgbBuffers;
     BufferFiller _nv12Buffers;
     D3dConverter _rgbToNv12;
+    mutable std::mutex _deviceMutex; // D3D设备访问的线程同步
 private:
     void drawCursor(HDC hdc, int left, int top, int right, int bottom);
 };

+ 7 - 1
AvRecorder/capturer/video/VideoCaptureManager.h

@@ -11,6 +11,12 @@ namespace video {
 class VideoCaptureManager {
 public:
     bool open(const CaptureTarget& target, CaptureMethod method, int width, int height) {
+        // 确保在创建新捕获器之前关闭旧的
+        if (m_capturer) {
+            m_capturer->close();
+            m_capturer.reset();
+        }
+        
         m_capturer = VideoCapturerFactory::create(method);
         if (!m_capturer) return false;
         return m_capturer->open(target, width, height);
@@ -31,4 +37,4 @@ private:
 } // namespace video
 } // namespace avrecorder
 
-#endif // VIDEOCAPTUREMANAGER_H 
+#endif // VIDEOCAPTUREMANAGER_H

+ 7 - 1
AvRecorder/capturer/video/WgcCapturer.cpp

@@ -79,7 +79,13 @@ bool WgcCapturer::open(const CaptureTarget& target, int width, int height) {
 
 void WgcCapturer::close() {
 #ifdef PLATFORM_WINDOWS
-    if (_app) _app->Close();
+    qDebug() << "WgcCapturer::close() - 开始关闭WGC捕获器";
+    if (_app) {
+        qDebug() << "WgcCapturer::close() - 调用App::Close()";
+        _app->Close();
+        qDebug() << "WgcCapturer::close() - App::Close()完成";
+    }
+    qDebug() << "WgcCapturer::close() - WGC捕获器关闭完成";
 #endif
 }
 

+ 5 - 0
AvRecorder/capturer/video/wgc/App.cpp

@@ -50,11 +50,16 @@ void App::Initialize(ContainerVisual const& root)
 
 void App::Close()
 {
+    qDebug() << "App::Close() - 开始关闭App";
     if (m_capture) {
+        qDebug() << "App::Close() - 调用SimpleCapture::Close()";
         m_capture->Close();
+        qDebug() << "App::Close() - 删除SimpleCapture对象";
         delete m_capture;
         m_capture = nullptr;
+        qDebug() << "App::Close() - SimpleCapture对象已删除";
     }
+    qDebug() << "App::Close() - App关闭完成";
 }
 
 bool App::StartCaptureWindow(HWND hwnd, int width, int height)

+ 1 - 1
AvRecorder/capturer/video/wgc/App.h

@@ -24,7 +24,7 @@
 class App {
 public:
     App() { }
-    ~App() { }
+    ~App() { Close(); }
 
     void Initialize(
         winrt::Windows::UI::Composition::ContainerVisual const& root);

+ 29 - 5
AvRecorder/capturer/video/wgc/SimpleCapture.cpp

@@ -88,7 +88,7 @@ SimpleCapture::SimpleCapture(
     outputColorSpace.RGB_Range = 0;
     outputColorSpace.YCbCr_Matrix = 1;
     outputColorSpace.YCbCr_xvYCC = 0;
-    outputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235;
+    outputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255; // 修复:使用相同的颜色范围
     m_rgbToNv12.Open(d3dDevice.get(), m_d3dContext.get(), inputColorSpace, outputColorSpace);
     m_nv12Frame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_NV12, width, height);
     m_xrgbFrame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_BGR0, width, height);
@@ -123,21 +123,45 @@ ICompositionSurface SimpleCapture::CreateSurface(
 // Process captured frames
 void SimpleCapture::Close()
 {
+    qDebug() << "SimpleCapture::Close: Starting cleanup";
+    
     auto expected = false;
     if (m_closed.compare_exchange_strong(expected, true)) {
+        qDebug() << "SimpleCapture::Close: Revoking frame callback and closing WGC resources";
         m_frameArrived.revoke();
-        m_framePool.Close();
-        m_session.Close();
+        
+        // 先停止捕获会话
+        if (m_session) {
+            m_session.Close();
+            m_session = nullptr;
+        }
+        
+        // 然后关闭帧池
+        if (m_framePool) {
+            m_framePool.Close();
+            m_framePool = nullptr;
+        }
+        
+        // 释放交换链
         m_swapChain = nullptr;
-        m_framePool = nullptr;
-        m_session = nullptr;
         m_item = nullptr;
     }
+    
+    // 清理缓冲区
+    qDebug() << "SimpleCapture::Close: Clearing buffers";
     m_nv12Buffers.Clear();
     m_xrgbBuffers.Clear();
+    
+    // 释放D3D转换器(在释放帧之前)
+    qDebug() << "SimpleCapture::Close: Closing D3D converter";
     m_rgbToNv12.Close();
+    
+    // 最后释放帧
+    qDebug() << "SimpleCapture::Close: Freeing frames";
     Free(m_nv12Frame, [this] { av_frame_free(&m_nv12Frame); });
     Free(m_xrgbFrame, [this] { av_frame_free(&m_xrgbFrame); });
+    
+    qDebug() << "SimpleCapture::Close: Cleanup completed";
 }
 
 void SimpleCapture::OnFrameArrived(

+ 6 - 1
AvRecorder/muxer/av_muxer.cpp

@@ -206,6 +206,11 @@ int AvMuxer::AddVideoStream(const Encoder<MediaType::VIDEO>::Param& param)
         return -1;
     }
     
+    qDebug() << "AddVideoStream: Available encoders:" << usableEncoders.size();
+    for (const auto& enc : usableEncoders) {
+        qDebug() << "  - " << QString::fromStdString(enc);
+    }
+    
     // 尝试使用指定的编码器,如果失败则自动回退
     auto encoder = new Encoder<MediaType::VIDEO>;
     auto modifiableParam = param; // 创建可修改的副本
@@ -224,7 +229,7 @@ int AvMuxer::AddVideoStream(const Encoder<MediaType::VIDEO>::Param& param)
         }
     }
     
-    // 如果指定编码器失败,尝试可用编码器列表
+    // 如果指定编码器失败或未指定,尝试可用编码器列表
     if (!encoderOpened) {
         qDebug() << "AddVideoStream: Trying fallback encoders...";
         for (const auto& encoderName : usableEncoders) {