Quellcode durchsuchen

格式化代码

zhuizhu vor 7 Monaten
Ursprung
Commit
b074bbaf33
93 geänderte Dateien mit 9495 neuen und 8987 gelöschten Zeilen
  1. 6 1
      libs/AvRecorder/capturer/video/WgcCapturer.cpp
  2. 96 9
      libs/AvRecorder/capturer/video/wgc/App.cpp
  3. 123 10
      libs/AvRecorder/capturer/video/wgc/capture.interop.h
  4. 146 69
      libs/AvRecorder/ui/av_recorder.cpp
  5. 29 1
      libs/AvRecorder/ui/capture_source_widget.cpp
  6. 48 44
      libs/Recorder/AecKsBinder.h
  7. 633 614
      libs/Recorder/Recorder.cpp
  8. 99 0
      libs/Recorder/Recorder.pri
  9. 5 5
      libs/Recorder/common.h
  10. 37 37
      libs/Recorder/d3d_helper.cpp
  11. 9 9
      libs/Recorder/d3d_helper.h
  12. 236 232
      libs/Recorder/device_audios.cpp
  13. 20 20
      libs/Recorder/device_audios.h
  14. 2 8
      libs/Recorder/device_videos.cpp
  15. 2 3
      libs/Recorder/device_videos.h
  16. 83 84
      libs/Recorder/dllmain.cpp
  17. 251 257
      libs/Recorder/encoder_aac.cpp
  18. 47 55
      libs/Recorder/encoder_aac.h
  19. 47 50
      libs/Recorder/encoder_video.cpp
  20. 43 52
      libs/Recorder/encoder_video.h
  21. 9 15
      libs/Recorder/encoder_video_define.h
  22. 31 34
      libs/Recorder/encoder_video_factory.cpp
  23. 4 5
      libs/Recorder/encoder_video_factory.h
  24. 190 183
      libs/Recorder/encoder_video_nvenc.cpp
  25. 32 40
      libs/Recorder/encoder_video_nvenc.h
  26. 208 200
      libs/Recorder/encoder_video_x264.cpp
  27. 30 31
      libs/Recorder/encoder_video_x264.h
  28. 208 207
      libs/Recorder/error_define.h
  29. 299 285
      libs/Recorder/export.cpp
  30. 12 10
      libs/Recorder/filter.cpp
  31. 21 22
      libs/Recorder/filter.h
  32. 293 260
      libs/Recorder/filter_amix.cpp
  33. 34 37
      libs/Recorder/filter_amix.h
  34. 241 216
      libs/Recorder/filter_aresample.cpp
  35. 34 38
      libs/Recorder/filter_aresample.h
  36. 149 144
      libs/Recorder/hardware_acceleration.cpp
  37. 28 28
      libs/Recorder/hardware_acceleration.h
  38. 14 13
      libs/Recorder/headers_ffmpeg.h
  39. 9 12
      libs/Recorder/headers_mmdevice.h
  40. 39 40
      libs/Recorder/log_helper.cpp
  41. 57 45
      libs/Recorder/log_helper.h
  42. 3 3
      libs/Recorder/mul_db.h
  43. 60 57
      libs/Recorder/muxer_define.h
  44. 796 756
      libs/Recorder/muxer_ffmpeg.cpp
  45. 51 58
      libs/Recorder/muxer_ffmpeg.h
  46. 13 18
      libs/Recorder/muxer_file.cpp
  47. 34 41
      libs/Recorder/muxer_file.h
  48. 19 22
      libs/Recorder/record_audio.cpp
  49. 60 64
      libs/Recorder/record_audio.h
  50. 6 6
      libs/Recorder/record_audio_define.h
  51. 236 239
      libs/Recorder/record_audio_dshow.cpp
  52. 24 27
      libs/Recorder/record_audio_dshow.h
  53. 28 30
      libs/Recorder/record_audio_factory.cpp
  54. 1 2
      libs/Recorder/record_audio_factory.h
  55. 590 596
      libs/Recorder/record_audio_wasapi.cpp
  56. 42 45
      libs/Recorder/record_audio_wasapi.h
  57. 11 14
      libs/Recorder/record_desktop.cpp
  58. 46 51
      libs/Recorder/record_desktop.h
  59. 16 23
      libs/Recorder/record_desktop_define.h
  60. 734 714
      libs/Recorder/record_desktop_duplication.cpp
  61. 54 58
      libs/Recorder/record_desktop_duplication.h
  62. 35 37
      libs/Recorder/record_desktop_factory.cpp
  63. 225 229
      libs/Recorder/record_desktop_ffmpeg_dshow.cpp
  64. 28 32
      libs/Recorder/record_desktop_ffmpeg_dshow.h
  65. 229 232
      libs/Recorder/record_desktop_ffmpeg_gdi.cpp
  66. 29 33
      libs/Recorder/record_desktop_ffmpeg_gdi.h
  67. 258 258
      libs/Recorder/record_desktop_gdi.cpp
  68. 27 32
      libs/Recorder/record_desktop_gdi.h
  69. 330 280
      libs/Recorder/record_desktop_mag.cpp
  70. 68 56
      libs/Recorder/record_desktop_mag.h
  71. 120 109
      libs/Recorder/record_desktop_wgc.cpp
  72. 46 44
      libs/Recorder/record_desktop_wgc.h
  73. 215 223
      libs/Recorder/remuxer_ffmpeg.cpp
  74. 35 37
      libs/Recorder/remuxer_ffmpeg.h
  75. 84 76
      libs/Recorder/resample_pcm.cpp
  76. 27 22
      libs/Recorder/resample_pcm.h
  77. 67 73
      libs/Recorder/ring_buffer.cpp
  78. 78 83
      libs/Recorder/ring_buffer.h
  79. 70 68
      libs/Recorder/sws_helper.cpp
  80. 22 22
      libs/Recorder/sws_helper.h
  81. 38 30
      libs/Recorder/system_error.cpp
  82. 4 5
      libs/Recorder/system_error.h
  83. 42 43
      libs/Recorder/system_lib.cpp
  84. 4 5
      libs/Recorder/system_lib.h
  85. 26 27
      libs/Recorder/system_time.cpp
  86. 10 11
      libs/Recorder/system_time.h
  87. 126 137
      libs/Recorder/system_version.cpp
  88. 22 22
      libs/Recorder/system_version.h
  89. 0 0
      libs/Recorder/test_main.cpp
  90. 434 442
      libs/Recorder/transcode_aac.cpp
  91. 55 57
      libs/Recorder/utils_string.cpp
  92. 11 13
      libs/Recorder/utils_string.h
  93. 2 0
      libs/libs.pri

+ 6 - 1
libs/AvRecorder/capturer/video/WgcCapturer.cpp

@@ -50,7 +50,12 @@ bool WgcCapturer::open(const CaptureTarget& target, int width, int height) {
         _app->Initialize(g_root);
     }
     if (target.type == CaptureTargetType::Window) {
-        return _app->StartCaptureWindow(target.hwnd, width, height);
+        qDebug() << "WgcCapturer::open: Starting window capture for HWND:" << target.hwnd;
+        bool result = _app->StartCaptureWindow(target.hwnd, width, height);
+        if (!result) {
+            qDebug() << "WgcCapturer::open: StartCaptureWindow failed for HWND:" << target.hwnd;
+        }
+        return result;
     } else if (target.type == CaptureTargetType::Monitor) {
         auto monitors = MonitorFinder::GetList();
         if (target.monitorIdx < 0 || target.monitorIdx >= (int)monitors.size()) return false;

+ 96 - 9
libs/AvRecorder/capturer/video/wgc/App.cpp

@@ -64,17 +64,104 @@ void App::Close()
 
 bool App::StartCaptureWindow(HWND hwnd, int width, int height)
 {
-    Close();
-    auto item = CreateCaptureItemForWindow(hwnd);
-    if (!item) {
-        __DebugPrint("CreateCaptureItemForWindow returned null");
+    __DebugPrint("App::StartCaptureWindow: Starting window capture (HWND=0x%p, %dx%d)", hwnd, width, height);
+    
+    // 验证输入参数
+    if (!hwnd) {
+        __DebugPrint("App::StartCaptureWindow: Invalid HWND (null)");
+        return false;
+    }
+    
+    if (width <= 0 || height <= 0) {
+        __DebugPrint("App::StartCaptureWindow: Invalid dimensions (%dx%d)", width, height);
+        return false;
+    }
+    
+    if (!m_device) {
+        __DebugPrint("App::StartCaptureWindow: D3D device is null");
+        return false;
+    }
+    
+    if (!m_compositor) {
+        __DebugPrint("App::StartCaptureWindow: Compositor is null");
+        return false;
+    }
+    
+    // 获取窗口信息用于调试
+    RECT windowRect;
+    if (::GetWindowRect(hwnd, &windowRect)) {
+        __DebugPrint("App::StartCaptureWindow: Window rect (%ld,%ld,%ld,%ld)", 
+            windowRect.left, windowRect.top, windowRect.right, windowRect.bottom);
+    }
+    
+    wchar_t windowTitle[256] = {0};
+    ::GetWindowTextW(hwnd, windowTitle, sizeof(windowTitle)/sizeof(wchar_t));
+    __DebugPrint("App::StartCaptureWindow: Window title: %ls", windowTitle);
+    
+    try {
+        Close();
+        
+        __DebugPrint("App::StartCaptureWindow: Creating capture item...");
+        auto item = CreateCaptureItemForWindow(hwnd);
+        if (!item) {
+            __DebugPrint("App::StartCaptureWindow: CreateCaptureItemForWindow returned null");
+            return false;
+        }
+        
+        __DebugPrint("App::StartCaptureWindow: Creating SimpleCapture...");
+        m_capture = new SimpleCapture(m_device, item, width, height);
+        if (!m_capture) {
+            __DebugPrint("App::StartCaptureWindow: Failed to create SimpleCapture");
+            return false;
+        }
+        
+        __DebugPrint("App::StartCaptureWindow: Creating surface...");
+        auto surface = m_capture->CreateSurface(m_compositor);
+        if (!surface) {
+            __DebugPrint("App::StartCaptureWindow: Failed to create surface");
+            delete m_capture;
+            m_capture = nullptr;
+            return false;
+        }
+        
+        __DebugPrint("App::StartCaptureWindow: Setting surface to brush...");
+        m_brush.Surface(surface);
+        
+        __DebugPrint("App::StartCaptureWindow: Starting capture...");
+        m_capture->StartCapture();
+        
+        __DebugPrint("App::StartCaptureWindow: Window capture started successfully");
+        return true;
+        
+    } catch (const winrt::hresult_error& e) {
+        __DebugPrint("App::StartCaptureWindow: WinRT exception - HRESULT=0x%08lx, Message=%s", 
+            static_cast<unsigned long>(e.code()), 
+            winrt::to_string(e.message()).c_str());
+        
+        if (m_capture) {
+            delete m_capture;
+            m_capture = nullptr;
+        }
+        return false;
+        
+    } catch (const std::exception& e) {
+        __DebugPrint("App::StartCaptureWindow: Standard exception - %s", e.what());
+        
+        if (m_capture) {
+            delete m_capture;
+            m_capture = nullptr;
+        }
+        return false;
+        
+    } catch (...) {
+        __DebugPrint("App::StartCaptureWindow: Unknown exception");
+        
+        if (m_capture) {
+            delete m_capture;
+            m_capture = nullptr;
+        }
         return false;
     }
-    m_capture = new SimpleCapture(m_device, item, width, height);
-    auto surface = m_capture->CreateSurface(m_compositor);
-    m_brush.Surface(surface);
-    m_capture->StartCapture();
-    return true;
 }
 
 void App::SetDrawCursor(bool isDrawCursor)

+ 123 - 10
libs/AvRecorder/capturer/video/wgc/capture.interop.h

@@ -5,20 +5,133 @@
 #include <windows.graphics.capture.interop.h>
 #include <windows.graphics.capture.h>
 
+// 包含调试宏定义
+#include "../../../basic/basic.h"
+
 inline auto CreateCaptureItemForWindow(HWND hwnd)
 {
-    auto activation_factory = winrt::get_activation_factory<winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
-    auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
-    winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
-    interop_factory->CreateForWindow(hwnd, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), reinterpret_cast<void**>(winrt::put_abi(item)));
-    return item;
+    // 首先检查窗口句柄是否有效
+    if (!hwnd || !::IsWindow(hwnd)) {
+        __DebugPrint("CreateCaptureItemForWindow: Invalid window handle (HWND=0x%p)", hwnd);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    }
+    
+    // 检查窗口是否可见
+    if (!::IsWindowVisible(hwnd)) {
+        __DebugPrint("CreateCaptureItemForWindow: Window is not visible (HWND=0x%p)", hwnd);
+        // 注意:不可见的窗口仍然可以被捕获,所以这里只是警告
+    }
+    
+    try {
+        auto activation_factory = winrt::get_activation_factory<winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
+        auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
+        winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
+        
+        HRESULT hr = interop_factory->CreateForWindow(hwnd, 
+            winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), 
+            reinterpret_cast<void**>(winrt::put_abi(item)));
+            
+        if (FAILED(hr)) {
+            __DebugPrint("CreateCaptureItemForWindow: CreateForWindow failed with HRESULT=0x%08lx (HWND=0x%p)", 
+                static_cast<unsigned long>(hr), hwnd);
+            
+            // 提供更详细的错误信息
+            switch (hr) {
+                case E_INVALIDARG:
+                    __DebugPrint("  Error: Invalid argument - window handle may be invalid");
+                    break;
+                case E_ACCESSDENIED:
+                    __DebugPrint("  Error: Access denied - window may be protected or system window");
+                    break;
+                case DXGI_ERROR_UNSUPPORTED:
+                    __DebugPrint("  Error: Unsupported - window capture not supported for this window");
+                    break;
+                case E_NOINTERFACE:
+                    __DebugPrint("  Error: No interface - WGC may not be available on this system");
+                    break;
+                default:
+                    __DebugPrint("  Error: Unknown error code");
+                    break;
+            }
+            
+            return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+        }
+        
+        __DebugPrint("CreateCaptureItemForWindow: Successfully created capture item (HWND=0x%p)", hwnd);
+        return item;
+        
+    } catch (const winrt::hresult_error& e) {
+        __DebugPrint("CreateCaptureItemForWindow: WinRT exception - HRESULT=0x%08lx, Message=%s (HWND=0x%p)", 
+            static_cast<unsigned long>(e.code()), 
+            winrt::to_string(e.message()).c_str(), 
+            hwnd);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    } catch (const std::exception& e) {
+        __DebugPrint("CreateCaptureItemForWindow: Standard exception - %s (HWND=0x%p)", e.what(), hwnd);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    } catch (...) {
+        __DebugPrint("CreateCaptureItemForWindow: Unknown exception (HWND=0x%p)", hwnd);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    }
 }
 
 inline auto CreateCaptureItemForMonitor(HMONITOR monitor)
 {
-    auto activation_factory = winrt::get_activation_factory<winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
-    auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
-    winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
-    interop_factory->CreateForMonitor(monitor, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), reinterpret_cast<void**>(winrt::put_abi(item)));
-    return item;
+    // 检查显示器句柄是否有效
+    if (!monitor) {
+        __DebugPrint("CreateCaptureItemForMonitor: Invalid monitor handle (HMONITOR=0x%p)", monitor);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    }
+    
+    try {
+        auto activation_factory = winrt::get_activation_factory<winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
+        auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
+        winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
+        
+        HRESULT hr = interop_factory->CreateForMonitor(monitor, 
+            winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), 
+            reinterpret_cast<void**>(winrt::put_abi(item)));
+            
+        if (FAILED(hr)) {
+            __DebugPrint("CreateCaptureItemForMonitor: CreateForMonitor failed with HRESULT=0x%08lx (HMONITOR=0x%p)", 
+                static_cast<unsigned long>(hr), monitor);
+            
+            // 提供更详细的错误信息
+            switch (hr) {
+                case E_INVALIDARG:
+                    __DebugPrint("  Error: Invalid argument - monitor handle may be invalid");
+                    break;
+                case E_ACCESSDENIED:
+                    __DebugPrint("  Error: Access denied - monitor capture may be restricted");
+                    break;
+                case DXGI_ERROR_UNSUPPORTED:
+                    __DebugPrint("  Error: Unsupported - monitor capture not supported");
+                    break;
+                case E_NOINTERFACE:
+                    __DebugPrint("  Error: No interface - WGC may not be available on this system");
+                    break;
+                default:
+                    __DebugPrint("  Error: Unknown error code");
+                    break;
+            }
+            
+            return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+        }
+        
+        __DebugPrint("CreateCaptureItemForMonitor: Successfully created capture item (HMONITOR=0x%p)", monitor);
+        return item;
+        
+    } catch (const winrt::hresult_error& e) {
+        __DebugPrint("CreateCaptureItemForMonitor: WinRT exception - HRESULT=0x%08lx, Message=%s (HMONITOR=0x%p)", 
+            static_cast<unsigned long>(e.code()), 
+            winrt::to_string(e.message()).c_str(), 
+            monitor);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    } catch (const std::exception& e) {
+        __DebugPrint("CreateCaptureItemForMonitor: Standard exception - %s (HMONITOR=0x%p)", e.what(), monitor);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    } catch (...) {
+        __DebugPrint("CreateCaptureItemForMonitor: Unknown exception (HMONITOR=0x%p)", monitor);
+        return winrt::Windows::Graphics::Capture::GraphicsCaptureItem{nullptr};
+    }
 }

+ 146 - 69
libs/AvRecorder/ui/av_recorder.cpp

@@ -49,12 +49,12 @@ AvRecorder::AvRecorder(QWidget* parent)
     QVBoxLayout* audioLayout = new QVBoxLayout;
     audioLayout->addWidget(m_microphoneWidget);
     audioLayout->addWidget(m_speakerWidget);
-    
+
     // 添加音频设备选择按钮
     m_audioDeviceBtn = new QPushButton("选择音频设备");
     m_audioDeviceBtn->setToolTip("打开音频设备选择窗口");
     audioLayout->addWidget(m_audioDeviceBtn);
-    
+
     audioGroup->setLayout(audioLayout);
     //audioGroup->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
 
@@ -153,8 +153,8 @@ void AvRecorder::initConnect()
                         + "." + format;
             // fileName += std::string("test.") + format;
             if (!startStream(fileName, format)) {
-            qDebug() << "startStream failed for recording";
-            return;
+                qDebug() << "startStream failed for recording";
+                return;
             }
             m_liveBtn->setEnabled(false);
             m_recordBtn->setText("停止录制");
@@ -171,17 +171,17 @@ void AvRecorder::initConnect()
             bool isRtsp = m_settingsParam.liveUrl.find("rtsp") != std::string::npos;
             qDebug() << "直播地址:" << QString::fromStdString(fileName);
             if (!startStream(fileName, isRtsp ? "rtsp" : "flv")) {
-            qDebug() << "startStream failed for live";
-            return;
+                qDebug() << "startStream failed for live";
+                return;
             }
 
-             // 如果勾选了同步录像,则开始录像
-             if (m_syncRecordBox->isChecked()) {
-             if (!startSyncRecord()) {
-             qDebug() << "startSyncRecord failed";
-             // 不阻断直播,仅提示
-             }
-             }
+            // 如果勾选了同步录像,则开始录像
+            if (m_syncRecordBox->isChecked()) {
+                if (!startSyncRecord()) {
+                    qDebug() << "startSyncRecord failed";
+                    // 不阻断直播,仅提示
+                }
+            }
 
             m_recordBtn->setEnabled(false);
             m_liveBtn->setText("停止直播");
@@ -206,23 +206,29 @@ void AvRecorder::initConnect()
     });
     // 连接音频设备选择按钮
     connect(m_audioDeviceBtn, &QPushButton::clicked, this, &AvRecorder::showAudioDeviceMenu);
-    
+
     // 连接捕获源控件信号
-    connect(m_captureSourceWidget, &CaptureSourceWidget::captureSourceTextChanged, this, [this](const QString& text) {
-        if (text.isEmpty() || m_isLocked) {
-            return;
-        }
-        m_isLocked = true;
-        if (!(m_isRecord || m_isLive)) {
-            stopPreview();
-            stopCapture();
-            startCapture(CaptureMethod::WGC);
-            startPreview();
-        }
-        m_isLocked = false;
-    });
-    connect(m_captureSourceWidget, &CaptureSourceWidget::captureSourceIndexChanged, this, &AvRecorder::onCaptureSourceChanged);
-    connect(m_captureSourceWidget, &CaptureSourceWidget::refreshRequested, this, [this]() {
+    connect(m_captureSourceWidget,
+            &CaptureSourceWidget::captureSourceTextChanged,
+            this,
+            [this](const QString& text) {
+                if (text.isEmpty() || m_isLocked) {
+                    return;
+                }
+                m_isLocked = true;
+                if (!(m_isRecord || m_isLive)) {
+                    stopPreview();
+                    stopCapture();
+                    startCapture(CaptureMethod::DXGI);
+                    startPreview();
+                }
+                m_isLocked = false;
+            });
+    connect(m_captureSourceWidget,
+            &CaptureSourceWidget::captureSourceIndexChanged,
+            this,
+            &AvRecorder::onCaptureSourceChanged);
+    connect(m_captureSourceWidget, &CaptureSourceWidget::refreshRequested, this, []() {
         // 刷新请求处理,可以在这里添加额外的逻辑
         qDebug() << "Capture source list refreshed";
     });
@@ -247,7 +253,9 @@ void AvRecorder::initConnect()
     connect(m_settingsBtn, &QPushButton::released, this, [this] {
         // 运行中禁止打开设置以切换编码器,避免异常
         if (m_isRecord || m_isLive || m_isSyncRecord) {
-            QMessageBox::warning(this, "提示", "正在直播/录制,无法修改编码器设置。请先停止后再修改。");
+            QMessageBox::warning(this,
+                                 "提示",
+                                 "正在直播/录制,无法修改编码器设置。请先停止后再修改。");
             return;
         }
         auto settingsPage = std::make_unique<SettingsPage>(&m_settingsParam, this);
@@ -255,7 +263,7 @@ void AvRecorder::initConnect()
         m_isLocked = true;
         stopPreview();
         stopCapture();
-        startCapture(CaptureMethod::WGC);
+        startCapture(CaptureMethod::DXGI);
         startPreview();
         m_isLocked = false;
     });
@@ -310,7 +318,7 @@ bool AvRecorder::start()
         m_isLocked = true;
         stopPreview();
         stopCapture();
-        startCapture(CaptureMethod::WGC);
+        startCapture(CaptureMethod::DXGI);
         startPreview();
         m_isLocked = false;
         timer->stop();
@@ -322,8 +330,9 @@ bool AvRecorder::start()
 void AvRecorder::startCapture(CaptureMethod method)
 {
     int idx = m_captureSourceWidget->getCurrentIndex();
-    if (idx < 0) return;
-    int monitorCnt = (int)MonitorFinder::GetList().size();
+    if (idx < 0)
+        return;
+    int monitorCnt = (int) MonitorFinder::GetList().size();
     QString type = (idx < monitorCnt) ? "monitor" : "window";
     qintptr ptrHwnd = m_captureSourceWidget->getCurrentData().value<qintptr>();
 
@@ -333,16 +342,78 @@ void AvRecorder::startCapture(CaptureMethod method)
         if (idx < monitorCnt) {
             m_videoRecorder.SetCaptureSource(idx, method);
             ok = true;
-        } else if (type == "window" && ::IsWindow((HWND)ptrHwnd)) {
-            m_videoRecorder.SetCaptureSource((HWND)ptrHwnd, method);
+        } else if (type == "window" && ::IsWindow((HWND) ptrHwnd)) {
+            HWND hwnd = (HWND) ptrHwnd;
+            
+            // 详细的窗口有效性检查
+            bool isVisible = IsWindowVisible(hwnd);
+            wchar_t title[256] = {0};
+            int titleLen = GetWindowTextW(hwnd, title, 256);
+            QString windowTitle = QString::fromWCharArray(title);
+            
+            RECT rect;
+            bool hasRect = GetWindowRect(hwnd, &rect);
+            
+            qDebug() << "AvRecorder::startCapture - 窗口捕获详情:";
+            qDebug() << "  HWND:" << Qt::hex << ptrHwnd;
+            qDebug() << "  标题:" << windowTitle;
+            qDebug() << "  可见:" << (isVisible ? "是" : "否");
+            qDebug() << "  标题长度:" << titleLen;
+            
+            if (hasRect) {
+                qDebug() << "  位置:" << rect.left << "," << rect.top 
+                         << " 大小:" << (rect.right - rect.left) << "x" << (rect.bottom - rect.top);
+            }
+            
+            // 检查窗口是否适合捕获
+            if (!isVisible) {
+                qWarning() << "AvRecorder::startCapture - 警告: 窗口不可见,可能影响捕获效果";
+            }
+            
+            if (titleLen == 0) {
+                qWarning() << "AvRecorder::startCapture - 警告: 窗口无标题,可能是系统窗口";
+            }
+            
+            m_videoRecorder.SetCaptureSource(hwnd, method);
             ok = true;
         }
     } else {
         // 未推流/录制时,正常 open
         if (idx < monitorCnt) { // 捕获屏幕
             ok = m_videoRecorder.Open(idx, m_settingsParam.videoParam, method);
-        } else if (type == "window" && ::IsWindow((HWND)ptrHwnd)) {
-            ok = m_videoRecorder.Open((HWND)ptrHwnd, m_settingsParam.videoParam, method);
+        } else if (type == "window" && ::IsWindow((HWND) ptrHwnd)) {
+            HWND hwnd = (HWND) ptrHwnd;
+            
+            // 详细的窗口有效性检查
+            bool isVisible = IsWindowVisible(hwnd);
+            wchar_t title[256] = {0};
+            int titleLen = GetWindowTextW(hwnd, title, 256);
+            QString windowTitle = QString::fromWCharArray(title);
+            
+            RECT rect;
+            bool hasRect = GetWindowRect(hwnd, &rect);
+            
+            qDebug() << "AvRecorder::startCapture - 窗口捕获详情:";
+            qDebug() << "  HWND:" << Qt::hex << ptrHwnd;
+            qDebug() << "  标题:" << windowTitle;
+            qDebug() << "  可见:" << (isVisible ? "是" : "否");
+            qDebug() << "  标题长度:" << titleLen;
+            
+            if (hasRect) {
+                qDebug() << "  位置:" << rect.left << "," << rect.top 
+                         << " 大小:" << (rect.right - rect.left) << "x" << (rect.bottom - rect.top);
+            }
+            
+            // 检查窗口是否适合捕获
+            if (!isVisible) {
+                qWarning() << "AvRecorder::startCapture - 警告: 窗口不可见,可能影响捕获效果";
+            }
+            
+            if (titleLen == 0) {
+                qWarning() << "AvRecorder::startCapture - 警告: 窗口无标题,可能是系统窗口";
+            }
+            
+            ok = m_videoRecorder.Open(hwnd, m_settingsParam.videoParam, method);
         }
     }
     if (!ok) {
@@ -366,13 +437,13 @@ void AvRecorder::dealCapture()
         qDebug() << "AudioRecorder::Open failed";
         return;
     }
-     m_microphoneWidget->setEnabled(m_audioRecorder.GetCaptureInfo(MICROPHONE_INDEX) != nullptr);
-     m_speakerWidget->setEnabled(m_audioRecorder.GetCaptureInfo(SPEAKER_INDEX) != nullptr);
-     m_fpsLabel->setText(QString("FPS: %1").arg(m_settingsParam.videoParam.fps));
-     m_videoEncodeLabel->setText(("编码器: " + m_settingsParam.videoParam.name).c_str());
-     if (m_audioEncodeLabel) {
-         m_audioEncodeLabel->setText(("音频编码器: " + m_settingsParam.audioParam.name).c_str());
-     }
+    m_microphoneWidget->setEnabled(m_audioRecorder.GetCaptureInfo(MICROPHONE_INDEX) != nullptr);
+    m_speakerWidget->setEnabled(m_audioRecorder.GetCaptureInfo(SPEAKER_INDEX) != nullptr);
+    m_fpsLabel->setText(QString("FPS: %1").arg(m_settingsParam.videoParam.fps));
+    m_videoEncodeLabel->setText(("编码器: " + m_settingsParam.videoParam.name).c_str());
+    if (m_audioEncodeLabel) {
+        m_audioEncodeLabel->setText(("音频编码器: " + m_settingsParam.audioParam.name).c_str());
+    }
 }
 
 void AvRecorder::stopCapture()
@@ -434,7 +505,8 @@ void AvRecorder::stopPreview()
 bool AvRecorder::startStream(std::string_view path, std::string_view format)
 {
     if (!m_avMuxer.Open(path, format)) {
-        qDebug() << "Failed to open muxer with path:" << QString::fromStdString(std::string(path)) << "format:" << QString::fromStdString(std::string(format));
+        qDebug() << "Failed to open muxer with path:" << QString::fromStdString(std::string(path))
+                 << "format:" << QString::fromStdString(std::string(format));
         return false;
     }
     if (!m_audioRecorder.LoadMuxer(m_avMuxer)) {
@@ -484,11 +556,11 @@ void AvRecorder::stopStream()
 {
     m_audioRecorder.StopRecord();
     m_videoRecorder.StopRecord();
-    
+
     // 从录制器中卸载直播muxer
     m_audioRecorder.UnloadMuxer(m_avMuxer);
     m_videoRecorder.UnloadMuxer(m_avMuxer);
-    
+
     m_avMuxer.Close();
 
     // 如果有同步录像,也需要关闭
@@ -496,7 +568,7 @@ void AvRecorder::stopStream()
         // 先从录制器中卸载同步录像muxer
         m_audioRecorder.UnloadMuxer(m_recordMuxer);
         m_videoRecorder.UnloadMuxer(m_recordMuxer);
-        
+
         m_recordMuxer.Close();
         m_isSyncRecord = false;
     }
@@ -514,13 +586,13 @@ bool AvRecorder::startSyncRecord()
         qDebug() << "Sync recording is already active";
         return true;
     }
-    
+
     // 检查是否正在直播(必须在直播状态下才能启动同步录像)
     if (!m_isLive) {
         qDebug() << "Cannot start sync recording: not in live streaming mode";
         return false;
     }
-    
+
     auto fileName = m_settingsParam.outputDir;
     if (fileName.back() != '\\') {
         fileName.push_back('\\');
@@ -534,21 +606,21 @@ bool AvRecorder::startSyncRecord()
         qDebug() << "Failed to open sync record muxer";
         return false;
     }
-    
+
     // 加载muxer到录制器
     if (!m_audioRecorder.LoadMuxer(m_recordMuxer)) {
         qDebug() << "Failed to load sync muxer for audio recorder";
         m_recordMuxer.Close();
         return false;
     }
-    
+
     if (!m_videoRecorder.LoadMuxer(m_recordMuxer)) {
         qDebug() << "Failed to load sync muxer for video recorder";
         m_audioRecorder.UnloadMuxer(m_recordMuxer);
         m_recordMuxer.Close();
         return false;
     }
-    
+
     // 写入头部
     if (!m_recordMuxer.WriteHeader()) {
         qDebug() << "Failed to write sync muxer header";
@@ -557,7 +629,7 @@ bool AvRecorder::startSyncRecord()
         m_recordMuxer.Close();
         return false;
     }
-    
+
     m_isSyncRecord = true;
     qDebug() << "Sync recording started successfully: " << QString::fromStdString(fileName);
     return true;
@@ -569,14 +641,13 @@ void AvRecorder::stopSyncRecord()
         // 先从录制器中卸载muxer
         m_audioRecorder.UnloadMuxer(m_recordMuxer);
         m_videoRecorder.UnloadMuxer(m_recordMuxer);
-        
+
         // 然后关闭muxer
         m_recordMuxer.Close();
         m_isSyncRecord = false;
     }
 }
 
-
 void AvRecorder::initStatusBarUi()
 {
     m_videoEncodeLabel = new QLabel;
@@ -609,7 +680,8 @@ void AvRecorder::initStatusBarUi()
     m_statusBar->addWidget(m_fpsLabel);
 }
 
-void AvRecorder::updateCaptureMethodBox(bool isMonitor) {
+void AvRecorder::updateCaptureMethodBox(bool isMonitor)
+{
     m_captureMethodBox->clear();
     m_captureMethodBox->addItem("WGC");
     if (isMonitor) {
@@ -620,29 +692,34 @@ void AvRecorder::updateCaptureMethodBox(bool isMonitor) {
 }
 
 // 捕获源切换时调用
-void AvRecorder::onCaptureSourceChanged() {
+void AvRecorder::onCaptureSourceChanged()
+{
     int idx = m_captureSourceWidget->getCurrentIndex();
-    int monitorCnt = (int)MonitorFinder::GetList().size();
+    int monitorCnt = (int) MonitorFinder::GetList().size();
     bool isMonitor = (idx >= 0 && idx < monitorCnt);
     updateCaptureMethodBox(isMonitor);
     // 新增:推流/录制时切换采集源不中断
     if (m_isRecord || m_isLive) {
-        CaptureMethod method = CaptureMethod::WGC;
+        CaptureMethod method = CaptureMethod::DXGI;
         QString methodText = m_captureMethodBox->currentText();
-        if (methodText == "DXGI") method = CaptureMethod::DXGI;
-        else if (methodText == "GDI") method = CaptureMethod::GDI;
+        if (methodText == "DXGI")
+            method = CaptureMethod::DXGI;
+        else if (methodText == "GDI")
+            method = CaptureMethod::GDI;
+        else
+            method = CaptureMethod::WGC;
         if (isMonitor) {
             m_videoRecorder.SetCaptureSource(idx, method);
         } else {
             qintptr ptrHwnd = m_captureSourceWidget->getCurrentData().value<qintptr>();
-            m_videoRecorder.SetCaptureSource((HWND)ptrHwnd, method);
+            m_videoRecorder.SetCaptureSource((HWND) ptrHwnd, method);
         }
     }
 }
 
 void AvRecorder::showAudioDeviceMenu()
 {
-    QMenu *menu = new QMenu(this);
+    QMenu* menu = new QMenu(this);
 
     // // 麦克风设备子菜单
     // QMenu *micMenu = menu->addMenu("麦克风设备");
@@ -687,19 +764,19 @@ void AvRecorder::showAudioDeviceMenu()
     // }
 
     menu->addSeparator();
-    
+
     // 刷新设备列表
-    QAction *refreshAction = menu->addAction("刷新设备列表");
+    QAction* refreshAction = menu->addAction("刷新设备列表");
     connect(refreshAction, &QAction::triggered, this, [this]() {
         qDebug() << "刷新音频设备列表";
         // 重新显示菜单以刷新设备列表
         QTimer::singleShot(100, this, &AvRecorder::showAudioDeviceMenu);
     });
-    
+
     // 在按钮下方显示菜单
     QPoint pos = m_audioDeviceBtn->mapToGlobal(QPoint(0, m_audioDeviceBtn->height()));
     menu->exec(pos);
-    
+
     menu->deleteLater();
 }
 

+ 29 - 1
libs/AvRecorder/ui/capture_source_widget.cpp

@@ -1,6 +1,10 @@
 #include "capture_source_widget.h"
+#include "qdebug.h"
 
 #include <capturer/finder.h>
+#ifdef _WIN32
+#include <Windows.h>
+#endif
 
 CaptureSourceWidget::CaptureSourceWidget(QWidget* parent)
     : QWidget(parent)
@@ -51,7 +55,31 @@ int CaptureSourceWidget::getCurrentIndex() const
 
 QVariant CaptureSourceWidget::getCurrentData() const
 {
-    return m_captureComboBox ? m_captureComboBox->currentData() : QVariant();
+    if (!m_captureComboBox) {
+        return QVariant();
+    }
+    
+    QVariant data = m_captureComboBox->currentData();
+    QString text = m_captureComboBox->currentText();
+    
+    // 如果是窗口类型,验证HWND有效性
+    if (text.startsWith("窗口: ")) {
+        qintptr ptrHwnd = data.value<qintptr>();
+        HWND hwnd = reinterpret_cast<HWND>(ptrHwnd);
+        
+        if (!IsWindow(hwnd)) {
+            qDebug() << "CaptureSourceWidget: 检测到无效窗口句柄" << Qt::hex << ptrHwnd 
+                     << "窗口标题:" << text << "- 自动刷新窗口列表";
+            
+            // 自动刷新窗口列表
+            const_cast<CaptureSourceWidget*>(this)->updateCaptureList();
+            
+            // 尝试重新获取数据
+            return m_captureComboBox->currentData();
+        }
+    }
+    
+    return data;
 }
 
 QString CaptureSourceWidget::getCurrentText() const

+ 48 - 44
libs/Recorder/AecKsBinder.h

@@ -1,7 +1,7 @@
 //-------------------------------------------------------------------------
 // File: AecKsBinder.h
-// 
-// Desciption: Definition of audio devices binding functions 
+//
+// Desciption: Definition of audio devices binding functions
 //
 // Copyright (c) 2004-2006, Microsoft Corporation. All rights reserved.
 //---------------------------------------------------------------------------
@@ -9,96 +9,100 @@
 #ifndef _AEC_KSBINDER_H_
 #define _AEC_KSBINDER_H_
 
-#include <atlbase.h>
 #include <ATLComCli.h>
-#include <audioclient.h>
-#include <MMDeviceApi.h>
 #include <AudioEngineEndPoint.h>
 #include <DeviceTopology.h>
 #include <EndpointVolume.h>
+#include <MMDeviceApi.h>
+#include <atlbase.h>
+#include <audioclient.h>
 
-typedef struct 
+typedef struct
 {
     KSPROPERTY KsProperty;
     BOOLEAN bEndpointFlag;
     ULONG ulEntityId;
     union {
-         ULONG ulEndpoint;
-         ULONG ulInterface;
+        ULONG ulEndpoint;
+        ULONG ulInterface;
     };
     ULONG ulOffset;
 } USBAUDIO_MEMORY_PROPERTY, *PUSBAUDIO_MEMORY_PROPERTY;
 
-static const GUID USB_AUDIO_PROP_SET_GUID = 
-     {0xC3FA16D7, 0x274E, 0x4f2b, 
-     {0xA6, 0x3B, 0xD5, 0xE1, 0x09, 0x55, 0xFA, 0x27}};
+static const GUID USB_AUDIO_PROP_SET_GUID = {0xC3FA16D7,
+                                             0x274E,
+                                             0x4f2b,
+                                             {0xA6, 0x3B, 0xD5, 0xE1, 0x09, 0x55, 0xFA, 0x27}};
 const DWORD USBAUDIO_PROPERTY_GETSET_MEM = 0;
 
 #define MAX_STR_LEN 512
 typedef struct
 {
     TCHAR szDeviceName[MAX_STR_LEN];
-	TCHAR szDeviceID[MAX_STR_LEN];
+    TCHAR szDeviceID[MAX_STR_LEN];
     bool bIsMicArrayDevice;
 } AUDIO_DEVICE_INFO, *PAUDIO_DEVICE_INFO;
-    
 
 HRESULT GetDeviceNum(EDataFlow eDataFlow, UINT &uDevCount);
 
 __inline HRESULT GetRenderDeviceNum(UINT &uDevCount)
-{ return GetDeviceNum(eRender, uDevCount); }
+{
+    return GetDeviceNum(eRender, uDevCount);
+}
 
 __inline HRESULT GetCaptureDeviceNum(UINT &uDevCount)
-{ return GetDeviceNum(eCapture, uDevCount); }
-
-
-HRESULT EnumDevice(
-    EDataFlow eDataFlow, 
-    UINT  uNumElements,
-    AUDIO_DEVICE_INFO *pDevicInfo);
+{
+    return GetDeviceNum(eCapture, uDevCount);
+}
 
-__inline HRESULT EnumRenderDevice(UINT  uNumElements, AUDIO_DEVICE_INFO *pDevicInfo) 
-    { return EnumDevice(eRender, uNumElements, pDevicInfo); }
+HRESULT EnumDevice(EDataFlow eDataFlow, UINT uNumElements, AUDIO_DEVICE_INFO *pDevicInfo);
 
-__inline HRESULT EnumCaptureDevice(UINT  uNumElements, AUDIO_DEVICE_INFO *pDevicInfo) 
-    { return EnumDevice(eCapture, uNumElements, pDevicInfo); }
+__inline HRESULT EnumRenderDevice(UINT uNumElements, AUDIO_DEVICE_INFO *pDevicInfo)
+{
+    return EnumDevice(eRender, uNumElements, pDevicInfo);
+}
 
+__inline HRESULT EnumCaptureDevice(UINT uNumElements, AUDIO_DEVICE_INFO *pDevicInfo)
+{
+    return EnumDevice(eCapture, uNumElements, pDevicInfo);
+}
 
 HRESULT DeviceBindTo(
-        EDataFlow eDataFlow,        // eCapture or eRender
-        INT uDevIdx,                // Device Index. USE_DEFAULT_DEVICE - use default device. 
-        IAudioClient **ppAudioClient,    // pointer pointer to IAudioClient interface
-        IAudioEndpointVolume **ppEndpointVolume,
-        WCHAR** ppszEndpointDeviceId   // Device ID. Need to be freed in caller with CoTaskMemoryFree
+    EDataFlow eDataFlow,          // eCapture or eRender
+    INT uDevIdx,                  // Device Index. USE_DEFAULT_DEVICE - use default device.
+    IAudioClient **ppAudioClient, // pointer pointer to IAudioClient interface
+    IAudioEndpointVolume **ppEndpointVolume,
+    WCHAR **ppszEndpointDeviceId // Device ID. Need to be freed in caller with CoTaskMemoryFree
 );
 
 __inline HRESULT CaptureDeviceBindTo(
-        INT uDevIdx, 
-        IAudioClient **ppAudioClient,    // pointer pointer to IAudioClient interface
-        IAudioEndpointVolume **ppEndpointVolume,
-        WCHAR** ppszEndpointDeviceId)
+    INT uDevIdx,
+    IAudioClient **ppAudioClient, // pointer pointer to IAudioClient interface
+    IAudioEndpointVolume **ppEndpointVolume,
+    WCHAR **ppszEndpointDeviceId)
 {
     return DeviceBindTo(eCapture, uDevIdx, ppAudioClient, ppEndpointVolume, ppszEndpointDeviceId);
 }
 
 __inline HRESULT RenderDeviceBindTo(
-        INT uDevIdx, 
-        IAudioClient **ppAudioClient,    // pointer pointer to IAudioClient interface
-        IAudioEndpointVolume **ppEndpointVolume,
-        WCHAR** ppszEndpointDeviceId)
+    INT uDevIdx,
+    IAudioClient **ppAudioClient, // pointer pointer to IAudioClient interface
+    IAudioEndpointVolume **ppEndpointVolume,
+    WCHAR **ppszEndpointDeviceId)
 {
     return DeviceBindTo(eRender, uDevIdx, ppAudioClient, ppEndpointVolume, ppszEndpointDeviceId);
 }
 
-HRESULT DeviceIsMicArray(wchar_t szDeviceId[], bool& bIsMicArray);
+HRESULT DeviceIsMicArray(wchar_t szDeviceId[], bool &bIsMicArray);
 
-HRESULT EndpointIsMicArray(IMMDevice* pEndpoint, bool& isMicrophoneArray);
+HRESULT EndpointIsMicArray(IMMDevice *pEndpoint, bool &isMicrophoneArray);
 
-HRESULT GetJackSubtypeForEndpoint(IMMDevice* pEndpoint, GUID* pgSubtype);
+HRESULT GetJackSubtypeForEndpoint(IMMDevice *pEndpoint, GUID *pgSubtype);
 
-__checkReturn HRESULT GetInputJack(IMMDevice* pDevice, CComPtr<IPart>& spPart);
+__checkReturn HRESULT GetInputJack(IMMDevice *pDevice, CComPtr<IPart> &spPart);
 
-HRESULT GetMicArrayGeometry(wchar_t szDeviceId[], KSAUDIO_MIC_ARRAY_GEOMETRY** ppGeometry, ULONG& cbSize);
+HRESULT GetMicArrayGeometry(wchar_t szDeviceId[],
+                            KSAUDIO_MIC_ARRAY_GEOMETRY **ppGeometry,
+                            ULONG &cbSize);
 
 #endif //_AEC_KSBINDER_H_
-

Datei-Diff unterdrückt, da er zu groß ist
+ 633 - 614
libs/Recorder/Recorder.cpp


+ 99 - 0
libs/Recorder/Recorder.pri

@@ -0,0 +1,99 @@
+DISTFILES += \
+    $$PWD/Recorder.vcxproj \
+    $$PWD/Recorder.vcxproj.filters \
+    $$PWD/d3d_pixelshader.hlsl \
+    $$PWD/d3d_vertexshader.hlsl
+
+HEADERS += \
+    # $$PWD/AecKsBinder.h \
+    $$PWD/common.h \
+    $$PWD/d3d_helper.h \
+    $$PWD/device_audios.h \
+    $$PWD/device_videos.h \
+    $$PWD/encoder_aac.h \
+    $$PWD/encoder_video.h \
+    $$PWD/encoder_video_define.h \
+    $$PWD/encoder_video_factory.h \
+    $$PWD/encoder_video_nvenc.h \
+    $$PWD/encoder_video_x264.h \
+    $$PWD/error_define.h \
+    $$PWD/export.h \
+    $$PWD/filter.h \
+    $$PWD/filter_amix.h \
+    $$PWD/filter_aresample.h \
+    $$PWD/hardware_acceleration.h \
+    $$PWD/headers_ffmpeg.h \
+    $$PWD/headers_mmdevice.h \
+    $$PWD/log_helper.h \
+    $$PWD/mul_db.h \
+    $$PWD/muxer_define.h \
+    $$PWD/muxer_ffmpeg.h \
+    $$PWD/muxer_file.h \
+    $$PWD/record_audio.h \
+    $$PWD/record_audio_define.h \
+    $$PWD/record_audio_dshow.h \
+    $$PWD/record_audio_factory.h \
+    $$PWD/record_audio_wasapi.h \
+    $$PWD/record_desktop.h \
+    $$PWD/record_desktop_define.h \
+    $$PWD/record_desktop_duplication.h \
+    $$PWD/record_desktop_factory.h \
+    $$PWD/record_desktop_ffmpeg_dshow.h \
+    $$PWD/record_desktop_ffmpeg_gdi.h \
+    $$PWD/record_desktop_gdi.h \
+    $$PWD/record_desktop_mag.h \
+    $$PWD/record_desktop_wgc.h \
+    $$PWD/remuxer_ffmpeg.h \
+    $$PWD/resample_pcm.h \
+    $$PWD/ring_buffer.h \
+    $$PWD/sws_helper.h \
+    $$PWD/system_error.h \
+    $$PWD/system_lib.h \
+    $$PWD/system_time.h \
+    $$PWD/system_version.h \
+    $$PWD/utils_string.h
+
+SOURCES += \
+    # $$PWD/AecKsBinder.cpp \
+    $$PWD/Recorder.cpp \
+    $$PWD/d3d_helper.cpp \
+    $$PWD/device_audios.cpp \
+    $$PWD/device_videos.cpp \
+    $$PWD/dllmain.cpp \
+    $$PWD/encoder_aac.cpp \
+    $$PWD/encoder_video.cpp \
+    $$PWD/encoder_video_factory.cpp \
+    $$PWD/encoder_video_nvenc.cpp \
+    $$PWD/encoder_video_x264.cpp \
+    $$PWD/export.cpp \
+    $$PWD/filter.cpp \
+    $$PWD/filter_amix.cpp \
+    $$PWD/filter_aresample.cpp \
+    $$PWD/hardware_acceleration.cpp \
+    $$PWD/headers_mmdevice.cpp \
+    $$PWD/log_helper.cpp \
+    $$PWD/muxer_ffmpeg.cpp \
+    $$PWD/muxer_file.cpp \
+    $$PWD/record_audio.cpp \
+    $$PWD/record_audio_dshow.cpp \
+    $$PWD/record_audio_factory.cpp \
+    $$PWD/record_audio_wasapi.cpp \
+    $$PWD/record_desktop.cpp \
+    $$PWD/record_desktop_duplication.cpp \
+    $$PWD/record_desktop_factory.cpp \
+    $$PWD/record_desktop_ffmpeg_dshow.cpp \
+    $$PWD/record_desktop_ffmpeg_gdi.cpp \
+    $$PWD/record_desktop_gdi.cpp \
+    $$PWD/record_desktop_mag.cpp \
+    $$PWD/record_desktop_wgc.cpp \
+    $$PWD/remuxer_ffmpeg.cpp \
+    $$PWD/resample_pcm.cpp \
+    $$PWD/ring_buffer.cpp \
+    $$PWD/sws_helper.cpp \
+    $$PWD/system_error.cpp \
+    $$PWD/system_lib.cpp \
+    $$PWD/system_time.cpp \
+    $$PWD/system_version.cpp \
+    $$PWD/test_main.cpp \
+    $$PWD/transcode_aac.cpp \
+    $$PWD/utils_string.cpp

+ 5 - 5
libs/Recorder/common.h

@@ -1,9 +1,9 @@
 #pragma once
 
+#include <libavcodec\avcodec.h>
+#include <libavdevice\avdevice.h>
 #include <libavformat\avformat.h>
+#include <libavutil\audio_fifo.h>
 #include <libavutil\avutil.h>
-#include <libavdevice\avdevice.h>
-#include "libavcodec\avcodec.h"  
-#include "libswscale\swscale.h"
-#include "libswresample\swresample.h"
-#include <libavutil\audio_fifo.h>
+#include <libswresample\swresample.h>
+#include <libswscale\swscale.h>

+ 37 - 37
libs/Recorder/d3d_helper.cpp

@@ -6,52 +6,52 @@
 #include "log_helper.h"
 
 namespace am {
-	typedef HRESULT(WINAPI *DXGI_FUNC_CREATEFACTORY)(REFIID, IDXGIFactory1 **);
+typedef HRESULT(WINAPI *DXGI_FUNC_CREATEFACTORY)(REFIID, IDXGIFactory1 **);
 
-	std::list<IDXGIAdapter*> d3d_helper::get_adapters(int * error, bool free_lib)
-	{
-		std::list<IDXGIAdapter*> adapters;
+std::list<IDXGIAdapter *> d3d_helper::get_adapters(int *error, bool free_lib)
+{
+    std::list<IDXGIAdapter *> adapters;
 
-		*error = AE_NO;
+    *error = AE_NO;
 
-		HMODULE hdxgi = load_system_library("dxgi.dll");
+    HMODULE hdxgi = load_system_library("dxgi.dll");
 
-		if (!hdxgi) {
-			*error = AE_D3D_LOAD_FAILED;
-			return adapters;
-		}
+    if (!hdxgi) {
+        *error = AE_D3D_LOAD_FAILED;
+        return adapters;
+    }
 
-		do {
-			DXGI_FUNC_CREATEFACTORY create_factory = nullptr;
-			create_factory = (DXGI_FUNC_CREATEFACTORY)GetProcAddress(hdxgi, "CreateDXGIFactory1");
+    do {
+        DXGI_FUNC_CREATEFACTORY create_factory = nullptr;
+        create_factory = (DXGI_FUNC_CREATEFACTORY) GetProcAddress(hdxgi, "CreateDXGIFactory1");
 
-			if (create_factory == nullptr) {
-				*error = AE_DXGI_GET_PROC_FAILED;
-				break;
-			}
+        if (create_factory == nullptr) {
+            *error = AE_DXGI_GET_PROC_FAILED;
+            break;
+        }
 
-			IDXGIFactory1 * dxgi_factory = nullptr;
-			HRESULT hr = create_factory(__uuidof(IDXGIFactory1), &dxgi_factory);
-			if (FAILED(hr)) {
-				*error = AE_DXGI_GET_FACTORY_FAILED;
-				break;
-			}
+        IDXGIFactory1 *dxgi_factory = nullptr;
+        HRESULT hr = create_factory(__uuidof(IDXGIFactory1), &dxgi_factory);
+        if (FAILED(hr)) {
+            *error = AE_DXGI_GET_FACTORY_FAILED;
+            break;
+        }
 
-			unsigned int i = 0;
-			IDXGIAdapter *adapter = nullptr;
-			while (dxgi_factory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND)
-			{
-				if(adapter)
-					adapters.push_back(adapter);
-				++i;
-			}
+        unsigned int i = 0;
+        IDXGIAdapter *adapter = nullptr;
+        while (dxgi_factory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND) {
+            if (adapter)
+                adapters.push_back(adapter);
+            ++i;
+        }
 
-			dxgi_factory->Release();
+        dxgi_factory->Release();
 
-		} while (0);
+    } while (0);
 
-		if (free_lib && hdxgi) free_system_library(hdxgi);
+    if (free_lib && hdxgi)
+        free_system_library(hdxgi);
 
-		return adapters;
-	}
-}
+    return adapters;
+}
+} // namespace am

+ 9 - 9
libs/Recorder/d3d_helper.h

@@ -6,13 +6,13 @@
 #include <list>
 
 namespace am {
-	class d3d_helper
-	{
-	private:
-		d3d_helper() {}
+class d3d_helper
+{
+private:
+    d3d_helper() {}
 
-	public:
-		static std::list<IDXGIAdapter*> get_adapters(int *error, bool free_lib = false);
-	};
-}
-#endif
+public:
+    static std::list<IDXGIAdapter *> get_adapters(int *error, bool free_lib = false);
+};
+} // namespace am
+#endif

+ 236 - 232
libs/Recorder/device_audios.cpp

@@ -10,102 +10,109 @@
 #include <memory>
 
 namespace am {
-
-	int device_audios::get_input_devices(std::list<DEVICE_AUDIOS>& devices)
-	{
-		return get_devices(true, devices);
-	}
-
-	int device_audios::get_output_devices(std::list<DEVICE_AUDIOS>& devices)
-	{
-		return get_devices(false, devices);
-	}
-
-	int device_audios::get_default_input_device(std::string & id, std::string & name)
-	{
-		return get_default(true, id, name);
-	}
-
-	int device_audios::get_default_ouput_device(std::string & id, std::string & name)
-	{
-		return get_default(false, id, name);
-	}
-
-	int device_audios::get_devices(bool input, std::list<DEVICE_AUDIOS>& devices)
-	{
-		com_initialize com_obj;
-
-		devices.clear();
-
-		Microsoft::WRL::ComPtr<IMMDeviceEnumerator> device_enumerator = nullptr;
-		Microsoft::WRL::ComPtr<IMMDevice> device = nullptr;
-		Microsoft::WRL::ComPtr<IMMDeviceCollection> collection = nullptr;
-		LPWSTR current_device_id = NULL;
-
-		int ret = AE_NO;
-
-		do {
-			std::shared_ptr<void> raii_ptr(nullptr, [&](void*) {
-				collection = nullptr;
-				device = nullptr;
-				device_enumerator = nullptr;
-			});
-
-			HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
-				__uuidof(IMMDeviceEnumerator), (void**)device_enumerator.GetAddressOf());
-
-			if (FAILED(hr)) {
-				ret = AE_CO_CREATE_FAILED;
-				break;
-			}
-
-			hr = device_enumerator->GetDefaultAudioEndpoint(input == true ? eCapture : eRender, eConsole, device.GetAddressOf());
-			if (FAILED(hr)) {
-				ret = AE_CO_GETENDPOINT_FAILED;
-				break;
-			}
-
-			hr = device_enumerator->EnumAudioEndpoints(input == true ? eCapture : eRender, DEVICE_STATE_ACTIVE, collection.GetAddressOf());
-			if (FAILED(hr)) {
-				ret = AE_CO_ENUMENDPOINT_FAILED;
-				break;
-			}
-
-			UINT count;
-			hr = collection->GetCount(&count);
-			if (FAILED(hr)) {
-				ret = AE_CO_GET_ENDPOINT_COUNT_FAILED;
-				break;
-			}
-
-			hr = device->GetId(&current_device_id);
-			if (FAILED(hr)) {
-				ret = AE_CO_GET_ENDPOINT_ID_FAILED;
-				break;
-			}
-
-			std::string default_id = utils_string::unicode_utf8(current_device_id);
-
-			CoTaskMemFree(current_device_id);
-
-			for (int i = 0; i < count; ++i) {
-				IMMDevice* pEndpointDevice = NULL;
-				IDeviceTopology* deviceTopology = NULL;
-				IConnector* connector = NULL;
-
-				IPropertyStore *pPropertyStore = NULL;
-				PROPVARIANT pv;
-				PropVariantInit(&pv);
-
-				LPWSTR device_name = NULL;
-				LPWSTR device_id = NULL;
-
-				std::string str_name, str_id, str_friendly;
-
-				hr = collection->Item(i, &pEndpointDevice);
-				if (FAILED(hr)) continue;
-
-				/*hr = pEndpointDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_INPROC_SERVER, NULL,
+int device_audios::get_input_devices(std::list<DEVICE_AUDIOS>& devices)
+{
+    return get_devices(true, devices);
+}
+
+int device_audios::get_output_devices(std::list<DEVICE_AUDIOS>& devices)
+{
+    return get_devices(false, devices);
+}
+
+int device_audios::get_default_input_device(std::string& id, std::string& name)
+{
+    return get_default(true, id, name);
+}
+
+int device_audios::get_default_ouput_device(std::string& id, std::string& name)
+{
+    return get_default(false, id, name);
+}
+
+int device_audios::get_devices(bool input, std::list<DEVICE_AUDIOS>& devices)
+{
+    com_initialize com_obj;
+
+    devices.clear();
+
+    Microsoft::WRL::ComPtr<IMMDeviceEnumerator> device_enumerator = nullptr;
+    Microsoft::WRL::ComPtr<IMMDevice> device = nullptr;
+    Microsoft::WRL::ComPtr<IMMDeviceCollection> collection = nullptr;
+    LPWSTR current_device_id = NULL;
+
+    int ret = AE_NO;
+
+    do {
+        std::shared_ptr<void> raii_ptr(nullptr, [&](void*) {
+            collection = nullptr;
+            device = nullptr;
+            device_enumerator = nullptr;
+        });
+
+        HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
+                                      NULL,
+                                      CLSCTX_ALL,
+                                      __uuidof(IMMDeviceEnumerator),
+                                      (void**) device_enumerator.GetAddressOf());
+
+        if (FAILED(hr)) {
+            ret = AE_CO_CREATE_FAILED;
+            break;
+        }
+
+        hr = device_enumerator->GetDefaultAudioEndpoint(input == true ? eCapture : eRender,
+                                                        eConsole,
+                                                        device.GetAddressOf());
+        if (FAILED(hr)) {
+            ret = AE_CO_GETENDPOINT_FAILED;
+            break;
+        }
+
+        hr = device_enumerator->EnumAudioEndpoints(input == true ? eCapture : eRender,
+                                                   DEVICE_STATE_ACTIVE,
+                                                   collection.GetAddressOf());
+        if (FAILED(hr)) {
+            ret = AE_CO_ENUMENDPOINT_FAILED;
+            break;
+        }
+
+        UINT count;
+        hr = collection->GetCount(&count);
+        if (FAILED(hr)) {
+            ret = AE_CO_GET_ENDPOINT_COUNT_FAILED;
+            break;
+        }
+
+        hr = device->GetId(&current_device_id);
+        if (FAILED(hr)) {
+            ret = AE_CO_GET_ENDPOINT_ID_FAILED;
+            break;
+        }
+
+        std::string default_id = utils_string::unicode_utf8(current_device_id);
+
+        CoTaskMemFree(current_device_id);
+
+        for (int i = 0; i < count; ++i) {
+            IMMDevice* pEndpointDevice = NULL;
+            IDeviceTopology* deviceTopology = NULL;
+            IConnector* connector = NULL;
+
+            IPropertyStore* pPropertyStore = NULL;
+            PROPVARIANT pv;
+            PropVariantInit(&pv);
+
+            LPWSTR device_name = NULL;
+            LPWSTR device_id = NULL;
+
+            std::string str_name, str_id, str_friendly;
+
+            hr = collection->Item(i, &pEndpointDevice);
+            if (FAILED(hr))
+                continue;
+
+            /*hr = pEndpointDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_INPROC_SERVER, NULL,
 					(LPVOID*)&deviceTopology);
 				hr = deviceTopology->GetConnector(0, &connector);
 
@@ -113,139 +120,136 @@ namespace am {
 
 				str_name = utils_string::unicode_utf8(device_name);*/
 
-				hr = pEndpointDevice->GetId(&device_id);
-				if (FAILED(hr)) continue;
-
-				str_id = utils_string::unicode_utf8(device_id);
-
-				hr = pEndpointDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
-				if (FAILED(hr)) continue;
-
-				hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
-				if (FAILED(hr)) {
-					PropVariantClear(&pv);
-					continue;
-				}
-
-				if (pv.vt == VT_LPWSTR) {
-					str_friendly = utils_string::unicode_utf8(pv.pwszVal);
-				}
-				else if (pv.vt == VT_LPSTR) {
-					str_friendly = utils_string::ascii_utf8(pv.pszVal);
-				}
-
-				devices.push_back({
-					str_id,
-					str_friendly,
-					str_id.compare(default_id) == 0
-				});
-
-				PropVariantClear(&pv);
-				CoTaskMemFree(device_name);
-				CoTaskMemFree(device_id);
-			}
-		} while (0);
-
-		if (ret == AE_NO && devices.size()) {
-			devices.push_front({
-				utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_ID),
-				utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_NAME),
-				true
-			});
-		}
-
-
-		if (ret != AE_NO)
-			al_error("get_devices failed(%lu): %s", GetLastError(), err2str(ret));
-
-		return ret;
-	}
-
-	int device_audios::get_default(bool input, std::string & id, std::string & name)
-	{
-		com_initialize com_obj;
-
-		Microsoft::WRL::ComPtr<IMMDeviceEnumerator> device_enumerator = nullptr;
-		Microsoft::WRL::ComPtr<IMMDevice> device = nullptr;
-		Microsoft::WRL::ComPtr<IMMDeviceCollection> collection = nullptr;
-		LPWSTR current_device_id = NULL;
-
-		std::shared_ptr<void> raii_ptr(nullptr, [&](void*) {
-			collection = nullptr;
-			device = nullptr;
-			device_enumerator = nullptr;
-		});
-
-		int ret = AE_NO;
-		do {
-
-			HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
-				__uuidof(IMMDeviceEnumerator), (void**)device_enumerator.GetAddressOf());
-			if (FAILED(hr)) {
-				ret = AE_CO_CREATE_FAILED;
-				break;
-			}
-
-			hr = device_enumerator->GetDefaultAudioEndpoint(input == true ? eCapture : eRender, eConsole, device.GetAddressOf());
-			if (FAILED(hr)) {
-				ret = AE_CO_GETENDPOINT_FAILED;
-				break;
-			}
-
-			hr = device_enumerator->EnumAudioEndpoints(input == true ? eCapture : eRender, DEVICE_STATE_ACTIVE, collection.GetAddressOf());
-			if (FAILED(hr)) {
-				ret = AE_CO_ENUMENDPOINT_FAILED;
-				break;
-			}
-
-			UINT count;
-			hr = collection->GetCount(&count);
-			if (FAILED(hr)) {
-				ret = AE_CO_GET_ENDPOINT_COUNT_FAILED;
-				break;
-			}
-
-			hr = device->GetId(&current_device_id);
-			if (FAILED(hr)) {
-				ret = AE_CO_GET_ENDPOINT_ID_FAILED;
-				break;
-			}
-
-			id = utils_string::unicode_utf8(current_device_id);
-
-			CoTaskMemFree(current_device_id);
-
-			IPropertyStore *pPropertyStore = NULL;
-			PROPVARIANT pv;
-			PropVariantInit(&pv);
-
-			hr = device->OpenPropertyStore(STGM_READ, &pPropertyStore);
-			if (FAILED(hr)) {
-				ret = AE_CO_OPEN_PROPERTY_FAILED;
-				break;
-			}
-
-			hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
-			if (FAILED(hr)) {
-				ret = AE_CO_GET_VALUE_FAILED;
-				break;
-			}
-
-			if (pv.vt == VT_LPWSTR) {
-				name = utils_string::unicode_utf8(pv.pwszVal);
-			}
-			else if (pv.vt == VT_LPSTR) {
-				name = utils_string::ascii_utf8(pv.pszVal);
-			}
-
-			PropVariantClear(&pv);
-		} while (0);
-
-
-		if (ret != AE_NO)
-			al_debug("get_devices failed(%lu): %s", GetLastError(), err2str(ret));
-
-		return ret;
-	}
-
-}
+            hr = pEndpointDevice->GetId(&device_id);
+            if (FAILED(hr))
+                continue;
+
+            str_id = utils_string::unicode_utf8(device_id);
+
+            hr = pEndpointDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
+            if (FAILED(hr))
+                continue;
+
+            hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
+            if (FAILED(hr)) {
+                PropVariantClear(&pv);
+                continue;
+            }
+
+            if (pv.vt == VT_LPWSTR) {
+                str_friendly = utils_string::unicode_utf8(pv.pwszVal);
+            } else if (pv.vt == VT_LPSTR) {
+                str_friendly = utils_string::ascii_utf8(pv.pszVal);
+            }
+
+            devices.push_back({str_id, str_friendly, str_id.compare(default_id) == 0});
+
+            PropVariantClear(&pv);
+            CoTaskMemFree(device_name);
+            CoTaskMemFree(device_id);
+        }
+    } while (0);
+
+    if (ret == AE_NO && devices.size()) {
+        devices.push_front({utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_ID),
+                            utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_NAME),
+                            true});
+    }
+
+    if (ret != AE_NO)
+        al_error("get_devices failed(%lu): %s", GetLastError(), err2str(ret));
+
+    return ret;
+}
+
+int device_audios::get_default(bool input, std::string& id, std::string& name)
+{
+    com_initialize com_obj;
+
+    Microsoft::WRL::ComPtr<IMMDeviceEnumerator> device_enumerator = nullptr;
+    Microsoft::WRL::ComPtr<IMMDevice> device = nullptr;
+    Microsoft::WRL::ComPtr<IMMDeviceCollection> collection = nullptr;
+    LPWSTR current_device_id = NULL;
+
+    std::shared_ptr<void> raii_ptr(nullptr, [&](void*) {
+        collection = nullptr;
+        device = nullptr;
+        device_enumerator = nullptr;
+    });
+
+    int ret = AE_NO;
+    do {
+        HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
+                                      NULL,
+                                      CLSCTX_ALL,
+                                      __uuidof(IMMDeviceEnumerator),
+                                      (void**) device_enumerator.GetAddressOf());
+        if (FAILED(hr)) {
+            ret = AE_CO_CREATE_FAILED;
+            break;
+        }
+
+        hr = device_enumerator->GetDefaultAudioEndpoint(input == true ? eCapture : eRender,
+                                                        eConsole,
+                                                        device.GetAddressOf());
+        if (FAILED(hr)) {
+            ret = AE_CO_GETENDPOINT_FAILED;
+            break;
+        }
+
+        hr = device_enumerator->EnumAudioEndpoints(input == true ? eCapture : eRender,
+                                                   DEVICE_STATE_ACTIVE,
+                                                   collection.GetAddressOf());
+        if (FAILED(hr)) {
+            ret = AE_CO_ENUMENDPOINT_FAILED;
+            break;
+        }
+
+        UINT count;
+        hr = collection->GetCount(&count);
+        if (FAILED(hr)) {
+            ret = AE_CO_GET_ENDPOINT_COUNT_FAILED;
+            break;
+        }
+
+        hr = device->GetId(&current_device_id);
+        if (FAILED(hr)) {
+            ret = AE_CO_GET_ENDPOINT_ID_FAILED;
+            break;
+        }
+
+        id = utils_string::unicode_utf8(current_device_id);
+
+        CoTaskMemFree(current_device_id);
+
+        IPropertyStore* pPropertyStore = NULL;
+        PROPVARIANT pv;
+        PropVariantInit(&pv);
+
+        hr = device->OpenPropertyStore(STGM_READ, &pPropertyStore);
+        if (FAILED(hr)) {
+            ret = AE_CO_OPEN_PROPERTY_FAILED;
+            break;
+        }
+
+        hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
+        if (FAILED(hr)) {
+            ret = AE_CO_GET_VALUE_FAILED;
+            break;
+        }
+
+        if (pv.vt == VT_LPWSTR) {
+            name = utils_string::unicode_utf8(pv.pwszVal);
+        } else if (pv.vt == VT_LPSTR) {
+            name = utils_string::ascii_utf8(pv.pszVal);
+        }
+
+        PropVariantClear(&pv);
+    } while (0);
+
+    if (ret != AE_NO)
+        al_debug("get_devices failed(%lu): %s", GetLastError(), err2str(ret));
+
+    return ret;
+}
+} // namespace am

+ 20 - 20
libs/Recorder/device_audios.h

@@ -1,33 +1,33 @@
-#ifndef  RECORD_DEVICES
+#ifndef RECORD_DEVICES
 #define RECORD_DEVICES
 
 #include <list>
 #include <string>
 
 namespace am {
-	typedef struct {
-		std::string id;
-		std::string name;
-		uint8_t is_default;
-	}DEVICE_AUDIOS;
+typedef struct
+{
+    std::string id;
+    std::string name;
+    uint8_t is_default;
+} DEVICE_AUDIOS;
 
-	class device_audios
-	{
-	public:
-		static int get_default_input_device(std::string &id, std::string &name);
+class device_audios
+{
+public:
+    static int get_default_input_device(std::string &id, std::string &name);
 
-		static int get_default_ouput_device(std::string &id, std::string &name);
+    static int get_default_ouput_device(std::string &id, std::string &name);
 
-		static int get_input_devices(std::list<DEVICE_AUDIOS> &devices);
+    static int get_input_devices(std::list<DEVICE_AUDIOS> &devices);
 
-		static int get_output_devices(std::list<DEVICE_AUDIOS> &devices);
+    static int get_output_devices(std::list<DEVICE_AUDIOS> &devices);
 
-	private:
-		static int get_devices(bool input, std::list<DEVICE_AUDIOS> &devices);
+private:
+    static int get_devices(bool input, std::list<DEVICE_AUDIOS> &devices);
 
-		static int get_default(bool input, std::string &id, std::string &name);
-	};
+    static int get_default(bool input, std::string &id, std::string &name);
+};
+} // namespace am
 
-}
-
-#endif // ! RECORD_DEVICES
+#endif // ! RECORD_DEVICES

+ 2 - 8
libs/Recorder/device_videos.cpp

@@ -1,11 +1,5 @@
 #include "device_videos.h"
 
+device_videos::device_videos() {}
 
-device_videos::device_videos()
-{
-}
-
-
-device_videos::~device_videos()
-{
-}
+device_videos::~device_videos() {}

+ 2 - 3
libs/Recorder/device_videos.h

@@ -2,7 +2,6 @@
 class device_videos
 {
 public:
-	device_videos();
-	~device_videos();
+    device_videos();
+    ~device_videos();
 };
-

+ 83 - 84
libs/Recorder/dllmain.cpp

@@ -1,84 +1,83 @@
-#include <Windows.h>
-
-#include <dbghelp.h>
-#include <stdio.h>
-#include <tchar.h>
-
-static void dump_file(const TCHAR *path, EXCEPTION_POINTERS *exception)
-{
-	HANDLE file = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-
-	MINIDUMP_EXCEPTION_INFORMATION dump;
-	dump.ExceptionPointers = exception;
-	dump.ThreadId = GetCurrentThreadId();
-	dump.ClientPointers = TRUE;
-
-	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpWithFullMemory, &dump, NULL, NULL);
-
-	CloseHandle(file);
-}
-
-#if _MSC_VER >= 1300    // for VC 7.0
-// from ATL 7.0 sources
-#ifndef _delayimp_h
-extern "C" IMAGE_DOS_HEADER __ImageBase;
-#endif
-#endif
-
-static HMODULE get_current_module()
-{
-#if _MSC_VER < 1300    // earlier than .NET compiler (VC 6.0)
-
-	// Here's a trick that will get you the handle of the module
-	// you're running in without any a-priori knowledge:
-	// http://www.dotnet247.com/247reference/msgs/13/65259.aspx
-
-	MEMORY_BASIC_INFORMATION mbi;
-	static int dummy;
-	VirtualQuery(&dummy, &mbi, sizeof(mbi));
-
-	return reinterpret_cast<HMODULE>(mbi.AllocationBase);
-
-#else    // VC 7.0
-
-	// from ATL 7.0 sources
-
-	return reinterpret_cast<HMODULE>(&__ImageBase);
-#endif
-}
-
-static long exception_handler(EXCEPTION_POINTERS *ep)
-{
-	char dmp_path[MAX_PATH] = { 0 };
-	char temp_path[MAX_PATH] = { 0 };
-
-	//c://users//appdata//local//temp//recorder.dmp
-	if (GetTempPath(MAX_PATH, temp_path)) {
-		sprintf_s(dmp_path, MAX_PATH, "%srecorder.dmp", temp_path);
-		printf("%s\r\n", dmp_path);
-	}
-	
-
-	dump_file(dmp_path, ep);
-
-	return EXCEPTION_EXECUTE_HANDLER;
-}
-
-bool APIENTRY DllMain(HMODULE hModule,
-	DWORD  ul_reason_for_call,
-	LPVOID lpReserved
-)
-{
-	switch (ul_reason_for_call)
-	{
-	case DLL_PROCESS_ATTACH:
-		SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)exception_handler);
-		break;
-	case DLL_THREAD_ATTACH:
-		break;
-	case DLL_THREAD_DETACH:
-	case DLL_PROCESS_DETACH:
-		break;
-	}
-	return TRUE;
-}
+// #include <Windows.h>
+
+// #include <dbghelp.h>
+// #include <stdio.h>
+// #include <tchar.h>
+
+// static void dump_file(const TCHAR *path, EXCEPTION_POINTERS *exception)
+// {
+// 	HANDLE file = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+// 	MINIDUMP_EXCEPTION_INFORMATION dump;
+// 	dump.ExceptionPointers = exception;
+// 	dump.ThreadId = GetCurrentThreadId();
+// 	dump.ClientPointers = TRUE;
+
+// 	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpWithFullMemory, &dump, NULL, NULL);
+
+// 	CloseHandle(file);
+// }
+
+// #if _MSC_VER >= 1300    // for VC 7.0
+// // from ATL 7.0 sources
+// #ifndef _delayimp_h
+// extern "C" IMAGE_DOS_HEADER __ImageBase;
+// #endif
+// #endif
+
+// static HMODULE get_current_module()
+// {
+// #if _MSC_VER < 1300    // earlier than .NET compiler (VC 6.0)
+
+// 	// Here's a trick that will get you the handle of the module
+// 	// you're running in without any a-priori knowledge:
+// 	// http://www.dotnet247.com/247reference/msgs/13/65259.aspx
+
+// 	MEMORY_BASIC_INFORMATION mbi;
+// 	static int dummy;
+// 	VirtualQuery(&dummy, &mbi, sizeof(mbi));
+
+// 	return reinterpret_cast<HMODULE>(mbi.AllocationBase);
+
+// #else    // VC 7.0
+
+// 	// from ATL 7.0 sources
+
+// 	return reinterpret_cast<HMODULE>(&__ImageBase);
+// #endif
+// }
+
+// static long exception_handler(EXCEPTION_POINTERS *ep)
+// {
+// 	char dmp_path[MAX_PATH] = { 0 };
+// 	char temp_path[MAX_PATH] = { 0 };
+
+// 	//c://users//appdata//local//temp//recorder.dmp
+// 	if (GetTempPath(MAX_PATH, temp_path)) {
+// 		sprintf_s(dmp_path, MAX_PATH, "%srecorder.dmp", temp_path);
+// 		printf("%s\r\n", dmp_path);
+// 	}
+
+// 	dump_file(dmp_path, ep);
+
+// 	return EXCEPTION_EXECUTE_HANDLER;
+// }
+
+// bool APIENTRY DllMain(HMODULE hModule,
+// 	DWORD  ul_reason_for_call,
+// 	LPVOID lpReserved
+// )
+// {
+// 	switch (ul_reason_for_call)
+// 	{
+// 	case DLL_PROCESS_ATTACH:
+// 		SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)exception_handler);
+// 		break;
+// 	case DLL_THREAD_ATTACH:
+// 		break;
+// 	case DLL_THREAD_DETACH:
+// 	case DLL_PROCESS_DETACH:
+// 		break;
+// 	}
+// 	return TRUE;
+// }

+ 251 - 257
libs/Recorder/encoder_aac.cpp

@@ -6,327 +6,321 @@
 #include "log_helper.h"
 
 namespace am {
+encoder_aac::encoder_aac()
+{
+    av_register_all();
 
-	encoder_aac::encoder_aac()
-	{
-		av_register_all();
+    _ring_buffer = new ring_buffer<AVFrame>(1024 * 1024 * 10);
 
-		_ring_buffer = new ring_buffer<AVFrame>(1024 * 1024 * 10);
+    _inited = false;
+    _running = false;
 
-		_inited = false;
-		_running = false;
+    _encoder = NULL;
+    _encoder_ctx = NULL;
+    _frame = NULL;
+    _buff = NULL;
+    _buff_size = 0;
 
-		_encoder = NULL;
-		_encoder_ctx = NULL;
-		_frame = NULL;
-		_buff = NULL;
-		_buff_size = 0;
-
-		_cond_notify = false;
+    _cond_notify = false;
 
 #ifdef SAVE_AAC
-		_aac_io_ctx = NULL;
-		_aac_stream = NULL;
-		_aac_fmt_ctx = NULL;
+    _aac_io_ctx = NULL;
+    _aac_stream = NULL;
+    _aac_fmt_ctx = NULL;
 #endif
-	}
-
-	encoder_aac::~encoder_aac()
-	{
-		stop();
-
-		cleanup();
-
-		delete _ring_buffer;
-	}
-
-	int encoder_aac::init(int nb_channels, int sample_rate, AVSampleFormat fmt,int bit_rate)
-	{
-		int err = AE_NO;
-		int ret = 0;
-
-		if (_inited == true)
-			return err;
-
-		do {
-			_encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
-			if (!_encoder) {
-				err = AE_FFMPEG_FIND_ENCODER_FAILED;
-				break;
-			}
-
-			_encoder_ctx = avcodec_alloc_context3(_encoder);
-			if (!_encoder_ctx) {
-				err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
-				break;
-			}
-
-			_encoder_ctx->channels = nb_channels;
-			_encoder_ctx->channel_layout = av_get_default_channel_layout(nb_channels);
-			_encoder_ctx->sample_rate = sample_rate;
-			_encoder_ctx->sample_fmt = fmt;
-			_encoder_ctx->bit_rate = bit_rate;
-
-			_encoder_ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
-			_encoder_ctx->time_base.den = sample_rate;
-			_encoder_ctx->time_base.num = 1;
-			_encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-
-			ret = avcodec_open2(_encoder_ctx, _encoder, NULL);
-			if (ret < 0) {
-				err = AE_FFMPEG_OPEN_CODEC_FAILED;
-				break;
-			}
-
-			_buff_size = av_samples_get_buffer_size(NULL, nb_channels, _encoder_ctx->frame_size, fmt, 1);
-			_buff = (uint8_t*)av_malloc(_buff_size);
-
-			_frame = av_frame_alloc();
-			if (!_frame) {
-				err = AE_FFMPEG_ALLOC_FRAME_FAILED;
-				break;
-			}
-
-			_frame->channels = nb_channels;
-			_frame->nb_samples = _encoder_ctx->frame_size;
-			_frame->channel_layout = av_get_default_channel_layout(nb_channels);
-			_frame->format = fmt;
-			_frame->sample_rate = sample_rate;
-
-			ret = avcodec_fill_audio_frame(_frame, nb_channels, fmt, _buff, _buff_size, 0);
+}
+
+encoder_aac::~encoder_aac()
+{
+    stop();
+
+    cleanup();
+
+    delete _ring_buffer;
+}
+
+int encoder_aac::init(int nb_channels, int sample_rate, AVSampleFormat fmt, int bit_rate)
+{
+    int err = AE_NO;
+    int ret = 0;
+
+    if (_inited == true)
+        return err;
+
+    do {
+        _encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
+        if (!_encoder) {
+            err = AE_FFMPEG_FIND_ENCODER_FAILED;
+            break;
+        }
+
+        _encoder_ctx = avcodec_alloc_context3(_encoder);
+        if (!_encoder_ctx) {
+            err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
+            break;
+        }
+
+        _encoder_ctx->channels = nb_channels;
+        _encoder_ctx->channel_layout = av_get_default_channel_layout(nb_channels);
+        _encoder_ctx->sample_rate = sample_rate;
+        _encoder_ctx->sample_fmt = fmt;
+        _encoder_ctx->bit_rate = bit_rate;
+
+        _encoder_ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+        _encoder_ctx->time_base.den = sample_rate;
+        _encoder_ctx->time_base.num = 1;
+        _encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+
+        ret = avcodec_open2(_encoder_ctx, _encoder, NULL);
+        if (ret < 0) {
+            err = AE_FFMPEG_OPEN_CODEC_FAILED;
+            break;
+        }
+
+        _buff_size = av_samples_get_buffer_size(NULL, nb_channels, _encoder_ctx->frame_size, fmt, 1);
+        _buff = (uint8_t *) av_malloc(_buff_size);
+
+        _frame = av_frame_alloc();
+        if (!_frame) {
+            err = AE_FFMPEG_ALLOC_FRAME_FAILED;
+            break;
+        }
+
+        _frame->channels = nb_channels;
+        _frame->nb_samples = _encoder_ctx->frame_size;
+        _frame->channel_layout = av_get_default_channel_layout(nb_channels);
+        _frame->format = fmt;
+        _frame->sample_rate = sample_rate;
+
+        ret = avcodec_fill_audio_frame(_frame, nb_channels, fmt, _buff, _buff_size, 0);
 
 #ifdef SAVE_AAC
-			ret = avio_open(&_aac_io_ctx, "save.aac", AVIO_FLAG_READ_WRITE);
-			if (ret < 0) {
-				err = AE_FFMPEG_OPEN_IO_FAILED;
-				break;
-			}
-
-			_aac_fmt_ctx = avformat_alloc_context();
-			if (!_aac_fmt_ctx) {
-				err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
-				break;
-			}
-
-			_aac_fmt_ctx->pb = _aac_io_ctx;
-			_aac_fmt_ctx->oformat = av_guess_format(NULL, "save.aac", NULL);
-			_aac_fmt_ctx->url = av_strdup("save.aac");
-
-			_aac_stream = avformat_new_stream(_aac_fmt_ctx, NULL);
-			if (!_aac_stream) {
-				err = AE_FFMPEG_CREATE_STREAM_FAILED;
-				break;
-			}
-
-			ret = avcodec_parameters_from_context(_aac_stream->codecpar, _encoder_ctx);
-			if (ret < 0) {
-				err = AE_FFMPEG_COPY_PARAMS_FAILED;
-				break;
-			}
-
-			if (_aac_fmt_ctx->oformat->flags | AV_CODEC_FLAG_GLOBAL_HEADER) {
-				_aac_stream->codec->extradata_size = _encoder_ctx->extradata_size;// +AV_INPUT_BUFFER_PADDING_SIZE;
-				_aac_stream->codec->extradata = (uint8_t*)av_memdup(_encoder_ctx->extradata, _encoder_ctx->extradata_size);
-			}
+        ret = avio_open(&_aac_io_ctx, "save.aac", AVIO_FLAG_READ_WRITE);
+        if (ret < 0) {
+            err = AE_FFMPEG_OPEN_IO_FAILED;
+            break;
+        }
+
+        _aac_fmt_ctx = avformat_alloc_context();
+        if (!_aac_fmt_ctx) {
+            err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
+            break;
+        }
+
+        _aac_fmt_ctx->pb = _aac_io_ctx;
+        _aac_fmt_ctx->oformat = av_guess_format(NULL, "save.aac", NULL);
+        _aac_fmt_ctx->url = av_strdup("save.aac");
+
+        _aac_stream = avformat_new_stream(_aac_fmt_ctx, NULL);
+        if (!_aac_stream) {
+            err = AE_FFMPEG_CREATE_STREAM_FAILED;
+            break;
+        }
+
+        ret = avcodec_parameters_from_context(_aac_stream->codecpar, _encoder_ctx);
+        if (ret < 0) {
+            err = AE_FFMPEG_COPY_PARAMS_FAILED;
+            break;
+        }
+
+        if (_aac_fmt_ctx->oformat->flags | AV_CODEC_FLAG_GLOBAL_HEADER) {
+            _aac_stream->codec->extradata_size
+                = _encoder_ctx->extradata_size; // +AV_INPUT_BUFFER_PADDING_SIZE;
+            _aac_stream->codec->extradata = (uint8_t *) av_memdup(_encoder_ctx->extradata,
+                                                                  _encoder_ctx->extradata_size);
+        }
 #endif
 
-			_inited = true;
+        _inited = true;
+
+    } while (0);
 
-		} while (0);
+    if (err != AE_NO) {
+        al_debug("%s,error:%d", err2str(err), ret);
+        cleanup();
+    }
 
-		if (err != AE_NO) {
-			al_debug("%s,error:%d", err2str(err), ret);
-			cleanup();
-		}
+    return err;
+}
 
-		return err;
-	}
+int encoder_aac::get_extradata_size()
+{
+    return _encoder_ctx->extradata_size;
+}
 
-		int encoder_aac::get_extradata_size()
-		{
-			return _encoder_ctx->extradata_size;
-		}
+const uint8_t *encoder_aac::get_extradata()
+{
+    return (const uint8_t *) _encoder_ctx->extradata;
+}
 
-		const uint8_t * encoder_aac::get_extradata()
-		{
-			return (const uint8_t*)_encoder_ctx->extradata;
-		}
+int encoder_aac::get_nb_samples()
+{
+    return _encoder_ctx->frame_size;
+}
 
-		int encoder_aac::get_nb_samples()
-		{
-			return _encoder_ctx->frame_size;
-		}
+int encoder_aac::start()
+{
+    int error = AE_NO;
 
-	int encoder_aac::start()
-	{
-		int error = AE_NO;
+    if (_running == true) {
+        return error;
+    }
 
-		if (_running == true) {
-			return error;
-		}
+    if (_inited == false) {
+        return AE_NEED_INIT;
+    }
 
-		if (_inited == false) {
-			return AE_NEED_INIT;
-		}
+    _running = true;
+    _thread = std::thread(std::bind(&encoder_aac::encode_loop, this));
 
-		_running = true;
-		_thread = std::thread(std::bind(&encoder_aac::encode_loop, this));
+    return error;
+}
 
-		return error;
-	}
+void encoder_aac::stop()
+{
+    _running = false;
 
-	void encoder_aac::stop()
-	{
-		_running = false;
+    _cond_notify = true;
+    _cond_var.notify_all();
 
-		_cond_notify = true;
-		_cond_var.notify_all();
+    if (_thread.joinable())
+        _thread.join();
+}
 
-		if (_thread.joinable())
-			_thread.join();
-	}
+int encoder_aac::put(const uint8_t *data, int data_len, AVFrame *frame)
+{
+    std::unique_lock<std::mutex> lock(_mutex);
 
-	int encoder_aac::put(const uint8_t * data, int data_len, AVFrame *frame)
-	{
-		std::unique_lock<std::mutex> lock(_mutex);
-		
-		AVFrame frame_cp;
-		memcpy(&frame_cp, frame, sizeof(AVFrame));
+    AVFrame frame_cp;
+    memcpy(&frame_cp, frame, sizeof(AVFrame));
 
-		_ring_buffer->put(data, data_len,frame_cp);
-		
-		_cond_notify = true;
-		_cond_var.notify_all();
+    _ring_buffer->put(data, data_len, frame_cp);
 
-		return 0;
-	}
+    _cond_notify = true;
+    _cond_var.notify_all();
 
-	const AVRational & encoder_aac::get_time_base()
-	{
-		return _encoder_ctx->time_base;
-	}
+    return 0;
+}
 
-	AVCodecID encoder_aac::get_codec_id()
-	{
-		if (_inited == false) return AV_CODEC_ID_NONE;
+const AVRational &encoder_aac::get_time_base()
+{
+    return _encoder_ctx->time_base;
+}
 
-		return _encoder->id;
-	}
+AVCodecID encoder_aac::get_codec_id()
+{
+    if (_inited == false)
+        return AV_CODEC_ID_NONE;
 
-	int encoder_aac::encode(AVFrame * frame, AVPacket * packet)
-	{
-		int ret = avcodec_send_frame(_encoder_ctx, frame);
-		if (ret < 0) {
-			return AE_FFMPEG_ENCODE_FRAME_FAILED;
-		}
+    return _encoder->id;
+}
 
+int encoder_aac::encode(AVFrame *frame, AVPacket *packet)
+{
+    int ret = avcodec_send_frame(_encoder_ctx, frame);
+    if (ret < 0) {
+        return AE_FFMPEG_ENCODE_FRAME_FAILED;
+    }
 
-		while (ret == 0) {
-			av_init_packet(packet);
+    while (ret == 0) {
+        av_init_packet(packet);
 
-			ret = avcodec_receive_packet(_encoder_ctx, packet);
-			if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-				break;
-			}
+        ret = avcodec_receive_packet(_encoder_ctx, packet);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+            break;
+        }
 
-			if (ret < 0) {
-				return AE_FFMPEG_READ_PACKET_FAILED;
-			}
+        if (ret < 0) {
+            return AE_FFMPEG_READ_PACKET_FAILED;
+        }
 
-			
-			if (ret == 0 && _on_data)
-				_on_data(packet);
-			
+        if (ret == 0 && _on_data)
+            _on_data(packet);
 
 #ifdef SAVE_AAC
-			av_packet_rescale_ts(packet, _encoder_ctx->time_base, _aac_stream->time_base);
-			packet->stream_index = _aac_stream->index;
-			av_write_frame(_aac_fmt_ctx, packet);
+        av_packet_rescale_ts(packet, _encoder_ctx->time_base, _aac_stream->time_base);
+        packet->stream_index = _aac_stream->index;
+        av_write_frame(_aac_fmt_ctx, packet);
 #endif
 
-			av_packet_unref(packet);
-		}
+        av_packet_unref(packet);
+    }
 
-		return AE_NO;
-	}
+    return AE_NO;
+}
 
-	void encoder_aac::encode_loop()
-	{
-		int len = 0;
-		int error = AE_NO;
+void encoder_aac::encode_loop()
+{
+    int len = 0;
+    int error = AE_NO;
 
-		AVPacket *packet = av_packet_alloc();
-		AVFrame pcm_frame;
+    AVPacket *packet = av_packet_alloc();
+    AVFrame pcm_frame;
 
 #ifdef SAVE_AAC
-		avformat_write_header(_aac_fmt_ctx, NULL);
+    avformat_write_header(_aac_fmt_ctx, NULL);
 #endif
 
-		while (_running)
-		{
-			std::unique_lock<std::mutex> lock(_mutex);
-			while (!_cond_notify && _running)
-				_cond_var.wait_for(lock, std::chrono::milliseconds(300));
-
-			while ((len = _ring_buffer->get(_buff, _buff_size, pcm_frame))) {
-				_frame->pts = pcm_frame.pts;
-				_frame->pkt_pts = pcm_frame.pkt_pts;
-				_frame->pkt_dts = pcm_frame.pkt_dts;
+    while (_running) {
+        std::unique_lock<std::mutex> lock(_mutex);
+        while (!_cond_notify && _running)
+            _cond_var.wait_for(lock, std::chrono::milliseconds(300));
 
-				if ((error = encode(_frame, packet)) != AE_NO) {
-					if (_on_error) 
-						_on_error(error);
+        while ((len = _ring_buffer->get(_buff, _buff_size, pcm_frame))) {
+            _frame->pts = pcm_frame.pts;
+            _frame->pkt_pts = pcm_frame.pkt_pts;
+            _frame->pkt_dts = pcm_frame.pkt_dts;
 
-					al_fatal("read aac packet failed:%d", error);
+            if ((error = encode(_frame, packet)) != AE_NO) {
+                if (_on_error)
+                    _on_error(error);
 
-					break;
-				}
+                al_fatal("read aac packet failed:%d", error);
 
-			}
+                break;
+            }
+        }
 
-			_cond_notify = false;
+        _cond_notify = false;
+    }
 
-		}
+    //flush pcm data in encoder
+    encode(NULL, packet);
 
-		//flush pcm data in encoder
-		encode(NULL, packet);
-
-		av_packet_free(&packet);
+    av_packet_free(&packet);
 #ifdef SAVE_AAC
-		av_write_trailer(_aac_fmt_ctx);
+    av_write_trailer(_aac_fmt_ctx);
 #endif
+}
 
-	}
-
-	void encoder_aac::cleanup()
-	{
-		if (_encoder) {
-			avcodec_close(_encoder_ctx);
-		}
+void encoder_aac::cleanup()
+{
+    if (_encoder) {
+        avcodec_close(_encoder_ctx);
+    }
 
-		_encoder = NULL;
+    _encoder = NULL;
 
-		if (_encoder_ctx) {
-			avcodec_free_context(&_encoder_ctx);
-		}
+    if (_encoder_ctx) {
+        avcodec_free_context(&_encoder_ctx);
+    }
 
-		if (_frame)
-			av_free(_frame);
-		_frame = NULL;
+    if (_frame)
+        av_free(_frame);
+    _frame = NULL;
 
-		if (_buff)
-			av_free(_buff);
+    if (_buff)
+        av_free(_buff);
 
-		_buff = NULL;
+    _buff = NULL;
 
-		_encoder_ctx = NULL;
+    _encoder_ctx = NULL;
 
 #ifdef SAVE_AAC
-		if (_aac_fmt_ctx) {
-			avio_closep(&_aac_fmt_ctx->pb);
-			avformat_free_context(_aac_fmt_ctx);
-		}
+    if (_aac_fmt_ctx) {
+        avio_closep(&_aac_fmt_ctx->pb);
+        avformat_free_context(_aac_fmt_ctx);
+    }
 #endif
-
-	}
-}
+}
+} // namespace am

+ 47 - 55
libs/Recorder/encoder_aac.h

@@ -2,10 +2,10 @@
 #define ENCODER_AAC
 
 #include <atomic>
-#include <thread>
+#include <condition_variable>
 #include <functional>
 #include <mutex>
-#include <condition_variable>
+#include <thread>
 
 #include "headers_ffmpeg.h"
 #include "ring_buffer.h"
@@ -13,80 +13,72 @@
 //#define SAVE_AAC
 
 namespace am {
-	typedef std::function<void(AVPacket *packet)> cb_aac_data;
-	typedef std::function<void(int)> cb_aac_error;
+typedef std::function<void(AVPacket *packet)> cb_aac_data;
+typedef std::function<void(int)> cb_aac_error;
 
+class encoder_aac
+{
+public:
+    encoder_aac();
+    ~encoder_aac();
 
-	class encoder_aac {
-	public:
-		encoder_aac();
-		~encoder_aac();
+    int init(int nb_channels, int sample_rate, AVSampleFormat fmt, int bit_rate);
 
-		int init(
-			int nb_channels,
-			int sample_rate,
-			AVSampleFormat fmt,
-			int bit_rate
-		);
+    int get_extradata_size();
+    const uint8_t *get_extradata();
 
-		int get_extradata_size();
-		const uint8_t* get_extradata();
+    int get_nb_samples();
 
-		int get_nb_samples();
+    int start();
 
-		int start();
+    void stop();
 
-		void stop();
-		
-		int put(const uint8_t *data,int data_len,AVFrame *frame);
+    int put(const uint8_t *data, int data_len, AVFrame *frame);
 
-		inline void registe_cb(
-			cb_aac_data on_data,
-			cb_aac_error on_error) {
-			_on_data = on_data;
-			_on_error = on_error;
-		}
+    inline void registe_cb(cb_aac_data on_data, cb_aac_error on_error)
+    {
+        _on_data = on_data;
+        _on_error = on_error;
+    }
 
-		const AVRational &get_time_base();
+    const AVRational &get_time_base();
 
-		AVCodecID get_codec_id();
+    AVCodecID get_codec_id();
 
-	private:
-		int encode(AVFrame *frame, AVPacket *packet);
+private:
+    int encode(AVFrame *frame, AVPacket *packet);
 
-		void encode_loop();
+    void encode_loop();
 
-		void cleanup();
+    void cleanup();
 
-	private:
-		cb_aac_data _on_data;
-		cb_aac_error _on_error;
+private:
+    cb_aac_data _on_data;
+    cb_aac_error _on_error;
 
-		ring_buffer<AVFrame> *_ring_buffer;
+    ring_buffer<AVFrame> *_ring_buffer;
 
-		std::atomic_bool _inited;
-		std::atomic_bool _running;
+    std::atomic_bool _inited;
+    std::atomic_bool _running;
 
-		std::thread _thread;
+    std::thread _thread;
 
-		AVCodec *_encoder;
-		AVCodecContext *_encoder_ctx;
-		AVFrame *_frame;
-		uint8_t *_buff;
-		int _buff_size;
+    AVCodec *_encoder;
+    AVCodecContext *_encoder_ctx;
+    AVFrame *_frame;
+    uint8_t *_buff;
+    int _buff_size;
 
-		std::mutex _mutex;
-		std::condition_variable _cond_var;
-		bool _cond_notify;
+    std::mutex _mutex;
+    std::condition_variable _cond_var;
+    bool _cond_notify;
 
 #ifdef SAVE_AAC
-		AVIOContext *_aac_io_ctx;
-		AVStream *_aac_stream;
-		AVFormatContext *_aac_fmt_ctx;
+    AVIOContext *_aac_io_ctx;
+    AVStream *_aac_stream;
+    AVFormatContext *_aac_fmt_ctx;
 #endif
-	};
-}
-
-
+};
+} // namespace am
 
 #endif

+ 47 - 50
libs/Recorder/encoder_video.cpp

@@ -1,70 +1,67 @@
 #include "encoder_video.h"
 
 namespace am {
+encoder_video::encoder_video()
+{
+    _inited = false;
+    _running = false;
 
-	encoder_video::encoder_video()
-	{
-		_inited = false;
-		_running = false;
+    _time_base = {0, AV_TIME_BASE};
 
-		_time_base = { 0,AV_TIME_BASE };
+    _encoder_id = EID_VIDEO_X264;
+    _encoder_type = ET_VIDEO_SOFT;
 
-		_encoder_id = EID_VIDEO_X264;
-		_encoder_type = ET_VIDEO_SOFT;
+    _cond_notify = false;
 
-		_cond_notify = false;
+    _ring_buffer = new ring_buffer<AVFrame>();
+}
 
-		_ring_buffer = new ring_buffer<AVFrame>();
-	}
+encoder_video::~encoder_video()
+{
+    if (_ring_buffer)
+        delete _ring_buffer;
+}
 
+int encoder_video::start()
+{
+    int error = AE_NO;
 
-	encoder_video::~encoder_video()
-	{
-		if(_ring_buffer)
-			delete _ring_buffer;
-	}
+    if (_running == true) {
+        return error;
+    }
 
-	int encoder_video::start()
-	{
-		int error = AE_NO;
+    if (_inited == false) {
+        return AE_NEED_INIT;
+    }
 
-		if (_running == true) {
-			return error;
-		}
+    _running = true;
+    _thread = std::thread(std::bind(&encoder_video::encode_loop, this));
 
-		if (_inited == false) {
-			return AE_NEED_INIT;
-		}
+    return error;
+}
 
-		_running = true;
-		_thread = std::thread(std::bind(&encoder_video::encode_loop, this));
+void encoder_video::stop()
+{
+    _running = false;
 
-		return error;
-	}
+    _cond_notify = true;
+    _cond_var.notify_all();
 
-	void encoder_video::stop()
-	{
-		_running = false;
+    if (_thread.joinable())
+        _thread.join();
+}
 
-		_cond_notify = true;
-		_cond_var.notify_all();
+int encoder_video::put(const uint8_t *data, int data_len, AVFrame *frame)
+{
+    std::unique_lock<std::mutex> lock(_mutex);
 
-		if (_thread.joinable())
-			_thread.join();
-	}
+    AVFrame frame_cp;
+    memcpy(&frame_cp, frame, sizeof(AVFrame));
 
-	int encoder_video::put(const uint8_t * data, int data_len, AVFrame * frame)
-	{
-		std::unique_lock<std::mutex> lock(_mutex);
+    _ring_buffer->put(data, data_len, frame_cp);
 
-		AVFrame frame_cp;
-		memcpy(&frame_cp, frame, sizeof(AVFrame));
-
-		_ring_buffer->put(data, data_len, frame_cp);
-
-		_cond_notify = true;
-		_cond_var.notify_all();
-		return 0;
-	}
-
-}
+    _cond_notify = true;
+    _cond_var.notify_all();
+    return 0;
+}
+} // namespace am

+ 43 - 52
libs/Recorder/encoder_video.h

@@ -2,10 +2,10 @@
 #define ENCODER_VIDEO
 
 #include <atomic>
-#include <thread>
+#include <condition_variable>
 #include <functional>
 #include <mutex>
-#include <condition_variable>
+#include <thread>
 
 #include "headers_ffmpeg.h"
 #include "ring_buffer.h"
@@ -13,71 +13,62 @@
 #include "encoder_video_define.h"
 
 namespace am {
+typedef std::function<void(AVPacket *packet)> cb_264_data;
+typedef std::function<void(int)> cb_264_error;
 
-	typedef std::function<void(AVPacket *packet)> cb_264_data;
-	typedef std::function<void(int)> cb_264_error;
-
-	class encoder_video
-	{
-	public:
-		encoder_video();
-		virtual ~encoder_video();
-
-		virtual int init(
-			int pic_width, 
-			int pic_height,
-			int frame_rate,
-			int bit_rate, 
-			int qb, 
-			int key_pic_sec = 2) = 0;
+class encoder_video
+{
+public:
+    encoder_video();
+    virtual ~encoder_video();
 
-		virtual int get_extradata_size() = 0;
-		virtual const uint8_t* get_extradata() = 0;
+    virtual int init(
+        int pic_width, int pic_height, int frame_rate, int bit_rate, int qb, int key_pic_sec = 2)
+        = 0;
 
-		inline void registe_cb(
-			cb_264_data on_data,
-			cb_264_error on_error) {
-			_on_data = on_data;
-			_on_error = on_error;
-		}
+    virtual int get_extradata_size() = 0;
+    virtual const uint8_t *get_extradata() = 0;
 
-		inline const AVRational &get_time_base() {
-			return _time_base;
-		};
+    inline void registe_cb(cb_264_data on_data, cb_264_error on_error)
+    {
+        _on_data = on_data;
+        _on_error = on_error;
+    }
 
-		virtual int start();
+    inline const AVRational &get_time_base() { return _time_base; };
 
-		virtual void stop();
+    virtual int start();
 
-		virtual int put(const uint8_t *data, int data_len, AVFrame *frame);
+    virtual void stop();
 
-		virtual AVCodecID get_codec_id() = 0;
+    virtual int put(const uint8_t *data, int data_len, AVFrame *frame);
 
-	protected:
-		virtual void cleanup() = 0;
-		virtual void encode_loop() = 0;
+    virtual AVCodecID get_codec_id() = 0;
 
-	protected:
-		ENCODER_VIDEO_ID _encoder_id;
-		ENCODER_VIDEO_TYPES _encoder_type;
+protected:
+    virtual void cleanup() = 0;
+    virtual void encode_loop() = 0;
 
-		cb_264_data _on_data;
-		cb_264_error _on_error;
+protected:
+    ENCODER_VIDEO_ID _encoder_id;
+    ENCODER_VIDEO_TYPES _encoder_type;
 
-		ring_buffer<AVFrame> *_ring_buffer;
+    cb_264_data _on_data;
+    cb_264_error _on_error;
 
-		AVRational _time_base;
+    ring_buffer<AVFrame> *_ring_buffer;
 
-		std::atomic_bool _inited;
-		std::atomic_bool _running;
+    AVRational _time_base;
 
-		std::thread _thread;
+    std::atomic_bool _inited;
+    std::atomic_bool _running;
 
-		std::mutex _mutex;
-		std::condition_variable _cond_var;
-		bool _cond_notify;
-	};
+    std::thread _thread;
 
-}
+    std::mutex _mutex;
+    std::condition_variable _cond_var;
+    bool _cond_notify;
+};
+} // namespace am
 
-#endif // !ENCODER_VIDEO
+#endif // !ENCODER_VIDEO

+ 9 - 15
libs/Recorder/encoder_video_define.h

@@ -4,21 +4,15 @@
 #include "hardware_acceleration.h"
 
 namespace am {
+typedef enum {
+    EID_VIDEO_X264 = HARDWARE_TYPE_UNKNOWN,
+    EID_VIDEO_NVENC = HARDWARE_TYPE_NVENC,
+    EID_VIDEO_QSV = HARDWARE_TYPE_QSV,
+    EID_VIDEO_AMF = HARDWARE_TYPE_AMF,
+    EID_VIDEO_VAAPI = HARDWARE_TYPE_VAAPI,
+} ENCODER_VIDEO_ID;
 
-	typedef enum {
-		EID_VIDEO_X264  = HARDWARE_TYPE_UNKNOWN,
-		EID_VIDEO_NVENC = HARDWARE_TYPE_NVENC,
-		EID_VIDEO_QSV = HARDWARE_TYPE_QSV,
-		EID_VIDEO_AMF = HARDWARE_TYPE_AMF,
-		EID_VIDEO_VAAPI = HARDWARE_TYPE_VAAPI,
-	}ENCODER_VIDEO_ID;
-
-	typedef enum {
-		ET_VIDEO_SOFT,
-		ET_VIDEO_HARDWARE
-	}ENCODER_VIDEO_TYPES;
-
-}
+typedef enum { ET_VIDEO_SOFT, ET_VIDEO_HARDWARE } ENCODER_VIDEO_TYPES;
+} // namespace am
 
 #endif // !ENCODER_VIDEO_DEFINE
-

+ 31 - 34
libs/Recorder/encoder_video_factory.cpp

@@ -1,43 +1,40 @@
 #include "encoder_video_factory.h"
 
 #include "encoder_video.h"
-#include "encoder_video_x264.h"
 #include "encoder_video_nvenc.h"
+#include "encoder_video_x264.h"
 
 #include "error_define.h"
 #include "log_helper.h"
 
 namespace am {
-
-	int encoder_video_new(ENCODER_VIDEO_ID id, encoder_video ** encoder)
-	{
-		int err = AE_NO;
-
-		switch (id)
-		{
-		case EID_VIDEO_X264:
-			*encoder = (encoder_video*)new encoder_video_x264();
-			break;
-		case EID_VIDEO_NVENC:
-			*encoder = (encoder_video*)new encoder_video_nvenc();
-			break;
-		default:
-			err = AE_UNSUPPORT;
-			break;
-		}
-
-		return err;
-	}
-
-	void encoder_video_destroy(encoder_video ** encoder)
-	{
-		if (*encoder != nullptr) {
-			(*encoder)->stop();
-
-			delete *encoder;
-		}
-
-		*encoder = nullptr;
-	}
-
-}
+int encoder_video_new(ENCODER_VIDEO_ID id, encoder_video **encoder)
+{
+    int err = AE_NO;
+
+    switch (id) {
+    case EID_VIDEO_X264:
+        *encoder = (encoder_video *) new encoder_video_x264();
+        break;
+    case EID_VIDEO_NVENC:
+        *encoder = (encoder_video *) new encoder_video_nvenc();
+        break;
+    default:
+        err = AE_UNSUPPORT;
+        break;
+    }
+
+    return err;
+}
+
+void encoder_video_destroy(encoder_video **encoder)
+{
+    if (*encoder != nullptr) {
+        (*encoder)->stop();
+
+        delete *encoder;
+    }
+
+    *encoder = nullptr;
+}
+} // namespace am

+ 4 - 5
libs/Recorder/encoder_video_factory.h

@@ -4,12 +4,11 @@
 #include "encoder_video_define.h"
 
 namespace am {
-	class encoder_video;
+class encoder_video;
 
-	int encoder_video_new(ENCODER_VIDEO_ID id, encoder_video **encoder);
+int encoder_video_new(ENCODER_VIDEO_ID id, encoder_video **encoder);
 
-	void encoder_video_destroy(encoder_video **encoder);
-}
+void encoder_video_destroy(encoder_video **encoder);
+} // namespace am
 
 #endif // !ENCODER_VIDEO_FACTORY
-

+ 190 - 183
libs/Recorder/encoder_video_nvenc.cpp

@@ -1,237 +1,244 @@
 #include "encoder_video_nvenc.h"
 
 namespace am {
-
-	encoder_video_nvenc::encoder_video_nvenc()
-	{
-		av_register_all();
-
-		_encoder = NULL;
-		_encoder_ctx = NULL;
-		_frame = NULL;
-		_buff = NULL;
-		_buff_size = 0;
-		_y_size = 0;
-	}
-
-
-	encoder_video_nvenc::~encoder_video_nvenc()
-	{
-		stop();
-
-		cleanup();
-	}
-
-	int encoder_video_nvenc::init(int pic_width, int pic_height, int frame_rate, int bit_rate, int qb, int key_pic_sec)
-	{
-		if (_inited == true)
-			return AE_NO;
-
-		int err = AE_NO;
-		int ret = 0;
-
-		do {
-			_encoder = avcodec_find_encoder_by_name("h264_nvenc");
-			if(!_encoder) _encoder = avcodec_find_encoder_by_name("nvenc_h264");
-
-			if (!_encoder) {
-				err = AE_FFMPEG_FIND_ENCODER_FAILED;
-				break;
-			}
-
-			_encoder_ctx = avcodec_alloc_context3(_encoder);
-			if (!_encoder_ctx) {
-				err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
-				break;
-			}
-
-			// ffmpeg -h encoder=h264_nvenc show all encoder options
-
-			const char *rate_control = "cbr"; // cbr | cqp | vbr | lossless
-			const char *profile = "baseline"; // baseline | main | high |high444p
-			const char *preset = "default";      // default | slow | medium | fast | 
-											  // hp | hq | bd | 11 | 11hq | 11hp | lossless | losslesshp
-
-#if 0//USE_CBR
+encoder_video_nvenc::encoder_video_nvenc()
+{
+    av_register_all();
+
+    _encoder = NULL;
+    _encoder_ctx = NULL;
+    _frame = NULL;
+    _buff = NULL;
+    _buff_size = 0;
+    _y_size = 0;
+}
+
+encoder_video_nvenc::~encoder_video_nvenc()
+{
+    stop();
+
+    cleanup();
+}
+
+int encoder_video_nvenc::init(
+    int pic_width, int pic_height, int frame_rate, int bit_rate, int qb, int key_pic_sec)
+{
+    if (_inited == true)
+        return AE_NO;
+
+    int err = AE_NO;
+    int ret = 0;
+
+    do {
+        _encoder = avcodec_find_encoder_by_name("h264_nvenc");
+        if (!_encoder)
+            _encoder = avcodec_find_encoder_by_name("nvenc_h264");
+
+        if (!_encoder) {
+            err = AE_FFMPEG_FIND_ENCODER_FAILED;
+            break;
+        }
+
+        _encoder_ctx = avcodec_alloc_context3(_encoder);
+        if (!_encoder_ctx) {
+            err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
+            break;
+        }
+
+        // ffmpeg -h encoder=h264_nvenc show all encoder options
+
+        const char *rate_control = "cbr"; // cbr | cqp | vbr | lossless
+        const char *profile = "baseline"; // baseline | main | high |high444p
+        const char *preset = "default";   // default | slow | medium | fast |
+                                          // hp | hq | bd | 11 | 11hq | 11hp | lossless | losslesshp
+
+#if 0 //USE_CBR
 			av_opt_set_int(_encoder_ctx->priv_data, "cbr", true, 0);
 			_encoder_ctx->bit_rate = bit_rate - bit_rate * (100 - qb) / 100;
 			_encoder_ctx->rc_buffer_size = _encoder_ctx->bit_rate;
 			_encoder_ctx->rc_max_rate = _encoder_ctx->bit_rate;
 			_encoder_ctx->rc_min_rate = _encoder_ctx->bit_rate;
 #else
-			_encoder_ctx->bit_rate = bit_rate;
-			
-			//qb is 0 ~ 100
-			qb = max(min(qb, 100), 0);
-
-			//for qmax more larger,quality is more less, max qmax is qmin + 30*(100 - 0)/100 = qmin + 30
-			_encoder_ctx->qmin = 30;
-			_encoder_ctx->qmax = _encoder_ctx->qmin + 15 * (100 - qb) / 100;
-			
-#endif
+        _encoder_ctx->bit_rate = bit_rate;
+
+        //qb is 0 ~ 100
+        qb = max(min(qb, 100), 0);
 
-			av_opt_set(_encoder_ctx->priv_data, "profile", profile, 0);
-			av_opt_set(_encoder_ctx->priv_data, "preset", preset, 0);
+        //for qmax more larger,quality is more less, max qmax is qmin + 30*(100 - 0)/100 = qmin + 30
+        _encoder_ctx->qmin = 30;
+        _encoder_ctx->qmax = _encoder_ctx->qmin + 15 * (100 - qb) / 100;
+
+#endif
 
-			av_opt_set(_encoder_ctx->priv_data, "level", "auto", 0);
-			av_opt_set_int(_encoder_ctx->priv_data, "2pass", false, 0);
-			av_opt_set_int(_encoder_ctx->priv_data, "gpu", 0, 0);
+        av_opt_set(_encoder_ctx->priv_data, "profile", profile, 0);
+        av_opt_set(_encoder_ctx->priv_data, "preset", preset, 0);
 
-			
-			_encoder_ctx->width = pic_width;
-			_encoder_ctx->height = pic_height;
-			_encoder_ctx->time_base.num = 1;
-			_encoder_ctx->time_base.den = frame_rate;
-			_encoder_ctx->framerate = { frame_rate,1 };
-			_encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;		
-			
-			if (key_pic_sec == 0)
-				_encoder_ctx->gop_size = 250;
-			else
-				_encoder_ctx->gop_size = key_pic_sec * _encoder_ctx->time_base.den / _encoder_ctx->time_base.num;
+        av_opt_set(_encoder_ctx->priv_data, "level", "auto", 0);
+        av_opt_set_int(_encoder_ctx->priv_data, "2pass", false, 0);
+        av_opt_set_int(_encoder_ctx->priv_data, "gpu", 0, 0);
 
-			_encoder_ctx->max_b_frames = 0;//NO B Frame
-			_encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+        _encoder_ctx->width = pic_width;
+        _encoder_ctx->height = pic_height;
+        _encoder_ctx->time_base.num = 1;
+        _encoder_ctx->time_base.den = frame_rate;
+        _encoder_ctx->framerate = {frame_rate, 1};
+        _encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
 
-			ret = avcodec_open2(_encoder_ctx, _encoder, nullptr);
-			if (ret != 0) {
-				err = AE_FFMPEG_OPEN_CODEC_FAILED;
-				break;
-			}
+        if (key_pic_sec == 0)
+            _encoder_ctx->gop_size = 250;
+        else
+            _encoder_ctx->gop_size = key_pic_sec * _encoder_ctx->time_base.den
+                                     / _encoder_ctx->time_base.num;
 
-			_frame = av_frame_alloc();
+        _encoder_ctx->max_b_frames = 0; //NO B Frame
+        _encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 
-			_buff_size = av_image_get_buffer_size(_encoder_ctx->pix_fmt, _encoder_ctx->width, _encoder_ctx->height, 1);
+        ret = avcodec_open2(_encoder_ctx, _encoder, nullptr);
+        if (ret != 0) {
+            err = AE_FFMPEG_OPEN_CODEC_FAILED;
+            break;
+        }
 
-			_buff = (uint8_t*)av_malloc(_buff_size);
-			if (!_buff) {
-				break;
-			}
+        _frame = av_frame_alloc();
 
-			av_image_fill_arrays(_frame->data, _frame->linesize, _buff, _encoder_ctx->pix_fmt, _encoder_ctx->width, _encoder_ctx->height, 1);
+        _buff_size = av_image_get_buffer_size(_encoder_ctx->pix_fmt,
+                                              _encoder_ctx->width,
+                                              _encoder_ctx->height,
+                                              1);
 
-			_frame->format = _encoder_ctx->pix_fmt;
-			_frame->width = _encoder_ctx->width;
-			_frame->height = _encoder_ctx->height;
+        _buff = (uint8_t *) av_malloc(_buff_size);
+        if (!_buff) {
+            break;
+        }
 
-			_y_size = _encoder_ctx->width * _encoder_ctx->height;
+        av_image_fill_arrays(_frame->data,
+                             _frame->linesize,
+                             _buff,
+                             _encoder_ctx->pix_fmt,
+                             _encoder_ctx->width,
+                             _encoder_ctx->height,
+                             1);
 
-			_time_base = _encoder_ctx->time_base;
+        _frame->format = _encoder_ctx->pix_fmt;
+        _frame->width = _encoder_ctx->width;
+        _frame->height = _encoder_ctx->height;
 
-			_inited = true;
-		} while (0);
+        _y_size = _encoder_ctx->width * _encoder_ctx->height;
 
-		if (err != AE_NO) {
-			al_debug("%s,error:%d %lu", err2str(err), ret, GetLastError());
-			cleanup();
-		}
+        _time_base = _encoder_ctx->time_base;
 
-		return err;
-	}
+        _inited = true;
+    } while (0);
 
-	int encoder_video_nvenc::get_extradata_size()
-	{
-		return _encoder_ctx->extradata_size;
-	}
+    if (err != AE_NO) {
+        al_debug("%s,error:%d %lu", err2str(err), ret, GetLastError());
+        cleanup();
+    }
 
-	const uint8_t * encoder_video_nvenc::get_extradata()
-	{
-		return (const uint8_t*)_encoder_ctx->extradata;
-	}
+    return err;
+}
 
-	AVCodecID encoder_video_nvenc::get_codec_id()
-	{
-		if (_inited == false) return AV_CODEC_ID_NONE;
+int encoder_video_nvenc::get_extradata_size()
+{
+    return _encoder_ctx->extradata_size;
+}
 
-		return _encoder->id;
-	}
+const uint8_t *encoder_video_nvenc::get_extradata()
+{
+    return (const uint8_t *) _encoder_ctx->extradata;
+}
 
-	void encoder_video_nvenc::cleanup()
-	{
-		if (_frame)
-			av_free(_frame);
-		_frame = NULL;
+AVCodecID encoder_video_nvenc::get_codec_id()
+{
+    if (_inited == false)
+        return AV_CODEC_ID_NONE;
 
-		if (_buff)
-			av_free(_buff);
+    return _encoder->id;
+}
 
-		_buff = NULL;
+void encoder_video_nvenc::cleanup()
+{
+    if (_frame)
+        av_free(_frame);
+    _frame = NULL;
 
-		if (_encoder)
-			avcodec_close(_encoder_ctx);
+    if (_buff)
+        av_free(_buff);
 
-		_encoder = NULL;
+    _buff = NULL;
 
-		if (_encoder_ctx)
-			avcodec_free_context(&_encoder_ctx);
+    if (_encoder)
+        avcodec_close(_encoder_ctx);
 
-		_encoder_ctx = NULL;
-	}
+    _encoder = NULL;
 
-	void encoder_video_nvenc::encode_loop()
-	{
-		AVPacket *packet = av_packet_alloc();
-		AVFrame yuv_frame;
+    if (_encoder_ctx)
+        avcodec_free_context(&_encoder_ctx);
 
-		int error = AE_NO;
+    _encoder_ctx = NULL;
+}
 
-		while (_running)
-		{
-			std::unique_lock<std::mutex> lock(_mutex);
-			while (!_cond_notify && _running)
-				_cond_var.wait_for(lock, std::chrono::milliseconds(300));
+void encoder_video_nvenc::encode_loop()
+{
+    AVPacket *packet = av_packet_alloc();
+    AVFrame yuv_frame;
 
-			while (_ring_buffer->get(_buff, _buff_size, yuv_frame)) {
-				_frame->pkt_dts = yuv_frame.pkt_dts;
-				_frame->pkt_dts = yuv_frame.pkt_dts;
-				_frame->pts = yuv_frame.pts;
+    int error = AE_NO;
 
-				if ((error = encode(_frame, packet)) != AE_NO) {
-					if (_on_error)
-						_on_error(error);
+    while (_running) {
+        std::unique_lock<std::mutex> lock(_mutex);
+        while (!_cond_notify && _running)
+            _cond_var.wait_for(lock, std::chrono::milliseconds(300));
 
-					al_fatal("encode 264 packet failed:%d", error);
+        while (_ring_buffer->get(_buff, _buff_size, yuv_frame)) {
+            _frame->pkt_dts = yuv_frame.pkt_dts;
+            _frame->pkt_dts = yuv_frame.pkt_dts;
+            _frame->pts = yuv_frame.pts;
 
-					break;
-				}
-			}
+            if ((error = encode(_frame, packet)) != AE_NO) {
+                if (_on_error)
+                    _on_error(error);
 
-			_cond_notify = false;
-		}
+                al_fatal("encode 264 packet failed:%d", error);
 
-		//flush frame in encoder
-		encode(NULL, packet);
+                break;
+            }
+        }
 
-		av_packet_free(&packet);
-	}
+        _cond_notify = false;
+    }
 
-	int encoder_video_nvenc::encode(AVFrame * frame, AVPacket * packet)
-	{
-		int ret = avcodec_send_frame(_encoder_ctx, frame);
-		if (ret < 0) {
-			return AE_FFMPEG_ENCODE_FRAME_FAILED;
-		}
+    //flush frame in encoder
+    encode(NULL, packet);
 
-		while (ret >= 0) {
+    av_packet_free(&packet);
+}
 
-			av_init_packet(packet);
+int encoder_video_nvenc::encode(AVFrame *frame, AVPacket *packet)
+{
+    int ret = avcodec_send_frame(_encoder_ctx, frame);
+    if (ret < 0) {
+        return AE_FFMPEG_ENCODE_FRAME_FAILED;
+    }
 
-			ret = avcodec_receive_packet(_encoder_ctx, packet);
-			if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-				break;
-			}
+    while (ret >= 0) {
+        av_init_packet(packet);
 
-			if (ret < 0) {
-				return AE_FFMPEG_READ_PACKET_FAILED;
-			}
+        ret = avcodec_receive_packet(_encoder_ctx, packet);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+            break;
+        }
 
-			if (ret == 0 && _on_data)
-				_on_data(packet);
+        if (ret < 0) {
+            return AE_FFMPEG_READ_PACKET_FAILED;
+        }
 
-			av_packet_unref(packet);
-		}
+        if (ret == 0 && _on_data)
+            _on_data(packet);
 
-		return AE_NO;
-	}
+        av_packet_unref(packet);
+    }
 
-}
+    return AE_NO;
+}
+} // namespace am

+ 32 - 40
libs/Recorder/encoder_video_nvenc.h

@@ -4,43 +4,35 @@
 #include "encoder_video.h"
 
 namespace am {
-
-	class encoder_video_nvenc :
-		public encoder_video
-	{
-	public:
-		encoder_video_nvenc();
-		~encoder_video_nvenc();
-
-		int init(int pic_width, 
-			int pic_height, 
-			int frame_rate, 
-			int bit_rate, 
-			int qb, 
-			int key_pic_sec = 2
-		);
-
-		int get_extradata_size();
-		const uint8_t* get_extradata();
-
-		AVCodecID get_codec_id();
-
-	protected:
-		void cleanup();
-		void encode_loop();
-
-	private:
-		int encode(AVFrame *frame, AVPacket *packet);
-
-	private:
-		AVCodec *_encoder;
-		AVCodecContext *_encoder_ctx;
-		AVFrame *_frame;
-		uint8_t *_buff;
-		int _buff_size;
-		int _y_size;
-	};
-
-}
-
-#endif // !ENCODER_VIDEO_NVENC
+class encoder_video_nvenc : public encoder_video
+{
+public:
+    encoder_video_nvenc();
+    ~encoder_video_nvenc();
+
+    int init(
+        int pic_width, int pic_height, int frame_rate, int bit_rate, int qb, int key_pic_sec = 2);
+
+    int get_extradata_size();
+    const uint8_t *get_extradata();
+
+    AVCodecID get_codec_id();
+
+protected:
+    void cleanup();
+    void encode_loop();
+
+private:
+    int encode(AVFrame *frame, AVPacket *packet);
+
+private:
+    AVCodec *_encoder;
+    AVCodecContext *_encoder_ctx;
+    AVFrame *_frame;
+    uint8_t *_buff;
+    int _buff_size;
+    int _y_size;
+};
+} // namespace am
+
+#endif // !ENCODER_VIDEO_NVENC

+ 208 - 200
libs/Recorder/encoder_video_x264.cpp

@@ -1,222 +1,230 @@
 #include "encoder_video_x264.h"
 
-#include "log_helper.h"
 #include "error_define.h"
+#include "log_helper.h"
 
 namespace am {
+encoder_video_x264::encoder_video_x264()
+{
+    av_register_all();
+
+    _encoder = NULL;
+    _encoder_ctx = NULL;
+    _frame = NULL;
+    _buff = NULL;
+    _buff_size = 0;
+    _y_size = 0;
+}
+
+encoder_video_x264::~encoder_video_x264()
+{
+    stop();
+
+    cleanup();
+}
+
+int encoder_video_x264::init(
+    int pic_width, int pic_height, int frame_rate, int bit_rate, int qb, int key_pic_sec)
+{
+    if (_inited == true)
+        return AE_NO;
+
+    int err = AE_NO;
+    int ret = 0;
+
+    AVDictionary *options = 0;
+
+    av_dict_set(&options, "preset", "superfast", 0);
+    av_dict_set(&options, "tune", "zerolatency", 0);
+
+    do {
+        _encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
+        if (!_encoder) {
+            err = AE_FFMPEG_FIND_ENCODER_FAILED;
+            break;
+        }
+
+        _encoder_ctx = avcodec_alloc_context3(_encoder);
+        if (!_encoder_ctx) {
+            err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
+            break;
+        }
+
+        _encoder_ctx->codec_id = AV_CODEC_ID_H264;
+        _encoder_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
+        _encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
+        _encoder_ctx->width = pic_width;
+        _encoder_ctx->height = pic_height;
+        _encoder_ctx->time_base.num = 1;
+        _encoder_ctx->time_base.den = frame_rate;
+        _encoder_ctx->framerate = {frame_rate, 1};
+        _encoder_ctx->bit_rate = bit_rate;
+
+        if (key_pic_sec == 0)
+            _encoder_ctx->gop_size = 250;
+        else
+            _encoder_ctx->gop_size = key_pic_sec * _encoder_ctx->time_base.den
+                                     / _encoder_ctx->time_base.num;
+
+        //qb is 0 ~ 100
+        qb = max(min(qb, 100), 0);
+
+        //for qmax more larger,quality is more less, max qmax is qmin + 30*(100 - 0)/100 = qmin + 30
+        _encoder_ctx->qmin = 30;
+        _encoder_ctx->qmax = _encoder_ctx->qmin + 15 * (100 - qb) / 100;
+
+        _encoder_ctx->max_b_frames = 0; //NO B Frame
+        _encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+
+        ret = avcodec_open2(_encoder_ctx, _encoder, &options);
+        if (ret != 0) {
+            err = AE_FFMPEG_OPEN_CODEC_FAILED;
+            break;
+        }
+
+        _frame = av_frame_alloc();
+
+        _buff_size = av_image_get_buffer_size(_encoder_ctx->pix_fmt,
+                                              _encoder_ctx->width,
+                                              _encoder_ctx->height,
+                                              1);
+
+        _buff = (uint8_t *) av_malloc(_buff_size);
+        if (!_buff) {
+            break;
+        }
+
+        av_image_fill_arrays(_frame->data,
+                             _frame->linesize,
+                             _buff,
+                             _encoder_ctx->pix_fmt,
+                             _encoder_ctx->width,
+                             _encoder_ctx->height,
+                             1);
+
+        _frame->format = _encoder_ctx->pix_fmt;
+        _frame->width = _encoder_ctx->width;
+        _frame->height = _encoder_ctx->height;
+
+        _y_size = _encoder_ctx->width * _encoder_ctx->height;
+
+        _time_base = _encoder_ctx->time_base;
+
+        _inited = true;
+    } while (0);
+
+    if (err != AE_NO) {
+        al_debug("%s,error:%d %lu", err2str(err), ret, GetLastError());
+        cleanup();
+    }
+
+    if (options)
+        av_dict_free(&options);
+
+    return err;
+}
+
+int encoder_video_x264::get_extradata_size()
+{
+    return _encoder_ctx->extradata_size;
+}
+
+const uint8_t *encoder_video_x264::get_extradata()
+{
+    return (const uint8_t *) _encoder_ctx->extradata;
+}
+
+AVCodecID encoder_video_x264::get_codec_id()
+{
+    if (_inited == false)
+        return AV_CODEC_ID_NONE;
+
+    return _encoder->id;
+}
+
+void encoder_video_x264::cleanup()
+{
+    if (_frame)
+        av_free(_frame);
+    _frame = NULL;
+
+    if (_buff)
+        av_free(_buff);
+
+    _buff = NULL;
+
+    if (_encoder)
+        avcodec_close(_encoder_ctx);
+
+    _encoder = NULL;
+
+    if (_encoder_ctx)
+        avcodec_free_context(&_encoder_ctx);
+
+    _encoder_ctx = NULL;
+}
 
-	encoder_video_x264::encoder_video_x264()
-	{
-		av_register_all();
-
-		_encoder = NULL;
-		_encoder_ctx = NULL;
-		_frame = NULL;
-		_buff = NULL;
-		_buff_size = 0;
-		_y_size = 0;
-	}
-
-	encoder_video_x264::~encoder_video_x264()
-	{
-		stop();
-
-		cleanup();
-	}
-
-	int encoder_video_x264::init(int pic_width, int pic_height, int frame_rate, int bit_rate ,int qb, int key_pic_sec)
-	{
-		if (_inited == true)
-			return AE_NO;
-
-		int err = AE_NO;
-		int ret = 0;
-
-		AVDictionary *options = 0;
-
-		av_dict_set(&options, "preset", "superfast", 0);
-		av_dict_set(&options, "tune", "zerolatency", 0);
-
-		do {
-			_encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
-			if (!_encoder) {
-				err = AE_FFMPEG_FIND_ENCODER_FAILED;
-				break;
-			}
-
-			_encoder_ctx = avcodec_alloc_context3(_encoder);
-			if (!_encoder_ctx) {
-				err = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
-				break;
-			}
-
-			_encoder_ctx->codec_id = AV_CODEC_ID_H264;
-			_encoder_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
-			_encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
-			_encoder_ctx->width = pic_width;
-			_encoder_ctx->height = pic_height;
-			_encoder_ctx->time_base.num = 1;
-			_encoder_ctx->time_base.den = frame_rate;
-			_encoder_ctx->framerate = { frame_rate,1 };
-			_encoder_ctx->bit_rate = bit_rate;
-			
-			if (key_pic_sec == 0)
-				_encoder_ctx->gop_size = 250;
-			else
-				_encoder_ctx->gop_size = key_pic_sec * _encoder_ctx->time_base.den / _encoder_ctx->time_base.num;
-			
-			//qb is 0 ~ 100
-			qb = max(min(qb, 100), 0);
-
-			//for qmax more larger,quality is more less, max qmax is qmin + 30*(100 - 0)/100 = qmin + 30
-			_encoder_ctx->qmin = 30;
-			_encoder_ctx->qmax = _encoder_ctx->qmin + 15 * (100 - qb) / 100;
-
-			_encoder_ctx->max_b_frames = 0;//NO B Frame
-			_encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-
-			ret = avcodec_open2(_encoder_ctx, _encoder, &options);
-			if (ret != 0) {
-				err = AE_FFMPEG_OPEN_CODEC_FAILED;
-				break;
-			}
-
-			_frame = av_frame_alloc();
-
-			_buff_size = av_image_get_buffer_size(_encoder_ctx->pix_fmt, _encoder_ctx->width, _encoder_ctx->height, 1);
-			
-			_buff = (uint8_t*)av_malloc(_buff_size);
-			if (!_buff) {
-				break;
-			}
-
-			av_image_fill_arrays(_frame->data, _frame->linesize, _buff, _encoder_ctx->pix_fmt, _encoder_ctx->width, _encoder_ctx->height, 1);
-
-			_frame->format = _encoder_ctx->pix_fmt;
-			_frame->width = _encoder_ctx->width;
-			_frame->height = _encoder_ctx->height;
-
-			_y_size = _encoder_ctx->width * _encoder_ctx->height;
-
-			_time_base = _encoder_ctx->time_base;
-			
-			_inited = true;
-		} while (0);
-
-		if (err != AE_NO) {
-			al_debug("%s,error:%d %lu", err2str(err), ret, GetLastError());
-			cleanup();
-		}
-
-		if(options)
-			av_dict_free(&options);
-
-		return err;
-	}
-
-	int encoder_video_x264::get_extradata_size()
-	{
-		return _encoder_ctx->extradata_size;
-	}
-
-	const uint8_t * encoder_video_x264::get_extradata()
-	{
-		return (const uint8_t*)_encoder_ctx->extradata;
-	}
-
-	AVCodecID encoder_video_x264::get_codec_id()
-	{
-		if (_inited == false) return AV_CODEC_ID_NONE;
-
-		return _encoder->id;
-	}
-
-	void encoder_video_x264::cleanup()
-	{
-		if (_frame)
-			av_free(_frame);
-		_frame = NULL;
-
-		if (_buff)
-			av_free(_buff);
-
-		_buff = NULL;
-
-		if (_encoder)
-			avcodec_close(_encoder_ctx);
-
-		_encoder = NULL;
-
-		if (_encoder_ctx)
-			avcodec_free_context(&_encoder_ctx);
-
-		_encoder_ctx = NULL;
-	}
-
-	int encoder_video_x264::encode(AVFrame * frame, AVPacket * packet)
-	{
-		int ret = avcodec_send_frame(_encoder_ctx, frame);
-		if (ret < 0) {
-			return AE_FFMPEG_ENCODE_FRAME_FAILED;
-		}
+int encoder_video_x264::encode(AVFrame *frame, AVPacket *packet)
+{
+    int ret = avcodec_send_frame(_encoder_ctx, frame);
+    if (ret < 0) {
+        return AE_FFMPEG_ENCODE_FRAME_FAILED;
+    }
 
-		while (ret >= 0) {
-			
-			av_init_packet(packet);
+    while (ret >= 0) {
+        av_init_packet(packet);
 
-			ret = avcodec_receive_packet(_encoder_ctx, packet);
-			if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-				break;
-			}
+        ret = avcodec_receive_packet(_encoder_ctx, packet);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+            break;
+        }
 
-			if (ret < 0) {
-				return AE_FFMPEG_READ_PACKET_FAILED;
-			}
+        if (ret < 0) {
+            return AE_FFMPEG_READ_PACKET_FAILED;
+        }
 
-			if (ret == 0 && _on_data)
-				_on_data(packet);
+        if (ret == 0 && _on_data)
+            _on_data(packet);
 
-			av_packet_unref(packet);
-		}
+        av_packet_unref(packet);
+    }
 
-		return AE_NO;
-	}
+    return AE_NO;
+}
 
-	void encoder_video_x264::encode_loop()
-	{
-		AVPacket *packet = av_packet_alloc();
-		AVFrame yuv_frame;
+void encoder_video_x264::encode_loop()
+{
+    AVPacket *packet = av_packet_alloc();
+    AVFrame yuv_frame;
 
-		int error = AE_NO;
+    int error = AE_NO;
 
-		while (_running)
-		{
-			std::unique_lock<std::mutex> lock(_mutex);
-			while (!_cond_notify && _running)
-				_cond_var.wait_for(lock, std::chrono::milliseconds(300));
+    while (_running) {
+        std::unique_lock<std::mutex> lock(_mutex);
+        while (!_cond_notify && _running)
+            _cond_var.wait_for(lock, std::chrono::milliseconds(300));
 
-			while (_ring_buffer->get(_buff, _buff_size, yuv_frame)) {
-				_frame->pkt_dts = yuv_frame.pkt_dts;
-				_frame->pkt_dts = yuv_frame.pkt_dts;
-				_frame->pts = yuv_frame.pts;
+        while (_ring_buffer->get(_buff, _buff_size, yuv_frame)) {
+            _frame->pkt_dts = yuv_frame.pkt_dts;
+            _frame->pkt_dts = yuv_frame.pkt_dts;
+            _frame->pts = yuv_frame.pts;
 
-				if ((error = encode(_frame, packet)) != AE_NO) {
-					if (_on_error) 
-						_on_error(error);
+            if ((error = encode(_frame, packet)) != AE_NO) {
+                if (_on_error)
+                    _on_error(error);
 
-					al_fatal("encode 264 packet failed:%d", error);
+                al_fatal("encode 264 packet failed:%d", error);
 
-					break;
-				}
-			}
-			
-			_cond_notify = false;
-		}
+                break;
+            }
+        }
 
-		//flush frame in encoder
-		encode(NULL, packet);
+        _cond_notify = false;
+    }
 
-		av_packet_free(&packet);
-	}
+    //flush frame in encoder
+    encode(NULL, packet);
 
-}
+    av_packet_free(&packet);
+}
+} // namespace am

+ 30 - 31
libs/Recorder/encoder_video_x264.h

@@ -4,36 +4,35 @@
 #include "encoder_video.h"
 
 namespace am {
-	class encoder_video_x264 :
-		public encoder_video
-	{
-	public:
-		encoder_video_x264();
-		~encoder_video_x264();
-
-		int init(int pic_width, int pic_height, int frame_rate, int bit_rate, int qb, int key_pic_sec = 2);
-
-		int get_extradata_size();
-		const uint8_t* get_extradata();
-
-		AVCodecID get_codec_id();
-
-	protected:
-		void cleanup();
-		void encode_loop();
-
-	private:
-		int encode(AVFrame *frame, AVPacket *packet);
-
-	private:
-		AVCodec *_encoder;
-		AVCodecContext *_encoder_ctx;
-		AVFrame *_frame;
-		uint8_t *_buff;
-		int _buff_size;
-		int _y_size;
-	};
-}
-
+class encoder_video_x264 : public encoder_video
+{
+public:
+    encoder_video_x264();
+    ~encoder_video_x264();
+
+    int init(
+        int pic_width, int pic_height, int frame_rate, int bit_rate, int qb, int key_pic_sec = 2);
+
+    int get_extradata_size();
+    const uint8_t *get_extradata();
+
+    AVCodecID get_codec_id();
+
+protected:
+    void cleanup();
+    void encode_loop();
+
+private:
+    int encode(AVFrame *frame, AVPacket *packet);
+
+private:
+    AVCodec *_encoder;
+    AVCodecContext *_encoder_ctx;
+    AVFrame *_frame;
+    uint8_t *_buff;
+    int _buff_size;
+    int _y_size;
+};
+} // namespace am
 
 #endif

+ 208 - 207
libs/Recorder/error_define.h

@@ -1,218 +1,219 @@
 #ifndef ERROR_DEFINE
 #define ERROR_DEFINE
 
-
-enum AM_ERROR{
-	AE_NO = 0,
-	AE_ERROR,
-	AE_UNSUPPORT,
-	AE_INVALID_CONTEXT,
-	AE_NEED_INIT,
-	AE_TIMEOUT,
-	AE_ALLOCATE_FAILED,
-
-	//AE_CO_
-	AE_CO_INITED_FAILED,
-	AE_CO_CREATE_FAILED,
-	AE_CO_GETENDPOINT_FAILED,
-	AE_CO_ACTIVE_DEVICE_FAILED,
-	AE_CO_GET_FORMAT_FAILED,
-	AE_CO_AUDIOCLIENT_INIT_FAILED,
-	AE_CO_GET_CAPTURE_FAILED,
-	AE_CO_CREATE_EVENT_FAILED,
-	AE_CO_SET_EVENT_FAILED,
-	AE_CO_START_FAILED,
-	AE_CO_ENUMENDPOINT_FAILED,
-	AE_CO_GET_ENDPOINT_COUNT_FAILED,
-	AE_CO_GET_ENDPOINT_ID_FAILED,
-	AE_CO_OPEN_PROPERTY_FAILED,
-	AE_CO_GET_VALUE_FAILED,
-	AE_CO_GET_BUFFER_FAILED,
-	AE_CO_RELEASE_BUFFER_FAILED,
-	AE_CO_GET_PACKET_FAILED,
-	AE_CO_PADDING_UNEXPECTED,
-
-	//AE_FFMPEG_
-	AE_FFMPEG_OPEN_INPUT_FAILED,
-	AE_FFMPEG_FIND_STREAM_FAILED,
-	AE_FFMPEG_FIND_DECODER_FAILED,
-	AE_FFMPEG_OPEN_CODEC_FAILED,
-	AE_FFMPEG_READ_FRAME_FAILED,
-	AE_FFMPEG_READ_PACKET_FAILED,
-	AE_FFMPEG_DECODE_FRAME_FAILED,
-	AE_FFMPEG_NEW_SWSCALE_FAILED,
-	AE_FFMPEG_FIND_ENCODER_FAILED,
-	AE_FFMPEG_ALLOC_CONTEXT_FAILED,
-	AE_FFMPEG_ENCODE_FRAME_FAILED,
-	AE_FFMPEG_ALLOC_FRAME_FAILED,
-	AE_FFMPEG_OPEN_IO_FAILED,
-	AE_FFMPEG_CREATE_STREAM_FAILED,
-	AE_FFMPEG_COPY_PARAMS_FAILED,
-	AE_RESAMPLE_INIT_FAILED,
-	AE_FFMPEG_NEW_STREAM_FAILED,
-	AE_FFMPEG_FIND_INPUT_FMT_FAILED,
-	AE_FFMPEG_WRITE_HEADER_FAILED,
-	AE_FFMPEG_WRITE_TRAILER_FAILED,
-	AE_FFMPEG_WRITE_FRAME_FAILED,
-
-	//AE_FILTER_
-	AE_FILTER_ALLOC_GRAPH_FAILED,
-	AE_FILTER_CREATE_FILTER_FAILED,
-	AE_FILTER_PARSE_PTR_FAILED,
-	AE_FILTER_CONFIG_FAILED,
-	AE_FILTER_INVALID_CTX_INDEX,
-	AE_FILTER_ADD_FRAME_FAILED,
-
-	//AE_GDI_
-	AE_GDI_GET_DC_FAILED,
-	AE_GDI_CREATE_DC_FAILED,
-	AE_GDI_CREATE_BMP_FAILED,
-	AE_GDI_BITBLT_FAILED,
-	AE_GDI_GET_DIBITS_FAILED,
-
-	//AE_D3D_
-	AE_D3D_LOAD_FAILED,
-	AE_D3D_GET_PROC_FAILED,
-	AE_D3D_CREATE_DEVICE_FAILED,
-	AE_D3D_QUERYINTERFACE_FAILED,
-	AE_D3D_CREATE_VERTEX_SHADER_FAILED,
-	AE_D3D_CREATE_INLAYOUT_FAILED,
-	AE_D3D_CREATE_PIXEL_SHADER_FAILED,
-	AE_D3D_CREATE_SAMPLERSTATE_FAILED,
-
-	//AE_DXGI_
-	AE_DXGI_GET_PROC_FAILED,
-	AE_DXGI_GET_ADAPTER_FAILED,
-	AE_DXGI_GET_FACTORY_FAILED,
-	AE_DXGI_FOUND_ADAPTER_FAILED,
-
-	//AE_DUP_
-	AE_DUP_ATTATCH_FAILED,
-	AE_DUP_QI_FAILED,
-	AE_DUP_GET_PARENT_FAILED,
-	AE_DUP_ENUM_OUTPUT_FAILED,
-	AE_DUP_DUPLICATE_MAX_FAILED,
-	AE_DUP_DUPLICATE_FAILED,
-	AE_DUP_RELEASE_FRAME_FAILED,
-	AE_DUP_ACQUIRE_FRAME_FAILED,
-	AE_DUP_QI_FRAME_FAILED,
-	AE_DUP_CREATE_TEXTURE_FAILED,
-	AE_DUP_QI_DXGI_FAILED,
-	AE_DUP_MAP_FAILED,
-	AE_DUP_GET_CURSORSHAPE_FAILED,
-
-	//AE_REMUX_
-	AE_REMUX_RUNNING,
-	AE_REMUX_NOT_EXIST,
-	AE_REMUX_INVALID_INOUT,
-
-	// AE_WGC_
-  AE_WGC_CREATE_CAPTURER_FAILED,
-
-	AE_MAX
+enum AM_ERROR {
+    AE_NO = 0,
+    AE_ERROR,
+    AE_UNSUPPORT,
+    AE_INVALID_CONTEXT,
+    AE_NEED_INIT,
+    AE_TIMEOUT,
+    AE_ALLOCATE_FAILED,
+
+    //AE_CO_
+    AE_CO_INITED_FAILED,
+    AE_CO_CREATE_FAILED,
+    AE_CO_GETENDPOINT_FAILED,
+    AE_CO_ACTIVE_DEVICE_FAILED,
+    AE_CO_GET_FORMAT_FAILED,
+    AE_CO_AUDIOCLIENT_INIT_FAILED,
+    AE_CO_GET_CAPTURE_FAILED,
+    AE_CO_CREATE_EVENT_FAILED,
+    AE_CO_SET_EVENT_FAILED,
+    AE_CO_START_FAILED,
+    AE_CO_ENUMENDPOINT_FAILED,
+    AE_CO_GET_ENDPOINT_COUNT_FAILED,
+    AE_CO_GET_ENDPOINT_ID_FAILED,
+    AE_CO_OPEN_PROPERTY_FAILED,
+    AE_CO_GET_VALUE_FAILED,
+    AE_CO_GET_BUFFER_FAILED,
+    AE_CO_RELEASE_BUFFER_FAILED,
+    AE_CO_GET_PACKET_FAILED,
+    AE_CO_PADDING_UNEXPECTED,
+
+    //AE_FFMPEG_
+    AE_FFMPEG_OPEN_INPUT_FAILED,
+    AE_FFMPEG_FIND_STREAM_FAILED,
+    AE_FFMPEG_FIND_DECODER_FAILED,
+    AE_FFMPEG_OPEN_CODEC_FAILED,
+    AE_FFMPEG_READ_FRAME_FAILED,
+    AE_FFMPEG_READ_PACKET_FAILED,
+    AE_FFMPEG_DECODE_FRAME_FAILED,
+    AE_FFMPEG_NEW_SWSCALE_FAILED,
+    AE_FFMPEG_FIND_ENCODER_FAILED,
+    AE_FFMPEG_ALLOC_CONTEXT_FAILED,
+    AE_FFMPEG_ENCODE_FRAME_FAILED,
+    AE_FFMPEG_ALLOC_FRAME_FAILED,
+    AE_FFMPEG_OPEN_IO_FAILED,
+    AE_FFMPEG_CREATE_STREAM_FAILED,
+    AE_FFMPEG_COPY_PARAMS_FAILED,
+    AE_RESAMPLE_INIT_FAILED,
+    AE_FFMPEG_NEW_STREAM_FAILED,
+    AE_FFMPEG_FIND_INPUT_FMT_FAILED,
+    AE_FFMPEG_WRITE_HEADER_FAILED,
+    AE_FFMPEG_WRITE_TRAILER_FAILED,
+    AE_FFMPEG_WRITE_FRAME_FAILED,
+
+    //AE_FILTER_
+    AE_FILTER_ALLOC_GRAPH_FAILED,
+    AE_FILTER_CREATE_FILTER_FAILED,
+    AE_FILTER_PARSE_PTR_FAILED,
+    AE_FILTER_CONFIG_FAILED,
+    AE_FILTER_INVALID_CTX_INDEX,
+    AE_FILTER_ADD_FRAME_FAILED,
+
+    //AE_GDI_
+    AE_GDI_GET_DC_FAILED,
+    AE_GDI_CREATE_DC_FAILED,
+    AE_GDI_CREATE_BMP_FAILED,
+    AE_GDI_BITBLT_FAILED,
+    AE_GDI_GET_DIBITS_FAILED,
+
+    //AE_D3D_
+    AE_D3D_LOAD_FAILED,
+    AE_D3D_GET_PROC_FAILED,
+    AE_D3D_CREATE_DEVICE_FAILED,
+    AE_D3D_QUERYINTERFACE_FAILED,
+    AE_D3D_CREATE_VERTEX_SHADER_FAILED,
+    AE_D3D_CREATE_INLAYOUT_FAILED,
+    AE_D3D_CREATE_PIXEL_SHADER_FAILED,
+    AE_D3D_CREATE_SAMPLERSTATE_FAILED,
+
+    //AE_DXGI_
+    AE_DXGI_GET_PROC_FAILED,
+    AE_DXGI_GET_ADAPTER_FAILED,
+    AE_DXGI_GET_FACTORY_FAILED,
+    AE_DXGI_FOUND_ADAPTER_FAILED,
+
+    //AE_DUP_
+    AE_DUP_ATTATCH_FAILED,
+    AE_DUP_QI_FAILED,
+    AE_DUP_GET_PARENT_FAILED,
+    AE_DUP_ENUM_OUTPUT_FAILED,
+    AE_DUP_DUPLICATE_MAX_FAILED,
+    AE_DUP_DUPLICATE_FAILED,
+    AE_DUP_RELEASE_FRAME_FAILED,
+    AE_DUP_ACQUIRE_FRAME_FAILED,
+    AE_DUP_QI_FRAME_FAILED,
+    AE_DUP_CREATE_TEXTURE_FAILED,
+    AE_DUP_QI_DXGI_FAILED,
+    AE_DUP_MAP_FAILED,
+    AE_DUP_GET_CURSORSHAPE_FAILED,
+
+    //AE_REMUX_
+    AE_REMUX_RUNNING,
+    AE_REMUX_NOT_EXIST,
+    AE_REMUX_INVALID_INOUT,
+
+    // AE_WGC_
+    AE_WGC_CREATE_CAPTURER_FAILED,
+
+    AE_MAX
 };
 
 static const char *ERRORS_STR[] = {
-	"no error",                         //AE_NO
-	"error",                            //AE_ERROR
-	"not support for now",              //AE_UNSUPPORT
-	"invalid context",                  //AE_INVALID_CONTEXT
-	"need init first",                  //AE_NEED_INIT
-	"operation timeout",                //AE_TIMEOUT
-	"allocate memory failed",           //AE_ALLOCATE_FAILED,
-
-	"com init failed",                  //AE_CO_INITED_FAILED
-	"com create instance failed",       //AE_CO_CREATE_FAILED
-	"com get endpoint failed",          //AE_CO_GETENDPOINT_FAILED
-	"com active device failed",         //AE_CO_ACTIVE_DEVICE_FAILED
-	"com get wave formatex failed",     //AE_CO_GET_FORMAT_FAILED
-	"com audio client init failed",     //AE_CO_AUDIOCLIENT_INIT_FAILED
-	"com audio get capture failed",     //AE_CO_GET_CAPTURE_FAILED
-	"com audio create event failed",    //AE_CO_CREATE_EVENT_FAILED
-	"com set ready event failed",       //AE_CO_SET_EVENT_FAILED
-	"com start to record failed",       //AE_CO_START_FAILED
-	"com enum audio endpoints failed",  //AE_CO_ENUMENDPOINT_FAILED
-	"com get endpoints count failed",   //AE_CO_GET_ENDPOINT_COUNT_FAILED
-	"com get endpoint id failed",       //AE_CO_GET_ENDPOINT_ID_FAILED
-	"com open endpoint property failed", //AE_CO_OPEN_PROPERTY_FAILED
-	"com get property value failed",    //AE_CO_GET_VALUE_FAILED
-	"com get buffer failed",            //AE_CO_GET_BUFFER_FAILED
-	"com release buffer failed",        //AE_CO_RELEASE_BUFFER_FAILED
-	"com get packet size failed",       //AE_CO_GET_PACKET_FAILED
-	"com get padding size unexpected",  //AE_CO_PADDING_UNEXPECTED
-
-	"ffmpeg open input failed",         //AE_FFMPEG_OPEN_INPUT_FAILED
-	"ffmpeg find stream info failed",   //AE_FFMPEG_FIND_STREAM_FAILED
-	"ffmpeg find decoder failed",       //AE_FFMPEG_FIND_DECODER_FAILED
-	"ffmpeg open codec failed",         //AE_FFMPEG_OPEN_CODEC_FAILED
-	"ffmpeg read frame failed",         //AE_FFMPEG_READ_FRAME_FAILED
-	"ffmpeg read packet failed",        //AE_FFMPEG_READ_PACKET_FAILED
-	"ffmpeg decode frame failed",       //AE_FFMPEG_DECODE_FRAME_FAILED
-	"ffmpeg create swscale failed",     //AE_FFMPEG_NEW_SWSCALE_FAILED
-
-	"ffmpeg find encoder failed",       //AE_FFMPEG_FIND_ENCODER_FAILED
-	"ffmpeg alloc context failed",      //AE_FFMPEG_ALLOC_CONTEXT_FAILED
-	"ffmpeg encode frame failed",       //AE_FFMPEG_ENCODE_FRAME_FAILED
-	"ffmpeg alloc frame failed",        //AE_FFMPEG_ALLOC_FRAME_FAILED
-	
-	"ffmpeg open io ctx failed",        //AE_FFMPEG_OPEN_IO_FAILED
-	"ffmpeg new stream failed",         //AE_FFMPEG_CREATE_STREAM_FAILED
-	"ffmpeg copy parameters failed",    //AE_FFMPEG_COPY_PARAMS_FAILED
-	"resampler init failed",            //AE_RESAMPLE_INIT_FAILED
-	"ffmpeg new out stream failed",     //AE_FFMPEG_NEW_STREAM_FAILED
-	"ffmpeg find input format failed",  //AE_FFMPEG_FIND_INPUT_FMT_FAILED
-	"ffmpeg write file header failed",  //AE_FFMPEG_WRITE_HEADER_FAILED
-	"ffmpeg write file trailer failed", //AE_FFMPEG_WRITE_TRAILER_FAILED
-	"ffmpeg write frame failed",        //AE_FFMPEG_WRITE_FRAME_FAILED
-
-	"avfilter alloc avfilter failed",   //AE_FILTER_ALLOC_GRAPH_FAILED
-	"avfilter create graph failed",     //AE_FILTER_CREATE_FILTER_FAILED
-	"avfilter parse ptr failed",        //AE_FILTER_PARSE_PTR_FAILED
-	"avfilter config graph failed",     //AE_FILTER_CONFIG_FAILED
-	"avfilter invalid ctx index",       //AE_FILTER_INVALID_CTX_INDEX
-	"avfilter add frame failed",        //AE_FILTER_ADD_FRAME_FAILED
-
-	"gdi get dc failed",                //AE_GDI_GET_DC_FAILED
-	"gdi create dc failed",             //AE_GDI_CREATE_DC_FAILED
-	"gdi create bmp failed",            //AE_GDI_CREATE_BMP_FAILED
-	"gdi bitblt failed",                //AE_GDI_BITBLT_FAILED
-	"gid geet dibbits failed",          //AE_GDI_GET_DIBITS_FAILED
-
-	"d3d11 library load failed",        //AE_D3D_LOAD_FAILED
-	"d3d11 proc get failed",            //AE_D3D_GET_PROC_FAILED
-	"d3d11 create device failed",       //AE_D3D_CREATE_DEVICE_FAILED
-	"d3d11 query interface failed",     //AE_D3D_QUERYINTERFACE_FAILED
-	"d3d11 create vertex shader failed",//AE_D3D_CREATE_VERTEX_SHADER_FAILED
-	"d3d11 create input layout failed", //AE_D3D_CREATE_INLAYOUT_FAILED
-	"d3d11 create pixel shader failed", //AE_D3D_CREATE_PIXEL_SHADER_FAILED
-	"d3d11 create sampler state failed",//AE_D3D_CREATE_SAMPLERSTATE_FAILED
-
-	"dxgi get proc address failed",     //AE_DXGI_GET_PROC_FAILED
-	"dxgi get adapter failed",          //AE_DXGI_GET_ADAPTER_FAILED
-	"dxgi get factory failed",          //AE_DXGI_GET_FACTORY_FAILED
-	"dxgi specified adapter not found", //AE_DXGI_FOUND_ADAPTER_FAILED
-
-	"duplication attatch desktop failed", //AE_DUP_ATTATCH_FAILED
-	"duplication query interface failed", //AE_DUP_QI_FAILED
-	"duplication get parent failed",      //AE_DUP_GET_PARENT_FAILED
-	"duplication enum ouput failed",      //AE_DUP_ENUM_OUTPUT_FAILED
-	"duplication duplicate unavailable",  //AE_DUP_DUPLICATE_MAX_FAILED
-	"duplication duplicate failed",       //AE_DUP_DUPLICATE_FAILED
-	"duplication release frame failed",   //AE_DUP_RELEASE_FRAME_FAILED
-	"duplication acquire frame failed",   //AE_DUP_ACQUIRE_FRAME_FAILED
-	"duplication qi frame failed",        //AE_DUP_QI_FRAME_FAILED
-	"duplication create texture failed",  //AE_DUP_CREATE_TEXTURE_FAILED
-	"duplication dxgi qi failed",         //AE_DUP_QI_DXGI_FAILED
-	"duplication map rects failed",       //AE_DUP_MAP_FAILED
-	"duplication get cursor shape failed",//AE_DUP_GET_CURSORSHAPE_FAILED
-
-	"remux is already running",           //AE_REMUX_RUNNING
-	"remux input file do not exist",      //AE_REMUX_NOT_EXIST
-	"remux input or output file invalid", //AE_REMUX_INVALID_INOUT
+    "no error",               //AE_NO
+    "error",                  //AE_ERROR
+    "not support for now",    //AE_UNSUPPORT
+    "invalid context",        //AE_INVALID_CONTEXT
+    "need init first",        //AE_NEED_INIT
+    "operation timeout",      //AE_TIMEOUT
+    "allocate memory failed", //AE_ALLOCATE_FAILED,
+
+    "com init failed",                   //AE_CO_INITED_FAILED
+    "com create instance failed",        //AE_CO_CREATE_FAILED
+    "com get endpoint failed",           //AE_CO_GETENDPOINT_FAILED
+    "com active device failed",          //AE_CO_ACTIVE_DEVICE_FAILED
+    "com get wave formatex failed",      //AE_CO_GET_FORMAT_FAILED
+    "com audio client init failed",      //AE_CO_AUDIOCLIENT_INIT_FAILED
+    "com audio get capture failed",      //AE_CO_GET_CAPTURE_FAILED
+    "com audio create event failed",     //AE_CO_CREATE_EVENT_FAILED
+    "com set ready event failed",        //AE_CO_SET_EVENT_FAILED
+    "com start to record failed",        //AE_CO_START_FAILED
+    "com enum audio endpoints failed",   //AE_CO_ENUMENDPOINT_FAILED
+    "com get endpoints count failed",    //AE_CO_GET_ENDPOINT_COUNT_FAILED
+    "com get endpoint id failed",        //AE_CO_GET_ENDPOINT_ID_FAILED
+    "com open endpoint property failed", //AE_CO_OPEN_PROPERTY_FAILED
+    "com get property value failed",     //AE_CO_GET_VALUE_FAILED
+    "com get buffer failed",             //AE_CO_GET_BUFFER_FAILED
+    "com release buffer failed",         //AE_CO_RELEASE_BUFFER_FAILED
+    "com get packet size failed",        //AE_CO_GET_PACKET_FAILED
+    "com get padding size unexpected",   //AE_CO_PADDING_UNEXPECTED
+
+    "ffmpeg open input failed",       //AE_FFMPEG_OPEN_INPUT_FAILED
+    "ffmpeg find stream info failed", //AE_FFMPEG_FIND_STREAM_FAILED
+    "ffmpeg find decoder failed",     //AE_FFMPEG_FIND_DECODER_FAILED
+    "ffmpeg open codec failed",       //AE_FFMPEG_OPEN_CODEC_FAILED
+    "ffmpeg read frame failed",       //AE_FFMPEG_READ_FRAME_FAILED
+    "ffmpeg read packet failed",      //AE_FFMPEG_READ_PACKET_FAILED
+    "ffmpeg decode frame failed",     //AE_FFMPEG_DECODE_FRAME_FAILED
+    "ffmpeg create swscale failed",   //AE_FFMPEG_NEW_SWSCALE_FAILED
+
+    "ffmpeg find encoder failed",  //AE_FFMPEG_FIND_ENCODER_FAILED
+    "ffmpeg alloc context failed", //AE_FFMPEG_ALLOC_CONTEXT_FAILED
+    "ffmpeg encode frame failed",  //AE_FFMPEG_ENCODE_FRAME_FAILED
+    "ffmpeg alloc frame failed",   //AE_FFMPEG_ALLOC_FRAME_FAILED
+
+    "ffmpeg open io ctx failed",        //AE_FFMPEG_OPEN_IO_FAILED
+    "ffmpeg new stream failed",         //AE_FFMPEG_CREATE_STREAM_FAILED
+    "ffmpeg copy parameters failed",    //AE_FFMPEG_COPY_PARAMS_FAILED
+    "resampler init failed",            //AE_RESAMPLE_INIT_FAILED
+    "ffmpeg new out stream failed",     //AE_FFMPEG_NEW_STREAM_FAILED
+    "ffmpeg find input format failed",  //AE_FFMPEG_FIND_INPUT_FMT_FAILED
+    "ffmpeg write file header failed",  //AE_FFMPEG_WRITE_HEADER_FAILED
+    "ffmpeg write file trailer failed", //AE_FFMPEG_WRITE_TRAILER_FAILED
+    "ffmpeg write frame failed",        //AE_FFMPEG_WRITE_FRAME_FAILED
+
+    "avfilter alloc avfilter failed", //AE_FILTER_ALLOC_GRAPH_FAILED
+    "avfilter create graph failed",   //AE_FILTER_CREATE_FILTER_FAILED
+    "avfilter parse ptr failed",      //AE_FILTER_PARSE_PTR_FAILED
+    "avfilter config graph failed",   //AE_FILTER_CONFIG_FAILED
+    "avfilter invalid ctx index",     //AE_FILTER_INVALID_CTX_INDEX
+    "avfilter add frame failed",      //AE_FILTER_ADD_FRAME_FAILED
+
+    "gdi get dc failed",       //AE_GDI_GET_DC_FAILED
+    "gdi create dc failed",    //AE_GDI_CREATE_DC_FAILED
+    "gdi create bmp failed",   //AE_GDI_CREATE_BMP_FAILED
+    "gdi bitblt failed",       //AE_GDI_BITBLT_FAILED
+    "gid geet dibbits failed", //AE_GDI_GET_DIBITS_FAILED
+
+    "d3d11 library load failed",         //AE_D3D_LOAD_FAILED
+    "d3d11 proc get failed",             //AE_D3D_GET_PROC_FAILED
+    "d3d11 create device failed",        //AE_D3D_CREATE_DEVICE_FAILED
+    "d3d11 query interface failed",      //AE_D3D_QUERYINTERFACE_FAILED
+    "d3d11 create vertex shader failed", //AE_D3D_CREATE_VERTEX_SHADER_FAILED
+    "d3d11 create input layout failed",  //AE_D3D_CREATE_INLAYOUT_FAILED
+    "d3d11 create pixel shader failed",  //AE_D3D_CREATE_PIXEL_SHADER_FAILED
+    "d3d11 create sampler state failed", //AE_D3D_CREATE_SAMPLERSTATE_FAILED
+
+    "dxgi get proc address failed",     //AE_DXGI_GET_PROC_FAILED
+    "dxgi get adapter failed",          //AE_DXGI_GET_ADAPTER_FAILED
+    "dxgi get factory failed",          //AE_DXGI_GET_FACTORY_FAILED
+    "dxgi specified adapter not found", //AE_DXGI_FOUND_ADAPTER_FAILED
+
+    "duplication attatch desktop failed",  //AE_DUP_ATTATCH_FAILED
+    "duplication query interface failed",  //AE_DUP_QI_FAILED
+    "duplication get parent failed",       //AE_DUP_GET_PARENT_FAILED
+    "duplication enum ouput failed",       //AE_DUP_ENUM_OUTPUT_FAILED
+    "duplication duplicate unavailable",   //AE_DUP_DUPLICATE_MAX_FAILED
+    "duplication duplicate failed",        //AE_DUP_DUPLICATE_FAILED
+    "duplication release frame failed",    //AE_DUP_RELEASE_FRAME_FAILED
+    "duplication acquire frame failed",    //AE_DUP_ACQUIRE_FRAME_FAILED
+    "duplication qi frame failed",         //AE_DUP_QI_FRAME_FAILED
+    "duplication create texture failed",   //AE_DUP_CREATE_TEXTURE_FAILED
+    "duplication dxgi qi failed",          //AE_DUP_QI_DXGI_FAILED
+    "duplication map rects failed",        //AE_DUP_MAP_FAILED
+    "duplication get cursor shape failed", //AE_DUP_GET_CURSORSHAPE_FAILED
+
+    "remux is already running",           //AE_REMUX_RUNNING
+    "remux input file do not exist",      //AE_REMUX_NOT_EXIST
+    "remux input or output file invalid", //AE_REMUX_INVALID_INOUT
 };
 
 #define err2str(e) e < AE_MAX ? ERRORS_STR[e] : "unknown"
 
-#define AMERROR_CHECK(err) if(err != AE_NO) return err
+#define AMERROR_CHECK(err) \
+    if (err != AE_NO) \
+    return err
 
-#endif // !ERROR_DEFINE
+#endif // !ERROR_DEFINE

+ 299 - 285
libs/Recorder/export.cpp

@@ -19,483 +19,497 @@
 #include "system_version.h"
 #endif
 
-#include <string>
 #include <atomic>
 #include <mutex>
+#include <string>
 
 #define USE_DSHOW 0
 
 namespace am {
 typedef std::lock_guard<std::mutex> lock_guard;
 
-static const double scaled_vals[] = { 1.0,         1.25, (1.0 / 0.75), 1.5,
-	(1.0 / 0.6), 1.75, 2.0,          2.25,
-	2.5,         2.75, 3.0,          0.0 };
+static const double scaled_vals[]
+    = {1.0, 1.25, (1.0 / 0.75), 1.5, (1.0 / 0.6), 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 0.0};
 
-class recorder {
+class recorder
+{
 private:
-	recorder();
+    recorder();
 
-	~recorder();
+    ~recorder();
 
 public:
-	static recorder *instance();
+    static recorder *instance();
 
-	static void release();
+    static void release();
 
-	int init(const AMRECORDER_SETTING & setting, const AMRECORDER_CALLBACK &callbacks);
+    int init(const AMRECORDER_SETTING &setting, const AMRECORDER_CALLBACK &callbacks);
 
-	int start();
+    int start();
 
-	void stop();
+    void stop();
 
-	int pause();
+    int pause();
 
-	int resume();
+    int resume();
 
-	void set_preview_enabled(bool enable);
+    void set_preview_enabled(bool enable);
 
 private:
-	void on_preview_yuv(const uint8_t *data, int size, int width, int height, int type);
-	void get_valid_out_resolution(int src_width, int src_height, int *out_width, int *out_height);
+    void on_preview_yuv(const uint8_t *data, int size, int width, int height, int type);
+    void get_valid_out_resolution(int src_width, int src_height, int *out_width, int *out_height);
+
 private:
-	AMRECORDER_SETTING _setting;
-	AMRECORDER_CALLBACK _callbacks;
+    AMRECORDER_SETTING _setting;
+    AMRECORDER_CALLBACK _callbacks;
 
-	record_audio *_recorder_speaker;
-	record_audio *_recorder_mic;
-	record_desktop *_recorder_desktop;
+    record_audio *_recorder_speaker;
+    record_audio *_recorder_mic;
+    record_desktop *_recorder_desktop;
 
-	muxer_file *_muxer;
+    muxer_file *_muxer;
 
-	std::atomic_bool _inited;
-	std::mutex _mutex;
+    std::atomic_bool _inited;
+    std::mutex _mutex;
 };
 
 static recorder *_g_instance = nullptr;
 static std::mutex _g_mutex;
 
-recorder::recorder() {
-	memset(&_setting, 0, sizeof(_setting));
-	memset(&_callbacks, 0, sizeof(_callbacks));
+recorder::recorder()
+{
+    memset(&_setting, 0, sizeof(_setting));
+    memset(&_callbacks, 0, sizeof(_callbacks));
 
-	_recorder_speaker = nullptr;
-	_recorder_mic = nullptr;
-	_recorder_desktop = nullptr;
+    _recorder_speaker = nullptr;
+    _recorder_mic = nullptr;
+    _recorder_desktop = nullptr;
 
-	_inited = false;
-	_muxer = nullptr;
+    _inited = false;
+    _muxer = nullptr;
 }
 
-recorder::~recorder() {
-	if (_muxer)
-		delete _muxer;
+recorder::~recorder()
+{
+    if (_muxer)
+        delete _muxer;
 
-	if (_recorder_desktop)
-		delete _recorder_desktop;
+    if (_recorder_desktop)
+        delete _recorder_desktop;
 
-	if (_recorder_mic)
-		delete _recorder_mic;
+    if (_recorder_mic)
+        delete _recorder_mic;
 
-	if (_recorder_speaker)
-		delete _recorder_speaker;
+    if (_recorder_speaker)
+        delete _recorder_speaker;
 }
 
-recorder * recorder::instance() {
-	lock_guard lock(_g_mutex);
+recorder *recorder::instance()
+{
+    lock_guard lock(_g_mutex);
 
-	if (_g_instance == nullptr) _g_instance = new recorder();
+    if (_g_instance == nullptr)
+        _g_instance = new recorder();
 
-	return _g_instance;
+    return _g_instance;
 }
 
 void recorder::release()
 {
-	lock_guard lock(_g_mutex);
+    lock_guard lock(_g_mutex);
 
-	if (_g_instance)
-		delete _g_instance;
+    if (_g_instance)
+        delete _g_instance;
 
-	_g_instance = nullptr;
+    _g_instance = nullptr;
 }
 
-int recorder::init(const AMRECORDER_SETTING & setting, const AMRECORDER_CALLBACK & callbacks)
+int recorder::init(const AMRECORDER_SETTING &setting, const AMRECORDER_CALLBACK &callbacks)
 {
-	lock_guard lock(_mutex);
-	if (_inited == true)
-		return AE_NO;
+    lock_guard lock(_mutex);
+    if (_inited == true)
+        return AE_NO;
 
-	int error = AE_NO;
-	int audio_num = 0;
+    int error = AE_NO;
+    int audio_num = 0;
 
-	_setting = setting;
-	_callbacks = callbacks;
+    _setting = setting;
+    _callbacks = callbacks;
 
-	am::record_audio *audios[2] = { 0 };
+    am::record_audio *audios[2] = {0};
 
 #if USE_DSHOW
 
-	error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_DSHOW, &_recorder_speaker);
-	AMERROR_CHECK(error);
+    error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_DSHOW, &_recorder_speaker);
+    AMERROR_CHECK(error);
 
-	error = _recorder_speaker->init("audio=virtual-audio-capturer", "audio=virtual-audio-capturer", false);
-	AMERROR_CHECK(error);
+    error = _recorder_speaker->init("audio=virtual-audio-capturer",
+                                    "audio=virtual-audio-capturer",
+                                    false);
+    AMERROR_CHECK(error);
 
-	error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_DSHOW, &_recorder_mic);
-	AMERROR_CHECK(error);
+    error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_DSHOW, &_recorder_mic);
+    AMERROR_CHECK(error);
 
-	error = _recorder_mic->init(std::string("audio=") + std::string(setting.a_mic.name), std::string("audio=") + std::string(setting.a_mic.name), true);
-	AMERROR_CHECK(error);
+    error = _recorder_mic->init(std::string("audio=") + std::string(setting.a_mic.name),
+                                std::string("audio=") + std::string(setting.a_mic.name),
+                                true);
+    AMERROR_CHECK(error);
 
-	audios = { _recorder_speaker,_recorder_mic };
+    audios = {_recorder_speaker, _recorder_mic};
 #else
-	if (utils_string::utf8_ascii(setting.a_speaker.name).length() && utils_string::utf8_ascii(setting.a_speaker.id).length()) {
-		error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_WAS, &_recorder_speaker);
-		AMERROR_CHECK(error);
-
-		error = _recorder_speaker->init(setting.a_speaker.name, setting.a_speaker.id, false);
-		AMERROR_CHECK(error);
-
-		audios[audio_num] = _recorder_speaker;
-		audio_num++;
-	}
+    if (utils_string::utf8_ascii(setting.a_speaker.name).length()
+        && utils_string::utf8_ascii(setting.a_speaker.id).length()) {
+        error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_WAS, &_recorder_speaker);
+        AMERROR_CHECK(error);
 
+        error = _recorder_speaker->init(setting.a_speaker.name, setting.a_speaker.id, false);
+        AMERROR_CHECK(error);
 
+        audios[audio_num] = _recorder_speaker;
+        audio_num++;
+    }
 
-	if (utils_string::utf8_ascii(setting.a_mic.name).length() && utils_string::utf8_ascii(setting.a_mic.id).length()) {
-		error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_WAS, &_recorder_mic);
-		AMERROR_CHECK(error);
+    if (utils_string::utf8_ascii(setting.a_mic.name).length()
+        && utils_string::utf8_ascii(setting.a_mic.id).length()) {
+        error = record_audio_new(RECORD_AUDIO_TYPES::AT_AUDIO_WAS, &_recorder_mic);
+        AMERROR_CHECK(error);
 
-		error = _recorder_mic->init(setting.a_mic.name, setting.a_mic.id, true);
-		AMERROR_CHECK(error);
+        error = _recorder_mic->init(setting.a_mic.name, setting.a_mic.id, true);
+        AMERROR_CHECK(error);
 
-		audios[audio_num] = _recorder_mic;
-		audio_num++;
-	}
-#endif 
+        audios[audio_num] = _recorder_mic;
+        audio_num++;
+    }
+#endif
 
 #ifdef _WIN32
 #if USE_MAG
-  if (_recorder_desktop == nullptr) {
-                error =
-                    record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_MAG,
-                                  &_recorder_desktop);
-    if (error == AE_NO) {
-      error = _recorder_desktop->init(
-          {setting.v_left, setting.v_top,
-            setting.v_width + setting.v_left,
-            setting.v_height + setting.v_top},
-          setting.v_frame_rate);
-
-      if (error != AE_NO)
-        record_desktop_destroy(&_recorder_desktop);
+    if (_recorder_desktop == nullptr) {
+        error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_MAG, &_recorder_desktop);
+        if (error == AE_NO) {
+            error = _recorder_desktop->init({setting.v_left,
+                                             setting.v_top,
+                                             setting.v_width + setting.v_left,
+                                             setting.v_height + setting.v_top},
+                                            setting.v_frame_rate);
+
+            if (error != AE_NO)
+                record_desktop_destroy(&_recorder_desktop);
+        }
     }
-  }
 #endif
 
-	// windows support wgc since win10.1803
-  if (_recorder_desktop == nullptr && system_version::is_win10_or_above(17134)) {
-    error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_WGC,
-        &_recorder_desktop);
-    if (error == AE_NO) {
-      error = _recorder_desktop->init({setting.v_left, setting.v_top,
-                                        setting.v_width + setting.v_left,
-                                        setting.v_height + setting.v_top},
-                                      setting.v_frame_rate);
-
-      if (error != AE_NO)
-        record_desktop_destroy(&_recorder_desktop);
+    // windows support wgc since win10.1803
+    if (_recorder_desktop == nullptr && system_version::is_win10_or_above(17134)) {
+        error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_WGC, &_recorder_desktop);
+        if (error == AE_NO) {
+            error = _recorder_desktop->init({setting.v_left,
+                                             setting.v_top,
+                                             setting.v_width + setting.v_left,
+                                             setting.v_height + setting.v_top},
+                                            setting.v_frame_rate);
+
+            if (error != AE_NO)
+                record_desktop_destroy(&_recorder_desktop);
+        }
     }
-	}
-
-  if (_recorder_desktop == nullptr &&
-      system_version::is_win8_or_above()) {
-		error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_DUPLICATION, &_recorder_desktop);
-		if (error == AE_NO) {
-
-			error = _recorder_desktop->init(
-			{
-				setting.v_left,setting.v_top,setting.v_width + setting.v_left,setting.v_height + setting.v_top
-			},
-				setting.v_frame_rate
-			);
-
-			if (error != AE_NO)
-				record_desktop_destroy(&_recorder_desktop);
-		}
-	}
-
-	if (_recorder_desktop == nullptr) {
-		error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_GDI, &_recorder_desktop);
-		AMERROR_CHECK(error);
-
-		error = _recorder_desktop->init(
-		{
-			setting.v_left,setting.v_top,setting.v_width + setting.v_left,setting.v_height + setting.v_top
-		},
-			setting.v_frame_rate
-		);
-
-		AMERROR_CHECK(error);
-	}
-#endif // _WIN32
 
-	am::MUX_SETTING mux_setting;
-	mux_setting.v_frame_rate = setting.v_frame_rate;
-	mux_setting.v_bit_rate = setting.v_bit_rate;
-	mux_setting.v_width = setting.v_width;
-	mux_setting.v_height = setting.v_height;
-	mux_setting.v_qb = setting.v_qb;
-	mux_setting.v_encoder_id = (am::ENCODER_VIDEO_ID)setting.v_enc_id;
+    if (_recorder_desktop == nullptr && system_version::is_win8_or_above()) {
+        error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_DUPLICATION,
+                                   &_recorder_desktop);
+        if (error == AE_NO) {
+            error = _recorder_desktop->init({setting.v_left,
+                                             setting.v_top,
+                                             setting.v_width + setting.v_left,
+                                             setting.v_height + setting.v_top},
+                                            setting.v_frame_rate);
+
+            if (error != AE_NO)
+                record_desktop_destroy(&_recorder_desktop);
+        }
+    }
+
+    if (_recorder_desktop == nullptr) {
+        error = record_desktop_new(RECORD_DESKTOP_TYPES::DT_DESKTOP_WIN_GDI, &_recorder_desktop);
+        AMERROR_CHECK(error);
+
+        error = _recorder_desktop->init({setting.v_left,
+                                         setting.v_top,
+                                         setting.v_width + setting.v_left,
+                                         setting.v_height + setting.v_top},
+                                        setting.v_frame_rate);
 
-	get_valid_out_resolution(setting.v_width, setting.v_height, &mux_setting.v_out_width, &mux_setting.v_out_height);
+        AMERROR_CHECK(error);
+    }
+#endif // _WIN32
 
-	mux_setting.a_nb_channel = 2;
-	mux_setting.a_sample_fmt = AV_SAMPLE_FMT_FLTP;
-	mux_setting.a_sample_rate = 44100;
-	mux_setting.a_bit_rate = 128000;
+    am::MUX_SETTING mux_setting;
+    mux_setting.v_frame_rate = setting.v_frame_rate;
+    mux_setting.v_bit_rate = setting.v_bit_rate;
+    mux_setting.v_width = setting.v_width;
+    mux_setting.v_height = setting.v_height;
+    mux_setting.v_qb = setting.v_qb;
+    mux_setting.v_encoder_id = (am::ENCODER_VIDEO_ID) setting.v_enc_id;
 
+    get_valid_out_resolution(setting.v_width,
+                             setting.v_height,
+                             &mux_setting.v_out_width,
+                             &mux_setting.v_out_height);
 
+    mux_setting.a_nb_channel = 2;
+    mux_setting.a_sample_fmt = AV_SAMPLE_FMT_FLTP;
+    mux_setting.a_sample_rate = 44100;
+    mux_setting.a_bit_rate = 128000;
 
-	_muxer = new muxer_ffmpeg();
+    _muxer = new muxer_ffmpeg();
 
-	_muxer->registe_yuv_data(std::bind(
-		&recorder::on_preview_yuv,
-		this,
-		std::placeholders::_1,
-		std::placeholders::_2,
-		std::placeholders::_3,
-		std::placeholders::_4,
-		std::placeholders::_5
-	));
+    _muxer->registe_yuv_data(std::bind(&recorder::on_preview_yuv,
+                                       this,
+                                       std::placeholders::_1,
+                                       std::placeholders::_2,
+                                       std::placeholders::_3,
+                                       std::placeholders::_4,
+                                       std::placeholders::_5));
 
-	error = _muxer->init(setting.output, _recorder_desktop, audios, audio_num, mux_setting);
-	AMERROR_CHECK(error);
+    error = _muxer->init(setting.output, _recorder_desktop, audios, audio_num, mux_setting);
+    AMERROR_CHECK(error);
 
-	_inited = true;
+    _inited = true;
 
-	return error;
+    return error;
 }
 
 int recorder::start()
 {
-	lock_guard lock(_mutex);
-	if (_inited == false)
-		return AE_NEED_INIT;
+    lock_guard lock(_mutex);
+    if (_inited == false)
+        return AE_NEED_INIT;
 
-	int error = _muxer->start();
+    int error = _muxer->start();
 
-	return error;
+    return error;
 }
 
 void recorder::stop()
 {
-	lock_guard lock(_mutex);
-	if (_inited == false)
-		return;
+    lock_guard lock(_mutex);
+    if (_inited == false)
+        return;
 
-	_muxer->stop();
+    _muxer->stop();
 }
 
 int recorder::pause()
 {
-	lock_guard lock(_mutex);
-	if (_inited == false)
-		return AE_NEED_INIT;
+    lock_guard lock(_mutex);
+    if (_inited == false)
+        return AE_NEED_INIT;
 
-	return _muxer->pause();
+    return _muxer->pause();
 }
 
 int recorder::resume()
 {
-	lock_guard lock(_mutex);
-	if (_inited == false)
-		return AE_NEED_INIT;
+    lock_guard lock(_mutex);
+    if (_inited == false)
+        return AE_NEED_INIT;
 
-	return _muxer->resume();
+    return _muxer->resume();
 }
 
 void recorder::set_preview_enabled(bool enable)
 {
-	lock_guard lock(_mutex);
-	if (_inited == false)
-		return;
+    lock_guard lock(_mutex);
+    if (_inited == false)
+        return;
 
-	_muxer->set_preview_enabled(enable);
+    _muxer->set_preview_enabled(enable);
 }
 
-void recorder::on_preview_yuv(const uint8_t * data, int size, int width, int height, int type)
+void recorder::on_preview_yuv(const uint8_t *data, int size, int width, int height, int type)
 {
-	if (_callbacks.func_preview_yuv != NULL)
-		_callbacks.func_preview_yuv(data, size, width, height, type);
+    if (_callbacks.func_preview_yuv != NULL)
+        _callbacks.func_preview_yuv(data, size, width, height, type);
 }
-void recorder::get_valid_out_resolution(int src_width, int src_height, int * out_width, int * out_height)
+void recorder::get_valid_out_resolution(int src_width,
+                                        int src_height,
+                                        int *out_width,
+                                        int *out_height)
 {
-	int scale_cx = src_width;
-	int scale_cy = src_height;
+    int scale_cx = src_width;
+    int scale_cy = src_height;
 
-	int i = 0;
+    int i = 0;
 
-	while (((scale_cx * scale_cy) > (1920 * 1080)) && scaled_vals[i] > 0.0) {
-		double scale = scaled_vals[i++];
-		scale_cx = uint32_t(double(src_width) / scale);
-		scale_cy = uint32_t(double(src_height) / scale);
-	}
+    while (((scale_cx * scale_cy) > (1920 * 1080)) && scaled_vals[i] > 0.0) {
+        double scale = scaled_vals[i++];
+        scale_cx = uint32_t(double(src_width) / scale);
+        scale_cy = uint32_t(double(src_height) / scale);
+    }
 
-	if (scale_cx % 2 != 0) {
-		scale_cx += 1;
-	}
+    if (scale_cx % 2 != 0) {
+        scale_cx += 1;
+    }
 
-	if (scale_cy % 2 != 0) {
-		scale_cy += 1;
-	}
+    if (scale_cy % 2 != 0) {
+        scale_cy += 1;
+    }
 
-	*out_width = scale_cx;
-	*out_height = scale_cy;
+    *out_width = scale_cx;
+    *out_height = scale_cy;
 
-	al_info("get valid output resolution from %dx%d to %dx%d,with scale:%lf", src_width, src_height, scale_cx, scale_cy, scaled_vals[i]);
-}
+    al_info("get valid output resolution from %dx%d to %dx%d,with scale:%lf",
+            src_width,
+            src_height,
+            scale_cx,
+            scale_cy,
+            scaled_vals[i]);
 }
+} // namespace am
 
-AMRECORDER_API const char * recorder_err2str(int error)
+AMRECORDER_API const char *recorder_err2str(int error)
 {
-	return am::utils_string::ascii_utf8(err2str(error)).c_str();
+    return am::utils_string::ascii_utf8(err2str(error)).c_str();
 }
 
-AMRECORDER_API int recorder_init(const AMRECORDER_SETTING & setting, const AMRECORDER_CALLBACK & callbacks)
+AMRECORDER_API int recorder_init(const AMRECORDER_SETTING &setting,
+                                 const AMRECORDER_CALLBACK &callbacks)
 {
-	return am::recorder::instance()->init(setting, callbacks);
+    return am::recorder::instance()->init(setting, callbacks);
 }
 
 AMRECORDER_API void recorder_release()
 {
-	return am::recorder::instance()->release();
+    return am::recorder::instance()->release();
 }
 
 AMRECORDER_API int recorder_start()
 {
-	return am::recorder::instance()->start();
+    return am::recorder::instance()->start();
 }
 
 AMRECORDER_API void recorder_stop()
 {
-	return am::recorder::instance()->stop();
+    return am::recorder::instance()->stop();
 }
 
 AMRECORDER_API int recorder_pause()
 {
-	return am::recorder::instance()->pause();
+    return am::recorder::instance()->pause();
 }
 
 AMRECORDER_API int recorder_resume()
 {
-	return am::recorder::instance()->resume();
+    return am::recorder::instance()->resume();
 }
 
-AMRECORDER_API int recorder_get_speakers(AMRECORDER_DEVICE ** devices)
+AMRECORDER_API int recorder_get_speakers(AMRECORDER_DEVICE **devices)
 {
-	std::list<am::DEVICE_AUDIOS> device_list;
+    std::list<am::DEVICE_AUDIOS> device_list;
 
-	int error = am::device_audios::get_output_devices(device_list);
-	if (error != AE_NO) return -error;
+    int error = am::device_audios::get_output_devices(device_list);
+    if (error != AE_NO)
+        return -error;
 
-	int count = device_list.size();
+    int count = device_list.size();
 
-	*devices = new AMRECORDER_DEVICE[count];
+    *devices = new AMRECORDER_DEVICE[count];
 
-	int index = 0;
-	for each (auto device in device_list)
-	{
-		al_info("audio input name:%s id:%s", device.name.c_str(), device.id.c_str());
+    int index = 0;
+    for each (auto device in device_list) {
+        al_info("audio input name:%s id:%s", device.name.c_str(), device.id.c_str());
 
-		(*devices)[index].is_default = device.is_default;
-		sprintf_s((*devices)[index].id, 260, "%s", device.id.c_str());
-		sprintf_s((*devices)[index].name, 260, "%s", device.name.c_str());
+        (*devices)[index].is_default = device.is_default;
+        sprintf_s((*devices)[index].id, 260, "%s", device.id.c_str());
+        sprintf_s((*devices)[index].name, 260, "%s", device.name.c_str());
 
-		index++;
-	}
+        index++;
+    }
 
-	return count;
+    return count;
 }
 
-AMRECORDER_API int recorder_get_mics(AMRECORDER_DEVICE ** devices)
+AMRECORDER_API int recorder_get_mics(AMRECORDER_DEVICE **devices)
 {
-	std::list<am::DEVICE_AUDIOS> device_list;
+    std::list<am::DEVICE_AUDIOS> device_list;
 
-	int error = am::device_audios::get_input_devices(device_list);
-	if (error != AE_NO) return -error;
+    int error = am::device_audios::get_input_devices(device_list);
+    if (error != AE_NO)
+        return -error;
 
-	int count = device_list.size();
+    int count = device_list.size();
 
-	*devices = new AMRECORDER_DEVICE[count];
+    *devices = new AMRECORDER_DEVICE[count];
 
-	int index = 0;
-	for each (auto device in device_list)
-	{
-		al_info("audio output name:%s id:%s", device.name.c_str(), device.id.c_str());
+    int index = 0;
+    for each (auto device in device_list) {
+        al_info("audio output name:%s id:%s", device.name.c_str(), device.id.c_str());
 
-		(*devices)[index].is_default = device.is_default;
-		sprintf_s((*devices)[index].id, 260, "%s", device.id.c_str());
-		sprintf_s((*devices)[index].name, 260, "%s", device.name.c_str());
+        (*devices)[index].is_default = device.is_default;
+        sprintf_s((*devices)[index].id, 260, "%s", device.id.c_str());
+        sprintf_s((*devices)[index].name, 260, "%s", device.name.c_str());
 
-		index++;
-	}
+        index++;
+    }
 
-	return count;
+    return count;
 }
 
-AMRECORDER_API int recorder_get_cameras(AMRECORDER_DEVICE ** devices)
+AMRECORDER_API int recorder_get_cameras(AMRECORDER_DEVICE **devices)
 {
-	return -AE_UNSUPPORT;
+    return -AE_UNSUPPORT;
 }
 
-AMRECORDER_API int recorder_get_vencoders(AMRECORDER_ENCODERS ** encoders)
+AMRECORDER_API int recorder_get_vencoders(AMRECORDER_ENCODERS **encoders)
 {
-	auto hw_encoders = am::hardware_acceleration::get_supported_video_encoders();
+    auto hw_encoders = am::hardware_acceleration::get_supported_video_encoders();
 
-	int count = hw_encoders.size() + 1;
-	*encoders = new AMRECORDER_ENCODERS[count];
+    int count = hw_encoders.size() + 1;
+    *encoders = new AMRECORDER_ENCODERS[count];
 
-	AMRECORDER_ENCODERS *ptr = *encoders;
-	ptr->id = am::EID_VIDEO_X264;
-	sprintf_s(ptr->name, 260, am::utils_string::ascii_utf8("Soft.X264").c_str());
+    AMRECORDER_ENCODERS *ptr = *encoders;
+    ptr->id = am::EID_VIDEO_X264;
+    sprintf_s(ptr->name, 260, am::utils_string::ascii_utf8("Soft.X264").c_str());
 
-	for each (auto hw_encoder in hw_encoders)
-	{
-		ptr++;
-		ptr->id = hw_encoder.type;
-		sprintf_s(ptr->name, 260, "%s", hw_encoder.name);
-	}
+    for each (auto hw_encoder in hw_encoders) {
+        ptr++;
+        ptr->id = hw_encoder.type;
+        sprintf_s(ptr->name, 260, "%s", hw_encoder.name);
+    }
 
-	return count;
+    return count;
 }
 
-AMRECORDER_API void recorder_free_array(void * array_address)
+AMRECORDER_API void recorder_free_array(void *array_address)
 {
-	if (array_address != nullptr)
-		delete[]array_address;
+    if (array_address != nullptr)
+        delete[] array_address;
 }
 
-AMRECORDER_API int recorder_remux(const char * src, const char * dst, AMRECORDER_FUNC_REMUX_PROGRESS func_progress, AMRECORDER_FUNC_REMUX_STATE func_state)
+AMRECORDER_API int recorder_remux(const char *src,
+                                  const char *dst,
+                                  AMRECORDER_FUNC_REMUX_PROGRESS func_progress,
+                                  AMRECORDER_FUNC_REMUX_STATE func_state)
 {
-	am::REMUXER_PARAM param = { 0 };
+    am::REMUXER_PARAM param = {0};
 
-	sprintf_s(param.src, 260, "%s", am::utils_string::utf8_ascii(src).c_str());
-	sprintf_s(param.dst, 260, "%s", am::utils_string::utf8_ascii(dst).c_str());
+    sprintf_s(param.src, 260, "%s", am::utils_string::utf8_ascii(src).c_str());
+    sprintf_s(param.dst, 260, "%s", am::utils_string::utf8_ascii(dst).c_str());
 
-	param.cb_progress = func_progress;
+    param.cb_progress = func_progress;
 
-	param.cb_state = func_state;
+    param.cb_state = func_state;
 
-	return am::remuxer_ffmpeg::instance()->create_remux(param);
+    return am::remuxer_ffmpeg::instance()->create_remux(param);
 }
 
 AMRECORDER_API void recorder_set_preview_enabled(int enable)
 {
-	am::recorder::instance()->set_preview_enabled(enable == 1);
+    am::recorder::instance()->set_preview_enabled(enable == 1);
 }
 
-AMRECORDER_API void recorder_set_logpath(const char * path)
+AMRECORDER_API void recorder_set_logpath(const char *path)
 {
-	AMLog *log = AMLog::get(path);
+    AMLog *log = AMLog::get(path);
 }

+ 12 - 10
libs/Recorder/filter.cpp

@@ -1,13 +1,15 @@
 #include "filter.h"
 
 namespace am {
-	void format_pad_arg(char *arg, int size, const FILTER_CTX &ctx)
-	{
-		sprintf_s(arg, size, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
-			ctx.time_base.num,
-			ctx.time_base.den,
-			ctx.sample_rate,
-			av_get_sample_fmt_name(ctx.sample_fmt),
-			av_get_default_channel_layout(ctx.nb_channel));
-	}
-}
+void format_pad_arg(char *arg, int size, const FILTER_CTX &ctx)
+{
+    sprintf_s(arg,
+              size,
+              "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
+              ctx.time_base.num,
+              ctx.time_base.den,
+              ctx.sample_rate,
+              av_get_sample_fmt_name(ctx.sample_fmt),
+              av_get_default_channel_layout(ctx.nb_channel));
+}
+} // namespace am

+ 21 - 22
libs/Recorder/filter.h

@@ -1,44 +1,43 @@
 #ifndef FILTER
 #define FILTER
 
-#include <thread>
 #include <atomic>
+#include <condition_variable>
 #include <functional>
-#include <string>
 #include <mutex>
-#include <condition_variable>
+#include <string>
+#include <thread>
 
 #include "headers_ffmpeg.h"
 
 namespace am {
-
-	typedef struct {
-		AVFilterContext *ctx;
-		AVFilterInOut *inout;
-
-		AVRational time_base;
-		int sample_rate;
-		AVSampleFormat sample_fmt;
-		int nb_channel;
-		int64_t channel_layout;
-	}FILTER_CTX;
-
-	/**
+typedef struct
+{
+    AVFilterContext *ctx;
+    AVFilterInOut *inout;
+
+    AVRational time_base;
+    int sample_rate;
+    AVSampleFormat sample_fmt;
+    int nb_channel;
+    int64_t channel_layout;
+} FILTER_CTX;
+
+/**
 	* filter data callback
 	* @param frame pointer to a AVFrame
 	* @param index resource index ,default is -1
 	*/
-	typedef std::function<void(AVFrame *frame, int index)> on_filter_data;
+typedef std::function<void(AVFrame *frame, int index)> on_filter_data;
 
-	/**
+/**
 	* filter error callback
 	* @param code error code
 	* @param index resource index ,default is -1
 	*/
-	typedef std::function<void(int code, int index)> on_filter_error;
+typedef std::function<void(int code, int index)> on_filter_error;
 
-	void format_pad_arg(char *arg, int size, const FILTER_CTX &ctx);
-}
+void format_pad_arg(char *arg, int size, const FILTER_CTX &ctx);
+} // namespace am
 
 #endif // !FILTER
-

+ 293 - 260
libs/Recorder/filter_amix.cpp

@@ -6,263 +6,296 @@
 #include "log_helper.h"
 
 namespace am {
-
-	static void print_frame(const AVFrame *frame, int index)
-	{
-		al_debug("index:%d %lld %d", index, frame->pts, frame->nb_samples);
-	}
-
-	filter_amix::filter_amix()
-	{
-		av_register_all();
-		avfilter_register_all();
-
-		memset(&_ctx_in_0, 0, sizeof(FILTER_CTX));
-		memset(&_ctx_in_1, 0, sizeof(FILTER_CTX));
-		memset(&_ctx_out, 0, sizeof(FILTER_CTX));
-
-		_filter_graph = NULL;
-
-		_inited = false;
-		_running = false;
-
-		_cond_notify = false;
-
-	}
-
-
-	filter_amix::~filter_amix()
-	{
-		stop();
-		cleanup();
-	}
-
-	int filter_amix::init(const FILTER_CTX & ctx_in0, const FILTER_CTX & ctx_in1, const FILTER_CTX & ctx_out)
-	{
-		int error = AE_NO;
-		int ret = 0;
-
-		if (_inited) return AE_NO;
-
-		do {
-			_ctx_in_0 = ctx_in0;
-			_ctx_in_1 = ctx_in1;
-			_ctx_out = ctx_out;
-
-			_filter_graph = avfilter_graph_alloc();
-			if (!_filter_graph) {
-				error = AE_FILTER_ALLOC_GRAPH_FAILED;
-				break;
-			}
-
-			const std::string filter_desrc = "[in0][in1]amix=inputs=2:duration=first:dropout_transition=0[out]";
-
-			_ctx_in_0.inout = avfilter_inout_alloc();
-			_ctx_in_1.inout = avfilter_inout_alloc();
-			_ctx_out.inout = avfilter_inout_alloc();
-
-			char pad_args0[512] = { 0 }, pad_args1[512] = { 0 };
-
-			format_pad_arg(pad_args0, 512, _ctx_in_0);
-			format_pad_arg(pad_args1, 512, _ctx_in_1);
-
-			ret = avfilter_graph_create_filter(&_ctx_in_0.ctx, avfilter_get_by_name("abuffer"), "in0", pad_args0, NULL, _filter_graph);
-			if (ret < 0) {
-				error = AE_FILTER_CREATE_FILTER_FAILED;
-				break;
-			}
-
-			ret = avfilter_graph_create_filter(&_ctx_in_1.ctx, avfilter_get_by_name("abuffer"), "in1", pad_args1, NULL, _filter_graph);
-			if (ret < 0) {
-				error = AE_FILTER_CREATE_FILTER_FAILED;
-				break;
-			}
-
-			ret = avfilter_graph_create_filter(&_ctx_out.ctx, avfilter_get_by_name("abuffersink"), "out", NULL, NULL, _filter_graph);
-			if (ret < 0) {
-				error = AE_FILTER_CREATE_FILTER_FAILED;
-				break;
-			}
-
-			av_opt_set_bin(_ctx_out.ctx, "sample_fmts", (uint8_t*)&_ctx_out.sample_fmt, sizeof(_ctx_out.sample_fmt), AV_OPT_SEARCH_CHILDREN);
-			av_opt_set_bin(_ctx_out.ctx, "channel_layouts", (uint8_t*)&_ctx_out.channel_layout, sizeof(_ctx_out.channel_layout), AV_OPT_SEARCH_CHILDREN);
-			av_opt_set_bin(_ctx_out.ctx, "sample_rates", (uint8_t*)&_ctx_out.sample_rate, sizeof(_ctx_out.sample_rate), AV_OPT_SEARCH_CHILDREN);
-
-			_ctx_in_0.inout->name = av_strdup("in0");
-			_ctx_in_0.inout->filter_ctx = _ctx_in_0.ctx;
-			_ctx_in_0.inout->pad_idx = 0;
-			_ctx_in_0.inout->next = _ctx_in_1.inout;
-
-			_ctx_in_1.inout->name = av_strdup("in1");
-			_ctx_in_1.inout->filter_ctx = _ctx_in_1.ctx;
-			_ctx_in_1.inout->pad_idx = 0;
-			_ctx_in_1.inout->next = NULL;
-
-			_ctx_out.inout->name = av_strdup("out");
-			_ctx_out.inout->filter_ctx = _ctx_out.ctx;
-			_ctx_out.inout->pad_idx = 0;
-			_ctx_out.inout->next = NULL;
-
-			AVFilterInOut *inoutputs[2] = { _ctx_in_0.inout,_ctx_in_1.inout };
-
-			ret = avfilter_graph_parse_ptr(_filter_graph, filter_desrc.c_str(), &_ctx_out.inout, inoutputs, NULL);
-			if (ret < 0) {
-				error = AE_FILTER_PARSE_PTR_FAILED;
-				break;
-			}
-
-			ret = avfilter_graph_config(_filter_graph, NULL);
-			if (ret < 0) {
-				error = AE_FILTER_CONFIG_FAILED;
-				break;
-			}
-
-			//al_debug("dump graph:\r\n%s", avfilter_graph_dump(_filter_graph, NULL));
-
-			_inited = true;
-		} while (0);
-
-		if (error != AE_NO) {
-			al_debug("filter init failed:%s %d", err2str(error), ret);
-			cleanup();
-		}
-
-		//if (_ctx_in_0.inout)
-		//	avfilter_inout_free(&_ctx_in_0.inout);
-
-		//if (_ctx_in_1.inout)
-		//	avfilter_inout_free(&_ctx_in_1.inout);
-
-		//if (_ctx_out.inout)
-		//	avfilter_inout_free(&_ctx_out.inout);
-
-		return error;
-	}
-
-	int filter_amix::start()
-	{
-		if (!_inited)
-			return AE_NEED_INIT;
-
-		if (_running)
-			return AE_NO;
-
-		_running = true;
-		_thread = std::thread(std::bind(&filter_amix::filter_loop, this));
-
-		return 0;
-	}
-
-	int filter_amix::stop()
-	{
-		if (!_inited || !_running)
-			return AE_NO;
-
-		_running = false;
-
-		_cond_notify = true;
-		_cond_var.notify_all();
-
-		if (_thread.joinable())
-			_thread.join();
-
-		return AE_NO;
-	}
-
-	int filter_amix::add_frame(AVFrame * frame, int index)
-	{
-		std::unique_lock<std::mutex> lock(_mutex);
-
-		int error = AE_NO;
-		int ret = 0;
-
-		do {
-			AVFilterContext *ctx = NULL;
-			switch (index) {
-			case 0:
-				ctx = _ctx_in_0.ctx;
-				break;
-			case 1:
-				ctx = _ctx_in_1.ctx;
-				break;
-			default:
-				ctx = NULL;
-				break;
-			}
-
-			if (!ctx) {
-				error = AE_FILTER_INVALID_CTX_INDEX;
-				break;
-			}
-
-			//print_frame(frame, index);
-			int ret = av_buffersrc_add_frame_flags(ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
-			if (ret < 0) {
-				error = AE_FILTER_ADD_FRAME_FAILED;
-				break;
-			}
-
-		} while (0);
-
-		if (error != AE_NO) {
-			al_debug("add frame failed:%s ,%d", err2str(error), ret);
-		}
-
-		_cond_notify = true;
-		_cond_var.notify_all();
-
-		return error;
-	}
-
-	const AVRational filter_amix::get_time_base()
-	{
-		return av_buffersink_get_time_base(_ctx_out.ctx);
-	}
-
-	void filter_amix::cleanup()
-	{
-		if (_filter_graph)
-			avfilter_graph_free(&_filter_graph);
-
-		memset(&_ctx_in_0, 0, sizeof(FILTER_CTX));
-		memset(&_ctx_in_1, 0, sizeof(FILTER_CTX));
-		memset(&_ctx_out, 0, sizeof(FILTER_CTX));
-
-		_inited = false;
-	}
-
-	void filter_amix::filter_loop()
-	{
-		AVFrame *frame = av_frame_alloc();
-
-		int ret = 0;
-		while (_running) {
-			std::unique_lock<std::mutex> lock(_mutex);
-			while (!_cond_notify && _running)
-				_cond_var.wait_for(lock,std::chrono::milliseconds(300));
-
-			while (_running && _cond_notify) {
-				ret = av_buffersink_get_frame(_ctx_out.ctx, frame);
-				if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-					break;;
-				}
-
-				if (ret < 0) {
-					al_fatal("avfilter get frame error:%d", ret);
-					if (_on_filter_error) _on_filter_error(ret, -1);
-					break;
-				}
-
-				if (_on_filter_data)
-					_on_filter_data(frame, -1);
-
-				av_frame_unref(frame);
-			}
-
-			_cond_notify = false;
-		}
-
-		av_frame_free(&frame);
-	}
-
-}
+static void print_frame(const AVFrame *frame, int index)
+{
+    al_debug("index:%d %lld %d", index, frame->pts, frame->nb_samples);
+}
+
+filter_amix::filter_amix()
+{
+    av_register_all();
+    avfilter_register_all();
+
+    memset(&_ctx_in_0, 0, sizeof(FILTER_CTX));
+    memset(&_ctx_in_1, 0, sizeof(FILTER_CTX));
+    memset(&_ctx_out, 0, sizeof(FILTER_CTX));
+
+    _filter_graph = NULL;
+
+    _inited = false;
+    _running = false;
+
+    _cond_notify = false;
+}
+
+filter_amix::~filter_amix()
+{
+    stop();
+    cleanup();
+}
+
+int filter_amix::init(const FILTER_CTX &ctx_in0,
+                      const FILTER_CTX &ctx_in1,
+                      const FILTER_CTX &ctx_out)
+{
+    int error = AE_NO;
+    int ret = 0;
+
+    if (_inited)
+        return AE_NO;
+
+    do {
+        _ctx_in_0 = ctx_in0;
+        _ctx_in_1 = ctx_in1;
+        _ctx_out = ctx_out;
+
+        _filter_graph = avfilter_graph_alloc();
+        if (!_filter_graph) {
+            error = AE_FILTER_ALLOC_GRAPH_FAILED;
+            break;
+        }
+
+        const std::string filter_desrc
+            = "[in0][in1]amix=inputs=2:duration=first:dropout_transition=0[out]";
+
+        _ctx_in_0.inout = avfilter_inout_alloc();
+        _ctx_in_1.inout = avfilter_inout_alloc();
+        _ctx_out.inout = avfilter_inout_alloc();
+
+        char pad_args0[512] = {0}, pad_args1[512] = {0};
+
+        format_pad_arg(pad_args0, 512, _ctx_in_0);
+        format_pad_arg(pad_args1, 512, _ctx_in_1);
+
+        ret = avfilter_graph_create_filter(&_ctx_in_0.ctx,
+                                           avfilter_get_by_name("abuffer"),
+                                           "in0",
+                                           pad_args0,
+                                           NULL,
+                                           _filter_graph);
+        if (ret < 0) {
+            error = AE_FILTER_CREATE_FILTER_FAILED;
+            break;
+        }
+
+        ret = avfilter_graph_create_filter(&_ctx_in_1.ctx,
+                                           avfilter_get_by_name("abuffer"),
+                                           "in1",
+                                           pad_args1,
+                                           NULL,
+                                           _filter_graph);
+        if (ret < 0) {
+            error = AE_FILTER_CREATE_FILTER_FAILED;
+            break;
+        }
+
+        ret = avfilter_graph_create_filter(&_ctx_out.ctx,
+                                           avfilter_get_by_name("abuffersink"),
+                                           "out",
+                                           NULL,
+                                           NULL,
+                                           _filter_graph);
+        if (ret < 0) {
+            error = AE_FILTER_CREATE_FILTER_FAILED;
+            break;
+        }
+
+        av_opt_set_bin(_ctx_out.ctx,
+                       "sample_fmts",
+                       (uint8_t *) &_ctx_out.sample_fmt,
+                       sizeof(_ctx_out.sample_fmt),
+                       AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_bin(_ctx_out.ctx,
+                       "channel_layouts",
+                       (uint8_t *) &_ctx_out.channel_layout,
+                       sizeof(_ctx_out.channel_layout),
+                       AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_bin(_ctx_out.ctx,
+                       "sample_rates",
+                       (uint8_t *) &_ctx_out.sample_rate,
+                       sizeof(_ctx_out.sample_rate),
+                       AV_OPT_SEARCH_CHILDREN);
+
+        _ctx_in_0.inout->name = av_strdup("in0");
+        _ctx_in_0.inout->filter_ctx = _ctx_in_0.ctx;
+        _ctx_in_0.inout->pad_idx = 0;
+        _ctx_in_0.inout->next = _ctx_in_1.inout;
+
+        _ctx_in_1.inout->name = av_strdup("in1");
+        _ctx_in_1.inout->filter_ctx = _ctx_in_1.ctx;
+        _ctx_in_1.inout->pad_idx = 0;
+        _ctx_in_1.inout->next = NULL;
+
+        _ctx_out.inout->name = av_strdup("out");
+        _ctx_out.inout->filter_ctx = _ctx_out.ctx;
+        _ctx_out.inout->pad_idx = 0;
+        _ctx_out.inout->next = NULL;
+
+        AVFilterInOut *inoutputs[2] = {_ctx_in_0.inout, _ctx_in_1.inout};
+
+        ret = avfilter_graph_parse_ptr(_filter_graph,
+                                       filter_desrc.c_str(),
+                                       &_ctx_out.inout,
+                                       inoutputs,
+                                       NULL);
+        if (ret < 0) {
+            error = AE_FILTER_PARSE_PTR_FAILED;
+            break;
+        }
+
+        ret = avfilter_graph_config(_filter_graph, NULL);
+        if (ret < 0) {
+            error = AE_FILTER_CONFIG_FAILED;
+            break;
+        }
+
+        //al_debug("dump graph:\r\n%s", avfilter_graph_dump(_filter_graph, NULL));
+
+        _inited = true;
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("filter init failed:%s %d", err2str(error), ret);
+        cleanup();
+    }
+
+    //if (_ctx_in_0.inout)
+    //	avfilter_inout_free(&_ctx_in_0.inout);
+
+    //if (_ctx_in_1.inout)
+    //	avfilter_inout_free(&_ctx_in_1.inout);
+
+    //if (_ctx_out.inout)
+    //	avfilter_inout_free(&_ctx_out.inout);
+
+    return error;
+}
+
+int filter_amix::start()
+{
+    if (!_inited)
+        return AE_NEED_INIT;
+
+    if (_running)
+        return AE_NO;
+
+    _running = true;
+    _thread = std::thread(std::bind(&filter_amix::filter_loop, this));
+
+    return 0;
+}
+
+int filter_amix::stop()
+{
+    if (!_inited || !_running)
+        return AE_NO;
+
+    _running = false;
+
+    _cond_notify = true;
+    _cond_var.notify_all();
+
+    if (_thread.joinable())
+        _thread.join();
+
+    return AE_NO;
+}
+
+int filter_amix::add_frame(AVFrame *frame, int index)
+{
+    std::unique_lock<std::mutex> lock(_mutex);
+
+    int error = AE_NO;
+    int ret = 0;
+
+    do {
+        AVFilterContext *ctx = NULL;
+        switch (index) {
+        case 0:
+            ctx = _ctx_in_0.ctx;
+            break;
+        case 1:
+            ctx = _ctx_in_1.ctx;
+            break;
+        default:
+            ctx = NULL;
+            break;
+        }
+
+        if (!ctx) {
+            error = AE_FILTER_INVALID_CTX_INDEX;
+            break;
+        }
+
+        //print_frame(frame, index);
+        int ret = av_buffersrc_add_frame_flags(ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
+        if (ret < 0) {
+            error = AE_FILTER_ADD_FRAME_FAILED;
+            break;
+        }
+
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("add frame failed:%s ,%d", err2str(error), ret);
+    }
+
+    _cond_notify = true;
+    _cond_var.notify_all();
+
+    return error;
+}
+
+const AVRational filter_amix::get_time_base()
+{
+    return av_buffersink_get_time_base(_ctx_out.ctx);
+}
+
+void filter_amix::cleanup()
+{
+    if (_filter_graph)
+        avfilter_graph_free(&_filter_graph);
+
+    memset(&_ctx_in_0, 0, sizeof(FILTER_CTX));
+    memset(&_ctx_in_1, 0, sizeof(FILTER_CTX));
+    memset(&_ctx_out, 0, sizeof(FILTER_CTX));
+
+    _inited = false;
+}
+
+void filter_amix::filter_loop()
+{
+    AVFrame *frame = av_frame_alloc();
+
+    int ret = 0;
+    while (_running) {
+        std::unique_lock<std::mutex> lock(_mutex);
+        while (!_cond_notify && _running)
+            _cond_var.wait_for(lock, std::chrono::milliseconds(300));
+
+        while (_running && _cond_notify) {
+            ret = av_buffersink_get_frame(_ctx_out.ctx, frame);
+            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+                break;
+                ;
+            }
+
+            if (ret < 0) {
+                al_fatal("avfilter get frame error:%d", ret);
+                if (_on_filter_error)
+                    _on_filter_error(ret, -1);
+                break;
+            }
+
+            if (_on_filter_data)
+                _on_filter_data(frame, -1);
+
+            av_frame_unref(frame);
+        }
+
+        _cond_notify = false;
+    }
+
+    av_frame_free(&frame);
+}
+} // namespace am

+ 34 - 37
libs/Recorder/filter_amix.h

@@ -3,55 +3,52 @@
 
 #include "filter.h"
 
-
 namespace am {
-	class filter_amix
-	{
-	public:
-		filter_amix();
-		~filter_amix();
-
-		int init(const FILTER_CTX &ctx_in0, const FILTER_CTX &ctx_in1, const FILTER_CTX &ctx_out);
-
-		inline void registe_cb(on_filter_data cb_on_filter_data, on_filter_error cb_on_filter_error) {
-			_on_filter_data = cb_on_filter_data;
-			_on_filter_error = cb_on_filter_error;
-		}
-
-		int start();
+class filter_amix
+{
+public:
+    filter_amix();
+    ~filter_amix();
 
-		int stop();
+    int init(const FILTER_CTX &ctx_in0, const FILTER_CTX &ctx_in1, const FILTER_CTX &ctx_out);
 
-		int add_frame(AVFrame *frame, int index);
+    inline void registe_cb(on_filter_data cb_on_filter_data, on_filter_error cb_on_filter_error)
+    {
+        _on_filter_data = cb_on_filter_data;
+        _on_filter_error = cb_on_filter_error;
+    }
 
-		const AVRational get_time_base();
+    int start();
 
-	private:
-		void cleanup();
-		void filter_loop();
+    int stop();
 
+    int add_frame(AVFrame *frame, int index);
 
+    const AVRational get_time_base();
 
-	private:
-		FILTER_CTX _ctx_in_0;
-		FILTER_CTX _ctx_in_1;
-		FILTER_CTX _ctx_out;
+private:
+    void cleanup();
+    void filter_loop();
 
-		AVFilterGraph *_filter_graph;
+private:
+    FILTER_CTX _ctx_in_0;
+    FILTER_CTX _ctx_in_1;
+    FILTER_CTX _ctx_out;
 
-		on_filter_data _on_filter_data;
-		on_filter_error _on_filter_error;
+    AVFilterGraph *_filter_graph;
 
-		std::atomic_bool _inited;
-		std::atomic_bool _running;
+    on_filter_data _on_filter_data;
+    on_filter_error _on_filter_error;
 
-		std::thread _thread;
+    std::atomic_bool _inited;
+    std::atomic_bool _running;
 
-		std::mutex _mutex;
-		std::condition_variable _cond_var;
-		bool _cond_notify;
-	};
+    std::thread _thread;
 
-}
+    std::mutex _mutex;
+    std::condition_variable _cond_var;
+    bool _cond_notify;
+};
+} // namespace am
 
-#endif
+#endif

+ 241 - 216
libs/Recorder/filter_aresample.cpp

@@ -7,225 +7,250 @@
 #include "log_helper.h"
 
 namespace am {
+filter_aresample::filter_aresample()
+{
+    av_register_all();
+    avfilter_register_all();
+
+    memset(&_ctx_in, 0, sizeof(FILTER_CTX));
+    memset(&_ctx_out, 0, sizeof(FILTER_CTX));
+
+    _filter_graph = NULL;
+
+    _inited = false;
+    _running = false;
+
+    _cond_notify = false;
+
+    _index = -1;
+}
+
+filter_aresample::~filter_aresample()
+{
+    stop();
+    cleanup();
+}
+
+int filter_aresample::init(const FILTER_CTX &ctx_in, const FILTER_CTX &ctx_out, int index)
+{
+    int error = AE_NO;
+    int ret = 0;
+
+    if (_inited)
+        return AE_NO;
+
+    _index = index;
+
+    do {
+        _ctx_in = ctx_in;
+        _ctx_out = ctx_out;
+
+        _filter_graph = avfilter_graph_alloc();
+        if (!_filter_graph) {
+            error = AE_FILTER_ALLOC_GRAPH_FAILED;
+            break;
+        }
+
+        char layout_name[256] = {0};
+        av_get_channel_layout_string(layout_name, 256, ctx_out.nb_channel, ctx_out.channel_layout);
+
+        std::stringstream filter_desrcss;
+        filter_desrcss << "aresample=";
+        filter_desrcss << ctx_out.sample_rate;
+        filter_desrcss << ",aformat=sample_fmts=";
+        filter_desrcss << av_get_sample_fmt_name(ctx_out.sample_fmt);
+        filter_desrcss << ":channel_layouts=";
+        filter_desrcss << layout_name;
+
+        std::string filter_desrc = filter_desrcss.str();
+
+        _ctx_in.inout = avfilter_inout_alloc();
+        _ctx_out.inout = avfilter_inout_alloc();
+
+        char pad_args[512] = {0};
+
+        format_pad_arg(pad_args, 512, _ctx_in);
+
+        ret = avfilter_graph_create_filter(&_ctx_in.ctx,
+                                           avfilter_get_by_name("abuffer"),
+                                           "in",
+                                           pad_args,
+                                           NULL,
+                                           _filter_graph);
+        if (ret < 0) {
+            error = AE_FILTER_CREATE_FILTER_FAILED;
+            break;
+        }
+
+        ret = avfilter_graph_create_filter(&_ctx_out.ctx,
+                                           avfilter_get_by_name("abuffersink"),
+                                           "out",
+                                           NULL,
+                                           NULL,
+                                           _filter_graph);
+        if (ret < 0) {
+            error = AE_FILTER_CREATE_FILTER_FAILED;
+            break;
+        }
+
+        av_opt_set_bin(_ctx_out.ctx,
+                       "sample_fmts",
+                       (uint8_t *) &_ctx_out.sample_fmt,
+                       sizeof(_ctx_out.sample_fmt),
+                       AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_bin(_ctx_out.ctx,
+                       "channel_layouts",
+                       (uint8_t *) &_ctx_out.channel_layout,
+                       sizeof(_ctx_out.channel_layout),
+                       AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_bin(_ctx_out.ctx,
+                       "sample_rates",
+                       (uint8_t *) &_ctx_out.sample_rate,
+                       sizeof(_ctx_out.sample_rate),
+                       AV_OPT_SEARCH_CHILDREN);
+
+        _ctx_in.inout->name = av_strdup("in");
+        _ctx_in.inout->filter_ctx = _ctx_in.ctx;
+        _ctx_in.inout->pad_idx = 0;
+        _ctx_in.inout->next = NULL;
+
+        _ctx_out.inout->name = av_strdup("out");
+        _ctx_out.inout->filter_ctx = _ctx_out.ctx;
+        _ctx_out.inout->pad_idx = 0;
+        _ctx_out.inout->next = NULL;
+
+        ret = avfilter_graph_parse_ptr(_filter_graph,
+                                       filter_desrc.c_str(),
+                                       &_ctx_out.inout,
+                                       &_ctx_in.inout,
+                                       NULL);
+        if (ret < 0) {
+            error = AE_FILTER_PARSE_PTR_FAILED;
+            break;
+        }
+
+        ret = avfilter_graph_config(_filter_graph, NULL);
+        if (ret < 0) {
+            error = AE_FILTER_CONFIG_FAILED;
+            break;
+        }
+
+        _inited = true;
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("filter init failed:%s %d", err2str(error), ret);
+        cleanup();
+    }
+
+    return error;
+}
+
+int filter_aresample::start()
+{
+    if (!_inited)
+        return AE_NEED_INIT;
+
+    if (_running)
+        return AE_NO;
+
+    _running = true;
+    _thread = std::thread(std::bind(&filter_aresample::filter_loop, this));
+
+    return 0;
+}
+
+int filter_aresample::stop()
+{
+    if (!_inited || !_running)
+        return AE_NO;
+
+    _running = false;
+
+    _cond_notify = true;
+    _cond_var.notify_all();
+
+    if (_thread.joinable())
+        _thread.join();
+
+    return AE_NO;
+}
+
+int filter_aresample::add_frame(AVFrame *frame)
+{
+    std::unique_lock<std::mutex> lock(_mutex);
+
+    int error = AE_NO;
+    int ret = 0;
+
+    do {
+        int ret = av_buffersrc_add_frame_flags(_ctx_in.ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
+        if (ret < 0) {
+            error = AE_FILTER_ADD_FRAME_FAILED;
+            break;
+        }
+
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("add frame failed:%s ,%d", err2str(error), ret);
+    }
+
+    _cond_notify = true;
+    _cond_var.notify_all();
+
+    return error;
+}
+
+const AVRational filter_aresample::get_time_base()
+{
+    return av_buffersink_get_time_base(_ctx_out.ctx);
+}
+
+void filter_aresample::cleanup()
+{
+    if (_filter_graph)
+        avfilter_graph_free(&_filter_graph);
+
+    memset(&_ctx_in, 0, sizeof(FILTER_CTX));
+    memset(&_ctx_out, 0, sizeof(FILTER_CTX));
+
+    _inited = false;
+}
+
+void filter_aresample::filter_loop()
+{
+    AVFrame *frame = av_frame_alloc();
+
+    int ret = 0;
+    while (_running) {
+        std::unique_lock<std::mutex> lock(_mutex);
+        while (!_cond_notify && _running)
+            _cond_var.wait_for(lock, std::chrono::milliseconds(300));
 
-	filter_aresample::filter_aresample()
-	{
-		av_register_all();
-		avfilter_register_all();
+        while (_running && _cond_notify) {
+            ret = av_buffersink_get_frame(_ctx_out.ctx, frame);
+            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+                break;
+                ;
+            }
 
-		memset(&_ctx_in, 0, sizeof(FILTER_CTX));
-		memset(&_ctx_out, 0, sizeof(FILTER_CTX));
+            if (ret < 0) {
+                al_fatal("avfilter get frame error:%d", ret);
+                if (_on_filter_error)
+                    _on_filter_error(ret, _index);
+                break;
+            }
 
-		_filter_graph = NULL;
+            if (_on_filter_data)
+                _on_filter_data(frame, _index);
 
-		_inited = false;
-		_running = false;
+            av_frame_unref(frame);
+        }
 
-		_cond_notify = false;
+        _cond_notify = false;
+    }
 
-		_index = -1;
-	}
-
-
-	filter_aresample::~filter_aresample()
-	{
-		stop();
-		cleanup();
-	}
-
-	int filter_aresample::init(const FILTER_CTX & ctx_in, const FILTER_CTX & ctx_out, int index)
-	{
-		int error = AE_NO;
-		int ret = 0;
-
-		if (_inited) return AE_NO;
-
-		_index = index;
-
-		do {
-			_ctx_in = ctx_in;
-			_ctx_out = ctx_out;
-
-			_filter_graph = avfilter_graph_alloc();
-			if (!_filter_graph) {
-				error = AE_FILTER_ALLOC_GRAPH_FAILED;
-				break;
-			}
-
-			char layout_name[256] = { 0 };
-			av_get_channel_layout_string(layout_name, 256, ctx_out.nb_channel, ctx_out.channel_layout);
-
-
-			std::stringstream filter_desrcss;
-			filter_desrcss << "aresample=";
-			filter_desrcss << ctx_out.sample_rate;
-			filter_desrcss << ",aformat=sample_fmts=";
-			filter_desrcss << av_get_sample_fmt_name(ctx_out.sample_fmt);
-			filter_desrcss << ":channel_layouts=";
-			filter_desrcss << layout_name;
-
-			std::string filter_desrc = filter_desrcss.str();
-
-			_ctx_in.inout = avfilter_inout_alloc();
-			_ctx_out.inout = avfilter_inout_alloc();
-
-			char pad_args[512] = { 0 };
-
-			format_pad_arg(pad_args, 512, _ctx_in);
-
-			ret = avfilter_graph_create_filter(&_ctx_in.ctx, avfilter_get_by_name("abuffer"), "in", pad_args, NULL, _filter_graph);
-			if (ret < 0) {
-				error = AE_FILTER_CREATE_FILTER_FAILED;
-				break;
-			}
-
-			ret = avfilter_graph_create_filter(&_ctx_out.ctx, avfilter_get_by_name("abuffersink"), "out", NULL, NULL, _filter_graph);
-			if (ret < 0) {
-				error = AE_FILTER_CREATE_FILTER_FAILED;
-				break;
-			}
-
-			av_opt_set_bin(_ctx_out.ctx, "sample_fmts", (uint8_t*)&_ctx_out.sample_fmt, sizeof(_ctx_out.sample_fmt), AV_OPT_SEARCH_CHILDREN);
-			av_opt_set_bin(_ctx_out.ctx, "channel_layouts", (uint8_t*)&_ctx_out.channel_layout, sizeof(_ctx_out.channel_layout), AV_OPT_SEARCH_CHILDREN);
-			av_opt_set_bin(_ctx_out.ctx, "sample_rates", (uint8_t*)&_ctx_out.sample_rate, sizeof(_ctx_out.sample_rate), AV_OPT_SEARCH_CHILDREN);
-
-			_ctx_in.inout->name = av_strdup("in");
-			_ctx_in.inout->filter_ctx = _ctx_in.ctx;
-			_ctx_in.inout->pad_idx = 0;
-			_ctx_in.inout->next = NULL;
-
-			_ctx_out.inout->name = av_strdup("out");
-			_ctx_out.inout->filter_ctx = _ctx_out.ctx;
-			_ctx_out.inout->pad_idx = 0;
-			_ctx_out.inout->next = NULL;
-
-			ret = avfilter_graph_parse_ptr(_filter_graph, filter_desrc.c_str(), &_ctx_out.inout, &_ctx_in.inout, NULL);
-			if (ret < 0) {
-				error = AE_FILTER_PARSE_PTR_FAILED;
-				break;
-			}
-
-			ret = avfilter_graph_config(_filter_graph, NULL);
-			if (ret < 0) {
-				error = AE_FILTER_CONFIG_FAILED;
-				break;
-			}
-
-			_inited = true;
-		} while (0);
-
-		if (error != AE_NO) {
-			al_debug("filter init failed:%s %d", err2str(error), ret);
-			cleanup();
-		}
-
-		return error;
-	}
-
-	int filter_aresample::start()
-	{
-		if (!_inited)
-			return AE_NEED_INIT;
-
-		if (_running)
-			return AE_NO;
-
-		_running = true;
-		_thread = std::thread(std::bind(&filter_aresample::filter_loop, this));
-
-		return 0;
-	}
-
-	int filter_aresample::stop()
-	{
-		if (!_inited || !_running)
-			return AE_NO;
-
-		_running = false;
-
-		_cond_notify = true;
-		_cond_var.notify_all();
-
-		if (_thread.joinable())
-			_thread.join();
-
-		return AE_NO;
-	}
-
-	int filter_aresample::add_frame(AVFrame * frame)
-	{
-		std::unique_lock<std::mutex> lock(_mutex);
-
-		int error = AE_NO;
-		int ret = 0;
-
-		do {
-			int ret = av_buffersrc_add_frame_flags(_ctx_in.ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
-			if (ret < 0) {
-				error = AE_FILTER_ADD_FRAME_FAILED;
-				break;
-			}
-
-		} while (0);
-
-		if (error != AE_NO) {
-			al_debug("add frame failed:%s ,%d", err2str(error), ret);
-		}
-
-		_cond_notify = true;
-		_cond_var.notify_all();
-
-		return error;
-	}
-
-	const AVRational filter_aresample::get_time_base()
-	{
-		return av_buffersink_get_time_base(_ctx_out.ctx);
-	}
-
-	void filter_aresample::cleanup()
-	{
-		if (_filter_graph)
-			avfilter_graph_free(&_filter_graph);
-
-		memset(&_ctx_in, 0, sizeof(FILTER_CTX));
-		memset(&_ctx_out, 0, sizeof(FILTER_CTX));
-
-		_inited = false;
-	}
-
-	void filter_aresample::filter_loop()
-	{
-		AVFrame *frame = av_frame_alloc();
-
-		int ret = 0;
-		while (_running) {
-			std::unique_lock<std::mutex> lock(_mutex);
-			while (!_cond_notify && _running)
-				_cond_var.wait_for(lock, std::chrono::milliseconds(300));
-
-			while (_running && _cond_notify) {
-				ret = av_buffersink_get_frame(_ctx_out.ctx, frame);
-				if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-					break;;
-				}
-
-				if (ret < 0) {
-					al_fatal("avfilter get frame error:%d", ret);
-					if (_on_filter_error) _on_filter_error(ret, _index);
-					break;
-				}
-
-				if (_on_filter_data)
-					_on_filter_data(frame, _index);
-
-				av_frame_unref(frame);
-			}
-
-			_cond_notify = false;
-		}
-
-		av_frame_free(&frame);
-	}
-
-}
+    av_frame_free(&frame);
+}
+} // namespace am

+ 34 - 38
libs/Recorder/filter_aresample.h

@@ -4,56 +4,52 @@
 #include "filter.h"
 
 namespace am {
-	
-	class filter_aresample
-	{
-	public:
-		filter_aresample();
-		~filter_aresample();
+class filter_aresample
+{
+public:
+    filter_aresample();
+    ~filter_aresample();
 
-		int init(const FILTER_CTX &ctx_in, const FILTER_CTX &ctx_out, int index);
+    int init(const FILTER_CTX &ctx_in, const FILTER_CTX &ctx_out, int index);
 
-		inline void registe_cb(on_filter_data cb_on_filter_data, on_filter_error cb_on_filter_error) {
-			_on_filter_data = cb_on_filter_data;
-			_on_filter_error = cb_on_filter_error;
-		}
+    inline void registe_cb(on_filter_data cb_on_filter_data, on_filter_error cb_on_filter_error)
+    {
+        _on_filter_data = cb_on_filter_data;
+        _on_filter_error = cb_on_filter_error;
+    }
 
-		int start();
+    int start();
 
-		int stop();
+    int stop();
 
-		int add_frame(AVFrame *frame);
+    int add_frame(AVFrame *frame);
 
-		const AVRational get_time_base();
+    const AVRational get_time_base();
 
-	private:
-		void cleanup();
-		void filter_loop();
+private:
+    void cleanup();
+    void filter_loop();
 
+private:
+    int _index;
 
+    FILTER_CTX _ctx_in;
+    FILTER_CTX _ctx_out;
 
-	private:
-		int _index;
+    AVFilterGraph *_filter_graph;
 
-		FILTER_CTX _ctx_in;
-		FILTER_CTX _ctx_out;
+    on_filter_data _on_filter_data;
+    on_filter_error _on_filter_error;
 
-		AVFilterGraph *_filter_graph;
+    std::atomic_bool _inited;
+    std::atomic_bool _running;
 
-		on_filter_data _on_filter_data;
-		on_filter_error _on_filter_error;
+    std::thread _thread;
 
-		std::atomic_bool _inited;
-		std::atomic_bool _running;
+    std::mutex _mutex;
+    std::condition_variable _cond_var;
+    bool _cond_notify;
+};
+} // namespace am
 
-		std::thread _thread;
-
-		std::mutex _mutex;
-		std::condition_variable _cond_var;
-		bool _cond_notify;
-	};
-
-}
-
-
-#endif
+#endif

+ 149 - 144
libs/Recorder/hardware_acceleration.cpp

@@ -1,206 +1,211 @@
 #include "hardware_acceleration.h"
 
-#include <map>
 #include <algorithm>
+#include <map>
 
 #include "headers_ffmpeg.h"
 
 #include "d3d_helper.h"
+#include "error_define.h"
 #include "log_helper.h"
 #include "utils_string.h"
-#include "error_define.h"
-
 
 namespace am {
+static const std::map<_HARDWARE_TYPE, const char *> encoder_map = {{HARDWARE_TYPE_NVENC,
+                                                                    "Nvidia.NVENC"},
+                                                                   {HARDWARE_TYPE_QSV, "Intel.QSV"},
+                                                                   {HARDWARE_TYPE_AMF, "AMD.AMF"},
+                                                                   {HARDWARE_TYPE_VAAPI,
+                                                                    "FFmpeg.Vaapi"}};
 
-	static const std::map<_HARDWARE_TYPE, const char*> encoder_map = {
-		{ HARDWARE_TYPE_NVENC , "Nvidia.NVENC" },
-		{ HARDWARE_TYPE_QSV , "Intel.QSV" },
-		{ HARDWARE_TYPE_AMF , "AMD.AMF" },
-		{ HARDWARE_TYPE_VAAPI , "FFmpeg.Vaapi"}
-	};
-
-	static const std::list<std::string> nvenc_blacklist = {
-		"720M", "730M",  "740M",  "745M",  "820M",  "830M",
-		"840M", "845M",  "920M",  "930M",  "940M",  "945M",
-		"1030", "MX110", "MX130", "MX150", "MX230", "MX250",
-		"M520", "M500",  "P500",  "K620M"
-	};
-	
-
-	static bool get_encoder_name(HARDWARE_TYPE type, char name[ENCODER_NAME_LEN]);
+static const std::list<std::string> nvenc_blacklist = {"720M",  "730M",  "740M",  "745M",  "820M",
+                                                       "830M",  "840M",  "845M",  "920M",  "930M",
+                                                       "940M",  "945M",  "1030",  "MX110", "MX130",
+                                                       "MX150", "MX230", "MX250", "M520",  "M500",
+                                                       "P500",  "K620M"};
 
-	static bool is_nvenc_blacklist(std::string desc);
+static bool get_encoder_name(HARDWARE_TYPE type, char name[ENCODER_NAME_LEN]);
 
-	static bool is_nvenc_canload();
+static bool is_nvenc_blacklist(std::string desc);
 
-	static bool is_nvenc_support();
+static bool is_nvenc_canload();
 
-	static bool is_qsv_support();
+static bool is_nvenc_support();
 
-	static bool is_amf_support();
+static bool is_qsv_support();
 
-	static bool is_vaapi_support();
+static bool is_amf_support();
 
-	bool get_encoder_name(HARDWARE_TYPE type, char name[ENCODER_NAME_LEN]) {
+static bool is_vaapi_support();
 
-		if (encoder_map.find(type) == encoder_map.end()) return false;
+bool get_encoder_name(HARDWARE_TYPE type, char name[ENCODER_NAME_LEN])
+{
+    if (encoder_map.find(type) == encoder_map.end())
+        return false;
 
-		strcpy_s(name, ENCODER_NAME_LEN, utils_string::ascii_utf8(encoder_map.at(type)).c_str());
+    strcpy_s(name, ENCODER_NAME_LEN, utils_string::ascii_utf8(encoder_map.at(type)).c_str());
 
-		return true;
-	}
+    return true;
+}
 
-	bool is_nvenc_blacklist(std::string desc) {
-		for (auto itr = nvenc_blacklist.begin(); itr != nvenc_blacklist.end(); itr++) {
-			if (desc.find((*itr).c_str()) != std::string::npos)
-				return true;
-		}
+bool is_nvenc_blacklist(std::string desc)
+{
+    for (auto itr = nvenc_blacklist.begin(); itr != nvenc_blacklist.end(); itr++) {
+        if (desc.find((*itr).c_str()) != std::string::npos)
+            return true;
+    }
 
-		return false;
-	}
+    return false;
+}
 
-	bool is_nvenc_canload() {		
-		std::string module_name;
-		if (sizeof(void *) == 8) {
-			module_name = "nvEncodeAPI64.dll";
-		}
-		else {
-			module_name = "nvEncodeAPI.dll";
-		}
+bool is_nvenc_canload()
+{
+    std::string module_name;
+    if (sizeof(void *) == 8) {
+        module_name = "nvEncodeAPI64.dll";
+    } else {
+        module_name = "nvEncodeAPI.dll";
+    }
 
-		HMODULE hnvenc = GetModuleHandleA(module_name.c_str());
-		if (!hnvenc)
-			hnvenc = LoadLibraryA(module_name.c_str());
+    HMODULE hnvenc = GetModuleHandleA(module_name.c_str());
+    if (!hnvenc)
+        hnvenc = LoadLibraryA(module_name.c_str());
 
+    bool is_canload = !!hnvenc;
 
-		bool is_canload = !!hnvenc;
+    if (hnvenc)
+        FreeModule(hnvenc);
 
-		if (hnvenc) FreeModule(hnvenc);
+    return is_canload;
+}
 
-		return is_canload;
-	}
-
-	bool is_nvenc_support() {
-		bool is_support = false;
+bool is_nvenc_support()
+{
+    bool is_support = false;
 
 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
-		av_register_all();
+    av_register_all();
 #endif
-		do {
-			if (avcodec_find_encoder_by_name("nvenc_h264") == nullptr &&
-				avcodec_find_encoder_by_name("h264_nvenc") == nullptr)
-				break;
+    do {
+        if (avcodec_find_encoder_by_name("nvenc_h264") == nullptr
+            && avcodec_find_encoder_by_name("h264_nvenc") == nullptr)
+            break;
 
 #if defined(_WIN32)
-			int error = AE_NO;
-			auto adapters = d3d_helper::get_adapters(&error);
-			if (error != AE_NO || adapters.size() == 0)
-				break;
-
-			bool has_device = false;
-			for (std::list<IDXGIAdapter *>::iterator itr = adapters.begin(); itr != adapters.end(); itr++) {
-				IDXGIOutput *adapter_output = nullptr;
-				DXGI_ADAPTER_DESC adapter_desc = { 0 };
-				DXGI_OUTPUT_DESC adapter_output_desc = { 0 };
-
-				HRESULT hr = (*itr)->GetDesc(&adapter_desc);
-				
-				std::string strdesc = utils_string::unicode_ascii(adapter_desc.Description);
-				std::transform(strdesc.begin(), strdesc.end(), strdesc.begin(), ::toupper);
-
-				if (SUCCEEDED(hr) && (strdesc.find("NVIDIA") != std::string::npos) && !is_nvenc_blacklist(strdesc)) {
-					has_device = true;
-					break;
-				}
-			}
-
-			if(!has_device) break;
-			
-			if (!is_nvenc_canload()) break;
+        int error = AE_NO;
+        auto adapters = d3d_helper::get_adapters(&error);
+        if (error != AE_NO || adapters.size() == 0)
+            break;
+
+        bool has_device = false;
+        for (std::list<IDXGIAdapter *>::iterator itr = adapters.begin(); itr != adapters.end();
+             itr++) {
+            IDXGIOutput *adapter_output = nullptr;
+            DXGI_ADAPTER_DESC adapter_desc = {0};
+            DXGI_OUTPUT_DESC adapter_output_desc = {0};
+
+            HRESULT hr = (*itr)->GetDesc(&adapter_desc);
+
+            std::string strdesc = utils_string::unicode_ascii(adapter_desc.Description);
+            std::transform(strdesc.begin(), strdesc.end(), strdesc.begin(), ::toupper);
+
+            if (SUCCEEDED(hr) && (strdesc.find("NVIDIA") != std::string::npos)
+                && !is_nvenc_blacklist(strdesc)) {
+                has_device = true;
+                break;
+            }
+        }
+
+        if (!has_device)
+            break;
+
+        if (!is_nvenc_canload())
+            break;
 #else
-			/*
+        /*
 			if (!os_dlopen("libnvidia-encode.so.1"))
 				break;
 				*/
 #endif
 
-			is_support = true;
-		} while (0);
-
-		return is_support;
-	}
-
-	bool is_qsv_support() {
-		bool is_support = false;
+        is_support = true;
+    } while (0);
 
-		return is_support;
-	}
+    return is_support;
+}
 
-	bool is_amf_support() {
-		bool is_support = false;
+bool is_qsv_support()
+{
+    bool is_support = false;
 
-		return is_support;
-	}
+    return is_support;
+}
 
-	bool is_vaapi_support() {
-		bool is_support = false;
+bool is_amf_support()
+{
+    bool is_support = false;
 
-		return is_support;
-	}
+    return is_support;
+}
 
-	std::vector<std::string> hardware_acceleration::get_video_hardware_devices() {
-		std::vector<std::string> devices;
+bool is_vaapi_support()
+{
+    bool is_support = false;
 
-		enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
+    return is_support;
+}
 
-		while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) {
-			devices.push_back(av_hwdevice_get_type_name(type));
-			al_debug("%s",av_hwdevice_get_type_name(type));
-		}
+std::vector<std::string> hardware_acceleration::get_video_hardware_devices()
+{
+    std::vector<std::string> devices;
 
-		
-		AVCodec *nvenc = avcodec_find_encoder_by_name("nvenc_h264");
-		if(nvenc == nullptr)
-			nvenc = avcodec_find_encoder_by_name("h264_nvenc");
+    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
 
-		if (nvenc)
-			al_debug("nvenc support");
+    while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) {
+        devices.push_back(av_hwdevice_get_type_name(type));
+        al_debug("%s", av_hwdevice_get_type_name(type));
+    }
 
-		AVCodec *vaapi = avcodec_find_encoder_by_name("h264_qsv");
-		if (vaapi)
-			al_debug("qsv support");
+    AVCodec *nvenc = avcodec_find_encoder_by_name("nvenc_h264");
+    if (nvenc == nullptr)
+        nvenc = avcodec_find_encoder_by_name("h264_nvenc");
 
-		return devices;
-	}
+    if (nvenc)
+        al_debug("nvenc support");
 
-	std::list<HARDWARE_ENCODER> hardware_acceleration::get_supported_video_encoders() {
-		std::list<HARDWARE_ENCODER> encoders;
+    AVCodec *vaapi = avcodec_find_encoder_by_name("h264_qsv");
+    if (vaapi)
+        al_debug("qsv support");
 
-		HARDWARE_ENCODER encoder;
+    return devices;
+}
 
-		encoder.type = HARDWARE_TYPE_NVENC;
-		if (is_nvenc_support() && get_encoder_name(encoder.type, encoder.name)) {
-			encoders.push_back(encoder);
-		}
+std::list<HARDWARE_ENCODER> hardware_acceleration::get_supported_video_encoders()
+{
+    std::list<HARDWARE_ENCODER> encoders;
 
-		encoder.type = HARDWARE_TYPE_QSV;
-		if (is_qsv_support() && get_encoder_name(encoder.type, encoder.name)) {
-			encoders.push_back(encoder);
-		}
+    HARDWARE_ENCODER encoder;
 
-		encoder.type = HARDWARE_TYPE_AMF;
-		if (is_amf_support() && get_encoder_name(encoder.type, encoder.name)) {
-			encoders.push_back(encoder);
-		}
+    encoder.type = HARDWARE_TYPE_NVENC;
+    if (is_nvenc_support() && get_encoder_name(encoder.type, encoder.name)) {
+        encoders.push_back(encoder);
+    }
 
-		encoder.type = HARDWARE_TYPE_VAAPI;
-		if (is_vaapi_support() && get_encoder_name(encoder.type, encoder.name)) {
-			encoders.push_back(encoder);
-		}
+    encoder.type = HARDWARE_TYPE_QSV;
+    if (is_qsv_support() && get_encoder_name(encoder.type, encoder.name)) {
+        encoders.push_back(encoder);
+    }
 
+    encoder.type = HARDWARE_TYPE_AMF;
+    if (is_amf_support() && get_encoder_name(encoder.type, encoder.name)) {
+        encoders.push_back(encoder);
+    }
 
-		return encoders;
-	}
+    encoder.type = HARDWARE_TYPE_VAAPI;
+    if (is_vaapi_support() && get_encoder_name(encoder.type, encoder.name)) {
+        encoders.push_back(encoder);
+    }
 
-}
+    return encoders;
+}
+} // namespace am

+ 28 - 28
libs/Recorder/hardware_acceleration.h

@@ -1,37 +1,37 @@
 #ifndef HARDWARE_ACCELERATION
 #define HARDWARE_ACCELERATION
 
+#include <list>
 #include <string>
 #include <vector>
-#include <list>
 
 #define ENCODER_NAME_LEN 100
 
 namespace am {
-	typedef enum _HARDWARE_TYPE {
-		HARDWARE_TYPE_UNKNOWN,
-		HARDWARE_TYPE_NVENC,
-		HARDWARE_TYPE_QSV,
-		HARDWARE_TYPE_AMF,
-		HARDWARE_TYPE_VAAPI
-	}HARDWARE_TYPE;
-
-	typedef struct _HARDWARE_ENCODER {
-		HARDWARE_TYPE type;
-		char name[ENCODER_NAME_LEN];
-	}HARDWARE_ENCODER;
-
-	class hardware_acceleration
-	{
-	private:
-		hardware_acceleration(){}
-		~hardware_acceleration(){}
-
-	public:
-		static std::vector<std::string> get_video_hardware_devices();
-		static std::list<HARDWARE_ENCODER> get_supported_video_encoders();
-	};
-
-}
-
-#endif
+typedef enum _HARDWARE_TYPE {
+    HARDWARE_TYPE_UNKNOWN,
+    HARDWARE_TYPE_NVENC,
+    HARDWARE_TYPE_QSV,
+    HARDWARE_TYPE_AMF,
+    HARDWARE_TYPE_VAAPI
+} HARDWARE_TYPE;
+
+typedef struct _HARDWARE_ENCODER
+{
+    HARDWARE_TYPE type;
+    char name[ENCODER_NAME_LEN];
+} HARDWARE_ENCODER;
+
+class hardware_acceleration
+{
+private:
+    hardware_acceleration() {}
+    ~hardware_acceleration() {}
+
+public:
+    static std::vector<std::string> get_video_hardware_devices();
+    static std::list<HARDWARE_ENCODER> get_supported_video_encoders();
+};
+} // namespace am
+
+#endif

+ 14 - 13
libs/Recorder/headers_ffmpeg.h

@@ -1,22 +1,23 @@
 #pragma once
+
 extern "C" {
-#include <libavformat\avformat.h>
+#include <libavcodec\adts_parser.h>
 #include <libavcodec\avcodec.h>
 #include <libavdevice\avdevice.h>
-#include <libswscale\swscale.h>
-#include <libswresample\swresample.h>
-#include <libavutil\avassert.h>
-#include <libavutil\channel_layout.h>
-#include <libavutil\opt.h>
-#include <libavutil\mathematics.h>
-#include <libavutil\timestamp.h>
-#include <libavutil\error.h>
-#include <libavcodec\adts_parser.h>
-#include <libavutil\time.h>
 #include <libavfilter\avfilter.h>
 #include <libavfilter\buffersink.h>
 #include <libavfilter\buffersrc.h>
+#include <libavformat\avformat.h>
+#include <libavutil\avassert.h>
+#include <libavutil\channel_layout.h>
+#include <libavutil\error.h>
 #include <libavutil\imgutils.h>
-#include <libavutil\samplefmt.h>
 #include <libavutil\log.h>
-}
+#include <libavutil\mathematics.h>
+#include <libavutil\opt.h>
+#include <libavutil\samplefmt.h>
+#include <libavutil\time.h>
+#include <libavutil\timestamp.h>
+#include <libswresample\swresample.h>
+#include <libswscale\swscale.h>
+}

+ 9 - 12
libs/Recorder/headers_mmdevice.h

@@ -4,28 +4,25 @@
 
 #include <windows.h>
 
-#include <mmdeviceapi.h>
-#include <propkeydef.h>//must include before functiondiscoverykeys_devpkey
 #include <functiondiscoverykeys_devpkey.h>
+#include <mmdeviceapi.h>
+#include <propkeydef.h> //must include before functiondiscoverykeys_devpkey
 
-#include <wrl/client.h>
 #include <devicetopology.h>
+#include <wrl/client.h>
 
-#include <propsys.h>
 #include <AudioClient.h>
 #include <AudioPolicy.h>
+#include <propsys.h>
 
-class com_initialize {
+class com_initialize
+{
 public:
-	com_initialize() {
-		CoInitializeEx(NULL, COINIT_MULTITHREADED);
-	}
-	~com_initialize() {
-		CoUninitialize();
-	}
+    com_initialize() { CoInitializeEx(NULL, COINIT_MULTITHREADED); }
+    ~com_initialize() { CoUninitialize(); }
 };
 
 #define DEFAULT_AUDIO_INOUTPUT_NAME "Default"
 #define DEFAULT_AUDIO_INOUTPUT_ID "Default"
 
-#endif // _WIN32
+#endif // _WIN32

+ 39 - 40
libs/Recorder/log_helper.cpp

@@ -1,7 +1,7 @@
 #include "log_helper.h"
-#include <stdio.h>
-#include <stdarg.h>
 #include <share.h>
+#include <stdarg.h>
+#include <stdio.h>
 
 #include <mutex>
 
@@ -13,56 +13,55 @@ AMLog* AMLog::_log = NULL;
 std::mutex _lock;
 
 AMLog::AMLog(FILE* handle)
-	: _handle(handle)
+    : _handle(handle)
 {
-	_log = this;
+    _log = this;
 }
 
 AMLog::~AMLog()
 {
-	AMLOCK(_lock);
-	if (_log && _handle) {
-		fclose(_handle);
-		_log = NULL;
-	}
+    AMLOCK(_lock);
+    if (_log && _handle) {
+        fclose(_handle);
+        _log = NULL;
+    }
 }
 
 AMLog* AMLog::get(const char* path)
 {
-	if (_log || !path) {
-		return _log;
-	}
-	DWORD size = 0;
-	HANDLE file = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
-		NULL);
-	if (file != INVALID_HANDLE_VALUE) {
-		size = GetFileSize(file, NULL);
-		CloseHandle(file);
-	}
-	if (size != INVALID_FILE_SIZE && size > LOG_ROLL_SIZE) {
-		if (DeleteFileA(path) == FALSE) {
-			TCHAR roll_path[MAX_PATH];
-			sprintf_s(roll_path, MAX_PATH, "%s.1", path);
-			if (!MoveFileEx(path, roll_path, MOVEFILE_REPLACE_EXISTING)) {
-				return NULL;
-			}
-		}
-	}
-	FILE* handle = _fsopen(path, "a+", _SH_DENYNO);
-	if (!handle) {
-		return NULL;
-	}
-	_log = new AMLog(handle);
-	return _log;
+    if (_log || !path) {
+        return _log;
+    }
+    DWORD size = 0;
+    HANDLE file = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (file != INVALID_HANDLE_VALUE) {
+        size = GetFileSize(file, NULL);
+        CloseHandle(file);
+    }
+    if (size != INVALID_FILE_SIZE && size > LOG_ROLL_SIZE) {
+        if (DeleteFileA(path) == FALSE) {
+            TCHAR roll_path[MAX_PATH];
+            sprintf_s(roll_path, MAX_PATH, "%s.1", path);
+            if (!MoveFileEx(path, roll_path, MOVEFILE_REPLACE_EXISTING)) {
+                return NULL;
+            }
+        }
+    }
+    FILE* handle = _fsopen(path, "a+", _SH_DENYNO);
+    if (!handle) {
+        return NULL;
+    }
+    _log = new AMLog(handle);
+    return _log;
 }
 
 void AMLog::printf(const char* format, ...)
 {
-	AMLOCK(_lock);
-	va_list args;
+    AMLOCK(_lock);
+    va_list args;
 
-	va_start(args, format);
-	vfprintf(_handle, format, args);
-	va_end(args);
-	fflush(_handle);
+    va_start(args, format);
+    vfprintf(_handle, format, args);
+    va_end(args);
+    fflush(_handle);
 }

+ 57 - 45
libs/Recorder/log_helper.h

@@ -2,62 +2,74 @@
 #define AM_LOG
 
 #include <stdio.h>
-#include <time.h>
 #include <sys\timeb.h>
+#include <time.h>
 
 #include <windows.h>
 
-class AMLog {
+class AMLog
+{
 public:
-	~AMLog();
-	static AMLog* get(const char* path = NULL);
-	void printf(const char* format, ...);
+    ~AMLog();
+    static AMLog* get(const char* path = NULL);
+    void printf(const char* format, ...);
 
 private:
-	AMLog(FILE* handle);
+    AMLog(FILE* handle);
 
 private:
-	static AMLog* _log;
-	FILE* _handle;
+    static AMLog* _log;
+    FILE* _handle;
 };
 
-
 enum AM_LOG_TYPE {
-	AL_TYPE_DEBUG = 0,
-	AL_TYPE_INFO,
-	AL_TYPE_WARN,
-	AL_TYPE_ERROR,
-	AL_TYPE_FATAL,
+    AL_TYPE_DEBUG = 0,
+    AL_TYPE_INFO,
+    AL_TYPE_WARN,
+    AL_TYPE_ERROR,
+    AL_TYPE_FATAL,
 };
 
-static const char *AM_LOG_STR[] = { "DEBUG", "INFO", "WARN", "ERROR", "FATAL" };
-
-#define al_printf(type,format,datetime,ms,...)                                 \
-         printf("%s-%.3d [%s] [%s(%d)] " format "\n",  datetime,ms,type, __FUNCTION__,__LINE__, ## __VA_ARGS__)
-
-#define PRINT_LINE(type, format, datetime, ms, ...)                     \
-    printf("%s-%.3d [%s] [%s(%d)] " format "\n",  datetime,ms,type, __FUNCTION__,__LINE__, ## __VA_ARGS__)
-
-#define al_log(type,format,...) do{                                            \
-	struct _timeb now;                                                           \
-	struct tm today;                                                             \
-	char datetime_str[20];                                                       \
-	_ftime_s(&now);                                                              \
-	localtime_s(&today, &now.time);                                              \
-	strftime(datetime_str, 20, "%Y-%m-%d %H:%M:%S", &today);                     \
-	AMLog *am_log = AMLog::get();                                                \
-	if(am_log){                                                                     \
-		am_log->PRINT_LINE(AM_LOG_STR[type], format, datetime_str, now.millitm, ## __VA_ARGS__);  \
-	} else {                                                                      \
-		al_printf(AM_LOG_STR[type], format, datetime_str, now.millitm, ## __VA_ARGS__);  \
-	}                                                                             \
-}while (0)   
-
-
-#define al_debug(format, ...) al_log(AL_TYPE_DEBUG, format, ## __VA_ARGS__)
-#define al_info(format, ...) al_log(AL_TYPE_INFO, format, ## __VA_ARGS__)
-#define al_warn(format, ...) al_log(AL_TYPE_WARN, format, ## __VA_ARGS__)
-#define al_error(format, ...) al_log(AL_TYPE_ERROR, format, ## __VA_ARGS__)
-#define al_fatal(format, ...) al_log(AL_TYPE_FATAL, format, ## __VA_ARGS__)
-
-#endif
+static const char* AM_LOG_STR[] = {"DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
+
+#define al_printf(type, format, datetime, ms, ...) \
+    printf("%s-%.3d [%s] [%s(%d)] " format "\n", \
+           datetime, \
+           ms, \
+           type, \
+           __FUNCTION__, \
+           __LINE__, \
+           ##__VA_ARGS__)
+
+#define PRINT_LINE(type, format, datetime, ms, ...) \
+    printf("%s-%.3d [%s] [%s(%d)] " format "\n", \
+           datetime, \
+           ms, \
+           type, \
+           __FUNCTION__, \
+           __LINE__, \
+           ##__VA_ARGS__)
+
+#define al_log(type, format, ...) \
+    do { \
+        struct _timeb now; \
+        struct tm today; \
+        char datetime_str[20]; \
+        _ftime_s(&now); \
+        localtime_s(&today, &now.time); \
+        strftime(datetime_str, 20, "%Y-%m-%d %H:%M:%S", &today); \
+        AMLog* am_log = AMLog::get(); \
+        if (am_log) { \
+            am_log->PRINT_LINE(AM_LOG_STR[type], format, datetime_str, now.millitm, ##__VA_ARGS__); \
+        } else { \
+            al_printf(AM_LOG_STR[type], format, datetime_str, now.millitm, ##__VA_ARGS__); \
+        } \
+    } while (0)
+
+#define al_debug(format, ...) al_log(AL_TYPE_DEBUG, format, ##__VA_ARGS__)
+#define al_info(format, ...) al_log(AL_TYPE_INFO, format, ##__VA_ARGS__)
+#define al_warn(format, ...) al_log(AL_TYPE_WARN, format, ##__VA_ARGS__)
+#define al_error(format, ...) al_log(AL_TYPE_ERROR, format, ##__VA_ARGS__)
+#define al_fatal(format, ...) al_log(AL_TYPE_FATAL, format, ##__VA_ARGS__)
+
+#endif

+ 3 - 3
libs/Recorder/mul_db.h

@@ -13,16 +13,16 @@
 
 static inline float mul_to_db(const float mul)
 {
-	return (mul == 0.0f) ? -INFINITY : (20.0f * log10f(mul));
+    return (mul == 0.0f) ? -INFINITY : (20.0f * log10f(mul));
 }
 
 static inline float db_to_mul(const float db)
 {
-	return isfinite((double)db) ? powf(10.0f, db / 20.0f) : 0.0f;
+    return isfinite((double) db) ? powf(10.0f, db / 20.0f) : 0.0f;
 }
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
-#endif // !MUL_DB
+#endif // !MUL_DB

+ 60 - 57
libs/Recorder/muxer_define.h

@@ -4,60 +4,63 @@
 #include "encoder_video_define.h"
 
 namespace am {
-	typedef struct {
-		uint8_t *buff;
-		int size;
-		int sample_in;
-	}AUDIO_SAMPLE;
-
-	class encoder_video;
-	class record_desktop;
-	class sws_helper;
-
-	class encoder_aac;
-	class filter_amix;
-	class filter_aresample;
-	class record_audio;
-
-	typedef struct MUX_SETTING_T {
-		int v_frame_rate;
-		int v_bit_rate;
-		int v_width;
-		int v_height;
-		int v_out_width;
-		int v_out_height;
-		int v_qb;
-		ENCODER_VIDEO_ID v_encoder_id;
-
-		int a_nb_channel;
-		int a_sample_rate;
-		AVSampleFormat a_sample_fmt;
-		int a_bit_rate;
-	}MUX_SETTING;
-
-	typedef struct MUX_STREAM_T {
-		//common
-		AVStream *st;               // av stream
-		AVBitStreamFilterContext *filter; //pps|sps adt
-
-		uint64_t pre_pts;
-
-		MUX_SETTING setting;        // output setting
-
-		//video
-		encoder_video *v_enc;         // video encoder
-		record_desktop *v_src;      // video source
-		sws_helper *v_sws;          // video sws
-
-		//audio
-		encoder_aac *a_enc;                     // audio encoder
-		filter_amix *a_filter_amix;             // audio mixer
-		filter_aresample **a_filter_aresample;  // audio resamplers
-		int a_nb;							    // audio source num
-		record_audio **a_src;				    // audio sources
-		AUDIO_SAMPLE **a_samples;			    // audio sample data
-		AUDIO_SAMPLE **a_resamples;			    // audio resampled data
-	}MUX_STREAM;
-}
-
-#endif
+typedef struct
+{
+    uint8_t *buff;
+    int size;
+    int sample_in;
+} AUDIO_SAMPLE;
+
+class encoder_video;
+class record_desktop;
+class sws_helper;
+
+class encoder_aac;
+class filter_amix;
+class filter_aresample;
+class record_audio;
+
+typedef struct MUX_SETTING_T
+{
+    int v_frame_rate;
+    int v_bit_rate;
+    int v_width;
+    int v_height;
+    int v_out_width;
+    int v_out_height;
+    int v_qb;
+    ENCODER_VIDEO_ID v_encoder_id;
+
+    int a_nb_channel;
+    int a_sample_rate;
+    AVSampleFormat a_sample_fmt;
+    int a_bit_rate;
+} MUX_SETTING;
+
+typedef struct MUX_STREAM_T
+{
+    //common
+    AVStream *st;                     // av stream
+    AVBitStreamFilterContext *filter; //pps|sps adt
+
+    uint64_t pre_pts;
+
+    MUX_SETTING setting; // output setting
+
+    //video
+    encoder_video *v_enc;  // video encoder
+    record_desktop *v_src; // video source
+    sws_helper *v_sws;     // video sws
+
+    //audio
+    encoder_aac *a_enc;                    // audio encoder
+    filter_amix *a_filter_amix;            // audio mixer
+    filter_aresample **a_filter_aresample; // audio resamplers
+    int a_nb;                              // audio source num
+    record_audio **a_src;                  // audio sources
+    AUDIO_SAMPLE **a_samples;              // audio sample data
+    AUDIO_SAMPLE **a_resamples;            // audio resampled data
+} MUX_STREAM;
+} // namespace am
+
+#endif

Datei-Diff unterdrückt, da er zu groß ist
+ 796 - 756
libs/Recorder/muxer_ffmpeg.cpp


+ 51 - 58
libs/Recorder/muxer_ffmpeg.h

@@ -1,100 +1,93 @@
 #ifndef MUXER_FFMPEG
 #define MUXER_FFMPEG
 
-#include <thread>
-#include <list>
 #include <functional>
+#include <list>
 #include <math.h>
 #include <mutex>
+#include <thread>
 
 #include "muxer_file.h"
 
 #include "headers_ffmpeg.h"
 
 namespace am {
+class muxer_ffmpeg : public muxer_file
+{
+public:
+    muxer_ffmpeg();
+    ~muxer_ffmpeg();
 
-	class muxer_ffmpeg : public muxer_file
-	{
-	public:
-		muxer_ffmpeg();
-		~muxer_ffmpeg();
-
-		int init(
-			const char *output_file,
-			record_desktop *source_desktop,
-			record_audio ** source_audios,
-			const int source_audios_nb,
-			const MUX_SETTING_T &setting
-		);
-
-		int start();
-		int stop();
-
-		int pause();
-		int resume();
-
-	private:
-		void on_desktop_data(AVFrame *frame);
-
-		void on_desktop_error(int error);
-
-		void on_audio_data(AVFrame *frame, int index);
-
-		void on_audio_error(int error, int index);
+    int init(const char *output_file,
+             record_desktop *source_desktop,
+             record_audio **source_audios,
+             const int source_audios_nb,
+             const MUX_SETTING_T &setting);
 
-		void on_filter_amix_data(AVFrame *frame, int index);
+    int start();
+    int stop();
 
-		void on_filter_amix_error(int error, int index);
+    int pause();
+    int resume();
 
-		void on_filter_aresample_data(AVFrame * frame,int index);
+private:
+    void on_desktop_data(AVFrame *frame);
 
-		void on_filter_aresample_error(int error, int index);
+    void on_desktop_error(int error);
 
+    void on_audio_data(AVFrame *frame, int index);
 
+    void on_audio_error(int error, int index);
 
-		void on_enc_264_data(AVPacket *packet);
+    void on_filter_amix_data(AVFrame *frame, int index);
 
-		void on_enc_264_error(int error);
+    void on_filter_amix_error(int error, int index);
 
-		void on_enc_aac_data(AVPacket *packet);
+    void on_filter_aresample_data(AVFrame *frame, int index);
 
-		void on_enc_aac_error(int error);
+    void on_filter_aresample_error(int error, int index);
 
+    void on_enc_264_data(AVPacket *packet);
 
+    void on_enc_264_error(int error);
 
-		int alloc_oc(const char *output_file, const MUX_SETTING_T &setting);
+    void on_enc_aac_data(AVPacket *packet);
 
-		int add_video_stream(const MUX_SETTING_T &setting, record_desktop *source_desktop);
+    void on_enc_aac_error(int error);
 
-		int add_audio_stream(const MUX_SETTING_T &setting, record_audio ** source_audios, const int source_audios_nb);
+    int alloc_oc(const char *output_file, const MUX_SETTING_T &setting);
 
-		int open_output(const char *output_file, const MUX_SETTING_T &setting);
+    int add_video_stream(const MUX_SETTING_T &setting, record_desktop *source_desktop);
 
-		void cleanup_video();
-		void cleanup_audio();
-		void cleanup();
+    int add_audio_stream(const MUX_SETTING_T &setting,
+                         record_audio **source_audios,
+                         const int source_audios_nb);
 
-		uint64_t get_current_time();
+    int open_output(const char *output_file, const MUX_SETTING_T &setting);
 
-		int write_video(AVPacket *packet);
+    void cleanup_video();
+    void cleanup_audio();
+    void cleanup();
 
-		int write_audio(AVPacket *packet);
+    uint64_t get_current_time();
 
-	private:
-		struct MUX_STREAM_T *_v_stream, *_a_stream;
+    int write_video(AVPacket *packet);
 
-		AVOutputFormat *_fmt;
-		AVFormatContext *_fmt_ctx;
+    int write_audio(AVPacket *packet);
 
-		int64_t _base_time;
+private:
+    struct MUX_STREAM_T *_v_stream, *_a_stream;
 
-		char ff_error[4096];
+    AVOutputFormat *_fmt;
+    AVFormatContext *_fmt_ctx;
 
-		std::mutex _mutex;
-		std::mutex _time_mutex;
-	};
-}
+    int64_t _base_time;
 
+    char ff_error[4096];
 
+    std::mutex _mutex;
+    std::mutex _time_mutex;
+};
+} // namespace am
 
 #endif

+ 13 - 18
libs/Recorder/muxer_file.cpp

@@ -1,26 +1,21 @@
 #include "muxer_file.h"
 
 namespace am {
+muxer_file::muxer_file()
+{
+    _on_yuv_data = nullptr;
 
-	muxer_file::muxer_file()
-	{
-		_on_yuv_data = nullptr;
+    _inited = false;
+    _running = false;
+    _paused = false;
 
-		_inited = false;
-		_running = false;
-		_paused = false;
+    _have_a = false;
+    _have_v = false;
 
-		_have_a = false;
-		_have_v = false;
+    _preview_enabled = false;
 
-		_preview_enabled = false;
+    _output_file = "";
+}
 
-		_output_file = "";
-	}
-
-
-	muxer_file::~muxer_file()
-	{
-	}
-
-}
+muxer_file::~muxer_file() {}
+} // namespace am

+ 34 - 41
libs/Recorder/muxer_file.h

@@ -1,59 +1,52 @@
 #pragma once
 
-#include <functional>
 #include <atomic>
+#include <functional>
 #include <string>
 
 namespace am {
+class record_audio;
+class record_desktop;
 
-	class record_audio;
-	class record_desktop;
-
-	struct MUX_STREAM_T;
-	struct MUX_SETTING_T;
-
-	typedef std::function<void(const uint8_t *data, int size, int width, int height,int type)> cb_yuv_data;
-
-	class muxer_file
-	{
-	public:
-		muxer_file();
-		virtual ~muxer_file();
+struct MUX_STREAM_T;
+struct MUX_SETTING_T;
 
-		virtual int init(
-			const char *output_file,
-			record_desktop *source_desktop,
-			record_audio ** source_audios,
-			const int source_audios_nb,
-			const MUX_SETTING_T &setting
-		) = 0;
+typedef std::function<void(const uint8_t *data, int size, int width, int height, int type)>
+    cb_yuv_data;
 
-		virtual int start() = 0;
-		virtual int stop() = 0;
+class muxer_file
+{
+public:
+    muxer_file();
+    virtual ~muxer_file();
 
-		virtual int pause() = 0;
-		virtual int resume() = 0;
+    virtual int init(const char *output_file,
+                     record_desktop *source_desktop,
+                     record_audio **source_audios,
+                     const int source_audios_nb,
+                     const MUX_SETTING_T &setting)
+        = 0;
 
-		inline void registe_yuv_data(cb_yuv_data on_yuv_data) {
-			_on_yuv_data = on_yuv_data;
-		}
+    virtual int start() = 0;
+    virtual int stop() = 0;
 
-		inline void set_preview_enabled(bool enable) {
-			_preview_enabled = enable;
-		}
+    virtual int pause() = 0;
+    virtual int resume() = 0;
 
-	protected:
-		cb_yuv_data _on_yuv_data;
+    inline void registe_yuv_data(cb_yuv_data on_yuv_data) { _on_yuv_data = on_yuv_data; }
 
-		std::atomic_bool _inited;
-		std::atomic_bool _running;
-		std::atomic_bool _paused;
-		std::atomic_bool _preview_enabled;
+    inline void set_preview_enabled(bool enable) { _preview_enabled = enable; }
 
-		bool _have_v, _have_a;
+protected:
+    cb_yuv_data _on_yuv_data;
 
-		std::string _output_file;
-	};
+    std::atomic_bool _inited;
+    std::atomic_bool _running;
+    std::atomic_bool _paused;
+    std::atomic_bool _preview_enabled;
 
+    bool _have_v, _have_a;
 
-}
+    std::string _output_file;
+};
+} // namespace am

+ 19 - 22
libs/Recorder/record_audio.cpp

@@ -1,28 +1,25 @@
 #include "record_audio.h"
 
 namespace am {
-	record_audio::record_audio()
-	{
-		_running = false;
-		_inited = false;
-		_paused = false;
+record_audio::record_audio()
+{
+    _running = false;
+    _inited = false;
+    _paused = false;
 
-		_sample_rate = 48000;
-		_bit_rate = 3072000;
-		_channel_num = 2;
-		_channel_layout = av_get_default_channel_layout(_channel_num);
-		_bit_per_sample = _bit_rate / _sample_rate / _channel_num;
-		_fmt = AV_SAMPLE_FMT_FLT;
-		_on_data = nullptr;
-		_on_error = nullptr;
+    _sample_rate = 48000;
+    _bit_rate = 3072000;
+    _channel_num = 2;
+    _channel_layout = av_get_default_channel_layout(_channel_num);
+    _bit_per_sample = _bit_rate / _sample_rate / _channel_num;
+    _fmt = AV_SAMPLE_FMT_FLT;
+    _on_data = nullptr;
+    _on_error = nullptr;
 
-		_device_name = "";
-		_device_id = "";
-		_is_input = false;
-	}
-
-	record_audio::~record_audio()
-	{
-
-	}
+    _device_name = "";
+    _device_id = "";
+    _is_input = false;
 }
+
+record_audio::~record_audio() {}
+} // namespace am

+ 60 - 64
libs/Recorder/record_audio.h

@@ -6,92 +6,88 @@
 #include "headers_ffmpeg.h"
 
 #include <atomic>
-#include <thread>
 #include <functional>
 #include <string>
+#include <thread>
 
 namespace am {
-	typedef std::function<void(AVFrame *packet, int index)> cb_audio_data;
-	typedef std::function<void(int,int)> cb_audio_error;
+typedef std::function<void(AVFrame *packet, int index)> cb_audio_data;
+typedef std::function<void(int, int)> cb_audio_error;
+
+class record_audio
+{
+public:
+    record_audio();
+    virtual ~record_audio();
+
+    virtual int init(const std::string &device_name, const std::string &device_id, bool is_input) = 0;
+
+    virtual int start() = 0;
+
+    virtual int pause() = 0;
+
+    virtual int resume() = 0;
+
+    virtual int stop() = 0;
+
+    virtual const AVRational get_time_base() = 0;
+
+    virtual int64_t get_start_time() = 0;
+
+public:
+    inline bool is_recording() { return _running; }
+
+    inline int get_sample_rate() { return _sample_rate; }
 
-	class record_audio
-	{
-	public:
-		record_audio();
-		virtual ~record_audio();
+    inline int get_bit_rate() { return _bit_rate; }
 
-		virtual int init(const std::string &device_name,
-			const std::string &device_id,
-			bool is_input) = 0;
+    inline int get_bit_per_sample() { return _bit_per_sample; }
 
-		virtual int start() = 0;
-		
-		virtual int pause() = 0;
-		
-		virtual int resume() = 0;
-		
-		virtual int stop() = 0;
+    inline int get_channel_num() { return _channel_num; }
 
-		virtual const AVRational get_time_base() = 0;
+    inline int64_t av_get_channel_layout() { return _channel_layout; }
 
-		virtual int64_t get_start_time() = 0;
+    inline AVSampleFormat get_fmt() { return _fmt; }
 
-	public:
-		inline bool is_recording() { return _running; }
-		
-		inline int get_sample_rate() { return _sample_rate; }
-		
-		inline int get_bit_rate() { return _bit_rate; }
+    inline const std::string &get_device_name() { return _device_name; }
 
-		inline int get_bit_per_sample() { return _bit_per_sample; }
+    inline void registe_cb(cb_audio_data on_data, cb_audio_error on_error, int cb_extra_index = -1)
+    {
+        _on_data = on_data;
+        _on_error = on_error;
+        _cb_extra_index = cb_extra_index;
+    }
 
-		inline int get_channel_num() { return _channel_num; }
+protected:
+    std::atomic_bool _running;
+    std::atomic_bool _inited;
+    std::atomic_bool _paused;
 
-		inline int64_t av_get_channel_layout() { return _channel_layout; }
-		
-		inline AVSampleFormat get_fmt() { return _fmt; }
+    std::thread _thread;
 
-		inline const std::string & get_device_name() { return _device_name; }
+    int _sample_rate;
 
-		inline void registe_cb(
-			cb_audio_data on_data,
-			cb_audio_error on_error,
-			int cb_extra_index = -1) {
-			_on_data = on_data;
-			_on_error = on_error;
-			_cb_extra_index = cb_extra_index;
-		}
+    int _bit_rate;
 
-	protected:
-		std::atomic_bool _running;
-		std::atomic_bool _inited;
-		std::atomic_bool _paused;
+    int _channel_num;
 
-		std::thread _thread;
+    int64_t _channel_layout;
 
-		int _sample_rate;
-		
-		int _bit_rate;
+    int _bit_per_sample;
 
-		int _channel_num;
+    AVSampleFormat _fmt;
 
-		int64_t _channel_layout;
+    std::string _device_name;
+    std::string _device_id;
 
-		int _bit_per_sample;
-		
-		AVSampleFormat _fmt;
-		
-		std::string _device_name;
-		std::string _device_id;
+    bool _is_input;
 
-		bool _is_input;
+    cb_audio_error _on_error;
 
-		cb_audio_error _on_error;
-		
-		cb_audio_data _on_data;
+    cb_audio_data _on_data;
 
-		int _cb_extra_index;
-	};
-}
+    int _cb_extra_index;
+};
+} // namespace am
 
-#endif // !RECORD_AUDIO
+#endif // !RECORD_AUDIO

+ 6 - 6
libs/Recorder/record_audio_define.h

@@ -8,11 +8,11 @@
 *
 */
 typedef enum {
-	AT_AUDIO_NO = 0,
-	AT_AUDIO_WAVE,    ///< wave api
-	AT_AUDIO_WAS,     ///< wasapi(core audio)
-	AT_AUDIO_DSHOW,   ///< direct show api
-	AT_AUDIO_FFMPEG,  ///< ffmpeg api
-}RECORD_AUDIO_TYPES;
+    AT_AUDIO_NO = 0,
+    AT_AUDIO_WAVE,   ///< wave api
+    AT_AUDIO_WAS,    ///< wasapi(core audio)
+    AT_AUDIO_DSHOW,  ///< direct show api
+    AT_AUDIO_FFMPEG, ///< ffmpeg api
+} RECORD_AUDIO_TYPES;
 
 #endif // !RECORD_AUDIO_DEFINE

+ 236 - 239
libs/Recorder/record_audio_dshow.cpp

@@ -1,244 +1,241 @@
 #include "record_audio_dshow.h"
 
-#include "log_helper.h"
 #include "error_define.h"
+#include "log_helper.h"
 
 namespace am {
-
-	record_audio_dshow::record_audio_dshow()
-	{
-		av_register_all();
-		avdevice_register_all();
-
-		_fmt_ctx = NULL;
-		_input_fmt = NULL;
-		_codec_ctx = NULL;
-		_codec = NULL;
-
-		_stream_index = -1;
-	}
-
-
-	record_audio_dshow::~record_audio_dshow()
-	{
-		stop();
-		cleanup();
-	}
-
-	int record_audio_dshow::init(const std::string & device_name, const std::string &device_id, bool is_input)
-	{
-		int error = AE_NO;
-		int ret = 0;
-
-		if (_inited == true)
-			return error;
-
-		do {
-
-			_device_name = device_name;
-			_device_id = device_id;
-			_is_input = is_input;
-
-			_input_fmt = av_find_input_format("dshow");
-			if (!_input_fmt) {
-				error = AE_FFMPEG_FIND_INPUT_FMT_FAILED;
-				break;
-			}
-
-			_fmt_ctx = avformat_alloc_context();
-			ret = avformat_open_input(&_fmt_ctx, _device_name.c_str(), _input_fmt, NULL);
-			if (ret != 0) {
-				error = AE_FFMPEG_OPEN_INPUT_FAILED;
-				break;
-			}
-
-
-			ret = avformat_find_stream_info(_fmt_ctx, NULL);
-			if (ret < 0) {
-				error = AE_FFMPEG_FIND_STREAM_FAILED;
-				break;
-			}
-
-			int stream_index = -1;
-			for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
-				if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
-					stream_index = i;
-					break;
-				}
-			}
-
-			if (stream_index == -1) {
-				error = AE_FFMPEG_FIND_STREAM_FAILED;
-				break;
-			}
-
-			_stream_index = stream_index;
-			_codec_ctx = _fmt_ctx->streams[stream_index]->codec;
-			_codec = avcodec_find_decoder(_codec_ctx->codec_id);
-			if (_codec == NULL) {
-				error = AE_FFMPEG_FIND_DECODER_FAILED;
-				break;
-			}
-
-			ret = avcodec_open2(_codec_ctx, _codec, NULL);
-			if (ret != 0) {
-				error = AE_FFMPEG_OPEN_CODEC_FAILED;
-				break;
-			}
-
-			_inited = true;
-
-			_sample_rate = _codec_ctx->sample_rate;
-			_bit_rate = _codec_ctx->bit_rate;
-			_bit_per_sample = _codec_ctx->bits_per_coded_sample;
-			_channel_num = _codec_ctx->channels;
-			_fmt = _codec_ctx->sample_fmt;
-
-			_inited = true;
-		} while (0);
-
-		if (error != AE_NO) {
-			al_debug("%s,error:%d", err2str(error), ret);
-			cleanup();
-		}
-
-		return error;
-	}
-
-	int record_audio_dshow::start()
-	{
-		if (_running == true) {
-			al_warn("record audio dshow is already running");
-			return AE_NO;
-		}
-
-		if (_inited == false) {
-			return AE_NEED_INIT;
-		}
-
-
-		_running = true;
-		_thread = std::thread(std::bind(&record_audio_dshow::record_loop, this));
-
-		return AE_NO;
-	}
-
-	int record_audio_dshow::pause()
-	{
-		return 0;
-	}
-
-	int record_audio_dshow::resume()
-	{
-		return 0;
-	}
-
-	int record_audio_dshow::stop()
-	{
-		_running = false;
-		if (_thread.joinable())
-			_thread.join();
-
-		return AE_NO;
-	}
-
-	const AVRational record_audio_dshow::get_time_base()
-	{
-		if (_inited && _fmt_ctx && _stream_index != -1) {
-			return _fmt_ctx->streams[_stream_index]->time_base;
-		}
-		else {
-			return{ 1,AV_TIME_BASE };
-		}
-	}
-
-	int64_t record_audio_dshow::get_start_time()
-	{
-		return _fmt_ctx->streams[_stream_index]->start_time;
-	}
-
-	int record_audio_dshow::decode(AVFrame * frame, AVPacket * packet)
-	{
-		int ret = avcodec_send_packet(_codec_ctx, packet);
-		if (ret < 0) {
-			al_error("avcodec_send_packet failed:%d", ret);
-
-			return AE_FFMPEG_DECODE_FRAME_FAILED;
-		}
-
-		while (ret >= 0)
-		{
-			ret = avcodec_receive_frame(_codec_ctx, frame);
-			if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-				break;
-			}
-
-			if (ret < 0) {
-				return AE_FFMPEG_READ_FRAME_FAILED;
-			}
-
-			if (ret == 0 && _on_data)
-				_on_data(frame, _cb_extra_index);
-
-			av_frame_unref(frame);//need to do this? avcodec_receive_frame said will call unref before receive
-		}
-
-		return AE_NO;
-	}
-
-	void record_audio_dshow::record_loop()
-	{
-		int ret = 0;
-
-		AVPacket *packet = av_packet_alloc();
-
-		AVFrame *frame = av_frame_alloc();
-
-		while (_running == true) {
-			av_init_packet(packet);
-
-			ret = av_read_frame(_fmt_ctx, packet);
-
-			if (ret < 0) {
-				if (_on_error) _on_error(AE_FFMPEG_READ_FRAME_FAILED, _cb_extra_index);
-				break;
-			}
-
-			if (packet->stream_index == _stream_index) {
-				ret = decode(frame, packet);
-				if (ret != AE_NO) {
-					if (_on_error) _on_error(AE_FFMPEG_DECODE_FRAME_FAILED, _cb_extra_index);
-
-					al_fatal("decode pcm packet failed:%d", ret);
-					break;
-				}
-			}
-
-			av_packet_unref(packet);
-		}
-
-		//flush packet left in decoder
-		decode(frame, NULL);
-
-		av_packet_free(&packet);
-		av_frame_free(&frame);
-	}
-
-	void record_audio_dshow::cleanup()
-	{
-		if (_codec_ctx)
-			avcodec_close(_codec_ctx);
-
-		if (_fmt_ctx)
-			avformat_close_input(&_fmt_ctx);
-
-		_fmt_ctx = NULL;
-		_input_fmt = NULL;
-		_codec_ctx = NULL;
-		_codec = NULL;
-
-		_stream_index = -1;
-		_inited = false;
-	}
-
-}
+record_audio_dshow::record_audio_dshow()
+{
+    av_register_all();
+    avdevice_register_all();
+
+    _fmt_ctx = NULL;
+    _input_fmt = NULL;
+    _codec_ctx = NULL;
+    _codec = NULL;
+
+    _stream_index = -1;
+}
+
+record_audio_dshow::~record_audio_dshow()
+{
+    stop();
+    cleanup();
+}
+
+int record_audio_dshow::init(const std::string &device_name,
+                             const std::string &device_id,
+                             bool is_input)
+{
+    int error = AE_NO;
+    int ret = 0;
+
+    if (_inited == true)
+        return error;
+
+    do {
+        _device_name = device_name;
+        _device_id = device_id;
+        _is_input = is_input;
+
+        _input_fmt = av_find_input_format("dshow");
+        if (!_input_fmt) {
+            error = AE_FFMPEG_FIND_INPUT_FMT_FAILED;
+            break;
+        }
+
+        _fmt_ctx = avformat_alloc_context();
+        ret = avformat_open_input(&_fmt_ctx, _device_name.c_str(), _input_fmt, NULL);
+        if (ret != 0) {
+            error = AE_FFMPEG_OPEN_INPUT_FAILED;
+            break;
+        }
+
+        ret = avformat_find_stream_info(_fmt_ctx, NULL);
+        if (ret < 0) {
+            error = AE_FFMPEG_FIND_STREAM_FAILED;
+            break;
+        }
+
+        int stream_index = -1;
+        for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
+            if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+                stream_index = i;
+                break;
+            }
+        }
+
+        if (stream_index == -1) {
+            error = AE_FFMPEG_FIND_STREAM_FAILED;
+            break;
+        }
+
+        _stream_index = stream_index;
+        _codec_ctx = _fmt_ctx->streams[stream_index]->codec;
+        _codec = avcodec_find_decoder(_codec_ctx->codec_id);
+        if (_codec == NULL) {
+            error = AE_FFMPEG_FIND_DECODER_FAILED;
+            break;
+        }
+
+        ret = avcodec_open2(_codec_ctx, _codec, NULL);
+        if (ret != 0) {
+            error = AE_FFMPEG_OPEN_CODEC_FAILED;
+            break;
+        }
+
+        _inited = true;
+
+        _sample_rate = _codec_ctx->sample_rate;
+        _bit_rate = _codec_ctx->bit_rate;
+        _bit_per_sample = _codec_ctx->bits_per_coded_sample;
+        _channel_num = _codec_ctx->channels;
+        _fmt = _codec_ctx->sample_fmt;
+
+        _inited = true;
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("%s,error:%d", err2str(error), ret);
+        cleanup();
+    }
+
+    return error;
+}
+
+int record_audio_dshow::start()
+{
+    if (_running == true) {
+        al_warn("record audio dshow is already running");
+        return AE_NO;
+    }
+
+    if (_inited == false) {
+        return AE_NEED_INIT;
+    }
+
+    _running = true;
+    _thread = std::thread(std::bind(&record_audio_dshow::record_loop, this));
+
+    return AE_NO;
+}
+
+int record_audio_dshow::pause()
+{
+    return 0;
+}
+
+int record_audio_dshow::resume()
+{
+    return 0;
+}
+
+int record_audio_dshow::stop()
+{
+    _running = false;
+    if (_thread.joinable())
+        _thread.join();
+
+    return AE_NO;
+}
+
+const AVRational record_audio_dshow::get_time_base()
+{
+    if (_inited && _fmt_ctx && _stream_index != -1) {
+        return _fmt_ctx->streams[_stream_index]->time_base;
+    } else {
+        return {1, AV_TIME_BASE};
+    }
+}
+
+int64_t record_audio_dshow::get_start_time()
+{
+    return _fmt_ctx->streams[_stream_index]->start_time;
+}
+
+int record_audio_dshow::decode(AVFrame *frame, AVPacket *packet)
+{
+    int ret = avcodec_send_packet(_codec_ctx, packet);
+    if (ret < 0) {
+        al_error("avcodec_send_packet failed:%d", ret);
+
+        return AE_FFMPEG_DECODE_FRAME_FAILED;
+    }
+
+    while (ret >= 0) {
+        ret = avcodec_receive_frame(_codec_ctx, frame);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+            break;
+        }
+
+        if (ret < 0) {
+            return AE_FFMPEG_READ_FRAME_FAILED;
+        }
+
+        if (ret == 0 && _on_data)
+            _on_data(frame, _cb_extra_index);
+
+        av_frame_unref(
+            frame); //need to do this? avcodec_receive_frame said will call unref before receive
+    }
+
+    return AE_NO;
+}
+
+void record_audio_dshow::record_loop()
+{
+    int ret = 0;
+
+    AVPacket *packet = av_packet_alloc();
+
+    AVFrame *frame = av_frame_alloc();
+
+    while (_running == true) {
+        av_init_packet(packet);
+
+        ret = av_read_frame(_fmt_ctx, packet);
+
+        if (ret < 0) {
+            if (_on_error)
+                _on_error(AE_FFMPEG_READ_FRAME_FAILED, _cb_extra_index);
+            break;
+        }
+
+        if (packet->stream_index == _stream_index) {
+            ret = decode(frame, packet);
+            if (ret != AE_NO) {
+                if (_on_error)
+                    _on_error(AE_FFMPEG_DECODE_FRAME_FAILED, _cb_extra_index);
+
+                al_fatal("decode pcm packet failed:%d", ret);
+                break;
+            }
+        }
+
+        av_packet_unref(packet);
+    }
+
+    //flush packet left in decoder
+    decode(frame, NULL);
+
+    av_packet_free(&packet);
+    av_frame_free(&frame);
+}
+
+void record_audio_dshow::cleanup()
+{
+    if (_codec_ctx)
+        avcodec_close(_codec_ctx);
+
+    if (_fmt_ctx)
+        avformat_close_input(&_fmt_ctx);
+
+    _fmt_ctx = NULL;
+    _input_fmt = NULL;
+    _codec_ctx = NULL;
+    _codec = NULL;
+
+    _stream_index = -1;
+    _inited = false;
+}
+} // namespace am

+ 24 - 27
libs/Recorder/record_audio_dshow.h

@@ -5,39 +5,36 @@
 #include "record_audio.h"
 
 namespace am {
+class record_audio_dshow : public record_audio
+{
+public:
+    record_audio_dshow();
+    ~record_audio_dshow();
 
-	class record_audio_dshow :public record_audio
-	{
-	public:
-		record_audio_dshow();
-		~record_audio_dshow();
+    virtual int init(const std::string &device_name, const std::string &device_id, bool is_input);
 
-		virtual int init(const std::string &device_name,
-			const std::string &device_id,
-			bool is_input);
+    virtual int start();
 
-		virtual int start();
+    virtual int pause();
 
-		virtual int pause();
+    virtual int resume();
 
-		virtual int resume();
+    virtual int stop();
 
-		virtual int stop();
+    virtual const AVRational get_time_base();
+    virtual int64_t get_start_time();
 
-		virtual const AVRational get_time_base();
-		virtual int64_t get_start_time();
+private:
+    int decode(AVFrame *frame, AVPacket *packet);
+    void record_loop();
+    void cleanup();
 
-	private:
-		int decode(AVFrame *frame, AVPacket *packet);
-		void record_loop();
-		void cleanup();
-	private:
-		AVFormatContext *_fmt_ctx;
-		AVInputFormat *_input_fmt;
-		AVCodecContext *_codec_ctx;
-		AVCodec *_codec;
+private:
+    AVFormatContext *_fmt_ctx;
+    AVInputFormat *_input_fmt;
+    AVCodecContext *_codec_ctx;
+    AVCodec *_codec;
 
-		int _stream_index;
-	};
-
-}
+    int _stream_index;
+};
+} // namespace am

+ 28 - 30
libs/Recorder/record_audio_factory.cpp

@@ -1,43 +1,41 @@
 #include "record_audio_factory.h"
-#include "record_audio_wasapi.h"
 #include "record_audio_dshow.h"
+#include "record_audio_wasapi.h"
 
 #include "error_define.h"
 #include "log_helper.h"
 
-
-int record_audio_new(RECORD_AUDIO_TYPES type,am::record_audio **recorder)
+int record_audio_new(RECORD_AUDIO_TYPES type, am::record_audio **recorder)
 {
-	int err = AE_NO;
+    int err = AE_NO;
 
-	switch (type)
-	{
-	case AT_AUDIO_WAVE:
-		err = AE_UNSUPPORT;
-		break;
-	case AT_AUDIO_WAS:
-		*recorder = (am::record_audio *)new am::record_audio_wasapi();
-		break;
-	case AT_AUDIO_DSHOW:
-		*recorder = (am::record_audio *)new am::record_audio_dshow();
-		break;
-	case AT_AUDIO_FFMPEG:
-		err = AE_UNSUPPORT;
-		break;
-	default:
-		err = AE_UNSUPPORT;
-		break;
-	}
+    switch (type) {
+    case AT_AUDIO_WAVE:
+        err = AE_UNSUPPORT;
+        break;
+    case AT_AUDIO_WAS:
+        *recorder = (am::record_audio *) new am::record_audio_wasapi();
+        break;
+    case AT_AUDIO_DSHOW:
+        *recorder = (am::record_audio *) new am::record_audio_dshow();
+        break;
+    case AT_AUDIO_FFMPEG:
+        err = AE_UNSUPPORT;
+        break;
+    default:
+        err = AE_UNSUPPORT;
+        break;
+    }
 
-	return err;
+    return err;
 }
 
-void record_audio_destroy(am::record_audio ** recorder)
+void record_audio_destroy(am::record_audio **recorder)
 {
-	if (*recorder != nullptr) {
-		(*recorder)->stop();
-		delete *recorder;
-	}
+    if (*recorder != nullptr) {
+        (*recorder)->stop();
+        delete *recorder;
+    }
 
-	*recorder = nullptr;
-}
+    *recorder = nullptr;
+}

+ 1 - 2
libs/Recorder/record_audio_factory.h

@@ -13,7 +13,6 @@ int record_audio_new(RECORD_AUDIO_TYPES type, am::record_audio **recorder);
 * Destroy audio record context
 *
 */
-void record_audio_destroy(am::record_audio ** recorder);
+void record_audio_destroy(am::record_audio **recorder);
 
 #endif // !RECORD_AUDIO_FACTORY
-

+ 590 - 596
libs/Recorder/record_audio_wasapi.cpp

@@ -11,605 +11,599 @@
 #ifdef _WIN32
 
 #define NS_PER_SEC 1000000000
-#define REFTIMES_PER_SEC  NS_PER_SEC/100            //100ns per buffer unit
+#define REFTIMES_PER_SEC NS_PER_SEC / 100 //100ns per buffer unit
 
 #endif // _WIN32
 
-
 namespace am {
+record_audio_wasapi::record_audio_wasapi()
+{
+    _co_inited = false;
+
+    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    DWORD err = GetLastError();
+    if (hr != S_OK && err != S_OK)
+        al_error("%s,error:%s", err2str(AE_CO_INITED_FAILED), system_error::error2str(err).c_str());
+
+    _co_inited = (hr == S_OK || hr == S_FALSE); //if already initialize will return S_FALSE
+
+    _is_default = false;
+
+    _wfex = NULL;
+    _enumerator = nullptr;
+    _device = nullptr;
+    _capture_client = nullptr;
+    _capture = nullptr;
+    _render = nullptr;
+    _render_client = nullptr;
+
+    _capture_sample_count = 0;
+    _render_sample_count = 0;
+
+    _ready_event = NULL;
+    _stop_event = NULL;
+    _render_event = NULL;
+
+    _use_device_ts = false;
+
+    _start_time = 0;
+}
+
+record_audio_wasapi::~record_audio_wasapi()
+{
+    stop();
+
+    clean_wasapi();
+
+    if (_co_inited == true)
+        CoUninitialize();
+}
+
+void get_device_info(IMMDevice *device)
+{
+    HRESULT resSample;
+    IPropertyStore *store = nullptr;
+    PWAVEFORMATEX deviceFormatProperties;
+    PROPVARIANT prop;
+    resSample = device->OpenPropertyStore(STGM_READ, &store);
+    if (!FAILED(resSample)) {
+        resSample = store->GetValue(PKEY_AudioEngine_DeviceFormat, &prop);
+        if (!FAILED(resSample)) {
+            deviceFormatProperties = (PWAVEFORMATEX) prop.blob.pBlobData;
+            std::string device_sample = std::to_string(deviceFormatProperties->nSamplesPerSec);
+        }
+    }
+}
+
+#define KSAUDIO_SPEAKER_2POINT1 (KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY)
+
+#define OBS_KSAUDIO_SPEAKER_4POINT1 (KSAUDIO_SPEAKER_SURROUND | SPEAKER_LOW_FREQUENCY)
+
+int64_t record_audio_wasapi::convert_layout(DWORD layout, WORD channels)
+{
+    switch (layout) {
+    case KSAUDIO_SPEAKER_2POINT1:
+        return AV_CH_LAYOUT_SURROUND;
+    case KSAUDIO_SPEAKER_SURROUND:
+        return AV_CH_LAYOUT_4POINT0;
+    case OBS_KSAUDIO_SPEAKER_4POINT1:
+        return AV_CH_LAYOUT_4POINT1;
+    case KSAUDIO_SPEAKER_5POINT1_SURROUND:
+        return AV_CH_LAYOUT_5POINT1_BACK;
+    case KSAUDIO_SPEAKER_7POINT1_SURROUND:
+        return AV_CH_LAYOUT_7POINT1;
+    }
+
+    return av_get_default_channel_layout(channels);
+}
+
+void record_audio_wasapi::init_format(WAVEFORMATEX *wfex)
+{
+    DWORD layout = 0;
+
+    if (wfex->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
+        WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE *) wfex;
+        layout = ext->dwChannelMask;
+    }
+
+    _channel_layout = convert_layout(layout, wfex->nChannels);
+    _sample_rate = wfex->nSamplesPerSec;
+    _bit_rate = wfex->nAvgBytesPerSec;
+    _bit_per_sample = wfex->wBitsPerSample;
+    _channel_num = wfex->nChannels;
+
+    //wasapi is always flt
+    _fmt = AV_SAMPLE_FMT_FLT;
+}
+
+int record_audio_wasapi::init_render()
+{
+    int error = AE_NO;
+    HRESULT res = S_OK;
+
+    do {
+        res = _device->Activate(__uuidof(IAudioClient),
+                                CLSCTX_ALL,
+                                nullptr,
+                                (void **) &_render_client);
+
+        if (FAILED(res)) {
+            error = AE_CO_ACTIVE_DEVICE_FAILED;
+            break;
+        }
+
+        WAVEFORMATEX *wfex;
+        res = _render_client->GetMixFormat(&wfex);
+        if (FAILED(res)) {
+            error = AE_CO_GET_FORMAT_FAILED;
+            break;
+        }
+
+        res = _render_client->Initialize(AUDCLNT_SHAREMODE_SHARED,
+                                         AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+                                         REFTIMES_PER_SEC,
+                                         0,
+                                         wfex,
+                                         nullptr);
+
+        CoTaskMemFree(wfex);
+        if (FAILED(res)) {
+            error = AE_CO_AUDIOCLIENT_INIT_FAILED;
+            break;
+        }
+
+        /* Silent loopback fix. Prevents audio stream from stopping and */
+        /* messing up timestamps and other weird glitches during silence */
+        /* by playing a silent sample all over again. */
+
+        res = _render_client->GetService(__uuidof(IAudioRenderClient), (void **) &_render);
+        if (FAILED(res)) {
+            error = AE_CO_GET_CAPTURE_FAILED;
+            break;
+        }
+
+        _render_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+        if (!_render_event) {
+            error = AE_CO_CREATE_EVENT_FAILED;
+            break;
+        }
+
+        res = _render_client->SetEventHandle(_render_event);
+        if (FAILED(res)) {
+            error = AE_CO_SET_EVENT_FAILED;
+            break;
+        }
+
+        //pre fill a single silent buffer
+        res = _render_client->GetBufferSize(&_render_sample_count);
+        if (FAILED(res)) {
+            error = AE_CO_GET_VALUE_FAILED;
+            break;
+        }
+
+        uint8_t *buffer = NULL;
+        res = _render->GetBuffer(_render_sample_count, &buffer);
+        if (FAILED(res)) {
+            error = AE_CO_GET_VALUE_FAILED;
+            break;
+        }
+
+        res = _render->ReleaseBuffer(_render_sample_count, AUDCLNT_BUFFERFLAGS_SILENT);
+        if (FAILED(res)) {
+            error = AE_CO_RELEASE_BUFFER_FAILED;
+            break;
+        }
+    } while (0);
+
+    if (error != AE_NO)
+        al_error("init render failed(%ld), %s,lasterror:%lu", res, err2str(error), GetLastError());
+
+    return error;
+}
+
+int record_audio_wasapi::init(const std::string &device_name,
+                              const std::string &device_id,
+                              bool is_input)
+{
+    int error = AE_NO;
+    HRESULT hr = S_OK;
+
+    al_info("wasapi start to initialize in %s mode with: %s",
+            is_input ? "input" : "output",
+            device_name.c_str());
+
+    if (_co_inited == false) {
+        return AE_CO_INITED_FAILED;
+    }
+
+    if (_inited == true) {
+        return AE_NO;
+    }
+
+    _device_name = device_name;
+    _device_id = device_id;
+    _is_input = is_input;
+    _is_default = (utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_ID).compare(_device_id) == 0);
+
+    do {
+        hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
+                              NULL,
+                              CLSCTX_ALL,
+                              __uuidof(IMMDeviceEnumerator),
+                              (void **) &_enumerator);
+
+        if (FAILED(hr)) {
+            error = AE_CO_CREATE_FAILED;
+            break;
+        }
+
+        if (_is_default) {
+            hr = _enumerator->GetDefaultAudioEndpoint(is_input ? eCapture : eRender,
+                                                      is_input ? eCommunications : eConsole,
+                                                      &_device);
+        } else {
+            hr = _enumerator->GetDevice(utils_string::utf8_unicode(_device_id).c_str(), &_device);
+        }
+
+        if (hr != S_OK) {
+            error = AE_CO_GETENDPOINT_FAILED;
+            break;
+        }
+
+        get_device_info(_device);
+
+        hr = _device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void **) &_capture_client);
+        if (hr != S_OK) {
+            error = AE_CO_ACTIVE_DEVICE_FAILED;
+            break;
+        }
+
+        hr = _capture_client->GetMixFormat(&_wfex);
+        if (hr != S_OK) {
+            error = AE_CO_GET_FORMAT_FAILED;
+            break;
+        }
+
+        init_format(_wfex);
+
+        DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
+        if (_is_input == false)
+            flags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
+
+        hr = _capture_client->Initialize(AUDCLNT_SHAREMODE_SHARED,
+                                         flags,
+                                         REFTIMES_PER_SEC,
+                                         0,
+                                         _wfex,
+                                         NULL);
+
+        // AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED
+        // https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient-initialize
+        if (hr != S_OK) {
+            error = AE_CO_AUDIOCLIENT_INIT_FAILED;
+            break;
+        }
+
+        //For ouotput mode,ready event will not signal when there is nothing rendering
+        //We run a render thread and render silent pcm data all time
+        if (!_is_input) {
+            error = init_render();
+            if (error != AE_NO)
+                break;
+        }
+
+        hr = _capture_client->GetBufferSize(&_capture_sample_count);
+        if (hr != S_OK) {
+            error = AE_CO_GET_VALUE_FAILED;
+            break;
+        }
+
+        hr = _capture_client->GetService(__uuidof(IAudioCaptureClient), (void **) &_capture);
+        if (hr != S_OK) {
+            error = AE_CO_GET_CAPTURE_FAILED;
+            break;
+        }
+
+        _ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+        if (!_ready_event) {
+            error = AE_CO_CREATE_EVENT_FAILED;
+            break;
+        }
+
+        _stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+        if (!_stop_event) {
+            error = AE_CO_CREATE_EVENT_FAILED;
+            break;
+        }
+
+        hr = _capture_client->SetEventHandle(_ready_event);
+        if (hr != S_OK) {
+            error = AE_CO_SET_EVENT_FAILED;
+            break;
+        }
+
+        _inited = true;
+
+    } while (0);
+
+    if (error != AE_NO) {
+        al_error("wasapi initialize failed,%s,error:%lu,hr:%lld",
+                 err2str(error),
+                 GetLastError(),
+                 hr);
+        clean_wasapi();
+    }
+
+    return error;
+}
+
+int record_audio_wasapi::start()
+{
+    if (_running == true) {
+        al_warn("audio record is already running");
+        return AE_NO;
+    }
+
+    if (_inited == false)
+        return AE_NEED_INIT;
+
+    HRESULT hr = S_OK;
+
+    if (!_is_input) {
+        hr = _render_client->Start();
+        if (FAILED(hr)) {
+            al_error("%s,error:%lu", err2str(AE_CO_START_FAILED), GetLastError());
+            return AE_CO_START_FAILED;
+        }
+    }
+
+    hr = _capture_client->Start();
+    if (hr != S_OK) {
+        al_error("%s,error:%lu", err2str(AE_CO_START_FAILED), GetLastError());
+        return AE_CO_START_FAILED;
+    }
+
+    _start_time = av_gettime_relative();
+
+    _running = true;
+
+    if (!_is_input) {
+        _render_thread = std::thread(std::bind(&record_audio_wasapi::render_loop, this));
+    }
+
+    _thread = std::thread(std::bind(&record_audio_wasapi::record_loop, this));
+
+    return AE_NO;
+}
+
+int record_audio_wasapi::pause()
+{
+    _paused = true;
+    return AE_NO;
+}
+
+int record_audio_wasapi::resume()
+{
+    _paused = false;
+    return AE_NO;
+}
+
+int record_audio_wasapi::stop()
+{
+    _running = false;
+    SetEvent(_stop_event);
+
+    if (_render_thread.joinable())
+        _render_thread.join();
+
+    if (_thread.joinable())
+        _thread.join();
+
+    if (_capture_client)
+        _capture_client->Stop();
+
+    if (_render_client)
+        _render_client->Stop();
+
+    return AE_NO;
+}
+
+const AVRational record_audio_wasapi::get_time_base()
+{
+    if (_use_device_ts)
+        return {1, NS_PER_SEC};
+    else
+        return {1, AV_TIME_BASE};
+}
+
+int64_t record_audio_wasapi::get_start_time()
+{
+    return _start_time;
+}
+
+void record_audio_wasapi::process_data(AVFrame *frame,
+                                       uint8_t *data,
+                                       uint32_t sample_count,
+                                       uint64_t device_ts)
+{
+    int sample_size = _bit_per_sample / 8 * _channel_num;
+
+    //wasapi time unit is 100ns,so time base is NS_PER_SEC
+    frame->pts = _use_device_ts ? device_ts * 100 : av_gettime_relative();
+
+    if (_use_device_ts == false) {
+        frame->pts -= (int64_t) sample_count * NS_PER_SEC / (int64_t) _sample_rate / 100;
+    }
+
+    frame->pkt_dts = frame->pts;
+    frame->nb_samples = sample_count;
+    frame->format = _fmt;
+    frame->sample_rate = _sample_rate;
+    frame->channels = _channel_num;
+    frame->pkt_size = sample_count * sample_size;
+
+    av_samples_fill_arrays(frame->data, frame->linesize, data, _channel_num, sample_count, _fmt, 1);
+
+    if (_on_data)
+        _on_data(frame, _cb_extra_index);
+}
+
+int record_audio_wasapi::do_record(AVFrame *frame)
+{
+    HRESULT res = S_OK;
+    LPBYTE buffer = NULL;
+    DWORD flags = 0;
+    uint32_t sample_count = 0;
+    UINT64 pos, ts;
+    int error = AE_NO;
+
+    while (_running) {
+        res = _capture->GetNextPacketSize(&sample_count);
+
+        if (FAILED(res)) {
+            if (res != AUDCLNT_E_DEVICE_INVALIDATED)
+                al_error("GetNextPacketSize failed: %lX", res);
+            error = AE_CO_GET_PACKET_FAILED;
+            break;
+        }
+
+        if (!sample_count)
+            break;
+
+        buffer = NULL;
+        res = _capture->GetBuffer(&buffer, &sample_count, &flags, &pos, &ts);
+        if (FAILED(res)) {
+            if (res != AUDCLNT_E_DEVICE_INVALIDATED)
+                al_error("GetBuffer failed: %lX", res);
+            error = AE_CO_GET_BUFFER_FAILED;
+            break;
+        }
+
+        //input mode do not have silent data flag do nothing here
+        if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
+            //al_warn("on slient data %d", sample_count);
+        }
+
+        if (buffer) {
+            process_data(frame, buffer, sample_count, ts);
+        } else {
+            al_error("buffer invalid is");
+        }
+
+        _capture->ReleaseBuffer(sample_count);
+    }
+
+    return error;
+}
+
+void record_audio_wasapi::render_loop()
+{
+    HANDLE events[2] = {_stop_event, _render_event};
+
+    HRESULT res = S_OK;
+    uint8_t *pData = NULL;
+    uint32_t padding_count = 0;
+
+    while (_running && WaitForMultipleObjects(2, events, FALSE, INFINITE) != WAIT_OBJECT_0) {
+        res = _render_client->GetCurrentPadding(&padding_count);
+        if (FAILED(res)) {
+            break;
+        }
+
+        if (padding_count == _render_sample_count) {
+            if (_on_error)
+                _on_error(AE_CO_PADDING_UNEXPECTED, _cb_extra_index);
+            break;
+        }
+
+        res = _render->GetBuffer(_render_sample_count - padding_count, &pData);
+        if (FAILED(res)) {
+            if (_on_error)
+                _on_error(AE_CO_GET_BUFFER_FAILED, _cb_extra_index);
+            break;
+        }
+
+        res = _render->ReleaseBuffer(_render_sample_count - padding_count,
+                                     AUDCLNT_BUFFERFLAGS_SILENT);
+        if (FAILED(res)) {
+            if (_on_error)
+                _on_error(AE_CO_RELEASE_BUFFER_FAILED, _cb_extra_index);
+            break;
+        }
+    }
+}
+
+void record_audio_wasapi::record_loop()
+{
+    AVFrame *frame = av_frame_alloc();
+
+    HANDLE events[2] = {_stop_event, _ready_event};
+
+    // while,sys will never not signal this ready_event in windows7,
+    // and only signal when something is rendring,so we just wait 10ms for speaker
+    DWORD dur = _is_input ? INFINITE : 10;
+
+    int error = AE_NO;
+    while (_running) {
+        if (WaitForMultipleObjects(2, events, FALSE, dur) == WAIT_OBJECT_0)
+            break;
+
+        if ((error = do_record(frame)) != AE_NO) {
+            if (_on_error)
+                _on_error(error, _cb_extra_index);
+            break;
+        }
+    } //while(_running)
+
+    av_frame_free(&frame);
+}
+
+void record_audio_wasapi::clean_wasapi()
+{
+    if (_wfex)
+        CoTaskMemFree(_wfex);
+    _wfex = NULL;
+
+    if (_enumerator)
+        _enumerator->Release();
+    _enumerator = nullptr;
+
+    if (_device)
+        _device->Release();
+    _device = nullptr;
+
+    if (_capture_client)
+        _capture_client->Release();
+    _capture_client = nullptr;
+
+    if (_render_client)
+        _render_client->Release();
+    _render_client = nullptr;
+
+    if (_capture)
+        _capture->Release();
+    _capture = nullptr;
+
+    if (_render)
+        _render->Release();
+    _render = nullptr;
+
+    if (_ready_event)
+        CloseHandle(_ready_event);
+    _ready_event = NULL;
+
+    if (_stop_event)
+        CloseHandle(_stop_event);
+    _stop_event = NULL;
+
+    if (_render_event)
+        CloseHandle(_render_event);
+    _render_event = NULL;
+
+    if (_co_inited == true)
+        CoUninitialize();
 
-	record_audio_wasapi::record_audio_wasapi()
-	{
-		_co_inited = false;
-
-		HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
-		DWORD err = GetLastError();
-		if (hr != S_OK && err != S_OK)
-			al_error("%s,error:%s",err2str(AE_CO_INITED_FAILED), system_error::error2str(err).c_str());
-
-		_co_inited = (hr == S_OK || hr == S_FALSE);//if already initialize will return S_FALSE
-
-		_is_default = false;
-
-		_wfex = NULL;
-		_enumerator = nullptr;
-		_device = nullptr;
-		_capture_client = nullptr;
-		_capture = nullptr;
-		_render = nullptr;
-		_render_client = nullptr;
-
-		_capture_sample_count = 0;
-		_render_sample_count = 0;
-
-		_ready_event = NULL;
-		_stop_event = NULL;
-		_render_event = NULL;
-
-		_use_device_ts = false;
-
-		_start_time = 0;
-	}
-
-	record_audio_wasapi::~record_audio_wasapi()
-	{
-		stop();
-
-		clean_wasapi();
-
-		if(_co_inited == true)
-			CoUninitialize();
-	}
-
-	void get_device_info(IMMDevice *device) {
-		HRESULT resSample;
-		IPropertyStore *store = nullptr;
-		PWAVEFORMATEX deviceFormatProperties;
-		PROPVARIANT prop;
-		resSample = device->OpenPropertyStore(STGM_READ, &store);
-		if (!FAILED(resSample)) {
-			resSample =
-				store->GetValue(PKEY_AudioEngine_DeviceFormat, &prop);
-			if (!FAILED(resSample)) {
-				deviceFormatProperties =
-					(PWAVEFORMATEX)prop.blob.pBlobData;
-				std::string device_sample = std::to_string(
-					deviceFormatProperties->nSamplesPerSec);
-			}
-		}
-	}
-
-#define KSAUDIO_SPEAKER_2POINT1     (KSAUDIO_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY)
-
-#define OBS_KSAUDIO_SPEAKER_4POINT1 \
-	(KSAUDIO_SPEAKER_SURROUND | SPEAKER_LOW_FREQUENCY)
-
-	int64_t record_audio_wasapi::convert_layout(DWORD layout, WORD channels)
-	{
-		switch (layout) {
-		case KSAUDIO_SPEAKER_2POINT1:
-			return AV_CH_LAYOUT_SURROUND;
-		case KSAUDIO_SPEAKER_SURROUND:
-			return AV_CH_LAYOUT_4POINT0;
-		case OBS_KSAUDIO_SPEAKER_4POINT1:
-			return AV_CH_LAYOUT_4POINT1;
-		case KSAUDIO_SPEAKER_5POINT1_SURROUND:
-			return AV_CH_LAYOUT_5POINT1_BACK;
-		case KSAUDIO_SPEAKER_7POINT1_SURROUND:
-			return AV_CH_LAYOUT_7POINT1;
-		}
-
-		return av_get_default_channel_layout(channels);
-	}
-
-	void record_audio_wasapi::init_format(WAVEFORMATEX * wfex)
-	{
-		DWORD layout = 0;
-
-		if (wfex->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
-			WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE *)wfex;
-			layout = ext->dwChannelMask;
-		}
-
-		_channel_layout = convert_layout(layout, wfex->nChannels);
-		_sample_rate = wfex->nSamplesPerSec;
-		_bit_rate = wfex->nAvgBytesPerSec;
-		_bit_per_sample = wfex->wBitsPerSample;
-		_channel_num = wfex->nChannels;
-
-		//wasapi is always flt
-		_fmt = AV_SAMPLE_FMT_FLT;
-	}
-
-	int record_audio_wasapi::init_render()
-	{
-		int error = AE_NO;
-		HRESULT res = S_OK;
-
-		do {
-			res = _device->Activate(__uuidof(IAudioClient),
-				CLSCTX_ALL, 
-				nullptr,
-				(void **)&_render_client
-			);
-
-			if (FAILED(res)) {
-				error = AE_CO_ACTIVE_DEVICE_FAILED;
-				break;
-			}
-
-			WAVEFORMATEX *wfex;
-			res = _render_client->GetMixFormat(&wfex);
-			if (FAILED(res)) {
-				error = AE_CO_GET_FORMAT_FAILED;
-				break;
-			}
-
-			res = _render_client->Initialize(AUDCLNT_SHAREMODE_SHARED,
-				AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
-				REFTIMES_PER_SEC,
-				0, wfex, nullptr);
-
-			CoTaskMemFree(wfex);
-			if (FAILED(res)) {
-				error = AE_CO_AUDIOCLIENT_INIT_FAILED;
-				break;
-			}
-
-			/* Silent loopback fix. Prevents audio stream from stopping and */
-			/* messing up timestamps and other weird glitches during silence */
-			/* by playing a silent sample all over again. */
-
-			res = _render_client->GetService(__uuidof(IAudioRenderClient),
-				(void **)&_render);
-			if (FAILED(res)) {
-				error = AE_CO_GET_CAPTURE_FAILED;
-				break;
-			}
-
-			_render_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-			if (!_render_event) {
-				error = AE_CO_CREATE_EVENT_FAILED;
-				break;
-			}
-			
-			res = _render_client->SetEventHandle(_render_event);
-			if (FAILED(res)) {
-				error = AE_CO_SET_EVENT_FAILED;
-				break;
-			}
-
-			//pre fill a single silent buffer
-			res = _render_client->GetBufferSize(&_render_sample_count);
-			if (FAILED(res)) {
-				error = AE_CO_GET_VALUE_FAILED;
-				break;
-			}
-
-			uint8_t *buffer = NULL;
-			res = _render->GetBuffer(_render_sample_count, &buffer);
-			if (FAILED(res)) {
-				error = AE_CO_GET_VALUE_FAILED;
-				break;
-			}
-
-			res = _render->ReleaseBuffer(_render_sample_count, AUDCLNT_BUFFERFLAGS_SILENT);
-			if (FAILED(res)) {
-				error = AE_CO_RELEASE_BUFFER_FAILED;
-				break;
-			}
-		} while (0);
-
-		if (error != AE_NO)
-			al_error("init render failed(%ld), %s,lasterror:%lu", res, err2str(error), GetLastError());
-
-		return error;
-	}
-
-	int record_audio_wasapi::init(const std::string & device_name, const std::string &device_id, bool is_input)
-	{
-		int error = AE_NO;
-		HRESULT hr = S_OK;
-
-		al_info("wasapi start to initialize in %s mode with: %s",
-			is_input ? "input" : "output", 
-			device_name.c_str());
-
-		if (_co_inited == false) {
-			return AE_CO_INITED_FAILED;
-		}
-
-		if (_inited == true) {
-			return AE_NO;
-		}
-
-		_device_name = device_name;
-		_device_id = device_id;
-		_is_input = is_input;
-		_is_default = (utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_ID).compare(_device_id) == 0);
-
-		do {
-			hr = CoCreateInstance(
-				__uuidof(MMDeviceEnumerator),
-				NULL,
-				CLSCTX_ALL,
-				__uuidof(IMMDeviceEnumerator),
-				(void **)&_enumerator);
-
-			if (FAILED(hr)) {
-				error = AE_CO_CREATE_FAILED;
-				break;
-			}
-
-			if (_is_default) {
-				hr = _enumerator->GetDefaultAudioEndpoint(
-					is_input ? eCapture : eRender,
-					is_input ? eCommunications : eConsole, &_device);
-			}
-			else {
-				hr = _enumerator->GetDevice(utils_string::utf8_unicode(_device_id).c_str(), &_device);
-			}
-
-			if (hr != S_OK) {
-				error = AE_CO_GETENDPOINT_FAILED;
-				break;
-			}
-
-			get_device_info(_device);
-
-			hr = _device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&_capture_client);
-			if (hr != S_OK) {
-				error = AE_CO_ACTIVE_DEVICE_FAILED;
-				break;
-			}
-			
-			hr = _capture_client->GetMixFormat(&_wfex);
-			if (hr != S_OK) {
-				error = AE_CO_GET_FORMAT_FAILED;
-				break;
-			}
-
-			init_format(_wfex);
-
-			DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
-			if (_is_input == false)
-				flags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
-
-			hr = _capture_client->Initialize(
-				AUDCLNT_SHAREMODE_SHARED,
-				flags,
-				REFTIMES_PER_SEC,
-				0,
-				_wfex,
-				NULL);
-
-			// AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED
-			// https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient-initialize
-			if (hr != S_OK) {
-				error = AE_CO_AUDIOCLIENT_INIT_FAILED;
-				break;
-			}
-
-			//For ouotput mode,ready event will not signal when there is nothing rendering
-			//We run a render thread and render silent pcm data all time
-			if (!_is_input) {
-				error = init_render();
-				if (error != AE_NO)
-					break;
-			}
-
-			hr = _capture_client->GetBufferSize(&_capture_sample_count);
-			if (hr != S_OK) {
-				error = AE_CO_GET_VALUE_FAILED;
-				break;
-			}
-
-
-			hr = _capture_client->GetService(__uuidof(IAudioCaptureClient), (void**)&_capture);
-			if (hr != S_OK) {
-				error = AE_CO_GET_CAPTURE_FAILED;
-				break;
-			}
-
-			_ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-			if (!_ready_event) {
-				error = AE_CO_CREATE_EVENT_FAILED;
-				break;
-			}
-
-			_stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
-			if (!_stop_event) {
-				error = AE_CO_CREATE_EVENT_FAILED;
-				break;
-			}
-
-			hr = _capture_client->SetEventHandle(_ready_event);
-			if (hr != S_OK) {
-				error = AE_CO_SET_EVENT_FAILED;
-				break;
-			}
-
-			_inited = true;
-
-		} while (0);
-
-		if (error != AE_NO) {
-			al_error("wasapi initialize failed,%s,error:%lu,hr:%lld",
-				err2str(error), GetLastError(), hr);
-			clean_wasapi();
-		}
-
-		return error;
-	}
-
-	int record_audio_wasapi::start()
-	{
-		if (_running == true) {
-			al_warn("audio record is already running");
-			return AE_NO;
-		}
-
-		if (_inited == false)
-			return AE_NEED_INIT;
-
-		HRESULT hr = S_OK;
-		
-		
-		if (!_is_input) {
-			hr = _render_client->Start();
-			if (FAILED(hr)) {
-				al_error("%s,error:%lu", err2str(AE_CO_START_FAILED), GetLastError());
-				return AE_CO_START_FAILED;
-			}
-		}
-		
-		
-		hr = _capture_client->Start();
-		if (hr != S_OK) {
-			al_error("%s,error:%lu", err2str(AE_CO_START_FAILED), GetLastError());
-			return AE_CO_START_FAILED;
-		}
-
-		_start_time = av_gettime_relative();
-
-		_running = true;
-
-		
-		if(!_is_input) {
-			_render_thread = std::thread(std::bind(&record_audio_wasapi::render_loop, this));
-		}
-		
-
-		_thread = std::thread(std::bind(&record_audio_wasapi::record_loop, this));
-
-		return AE_NO;
-	}
-
-	int record_audio_wasapi::pause()
-	{
-		_paused = true;
-		return AE_NO;
-	}
-
-	int record_audio_wasapi::resume()
-	{
-		_paused = false;
-		return AE_NO;
-	}
-
-	int record_audio_wasapi::stop()
-	{
-		_running = false;
-		SetEvent(_stop_event);
-
-		if (_render_thread.joinable())
-			_render_thread.join();
-
-		if (_thread.joinable())
-			_thread.join();
-
-		if (_capture_client)
-			_capture_client->Stop();
-
-		if (_render_client)
-			_render_client->Stop();
-
-		return AE_NO;
-	}
-
-	const AVRational record_audio_wasapi::get_time_base()
-	{
-		if (_use_device_ts)
-			return{ 1,NS_PER_SEC };
-		else return{ 1,AV_TIME_BASE };
-	}
-
-	int64_t record_audio_wasapi::get_start_time()
-	{
-		return _start_time;
-	}
-
-	void record_audio_wasapi::process_data(AVFrame *frame, uint8_t* data, uint32_t sample_count, uint64_t device_ts)
-	{
-		int sample_size = _bit_per_sample / 8 * _channel_num;
-
-		//wasapi time unit is 100ns,so time base is NS_PER_SEC
-		frame->pts = _use_device_ts ? device_ts * 100 : av_gettime_relative();
-
-		if (_use_device_ts == false) {
-			frame->pts -= (int64_t)sample_count * NS_PER_SEC / (int64_t)_sample_rate / 100;
-		}
-
-		frame->pkt_dts = frame->pts;
-		frame->nb_samples = sample_count;
-		frame->format = _fmt;
-		frame->sample_rate = _sample_rate;
-		frame->channels = _channel_num;
-		frame->pkt_size = sample_count*sample_size;
-
-		av_samples_fill_arrays(frame->data, frame->linesize, data, _channel_num, sample_count, _fmt, 1);
-
-		if (_on_data) _on_data(frame, _cb_extra_index);
-	}
-
-	int record_audio_wasapi::do_record(AVFrame *frame)
-	{
-		HRESULT res = S_OK;
-		LPBYTE buffer = NULL;
-		DWORD flags = 0;
-		uint32_t sample_count = 0;
-		UINT64 pos, ts;
-		int error = AE_NO;
-
-		while (_running) {
-			res = _capture->GetNextPacketSize(&sample_count);
-
-			if (FAILED(res)) {
-				if (res != AUDCLNT_E_DEVICE_INVALIDATED)
-					al_error("GetNextPacketSize failed: %lX", res);
-				error = AE_CO_GET_PACKET_FAILED;
-				break;
-			}
-
-			if (!sample_count)
-				break;
-
-			buffer = NULL;
-			res = _capture->GetBuffer(&buffer, &sample_count, &flags, &pos, &ts);
-			if (FAILED(res)) {
-				if (res != AUDCLNT_E_DEVICE_INVALIDATED)
-					al_error("GetBuffer failed: %lX",res);
-				error = AE_CO_GET_BUFFER_FAILED;
-				break;
-			}
-
-			//input mode do not have silent data flag do nothing here
-			if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
-				//al_warn("on slient data %d", sample_count);
-			}
-
-
-
-			if (buffer) {
-				process_data(frame, buffer, sample_count, ts);
-			}
-			else {
-				al_error("buffer invalid is");
-			}
-
-			_capture->ReleaseBuffer(sample_count);
-		}
-
-		return error;
-	}
-
-	void record_audio_wasapi::render_loop()
-	{
-		HANDLE events[2] = { _stop_event,_render_event };
-
-		HRESULT res = S_OK;
-		uint8_t *pData = NULL;
-		uint32_t padding_count = 0;
-
-		while (_running && 
-			WaitForMultipleObjects(2, events, FALSE, INFINITE) != WAIT_OBJECT_0
-			) {
-			
-			res = _render_client->GetCurrentPadding(&padding_count);
-			if (FAILED(res)) {
-				break;
-			}
-
-			if (padding_count == _render_sample_count) {
-				if (_on_error) _on_error(AE_CO_PADDING_UNEXPECTED, _cb_extra_index);
-				break;
-			}
-
-			res = _render->GetBuffer(_render_sample_count - padding_count, &pData);
-			if (FAILED(res)) {
-				if (_on_error) _on_error(AE_CO_GET_BUFFER_FAILED, _cb_extra_index);
-				break;
-			}
-
-			res = _render->ReleaseBuffer(_render_sample_count - padding_count, AUDCLNT_BUFFERFLAGS_SILENT);
-			if (FAILED(res)) {
-				if (_on_error) _on_error(AE_CO_RELEASE_BUFFER_FAILED, _cb_extra_index);
-				break;
-			}
-		}
-	}
-
-	void record_audio_wasapi::record_loop()
-	{
-		AVFrame *frame = av_frame_alloc();
-
-		HANDLE events[2] = { _stop_event,_ready_event };
-
-		// while,sys will never not signal this ready_event in windows7,
-		// and only signal when something is rendring,so we just wait 10ms for speaker
-		DWORD dur = _is_input ? INFINITE : 10;
-
-		int error = AE_NO;
-		while (_running)
-		{
-			if (WaitForMultipleObjects(2, events, FALSE, dur) == WAIT_OBJECT_0)
-				break;
-
-			if ((error = do_record(frame)) != AE_NO) {
-				if (_on_error) _on_error(error, _cb_extra_index);
-				break;
-			}
-		}//while(_running)
-
-		av_frame_free(&frame);
- 	}
-
-	void record_audio_wasapi::clean_wasapi()
-	{
-		if (_wfex)
-			CoTaskMemFree(_wfex);
-		_wfex = NULL;
-
-		if (_enumerator)
-			_enumerator->Release();
-		_enumerator = nullptr;
-
-		if (_device)
-			_device->Release();
-		_device = nullptr;
-
-		if (_capture_client)
-			_capture_client->Release();
-		_capture_client = nullptr;
-
-		if (_render_client)
-			_render_client->Release();
-		_render_client = nullptr;
-
-		if (_capture)
-			_capture->Release();
-		_capture = nullptr;
-
-		if (_render)
-			_render->Release();
-		_render = nullptr;
-
-		if (_ready_event)
-			CloseHandle(_ready_event);
-		_ready_event = NULL;
-
-		if (_stop_event)
-			CloseHandle(_stop_event);
-		_stop_event = NULL;
-
-		if (_render_event)
-			CloseHandle(_render_event);
-		_render_event = NULL;
-
-		if(_co_inited == true)
-			CoUninitialize();
-
-		_co_inited = false;
-		_inited = false;
-	}
+    _co_inited = false;
+    _inited = false;
 }
+} // namespace am

+ 42 - 45
libs/Recorder/record_audio_wasapi.h

@@ -10,79 +10,76 @@
 #endif // _WIN32
 
 namespace am {
-	class record_audio_wasapi:public record_audio
-	{
-	public:
-		record_audio_wasapi();
-		~record_audio_wasapi();
+class record_audio_wasapi : public record_audio
+{
+public:
+    record_audio_wasapi();
+    ~record_audio_wasapi();
 
-		virtual int init(const std::string &device_name,
-			const std::string &device_id,
-			bool is_input);
+    virtual int init(const std::string &device_name, const std::string &device_id, bool is_input);
 
-		virtual int start();
+    virtual int start();
 
-		virtual int pause();
+    virtual int pause();
 
-		virtual int resume();
+    virtual int resume();
 
-		virtual int stop();
+    virtual int stop();
 
-		virtual const AVRational get_time_base();
+    virtual const AVRational get_time_base();
 
-		virtual int64_t get_start_time();
+    virtual int64_t get_start_time();
 
-	private:
-		int64_t convert_layout(DWORD layout, WORD channels);
+private:
+    int64_t convert_layout(DWORD layout, WORD channels);
 
-		void init_format(WAVEFORMATEX *wfex);
+    void init_format(WAVEFORMATEX *wfex);
 
-		int init_render();
+    int init_render();
 
-		void render_loop();
+    void render_loop();
 
-		void process_data(AVFrame *frame, uint8_t* data, uint32_t sample_count, uint64_t device_ts);
+    void process_data(AVFrame *frame, uint8_t *data, uint32_t sample_count, uint64_t device_ts);
 
-		int do_record(AVFrame *frame);
+    int do_record(AVFrame *frame);
 
-		void record_loop();
+    void record_loop();
 
-		void clean_wasapi();
+    void clean_wasapi();
 
-	private:
-		WAVEFORMATEX *_wfex;
+private:
+    WAVEFORMATEX *_wfex;
 
-		IMMDeviceEnumerator *_enumerator;
+    IMMDeviceEnumerator *_enumerator;
 
-		IMMDevice *_device;
+    IMMDevice *_device;
 
-		IAudioClient *_capture_client;
+    IAudioClient *_capture_client;
 
-		IAudioCaptureClient *_capture;
+    IAudioCaptureClient *_capture;
 
-		IAudioRenderClient *_render;
+    IAudioRenderClient *_render;
 
-		IAudioClient *_render_client;
+    IAudioClient *_render_client;
 
-		std::thread _render_thread;
+    std::thread _render_thread;
 
-		uint32_t _capture_sample_count;
-		uint32_t _render_sample_count;
+    uint32_t _capture_sample_count;
+    uint32_t _render_sample_count;
 
-		HANDLE _ready_event;
-		HANDLE _stop_event;
-		HANDLE _render_event;
+    HANDLE _ready_event;
+    HANDLE _stop_event;
+    HANDLE _render_event;
 
-		bool _co_inited;
+    bool _co_inited;
 
-		bool _is_default;
+    bool _is_default;
 
-		bool _use_device_ts;
+    bool _use_device_ts;
 
-		//define time stamps here
-		int64_t _start_time;
-	};
-}
+    //define time stamps here
+    int64_t _start_time;
+};
+} // namespace am
 
 #endif // !RECORD_AUDIO_WASAPI
-

+ 11 - 14
libs/Recorder/record_desktop.cpp

@@ -2,22 +2,19 @@
 
 am::record_desktop::record_desktop()
 {
-	_running = false;
-	_paused = false;
-	_inited = false;
+    _running = false;
+    _paused = false;
+    _inited = false;
 
-	_on_data = nullptr;
-	_on_error = nullptr;
+    _on_data = nullptr;
+    _on_error = nullptr;
 
-	_device_name = "";
-	_data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
+    _device_name = "";
+    _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
 
-	_time_base = { 1,AV_TIME_BASE };
-	_start_time = 0;
-	_pixel_fmt = AV_PIX_FMT_NONE;
+    _time_base = {1, AV_TIME_BASE};
+    _start_time = 0;
+    _pixel_fmt = AV_PIX_FMT_NONE;
 }
 
-am::record_desktop::~record_desktop()
-{
-	
-}
+am::record_desktop::~record_desktop() {}

+ 46 - 51
libs/Recorder/record_desktop.h

@@ -6,75 +6,70 @@
 #include "headers_ffmpeg.h"
 
 #include <atomic>
-#include <thread>
 #include <functional>
 #include <string>
+#include <thread>
 
 namespace am {
-	typedef std::function<void(AVFrame *frame)> cb_desktop_data;
-	typedef std::function<void(int)> cb_desktop_error;
-
-	class record_desktop
-	{
-	public:
-		record_desktop();
-		virtual ~record_desktop();
+typedef std::function<void(AVFrame *frame)> cb_desktop_data;
+typedef std::function<void(int)> cb_desktop_error;
 
-		virtual int init(
-			const RECORD_DESKTOP_RECT &rect,
-			const int fps
-		) = 0;
+class record_desktop
+{
+public:
+    record_desktop();
+    virtual ~record_desktop();
 
-		virtual int start() = 0;
-		virtual int pause() = 0;
-		virtual int resume() = 0;
-		virtual int stop() = 0;
+    virtual int init(const RECORD_DESKTOP_RECT &rect, const int fps) = 0;
 
-		inline const AVRational & get_time_base() { return _time_base; }
+    virtual int start() = 0;
+    virtual int pause() = 0;
+    virtual int resume() = 0;
+    virtual int stop() = 0;
 
-		inline int64_t get_start_time() { return _start_time; }
+    inline const AVRational &get_time_base() { return _time_base; }
 
-		inline AVPixelFormat get_pixel_fmt() { return _pixel_fmt; }
+    inline int64_t get_start_time() { return _start_time; }
 
-	public:
-		inline bool is_recording() { return _running; }
-		inline const std::string & get_device_name() { return _device_name; }
-		inline const RECORD_DESKTOP_DATA_TYPES get_data_type() { return _data_type; }
-		inline void registe_cb(
-			cb_desktop_data on_data,
-			cb_desktop_error on_error) {
-			_on_data = on_data;
-			_on_error = on_error;
-		}
-		inline const RECORD_DESKTOP_RECT & get_rect() { return _rect; }
+    inline AVPixelFormat get_pixel_fmt() { return _pixel_fmt; }
 
-		inline const int get_frame_rate() { return _fps; }
+public:
+    inline bool is_recording() { return _running; }
+    inline const std::string &get_device_name() { return _device_name; }
+    inline const RECORD_DESKTOP_DATA_TYPES get_data_type() { return _data_type; }
+    inline void registe_cb(cb_desktop_data on_data, cb_desktop_error on_error)
+    {
+        _on_data = on_data;
+        _on_error = on_error;
+    }
+    inline const RECORD_DESKTOP_RECT &get_rect() { return _rect; }
 
-	protected:
-		virtual void clean_up() = 0;
+    inline const int get_frame_rate() { return _fps; }
 
-	protected:
-		std::atomic_bool _running;
-		std::atomic_bool _paused;
-		std::atomic_bool _inited;
+protected:
+    virtual void clean_up() = 0;
 
-		std::thread _thread;
+protected:
+    std::atomic_bool _running;
+    std::atomic_bool _paused;
+    std::atomic_bool _inited;
 
-		std::string _device_name;
+    std::thread _thread;
 
-		RECORD_DESKTOP_RECT _rect;
-		RECORD_DESKTOP_DATA_TYPES _data_type;
+    std::string _device_name;
 
-		int _fps;
+    RECORD_DESKTOP_RECT _rect;
+    RECORD_DESKTOP_DATA_TYPES _data_type;
 
-		cb_desktop_data _on_data;
-		cb_desktop_error _on_error;
+    int _fps;
 
-		AVRational _time_base;
-		int64_t _start_time;
-		AVPixelFormat _pixel_fmt;
-	};
-}
+    cb_desktop_data _on_data;
+    cb_desktop_error _on_error;
 
+    AVRational _time_base;
+    int64_t _start_time;
+    AVPixelFormat _pixel_fmt;
+};
+} // namespace am
 
-#endif
+#endif

+ 16 - 23
libs/Recorder/record_desktop_define.h

@@ -6,40 +6,33 @@
 *
 */
 typedef enum {
-	DT_DESKTOP_NO = 0,
-	DT_DESKTOP_FFMPEG_GDI,
-	DT_DESKTOP_FFMPEG_DSHOW,
-	DT_DESKTOP_WIN_GDI,
-	DT_DESKTOP_WIN_DUPLICATION,
-  DT_DESKTOP_WIN_WGC,
-	DT_DESKTOP_WIN_MAG
-}RECORD_DESKTOP_TYPES;
+    DT_DESKTOP_NO = 0,
+    DT_DESKTOP_FFMPEG_GDI,
+    DT_DESKTOP_FFMPEG_DSHOW,
+    DT_DESKTOP_WIN_GDI,
+    DT_DESKTOP_WIN_DUPLICATION,
+    DT_DESKTOP_WIN_WGC,
+    DT_DESKTOP_WIN_MAG
+} RECORD_DESKTOP_TYPES;
 
 /*
 * Record desktop data type
 *
 */
 
-typedef enum {
-	AT_DESKTOP_NO = 0,
-	AT_DESKTOP_RGBA,
-	AT_DESKTOP_BGRA
-}RECORD_DESKTOP_DATA_TYPES;
+typedef enum { AT_DESKTOP_NO = 0, AT_DESKTOP_RGBA, AT_DESKTOP_BGRA } RECORD_DESKTOP_DATA_TYPES;
 
 /**
 * Record desktop rect
 *
 */
 
-typedef struct {
-	int left;
-	int top;
-	int right;
-	int bottom;
-}RECORD_DESKTOP_RECT;
-
-
-
-
+typedef struct
+{
+    int left;
+    int top;
+    int right;
+    int bottom;
+} RECORD_DESKTOP_RECT;
 
 #endif

Datei-Diff unterdrückt, da er zu groß ist
+ 734 - 714
libs/Recorder/record_desktop_duplication.cpp


+ 54 - 58
libs/Recorder/record_desktop_duplication.h

@@ -8,85 +8,81 @@
 #include <dxgi1_2.h>
 
 namespace am {
-	typedef struct _PTR_INFO
-	{
-		_Field_size_bytes_(BufferSize) BYTE* buff;
-		DXGI_OUTDUPL_POINTER_SHAPE_INFO shape;
-		POINT position;
-		bool visible;
-		UINT size;
-		UINT output_index;
-		LARGE_INTEGER pre_timestamp;
-	} DUPLICATION_CURSOR_INFO;
+typedef struct _PTR_INFO
+{
+    _Field_size_bytes_(BufferSize) BYTE *buff;
+    DXGI_OUTDUPL_POINTER_SHAPE_INFO shape;
+    POINT position;
+    bool visible;
+    UINT size;
+    UINT output_index;
+    LARGE_INTEGER pre_timestamp;
+} DUPLICATION_CURSOR_INFO;
 
-	class record_desktop_duplication:
-		public record_desktop
-	{
-	public:
-		record_desktop_duplication();
-		~record_desktop_duplication();
+class record_desktop_duplication : public record_desktop
+{
+public:
+    record_desktop_duplication();
+    ~record_desktop_duplication();
 
-		virtual int init(
-			const RECORD_DESKTOP_RECT &rect,
-			const int fps);
+    virtual int init(const RECORD_DESKTOP_RECT &rect, const int fps);
 
-		virtual int start();
-		virtual int pause();
-		virtual int resume();
-		virtual int stop();
+    virtual int start();
+    virtual int pause();
+    virtual int resume();
+    virtual int stop();
 
-	protected:
-		virtual void clean_up();
+protected:
+    virtual void clean_up();
 
-	private:
-		int get_dst_adapter(IDXGIAdapter **adapter);
+private:
+    int get_dst_adapter(IDXGIAdapter **adapter);
 
-		int create_d3d_device(IDXGIAdapter *adapter,ID3D11Device **device);
+    int create_d3d_device(IDXGIAdapter *adapter, ID3D11Device **device);
 
-		int init_d3d11();
+    int init_d3d11();
 
-		void clean_d3d11();
+    void clean_d3d11();
 
-		int init_duplication();
+    int init_duplication();
 
-		int free_duplicated_frame();
+    int free_duplicated_frame();
 
-		void clean_duplication();
+    void clean_duplication();
 
-		bool attatch_desktop();
+    bool attatch_desktop();
 
-		int get_desktop_image(DXGI_OUTDUPL_FRAME_INFO *frame_info);
+    int get_desktop_image(DXGI_OUTDUPL_FRAME_INFO *frame_info);
 
-		int get_desktop_cursor(const DXGI_OUTDUPL_FRAME_INFO *frame_info);
+    int get_desktop_cursor(const DXGI_OUTDUPL_FRAME_INFO *frame_info);
 
-		void draw_cursor();
+    void draw_cursor();
 
-		void do_sleep(int64_t dur, int64_t pre, int64_t now);
+    void do_sleep(int64_t dur, int64_t pre, int64_t now);
 
-		void record_func();
+    void record_func();
 
-	private:
-		uint8_t *_buffer;
-		uint32_t _buffer_size;
-		uint32_t _width, _height;
+private:
+    uint8_t *_buffer;
+    uint32_t _buffer_size;
+    uint32_t _width, _height;
 
-		HMODULE _d3d11, _dxgi;
+    HMODULE _d3d11, _dxgi;
 
-		ID3D11Device* _d3d_device;
-		ID3D11DeviceContext* _d3d_ctx;
-		ID3D11VertexShader* _d3d_vshader;
-		ID3D11PixelShader* _d3d_pshader;
-		ID3D11InputLayout* _d3d_inlayout;
-		ID3D11SamplerState* _d3d_samplerlinear;
+    ID3D11Device *_d3d_device;
+    ID3D11DeviceContext *_d3d_ctx;
+    ID3D11VertexShader *_d3d_vshader;
+    ID3D11PixelShader *_d3d_pshader;
+    ID3D11InputLayout *_d3d_inlayout;
+    ID3D11SamplerState *_d3d_samplerlinear;
 
-		IDXGIOutputDuplication *_duplication;
-		ID3D11Texture2D *_image;
-		DXGI_OUTPUT_DESC _output_des;
-		
-		int _output_index;
-		DUPLICATION_CURSOR_INFO _cursor_info;
-	};
+    IDXGIOutputDuplication *_duplication;
+    ID3D11Texture2D *_image;
+    DXGI_OUTPUT_DESC _output_des;
 
-}
+    int _output_index;
+    DUPLICATION_CURSOR_INFO _cursor_info;
+};
+} // namespace am
 
 #endif

+ 35 - 37
libs/Recorder/record_desktop_factory.cpp

@@ -1,53 +1,51 @@
 #include "record_desktop_factory.h"
-#include "record_desktop_ffmpeg_gdi.h"
+#include "record_desktop_duplication.h"
 #include "record_desktop_ffmpeg_dshow.h"
+#include "record_desktop_ffmpeg_gdi.h"
 #include "record_desktop_gdi.h"
-#include "record_desktop_duplication.h"
-#include "record_desktop_wgc.h"
 #include "record_desktop_mag.h"
+#include "record_desktop_wgc.h"
 
 #include "error_define.h"
 #include "log_helper.h"
 
-int record_desktop_new(RECORD_DESKTOP_TYPES type, am::record_desktop ** recorder)
+int record_desktop_new(RECORD_DESKTOP_TYPES type, am::record_desktop **recorder)
 {
-	int err = AE_NO;
-	switch (type)
-	{
-	case DT_DESKTOP_FFMPEG_GDI:
-		*recorder = (am::record_desktop*)new am::record_desktop_ffmpeg_gdi();
-		break;
-	case DT_DESKTOP_FFMPEG_DSHOW:
-		*recorder = (am::record_desktop*)new am::record_desktop_ffmpeg_dshow();
-		break;
-	case DT_DESKTOP_WIN_GDI:
-		*recorder = (am::record_desktop*)new am::record_desktop_gdi();
-		break;
-	case DT_DESKTOP_WIN_DUPLICATION:
-		*recorder = (am::record_desktop*)new am::record_desktop_duplication();
-		break;
-  case DT_DESKTOP_WIN_WGC:
-    *recorder =
-        (am::record_desktop *)new am::record_desktop_wgc();
-    break;
-  case DT_DESKTOP_WIN_MAG:
-    *recorder = (am::record_desktop *)new am::record_desktop_mag();
-    break;
-	default:
-		err = AE_UNSUPPORT;
-		break;
-	}
+    int err = AE_NO;
+    switch (type) {
+    case DT_DESKTOP_FFMPEG_GDI:
+        *recorder = (am::record_desktop *) new am::record_desktop_ffmpeg_gdi();
+        break;
+    case DT_DESKTOP_FFMPEG_DSHOW:
+        *recorder = (am::record_desktop *) new am::record_desktop_ffmpeg_dshow();
+        break;
+    case DT_DESKTOP_WIN_GDI:
+        *recorder = (am::record_desktop *) new am::record_desktop_gdi();
+        break;
+    case DT_DESKTOP_WIN_DUPLICATION:
+        *recorder = (am::record_desktop *) new am::record_desktop_duplication();
+        break;
+    case DT_DESKTOP_WIN_WGC:
+        *recorder = (am::record_desktop *) new am::record_desktop_wgc();
+        break;
+    case DT_DESKTOP_WIN_MAG:
+        *recorder = (am::record_desktop *) new am::record_desktop_mag();
+        break;
+    default:
+        err = AE_UNSUPPORT;
+        break;
+    }
 
-	return err;
+    return err;
 }
 
-void record_desktop_destroy(am::record_desktop ** recorder)
+void record_desktop_destroy(am::record_desktop **recorder)
 {
-	if (*recorder != nullptr) {
-		(*recorder)->stop();
+    if (*recorder != nullptr) {
+        (*recorder)->stop();
 
-		delete *recorder;
-	}
+        delete *recorder;
+    }
 
-	*recorder = nullptr;
+    *recorder = nullptr;
 }

+ 225 - 229
libs/Recorder/record_desktop_ffmpeg_dshow.cpp

@@ -3,233 +3,229 @@
 #include "error_define.h"
 #include "log_helper.h"
 
-
 namespace am {
-
-	record_desktop_ffmpeg_dshow::record_desktop_ffmpeg_dshow()
-	{
-		av_register_all();
-		avdevice_register_all();
-
-		_fmt_ctx = NULL;
-		_input_fmt = NULL;
-		_codec_ctx = NULL;
-		_codec = NULL;
-
-		_stream_index = -1;
-		_data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_RGBA;
-	}
-
-
-	record_desktop_ffmpeg_dshow::~record_desktop_ffmpeg_dshow()
-	{
-		stop();
-		clean_up();
-	}
-
-	int record_desktop_ffmpeg_dshow::init(const RECORD_DESKTOP_RECT & rect, const int fps)
-	{
-		int error = AE_NO;
-		if (_inited == true) {
-			return error;
-		}
-
-		_fps = fps;
-		_rect = rect;
-
-		char buff_video_size[50] = { 0 };
-		sprintf_s(buff_video_size, 50, "%dx%d", rect.right - rect.left, rect.bottom - rect.top);
-
-		AVDictionary *options = NULL;
-		av_dict_set_int(&options, "framerate", fps, AV_DICT_MATCH_CASE);
-		av_dict_set_int(&options, "offset_x", rect.left, AV_DICT_MATCH_CASE);
-		av_dict_set_int(&options, "offset_y", rect.top, AV_DICT_MATCH_CASE);
-		av_dict_set(&options, "video_size", buff_video_size, AV_DICT_MATCH_CASE);
-		av_dict_set_int(&options, "draw_mouse", 1, AV_DICT_MATCH_CASE);
-
-		int ret = 0;
-		do {
-			_fmt_ctx = avformat_alloc_context();
-			_input_fmt = av_find_input_format("dshow");
-
-			//the framerate must be same like encoder & muxer 's framerate,otherwise the video can not sync with audio
-			ret = avformat_open_input(&_fmt_ctx, "video=screen-capture-recorder", _input_fmt, &options);
-			if (ret != 0) {
-				error = AE_FFMPEG_OPEN_INPUT_FAILED;
-				break;
-			}
-
-			ret = avformat_find_stream_info(_fmt_ctx, NULL);
-			if (ret < 0) {
-				error = AE_FFMPEG_FIND_STREAM_FAILED;
-				break;
-			}
-
-			int stream_index = -1;
-			for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
-				if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-					stream_index = i;
-					break;
-				}
-			}
-
-			if (stream_index == -1) {
-				error = AE_FFMPEG_FIND_STREAM_FAILED;
-				break;
-			}
-
-			_stream_index = stream_index;
-			_codec_ctx = _fmt_ctx->streams[stream_index]->codec;
-			_codec = avcodec_find_decoder(_codec_ctx->codec_id);
-			if (_codec == NULL) {
-				error = AE_FFMPEG_FIND_DECODER_FAILED;
-				break;
-			}
-
-			ret = avcodec_open2(_codec_ctx, _codec, NULL);
-			if (ret != 0) {
-				error = AE_FFMPEG_OPEN_CODEC_FAILED;
-				break;
-			}
-
-			_start_time = _fmt_ctx->streams[_stream_index]->start_time;
-			_time_base = _fmt_ctx->streams[_stream_index]->time_base;
-			_pixel_fmt = _fmt_ctx->streams[_stream_index]->codec->pix_fmt;
-
-			_inited = true;
-		} while (0);
-
-		if (error != AE_NO) {
-			al_debug("%s,error: %d %lu", err2str(error), ret, GetLastError());
-			clean_up();
-		}
-
-		av_dict_free(&options);
-
-		return error;
-	}
-
-	int record_desktop_ffmpeg_dshow::start()
-	{
-		if (_running == true) {
-			al_warn("record desktop gdi is already running");
-			return AE_NO;
-		}
-
-		if (_inited == false) {
-			return AE_NEED_INIT;
-		}
-
-		_running = true;
-		_thread = std::thread(std::bind(&record_desktop_ffmpeg_dshow::record_func, this));
-
-		return AE_NO;
-	}
-
-	int record_desktop_ffmpeg_dshow::pause()
-	{
-		return 0;
-	}
-
-	int record_desktop_ffmpeg_dshow::resume()
-	{
-		return 0;
-	}
-
-	int record_desktop_ffmpeg_dshow::stop()
-	{
-		_running = false;
-		if (_thread.joinable())
-			_thread.join();
-
-		return AE_NO;
-	}
-
-	void record_desktop_ffmpeg_dshow::clean_up()
-	{
-		if (_codec_ctx)
-			avcodec_close(_codec_ctx);
-
-		if (_fmt_ctx)
-			avformat_close_input(&_fmt_ctx);
-
-		_fmt_ctx = NULL;
-		_input_fmt = NULL;
-		_codec_ctx = NULL;
-		_codec = NULL;
-
-		_stream_index = -1;
-		_inited = false;
-	}
-
-	int record_desktop_ffmpeg_dshow::decode(AVFrame * frame, AVPacket * packet)
-	{
-		int ret = avcodec_send_packet(_codec_ctx, packet);
-		if (ret < 0) {
-			al_error("avcodec_send_packet failed:%d", ret);
-
-			return AE_FFMPEG_DECODE_FRAME_FAILED;
-		}
-
-		while (ret >=0)
-		{
-			ret = avcodec_receive_frame(_codec_ctx, frame);
-			if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-				break;
-			}
-
-			if (ret < 0) {
-				return AE_FFMPEG_READ_FRAME_FAILED;
-			}
-
-			if (ret == 0 && _on_data)
-				_on_data(frame);
-
-			av_frame_unref(frame);//need to do this? avcodec_receive_frame said will call unref before receive
-		}
-
-		return AE_NO;
-	}
-
-	void record_desktop_ffmpeg_dshow::record_func()
-	{
-		AVPacket *packet = av_packet_alloc();
-		AVFrame *frame = av_frame_alloc();
-
-		int ret = 0;
-
-		int got_pic = 0;
-		while (_running == true) {
-
-			av_init_packet(packet);
-
-			ret = av_read_frame(_fmt_ctx, packet);
-
-			if (ret < 0) {
-				if (_on_error) _on_error(AE_FFMPEG_READ_FRAME_FAILED);
-
-				al_fatal("read frame failed:%d", ret);
-				break;
-			}
-
-			if (packet->stream_index == _stream_index) {
-				
-				ret = decode(frame, packet);
-				if (ret != AE_NO) {
-					if (_on_error) _on_error(AE_FFMPEG_DECODE_FRAME_FAILED);
-					al_fatal("decode desktop frame failed");
-					break;
-				}
-			}
-
-			av_packet_unref(packet);
-		}
-
-		//flush packet in decoder
-		decode(frame, NULL);
-
-		av_packet_free(&packet);
-		av_frame_free(&frame);
-	}
-
-}
+record_desktop_ffmpeg_dshow::record_desktop_ffmpeg_dshow()
+{
+    av_register_all();
+    avdevice_register_all();
+
+    _fmt_ctx = NULL;
+    _input_fmt = NULL;
+    _codec_ctx = NULL;
+    _codec = NULL;
+
+    _stream_index = -1;
+    _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_RGBA;
+}
+
+record_desktop_ffmpeg_dshow::~record_desktop_ffmpeg_dshow()
+{
+    stop();
+    clean_up();
+}
+
+int record_desktop_ffmpeg_dshow::init(const RECORD_DESKTOP_RECT &rect, const int fps)
+{
+    int error = AE_NO;
+    if (_inited == true) {
+        return error;
+    }
+
+    _fps = fps;
+    _rect = rect;
+
+    char buff_video_size[50] = {0};
+    sprintf_s(buff_video_size, 50, "%dx%d", rect.right - rect.left, rect.bottom - rect.top);
+
+    AVDictionary *options = NULL;
+    av_dict_set_int(&options, "framerate", fps, AV_DICT_MATCH_CASE);
+    av_dict_set_int(&options, "offset_x", rect.left, AV_DICT_MATCH_CASE);
+    av_dict_set_int(&options, "offset_y", rect.top, AV_DICT_MATCH_CASE);
+    av_dict_set(&options, "video_size", buff_video_size, AV_DICT_MATCH_CASE);
+    av_dict_set_int(&options, "draw_mouse", 1, AV_DICT_MATCH_CASE);
+
+    int ret = 0;
+    do {
+        _fmt_ctx = avformat_alloc_context();
+        _input_fmt = av_find_input_format("dshow");
+
+        //the framerate must be same like encoder & muxer 's framerate,otherwise the video can not sync with audio
+        ret = avformat_open_input(&_fmt_ctx, "video=screen-capture-recorder", _input_fmt, &options);
+        if (ret != 0) {
+            error = AE_FFMPEG_OPEN_INPUT_FAILED;
+            break;
+        }
+
+        ret = avformat_find_stream_info(_fmt_ctx, NULL);
+        if (ret < 0) {
+            error = AE_FFMPEG_FIND_STREAM_FAILED;
+            break;
+        }
+
+        int stream_index = -1;
+        for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
+            if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+                stream_index = i;
+                break;
+            }
+        }
+
+        if (stream_index == -1) {
+            error = AE_FFMPEG_FIND_STREAM_FAILED;
+            break;
+        }
+
+        _stream_index = stream_index;
+        _codec_ctx = _fmt_ctx->streams[stream_index]->codec;
+        _codec = avcodec_find_decoder(_codec_ctx->codec_id);
+        if (_codec == NULL) {
+            error = AE_FFMPEG_FIND_DECODER_FAILED;
+            break;
+        }
+
+        ret = avcodec_open2(_codec_ctx, _codec, NULL);
+        if (ret != 0) {
+            error = AE_FFMPEG_OPEN_CODEC_FAILED;
+            break;
+        }
+
+        _start_time = _fmt_ctx->streams[_stream_index]->start_time;
+        _time_base = _fmt_ctx->streams[_stream_index]->time_base;
+        _pixel_fmt = _fmt_ctx->streams[_stream_index]->codec->pix_fmt;
+
+        _inited = true;
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("%s,error: %d %lu", err2str(error), ret, GetLastError());
+        clean_up();
+    }
+
+    av_dict_free(&options);
+
+    return error;
+}
+
+int record_desktop_ffmpeg_dshow::start()
+{
+    if (_running == true) {
+        al_warn("record desktop gdi is already running");
+        return AE_NO;
+    }
+
+    if (_inited == false) {
+        return AE_NEED_INIT;
+    }
+
+    _running = true;
+    _thread = std::thread(std::bind(&record_desktop_ffmpeg_dshow::record_func, this));
+
+    return AE_NO;
+}
+
+int record_desktop_ffmpeg_dshow::pause()
+{
+    return 0;
+}
+
+int record_desktop_ffmpeg_dshow::resume()
+{
+    return 0;
+}
+
+int record_desktop_ffmpeg_dshow::stop()
+{
+    _running = false;
+    if (_thread.joinable())
+        _thread.join();
+
+    return AE_NO;
+}
+
+void record_desktop_ffmpeg_dshow::clean_up()
+{
+    if (_codec_ctx)
+        avcodec_close(_codec_ctx);
+
+    if (_fmt_ctx)
+        avformat_close_input(&_fmt_ctx);
+
+    _fmt_ctx = NULL;
+    _input_fmt = NULL;
+    _codec_ctx = NULL;
+    _codec = NULL;
+
+    _stream_index = -1;
+    _inited = false;
+}
+
+int record_desktop_ffmpeg_dshow::decode(AVFrame *frame, AVPacket *packet)
+{
+    int ret = avcodec_send_packet(_codec_ctx, packet);
+    if (ret < 0) {
+        al_error("avcodec_send_packet failed:%d", ret);
+
+        return AE_FFMPEG_DECODE_FRAME_FAILED;
+    }
+
+    while (ret >= 0) {
+        ret = avcodec_receive_frame(_codec_ctx, frame);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+            break;
+        }
+
+        if (ret < 0) {
+            return AE_FFMPEG_READ_FRAME_FAILED;
+        }
+
+        if (ret == 0 && _on_data)
+            _on_data(frame);
+
+        av_frame_unref(
+            frame); //need to do this? avcodec_receive_frame said will call unref before receive
+    }
+
+    return AE_NO;
+}
+
+void record_desktop_ffmpeg_dshow::record_func()
+{
+    AVPacket *packet = av_packet_alloc();
+    AVFrame *frame = av_frame_alloc();
+
+    int ret = 0;
+
+    int got_pic = 0;
+    while (_running == true) {
+        av_init_packet(packet);
+
+        ret = av_read_frame(_fmt_ctx, packet);
+
+        if (ret < 0) {
+            if (_on_error)
+                _on_error(AE_FFMPEG_READ_FRAME_FAILED);
+
+            al_fatal("read frame failed:%d", ret);
+            break;
+        }
+
+        if (packet->stream_index == _stream_index) {
+            ret = decode(frame, packet);
+            if (ret != AE_NO) {
+                if (_on_error)
+                    _on_error(AE_FFMPEG_DECODE_FRAME_FAILED);
+                al_fatal("decode desktop frame failed");
+                break;
+            }
+        }
+
+        av_packet_unref(packet);
+    }
+
+    //flush packet in decoder
+    decode(frame, NULL);
+
+    av_packet_free(&packet);
+    av_frame_free(&frame);
+}
+} // namespace am

+ 28 - 32
libs/Recorder/record_desktop_ffmpeg_dshow.h

@@ -3,35 +3,31 @@
 #include "record_desktop.h"
 
 namespace am {
-
-	class record_desktop_ffmpeg_dshow:public record_desktop
-	{
-	public:
-		record_desktop_ffmpeg_dshow();
-		~record_desktop_ffmpeg_dshow();
-
-		virtual int init(
-			const RECORD_DESKTOP_RECT &rect,
-			const int fps);
-
-		virtual int start();
-		virtual int pause();
-		virtual int resume();
-		virtual int stop();
-
-	protected:
-		virtual void clean_up();
-
-	private:
-		int decode(AVFrame *frame, AVPacket *packet);
-
-		void record_func();
-
-		int _stream_index;
-		AVFormatContext *_fmt_ctx;
-		AVInputFormat *_input_fmt;
-		AVCodecContext *_codec_ctx;
-		AVCodec *_codec;
-	};
-
-}
+class record_desktop_ffmpeg_dshow : public record_desktop
+{
+public:
+    record_desktop_ffmpeg_dshow();
+    ~record_desktop_ffmpeg_dshow();
+
+    virtual int init(const RECORD_DESKTOP_RECT &rect, const int fps);
+
+    virtual int start();
+    virtual int pause();
+    virtual int resume();
+    virtual int stop();
+
+protected:
+    virtual void clean_up();
+
+private:
+    int decode(AVFrame *frame, AVPacket *packet);
+
+    void record_func();
+
+    int _stream_index;
+    AVFormatContext *_fmt_ctx;
+    AVInputFormat *_input_fmt;
+    AVCodecContext *_codec_ctx;
+    AVCodec *_codec;
+};
+} // namespace am

+ 229 - 232
libs/Recorder/record_desktop_ffmpeg_gdi.cpp

@@ -3,236 +3,233 @@
 #include "error_define.h"
 #include "log_helper.h"
 
-
 namespace am {
-
-	record_desktop_ffmpeg_gdi::record_desktop_ffmpeg_gdi()
-	{
-		av_register_all();
-		avdevice_register_all();
-
-		_fmt_ctx = NULL;
-		_input_fmt = NULL;
-		_codec_ctx = NULL;
-		_codec = NULL;
-
-		_stream_index = -1;
-		_data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_RGBA;
-	}
-
-
-	record_desktop_ffmpeg_gdi::~record_desktop_ffmpeg_gdi()
-	{
-		stop();
-		clean_up();
-	}
-
-	int record_desktop_ffmpeg_gdi::init(const RECORD_DESKTOP_RECT & rect, const int fps)
-	{
-		int error = AE_NO;
-		if (_inited == true) {
-			return error;
-		}
-
-		_fps = fps;
-		_rect = rect;
-
-		char buff_video_size[50] = { 0 };
-		sprintf_s(buff_video_size, 50, "%dx%d", rect.right - rect.left, rect.bottom - rect.top);
-
-		AVDictionary *options = NULL;
-		av_dict_set_int(&options, "framerate", fps, AV_DICT_MATCH_CASE);
-		av_dict_set_int(&options, "offset_x", rect.left, AV_DICT_MATCH_CASE);
-		av_dict_set_int(&options, "offset_y", rect.top, AV_DICT_MATCH_CASE);
-		av_dict_set(&options, "video_size", buff_video_size, AV_DICT_MATCH_CASE);
-		av_dict_set_int(&options, "draw_mouse", 1, AV_DICT_MATCH_CASE);
-
-		int ret = 0;
-		do {
-			_fmt_ctx = avformat_alloc_context();
-			_input_fmt = av_find_input_format("gdigrab");
-
-			//the framerate must be same like encoder & muxer 's framerate,otherwise the video can not sync with audio
-			ret = avformat_open_input(&_fmt_ctx, "desktop", _input_fmt, &options);
-			if (ret != 0) {
-				error = AE_FFMPEG_OPEN_INPUT_FAILED;
-				break;
-			}
-
-			ret = avformat_find_stream_info(_fmt_ctx, NULL);
-			if (ret < 0) {
-				error = AE_FFMPEG_FIND_STREAM_FAILED;
-				break;
-			}
-
-			int stream_index = -1;
-			for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
-				if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-					stream_index = i;
-					break;
-				}
-			}
-
-			if (stream_index == -1) {
-				error = AE_FFMPEG_FIND_STREAM_FAILED;
-				break;
-			}
-
-			_stream_index = stream_index;
-			_codec_ctx = _fmt_ctx->streams[stream_index]->codec;
-			_codec = avcodec_find_decoder(_codec_ctx->codec_id);
-			if (_codec == NULL) {
-				error = AE_FFMPEG_FIND_DECODER_FAILED;
-				break;
-			}
-
-			ret = avcodec_open2(_codec_ctx, _codec, NULL);
-			if (ret != 0) {
-				error = AE_FFMPEG_OPEN_CODEC_FAILED;
-				break;
-			}
-
-			_start_time = _fmt_ctx->streams[_stream_index]->start_time;
-			_time_base = _fmt_ctx->streams[_stream_index]->time_base;
-			_pixel_fmt = _fmt_ctx->streams[_stream_index]->codec->pix_fmt;
-
-			_inited = true;
-		} while (0);
-
-		if (error != AE_NO) {
-			al_debug("%s,error: %d %lu", err2str(error), ret, GetLastError());
-			clean_up();
-		}
-
-		av_dict_free(&options);
-
-		return error;
-	}
-
-	int record_desktop_ffmpeg_gdi::start()
-	{
-		if (_running == true) {
-			al_warn("record desktop gdi is already running");
-			return AE_NO;
-		}
-
-		if (_inited == false) {
-			return AE_NEED_INIT;
-		}
-
-		_running = true;
-		_thread = std::thread(std::bind(&record_desktop_ffmpeg_gdi::record_func, this));
-
-		return AE_NO;
-	}
-
-	int record_desktop_ffmpeg_gdi::pause()
-	{
-		_paused = true;
-		return AE_NO;
-	}
-
-	int record_desktop_ffmpeg_gdi::resume()
-	{
-		_paused = false;
-		return AE_NO;
-	}
-
-	int record_desktop_ffmpeg_gdi::stop()
-	{
-		_running = false;
-		if (_thread.joinable())
-			_thread.join();
-
-		return AE_NO;
-	}
-
-	void record_desktop_ffmpeg_gdi::clean_up()
-	{
-		if (_codec_ctx)
-			avcodec_close(_codec_ctx);
-
-		if (_fmt_ctx)
-			avformat_close_input(&_fmt_ctx);
-
-		_fmt_ctx = NULL;
-		_input_fmt = NULL;
-		_codec_ctx = NULL;
-		_codec = NULL;
-
-		_stream_index = -1;
-		_inited = false;
-	}
-
-	int record_desktop_ffmpeg_gdi::decode(AVFrame * frame, AVPacket * packet)
-	{
-		int ret = avcodec_send_packet(_codec_ctx, packet);
-		if (ret < 0) {
-			al_error("avcodec_send_packet failed:%d", ret);
-
-			return AE_FFMPEG_DECODE_FRAME_FAILED;
-		}
-
-		while (ret >= 0)
-		{
-			ret = avcodec_receive_frame(_codec_ctx, frame);
-			if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
-				break;
-			}
-
-			if (ret < 0) {
-				return AE_FFMPEG_READ_FRAME_FAILED;
-			}
-
-			if (ret == 0 && _on_data) {
-				//use relative time instead of device time
-				frame->pts = av_gettime_relative();// -_start_time;
-				frame->pkt_dts = frame->pts;
-				_on_data(frame);
-			}
-
-			av_frame_unref(frame);//need to do this? avcodec_receive_frame said will call unref before receive
-		}
-
-		return AE_NO;
-	}
-
-	void record_desktop_ffmpeg_gdi::record_func()
-	{
-		AVPacket *packet = av_packet_alloc();
-		AVFrame *frame = av_frame_alloc();
-
-		int ret = 0;
-
-		int got_pic = 0;
-		while (_running == true) {
-			ret = av_read_frame(_fmt_ctx, packet);
-
-			if (ret < 0) {
-				if (_on_error) _on_error(AE_FFMPEG_READ_FRAME_FAILED);
-
-				al_fatal("read frame failed:%d", ret);
-				break;
-			}
-
-			if (packet->stream_index == _stream_index) {
-
-				ret = decode(frame, packet);
-				if (ret != AE_NO) {
-					if (_on_error) _on_error(AE_FFMPEG_DECODE_FRAME_FAILED);
-					al_fatal("decode desktop frame failed");
-					break;
-				}
-			}
-
-			av_packet_unref(packet);
-		}
-
-		//flush packet in decoder
-		decode(frame, NULL);
-
-		av_packet_free(&packet);
-		av_frame_free(&frame);
-	}
-
-}
+record_desktop_ffmpeg_gdi::record_desktop_ffmpeg_gdi()
+{
+    av_register_all();
+    avdevice_register_all();
+
+    _fmt_ctx = NULL;
+    _input_fmt = NULL;
+    _codec_ctx = NULL;
+    _codec = NULL;
+
+    _stream_index = -1;
+    _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_RGBA;
+}
+
+record_desktop_ffmpeg_gdi::~record_desktop_ffmpeg_gdi()
+{
+    stop();
+    clean_up();
+}
+
+int record_desktop_ffmpeg_gdi::init(const RECORD_DESKTOP_RECT &rect, const int fps)
+{
+    int error = AE_NO;
+    if (_inited == true) {
+        return error;
+    }
+
+    _fps = fps;
+    _rect = rect;
+
+    char buff_video_size[50] = {0};
+    sprintf_s(buff_video_size, 50, "%dx%d", rect.right - rect.left, rect.bottom - rect.top);
+
+    AVDictionary *options = NULL;
+    av_dict_set_int(&options, "framerate", fps, AV_DICT_MATCH_CASE);
+    av_dict_set_int(&options, "offset_x", rect.left, AV_DICT_MATCH_CASE);
+    av_dict_set_int(&options, "offset_y", rect.top, AV_DICT_MATCH_CASE);
+    av_dict_set(&options, "video_size", buff_video_size, AV_DICT_MATCH_CASE);
+    av_dict_set_int(&options, "draw_mouse", 1, AV_DICT_MATCH_CASE);
+
+    int ret = 0;
+    do {
+        _fmt_ctx = avformat_alloc_context();
+        _input_fmt = av_find_input_format("gdigrab");
+
+        //the framerate must be same like encoder & muxer 's framerate,otherwise the video can not sync with audio
+        ret = avformat_open_input(&_fmt_ctx, "desktop", _input_fmt, &options);
+        if (ret != 0) {
+            error = AE_FFMPEG_OPEN_INPUT_FAILED;
+            break;
+        }
+
+        ret = avformat_find_stream_info(_fmt_ctx, NULL);
+        if (ret < 0) {
+            error = AE_FFMPEG_FIND_STREAM_FAILED;
+            break;
+        }
+
+        int stream_index = -1;
+        for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
+            if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+                stream_index = i;
+                break;
+            }
+        }
+
+        if (stream_index == -1) {
+            error = AE_FFMPEG_FIND_STREAM_FAILED;
+            break;
+        }
+
+        _stream_index = stream_index;
+        _codec_ctx = _fmt_ctx->streams[stream_index]->codec;
+        _codec = avcodec_find_decoder(_codec_ctx->codec_id);
+        if (_codec == NULL) {
+            error = AE_FFMPEG_FIND_DECODER_FAILED;
+            break;
+        }
+
+        ret = avcodec_open2(_codec_ctx, _codec, NULL);
+        if (ret != 0) {
+            error = AE_FFMPEG_OPEN_CODEC_FAILED;
+            break;
+        }
+
+        _start_time = _fmt_ctx->streams[_stream_index]->start_time;
+        _time_base = _fmt_ctx->streams[_stream_index]->time_base;
+        _pixel_fmt = _fmt_ctx->streams[_stream_index]->codec->pix_fmt;
+
+        _inited = true;
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("%s,error: %d %lu", err2str(error), ret, GetLastError());
+        clean_up();
+    }
+
+    av_dict_free(&options);
+
+    return error;
+}
+
+int record_desktop_ffmpeg_gdi::start()
+{
+    if (_running == true) {
+        al_warn("record desktop gdi is already running");
+        return AE_NO;
+    }
+
+    if (_inited == false) {
+        return AE_NEED_INIT;
+    }
+
+    _running = true;
+    _thread = std::thread(std::bind(&record_desktop_ffmpeg_gdi::record_func, this));
+
+    return AE_NO;
+}
+
+int record_desktop_ffmpeg_gdi::pause()
+{
+    _paused = true;
+    return AE_NO;
+}
+
+int record_desktop_ffmpeg_gdi::resume()
+{
+    _paused = false;
+    return AE_NO;
+}
+
+int record_desktop_ffmpeg_gdi::stop()
+{
+    _running = false;
+    if (_thread.joinable())
+        _thread.join();
+
+    return AE_NO;
+}
+
+void record_desktop_ffmpeg_gdi::clean_up()
+{
+    if (_codec_ctx)
+        avcodec_close(_codec_ctx);
+
+    if (_fmt_ctx)
+        avformat_close_input(&_fmt_ctx);
+
+    _fmt_ctx = NULL;
+    _input_fmt = NULL;
+    _codec_ctx = NULL;
+    _codec = NULL;
+
+    _stream_index = -1;
+    _inited = false;
+}
+
+int record_desktop_ffmpeg_gdi::decode(AVFrame *frame, AVPacket *packet)
+{
+    int ret = avcodec_send_packet(_codec_ctx, packet);
+    if (ret < 0) {
+        al_error("avcodec_send_packet failed:%d", ret);
+
+        return AE_FFMPEG_DECODE_FRAME_FAILED;
+    }
+
+    while (ret >= 0) {
+        ret = avcodec_receive_frame(_codec_ctx, frame);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+            break;
+        }
+
+        if (ret < 0) {
+            return AE_FFMPEG_READ_FRAME_FAILED;
+        }
+
+        if (ret == 0 && _on_data) {
+            //use relative time instead of device time
+            frame->pts = av_gettime_relative(); // -_start_time;
+            frame->pkt_dts = frame->pts;
+            _on_data(frame);
+        }
+
+        av_frame_unref(
+            frame); //need to do this? avcodec_receive_frame said will call unref before receive
+    }
+
+    return AE_NO;
+}
+
+void record_desktop_ffmpeg_gdi::record_func()
+{
+    AVPacket *packet = av_packet_alloc();
+    AVFrame *frame = av_frame_alloc();
+
+    int ret = 0;
+
+    int got_pic = 0;
+    while (_running == true) {
+        ret = av_read_frame(_fmt_ctx, packet);
+
+        if (ret < 0) {
+            if (_on_error)
+                _on_error(AE_FFMPEG_READ_FRAME_FAILED);
+
+            al_fatal("read frame failed:%d", ret);
+            break;
+        }
+
+        if (packet->stream_index == _stream_index) {
+            ret = decode(frame, packet);
+            if (ret != AE_NO) {
+                if (_on_error)
+                    _on_error(AE_FFMPEG_DECODE_FRAME_FAILED);
+                al_fatal("decode desktop frame failed");
+                break;
+            }
+        }
+
+        av_packet_unref(packet);
+    }
+
+    //flush packet in decoder
+    decode(frame, NULL);
+
+    av_packet_free(&packet);
+    av_frame_free(&frame);
+}
+} // namespace am

+ 29 - 33
libs/Recorder/record_desktop_ffmpeg_gdi.h

@@ -4,36 +4,32 @@
 #include "record_desktop.h"
 
 namespace am {
-
-	class record_desktop_ffmpeg_gdi :public record_desktop
-	{
-	public:
-		record_desktop_ffmpeg_gdi();
-		~record_desktop_ffmpeg_gdi();
-
-		virtual int init(
-			const RECORD_DESKTOP_RECT &rect,
-			const int fps);
-		
-		virtual int start();
-		virtual int pause();
-		virtual int resume();
-		virtual int stop();
-
-	protected:
-		virtual void clean_up();
-
-	private:
-		int decode(AVFrame *frame, AVPacket *packet);
-
-		void record_func();
-
-		int _stream_index;
-		AVFormatContext *_fmt_ctx;
-		AVInputFormat *_input_fmt;
-		AVCodecContext *_codec_ctx;
-		AVCodec *_codec;
-	};
-
-}
-#endif
+class record_desktop_ffmpeg_gdi : public record_desktop
+{
+public:
+    record_desktop_ffmpeg_gdi();
+    ~record_desktop_ffmpeg_gdi();
+
+    virtual int init(const RECORD_DESKTOP_RECT &rect, const int fps);
+
+    virtual int start();
+    virtual int pause();
+    virtual int resume();
+    virtual int stop();
+
+protected:
+    virtual void clean_up();
+
+private:
+    int decode(AVFrame *frame, AVPacket *packet);
+
+    void record_func();
+
+    int _stream_index;
+    AVFormatContext *_fmt_ctx;
+    AVInputFormat *_input_fmt;
+    AVCodecContext *_codec_ctx;
+    AVCodec *_codec;
+};
+} // namespace am
+#endif

+ 258 - 258
libs/Recorder/record_desktop_gdi.cpp

@@ -4,209 +4,211 @@
 #include "log_helper.h"
 
 namespace am {
-
-	record_desktop_gdi::record_desktop_gdi()
-	{
-		_data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
-		_buffer = NULL;
-		_buffer_size = 0;
-
-		_draw_cursor = true;
-
-		_hdc = NULL;
-		_bmp = NULL;
-		_bmp_old = NULL;
-		_ci = { 0 };
-	}
-
-	record_desktop_gdi::~record_desktop_gdi()
-	{
-		stop();
-		clean_up();
-	}
-
-	int record_desktop_gdi::init(const RECORD_DESKTOP_RECT & rect, const int fps)
-	{
-		int error = AE_NO;
-		if (_inited == true) {
-			return error;
-		}
-
-		_fps = fps;
-		_rect = rect;
-
-
-		do {
-			_width = rect.right - rect.left;
-			_height = rect.bottom - rect.top;
-			_buffer_size = (_width * 32 + 31) / 32 * _height * 4;
-			_buffer = new uint8_t[_buffer_size];
-
-			_start_time = av_gettime_relative();
-			_time_base = { 1,AV_TIME_BASE };
-			_pixel_fmt = AV_PIX_FMT_BGRA;
-
-
-			_inited = true;
-		} while (0);
-
-		al_info("init gdi finished,error: %s %ld", err2str(error), GetLastError());
-
-		return error;
-	}
-
-	int record_desktop_gdi::start()
-	{
-		if (_running == true) {
-			al_warn("record desktop gdi is already running");
-			return AE_NO;
-		}
-
-		if (_inited == false) {
-			return AE_NEED_INIT;
-		}
-
-		_running = true;
-		_thread = std::thread(std::bind(&record_desktop_gdi::record_func, this));
-
-		return AE_NO;
-	}
-
-	int record_desktop_gdi::pause()
-	{
-		_paused = true;
-		return AE_NO;
-	}
-
-	int record_desktop_gdi::resume()
-	{
-		_paused = false;
-		return AE_NO;
-	}
-
-	int record_desktop_gdi::stop()
-	{
-		_running = false;
-		if (_thread.joinable())
-			_thread.join();
-
-		return AE_NO;
-	}
-
-	void record_desktop_gdi::clean_up()
-	{
-		_inited = false;
-
-		if (_buffer)
-			delete[] _buffer;
-
-		_buffer = nullptr;
-	}
-
-	void record_desktop_gdi::draw_cursor(HDC hdc)
-	{
-		if (!(_ci.flags & CURSOR_SHOWING))
-			return;
-
-		//is cursor in the tartet zone
-		if (_ci.ptScreenPos.x < _rect.left ||
-			_ci.ptScreenPos.x > _rect.right ||
-			_ci.ptScreenPos.y < _rect.top ||
-			_ci.ptScreenPos.y > _rect.bottom
-			)
-			return;
-
-		HICON icon;
-		ICONINFO ii;
-
-		icon = CopyIcon(_ci.hCursor);
-		if (!icon)
-			return;
-
-		int dstx = 0, dsty = 0;
-		dstx = abs(_ci.ptScreenPos.x - _rect.left);
-		dsty = abs(_ci.ptScreenPos.y - _rect.top);
-
-		if (GetIconInfo(icon, &ii)) {
-			POINT pos;
-			DrawIconEx(hdc, dstx, dsty, icon, 0, 0, 0, NULL, DI_NORMAL);
-
-			DeleteObject(ii.hbmColor);
-			DeleteObject(ii.hbmMask);
-		}
-
-		DestroyIcon(icon);
-	}
-
-	int record_desktop_gdi::do_record()
-	{
-		//int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
-		//int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
-		HDC hdc_screen = NULL, hdc_mem = NULL;
-		HBITMAP hbm_mem = NULL;
-
-		int error = AE_ERROR;
-
-		do {
-
-			hdc_screen = GetWindowDC(NULL);
-			if (!hdc_screen) {
-				al_error("get window dc failed:%lu", GetLastError());
-				error = AE_GDI_GET_DC_FAILED;
-				break;
-			}
-
-			hdc_mem = CreateCompatibleDC(hdc_screen);
-			if (!hdc_mem) {
-				al_error("create compatible dc failed:%lu", GetLastError());
-				error = AE_GDI_CREATE_DC_FAILED;
-				break;
-			}
-
-			hbm_mem = CreateCompatibleBitmap(hdc_screen, _width, _height);
-			if (!hbm_mem) {
-				al_error("create compatible bitmap failed:%lu", GetLastError());
-				error = AE_GDI_CREATE_BMP_FAILED;
-				break;
-			}
-
-			SelectObject(hdc_mem, hbm_mem);
-
-			//must have CAPTUREBLT falg,otherwise some layered window can not be captured
-			if (!BitBlt(hdc_mem, 0, 0, _width, _height, hdc_screen, _rect.left, _rect.top, SRCCOPY | CAPTUREBLT)) {
-				al_error("bitblt data failed:%lu", GetLastError());
-				//error = AE_GDI_BITBLT_FAILED;
-				//administrator UAC will trigger invalid handle error
-				break;
-			}
-
-			memset(&_ci, 0, sizeof(CURSORINFO));
-			_ci.cbSize = sizeof(CURSORINFO);
-			if (GetCursorInfo(&_ci)) {
-				draw_cursor(hdc_mem);
-			}
-
-			BITMAPINFOHEADER   bi;
-
-			bi.biSize = sizeof(BITMAPINFOHEADER);
-			bi.biWidth = _width;
-			bi.biHeight = _height * (-1);
-			bi.biPlanes = 1;
-			bi.biBitCount = 32;//should get from system color bits
-			bi.biCompression = BI_RGB;
-			bi.biSizeImage = 0;
-			bi.biXPelsPerMeter = 0;
-			bi.biYPelsPerMeter = 0;
-			bi.biClrUsed = 0;
-			bi.biClrImportant = 0;
-
-			//scan colors by line order
-			int ret = GetDIBits(hdc_mem, hbm_mem, 0, _height, _buffer, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
-			if (ret <= 0 || ret == ERROR_INVALID_PARAMETER) {
-				al_error("get dibits failed:%lu", GetLastError());
-				error = AE_GDI_GET_DIBITS_FAILED;
-				break;
-			}
+record_desktop_gdi::record_desktop_gdi()
+{
+    _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
+    _buffer = NULL;
+    _buffer_size = 0;
+
+    _draw_cursor = true;
+
+    _hdc = NULL;
+    _bmp = NULL;
+    _bmp_old = NULL;
+    _ci = {0};
+}
+
+record_desktop_gdi::~record_desktop_gdi()
+{
+    stop();
+    clean_up();
+}
+
+int record_desktop_gdi::init(const RECORD_DESKTOP_RECT &rect, const int fps)
+{
+    int error = AE_NO;
+    if (_inited == true) {
+        return error;
+    }
+
+    _fps = fps;
+    _rect = rect;
+
+    do {
+        _width = rect.right - rect.left;
+        _height = rect.bottom - rect.top;
+        _buffer_size = (_width * 32 + 31) / 32 * _height * 4;
+        _buffer = new uint8_t[_buffer_size];
+
+        _start_time = av_gettime_relative();
+        _time_base = {1, AV_TIME_BASE};
+        _pixel_fmt = AV_PIX_FMT_BGRA;
+
+        _inited = true;
+    } while (0);
+
+    al_info("init gdi finished,error: %s %ld", err2str(error), GetLastError());
+
+    return error;
+}
+
+int record_desktop_gdi::start()
+{
+    if (_running == true) {
+        al_warn("record desktop gdi is already running");
+        return AE_NO;
+    }
+
+    if (_inited == false) {
+        return AE_NEED_INIT;
+    }
+
+    _running = true;
+    _thread = std::thread(std::bind(&record_desktop_gdi::record_func, this));
+
+    return AE_NO;
+}
+
+int record_desktop_gdi::pause()
+{
+    _paused = true;
+    return AE_NO;
+}
+
+int record_desktop_gdi::resume()
+{
+    _paused = false;
+    return AE_NO;
+}
+
+int record_desktop_gdi::stop()
+{
+    _running = false;
+    if (_thread.joinable())
+        _thread.join();
+
+    return AE_NO;
+}
+
+void record_desktop_gdi::clean_up()
+{
+    _inited = false;
+
+    if (_buffer)
+        delete[] _buffer;
+
+    _buffer = nullptr;
+}
+
+void record_desktop_gdi::draw_cursor(HDC hdc)
+{
+    if (!(_ci.flags & CURSOR_SHOWING))
+        return;
+
+    //is cursor in the tartet zone
+    if (_ci.ptScreenPos.x < _rect.left || _ci.ptScreenPos.x > _rect.right
+        || _ci.ptScreenPos.y < _rect.top || _ci.ptScreenPos.y > _rect.bottom)
+        return;
+
+    HICON icon;
+    ICONINFO ii;
+
+    icon = CopyIcon(_ci.hCursor);
+    if (!icon)
+        return;
+
+    int dstx = 0, dsty = 0;
+    dstx = abs(_ci.ptScreenPos.x - _rect.left);
+    dsty = abs(_ci.ptScreenPos.y - _rect.top);
+
+    if (GetIconInfo(icon, &ii)) {
+        POINT pos;
+        DrawIconEx(hdc, dstx, dsty, icon, 0, 0, 0, NULL, DI_NORMAL);
+
+        DeleteObject(ii.hbmColor);
+        DeleteObject(ii.hbmMask);
+    }
+
+    DestroyIcon(icon);
+}
+
+int record_desktop_gdi::do_record()
+{
+    //int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
+    //int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
+    HDC hdc_screen = NULL, hdc_mem = NULL;
+    HBITMAP hbm_mem = NULL;
+
+    int error = AE_ERROR;
+
+    do {
+        hdc_screen = GetWindowDC(NULL);
+        if (!hdc_screen) {
+            al_error("get window dc failed:%lu", GetLastError());
+            error = AE_GDI_GET_DC_FAILED;
+            break;
+        }
+
+        hdc_mem = CreateCompatibleDC(hdc_screen);
+        if (!hdc_mem) {
+            al_error("create compatible dc failed:%lu", GetLastError());
+            error = AE_GDI_CREATE_DC_FAILED;
+            break;
+        }
+
+        hbm_mem = CreateCompatibleBitmap(hdc_screen, _width, _height);
+        if (!hbm_mem) {
+            al_error("create compatible bitmap failed:%lu", GetLastError());
+            error = AE_GDI_CREATE_BMP_FAILED;
+            break;
+        }
+
+        SelectObject(hdc_mem, hbm_mem);
+
+        //must have CAPTUREBLT falg,otherwise some layered window can not be captured
+        if (!BitBlt(hdc_mem,
+                    0,
+                    0,
+                    _width,
+                    _height,
+                    hdc_screen,
+                    _rect.left,
+                    _rect.top,
+                    SRCCOPY | CAPTUREBLT)) {
+            al_error("bitblt data failed:%lu", GetLastError());
+            //error = AE_GDI_BITBLT_FAILED;
+            //administrator UAC will trigger invalid handle error
+            break;
+        }
+
+        memset(&_ci, 0, sizeof(CURSORINFO));
+        _ci.cbSize = sizeof(CURSORINFO);
+        if (GetCursorInfo(&_ci)) {
+            draw_cursor(hdc_mem);
+        }
+
+        BITMAPINFOHEADER bi;
+
+        bi.biSize = sizeof(BITMAPINFOHEADER);
+        bi.biWidth = _width;
+        bi.biHeight = _height * (-1);
+        bi.biPlanes = 1;
+        bi.biBitCount = 32; //should get from system color bits
+        bi.biCompression = BI_RGB;
+        bi.biSizeImage = 0;
+        bi.biXPelsPerMeter = 0;
+        bi.biYPelsPerMeter = 0;
+        bi.biClrUsed = 0;
+        bi.biClrImportant = 0;
+
+        //scan colors by line order
+        int ret
+            = GetDIBits(hdc_mem, hbm_mem, 0, _height, _buffer, (BITMAPINFO *) &bi, DIB_RGB_COLORS);
+        if (ret <= 0 || ret == ERROR_INVALID_PARAMETER) {
+            al_error("get dibits failed:%lu", GetLastError());
+            error = AE_GDI_GET_DIBITS_FAILED;
+            break;
+        }
 
 #if 0
 			//save bmp to test
@@ -226,75 +228,73 @@ namespace am {
 			fflush(fp);
 			fclose(fp);
 #endif
-			error = AE_NO;
-		} while (0);
-
-		if(hbm_mem)
-			DeleteObject(hbm_mem);
-
-		if(hdc_mem)
-			DeleteObject(hdc_mem);
+        error = AE_NO;
+    } while (0);
 
-		if(hdc_screen)
-			ReleaseDC(NULL, hdc_screen);
+    if (hbm_mem)
+        DeleteObject(hbm_mem);
 
-		return  AE_NO;
-	}
+    if (hdc_mem)
+        DeleteObject(hdc_mem);
 
-	void record_desktop_gdi::do_sleep(int64_t dur, int64_t pre, int64_t now)
-	{
-		int64_t delay = now - pre;
-		dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
+    if (hdc_screen)
+        ReleaseDC(NULL, hdc_screen);
 
-		//al_debug("%lld", delay);
+    return AE_NO;
+}
 
-		if(dur)
-			av_usleep(dur);
-	}
+void record_desktop_gdi::do_sleep(int64_t dur, int64_t pre, int64_t now)
+{
+    int64_t delay = now - pre;
+    dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
 
-	void record_desktop_gdi::record_func()
-	{
-		AVFrame *frame = av_frame_alloc();
+    //al_debug("%lld", delay);
 
-		int64_t pre_pts = 0;
-		int64_t dur = AV_TIME_BASE / _fps;
+    if (dur)
+        av_usleep(dur);
+}
 
-		int ret = AE_NO;
-		while (_running)
-		{
-			ret = do_record();
-			if (ret != AE_NO) {
-				if (_on_error) _on_error(ret);
-				break;
-			}
+void record_desktop_gdi::record_func()
+{
+    AVFrame *frame = av_frame_alloc();
 
-			frame->pts = av_gettime_relative();
-			frame->pkt_dts = frame->pts;
+    int64_t pre_pts = 0;
+    int64_t dur = AV_TIME_BASE / _fps;
 
-			frame->width = _width;
-			frame->height = _height;
-			frame->format = AV_PIX_FMT_BGRA;
-			frame->pict_type = AV_PICTURE_TYPE_I;
-			frame->pkt_size = _width * _height * 4;
+    int ret = AE_NO;
+    while (_running) {
+        ret = do_record();
+        if (ret != AE_NO) {
+            if (_on_error)
+                _on_error(ret);
+            break;
+        }
 
-			av_image_fill_arrays(frame->data, 
-				frame->linesize, 
-				_buffer,
-				AV_PIX_FMT_BGRA,
-				_width,
-				_height,
-				1
-			);
+        frame->pts = av_gettime_relative();
+        frame->pkt_dts = frame->pts;
 
-			if (_on_data) _on_data(frame);
+        frame->width = _width;
+        frame->height = _height;
+        frame->format = AV_PIX_FMT_BGRA;
+        frame->pict_type = AV_PICTURE_TYPE_I;
+        frame->pkt_size = _width * _height * 4;
 
-			do_sleep(dur, pre_pts, frame->pts);
+        av_image_fill_arrays(frame->data,
+                             frame->linesize,
+                             _buffer,
+                             AV_PIX_FMT_BGRA,
+                             _width,
+                             _height,
+                             1);
 
-			pre_pts = frame->pts;
-		}
+        if (_on_data)
+            _on_data(frame);
 
-		av_frame_free(&frame);
-	}
+        do_sleep(dur, pre_pts, frame->pts);
 
+        pre_pts = frame->pts;
+    }
 
-}
+    av_frame_free(&frame);
+}
+} // namespace am

+ 27 - 32
libs/Recorder/record_desktop_gdi.h

@@ -6,46 +6,41 @@
 #include <Windows.h>
 
 namespace am {
+class record_desktop_gdi : public record_desktop
+{
+public:
+    record_desktop_gdi();
+    ~record_desktop_gdi();
 
-	class record_desktop_gdi :
-		public record_desktop
-	{
-	public:
-		record_desktop_gdi();
-		~record_desktop_gdi();
+    virtual int init(const RECORD_DESKTOP_RECT &rect, const int fps);
 
-		virtual int init(
-			const RECORD_DESKTOP_RECT &rect,
-			const int fps);
+    virtual int start();
+    virtual int pause();
+    virtual int resume();
+    virtual int stop();
 
-		virtual int start();
-		virtual int pause();
-		virtual int resume();
-		virtual int stop();
+protected:
+    virtual void clean_up();
 
-	protected:
-		virtual void clean_up();
+private:
+    void draw_cursor(HDC hdc);
 
-	private:
-		void draw_cursor(HDC hdc);
+    int do_record();
 
-		int do_record();
+    void do_sleep(int64_t dur, int64_t pre, int64_t now);
 
-		void do_sleep(int64_t dur, int64_t pre, int64_t now);
+    void record_func();
 
-		void record_func();
+    uint8_t *_buffer;
+    uint32_t _buffer_size;
+    uint32_t _width, _height;
 
-		uint8_t *_buffer;
-		uint32_t _buffer_size;
-		uint32_t _width, _height;
+    std::atomic_bool _draw_cursor;
 
-		std::atomic_bool _draw_cursor;
+    HDC _hdc;
+    HBITMAP _bmp, _bmp_old;
+    CURSORINFO _ci;
+};
+} // namespace am
 
-		HDC _hdc;
-		HBITMAP _bmp, _bmp_old;
-		CURSORINFO _ci;
-	};
-
-}
-
-#endif
+#endif

+ 330 - 280
libs/Recorder/record_desktop_mag.cpp

@@ -6,7 +6,6 @@
 #include "log_helper.h"
 
 namespace am {
-
 namespace {
 // kMagnifierWindowClass has to be "Magnifier" according to the Magnification
 // API. The other strings can be anything.
@@ -15,135 +14,150 @@ static wchar_t kHostWindowName[] = L"MagnifierHost";
 static wchar_t kMagnifierWindowClass[] = L"Magnifier";
 static wchar_t kMagnifierWindowName[] = L"MagnifierWindow";
 
-DWORD GetTlsIndex() {
-  static const DWORD tls_index = TlsAlloc();
-  return tls_index;
+DWORD GetTlsIndex()
+{
+    static const DWORD tls_index = TlsAlloc();
+    return tls_index;
 }
 } // namespace
 
-BOOL __stdcall record_desktop_mag::on_mag_scaling_callback(
-    HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata,
-    MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty) {
-  record_desktop_mag *owner =
-      reinterpret_cast<record_desktop_mag *>(TlsGetValue(GetTlsIndex()));
-  TlsSetValue(GetTlsIndex(), nullptr);
-  owner->on_mag_data(srcdata, srcheader);
-  return TRUE;
+BOOL __stdcall record_desktop_mag::on_mag_scaling_callback(HWND hwnd,
+                                                           void *srcdata,
+                                                           MAGIMAGEHEADER srcheader,
+                                                           void *destdata,
+                                                           MAGIMAGEHEADER destheader,
+                                                           RECT unclipped,
+                                                           RECT clipped,
+                                                           HRGN dirty)
+{
+    record_desktop_mag *owner = reinterpret_cast<record_desktop_mag *>(TlsGetValue(GetTlsIndex()));
+    TlsSetValue(GetTlsIndex(), nullptr);
+    owner->on_mag_data(srcdata, srcheader);
+    return TRUE;
 }
 
 record_desktop_mag::record_desktop_mag() {}
 
 record_desktop_mag::~record_desktop_mag() {}
 
-int record_desktop_mag::init(const RECORD_DESKTOP_RECT &rect, const int fps) {
-  if (_inited == true) {
-    return AE_NO;
-  }
+int record_desktop_mag::init(const RECORD_DESKTOP_RECT &rect, const int fps)
+{
+    if (_inited == true) {
+        return AE_NO;
+    }
 
-  _fps = fps;
-  _rect = rect;
-  _width = rect.right - rect.left;
-  _height = rect.bottom - rect.top;
+    _fps = fps;
+    _rect = rect;
+    _width = rect.right - rect.left;
+    _height = rect.bottom - rect.top;
 
-  _start_time = av_gettime_relative();
-  _time_base = {1, AV_TIME_BASE};
-  _pixel_fmt = AV_PIX_FMT_BGRA;
+    _start_time = av_gettime_relative();
+    _time_base = {1, AV_TIME_BASE};
+    _pixel_fmt = AV_PIX_FMT_BGRA;
 
-  _inited = true;
+    _inited = true;
 
-  return AE_NO;
+    return AE_NO;
 }
 
-int record_desktop_mag::start() {
-  if (_running == true) {
-    al_warn("record desktop gdi is already running");
-    return AE_NO;
-  }
+int record_desktop_mag::start()
+{
+    if (_running == true) {
+        al_warn("record desktop gdi is already running");
+        return AE_NO;
+    }
 
-  if (_inited == false) {
-    return AE_NEED_INIT;
-  }
+    if (_inited == false) {
+        return AE_NEED_INIT;
+    }
 
-  _running = true;
-  _thread = std::thread(std::bind(&record_desktop_mag::record_func, this));
+    _running = true;
+    _thread = std::thread(std::bind(&record_desktop_mag::record_func, this));
 
-  return AE_NO;
+    return AE_NO;
 }
 
-int record_desktop_mag::pause() {
-  _paused = true;
-  return AE_NO;
+int record_desktop_mag::pause()
+{
+    _paused = true;
+    return AE_NO;
 }
 
-int record_desktop_mag::resume() {
-  _paused = false;
-  return AE_NO;
+int record_desktop_mag::resume()
+{
+    _paused = false;
+    return AE_NO;
 }
 
-int record_desktop_mag::stop() {
-  _running = false;
-  if (_thread.joinable())
-    _thread.join();
+int record_desktop_mag::stop()
+{
+    _running = false;
+    if (_thread.joinable())
+        _thread.join();
 
-  return AE_NO;
+    return AE_NO;
 }
 
-void record_desktop_mag::clean_up() {
-  // DestroyWindow must be called before MagUninitialize. _magnifier_window is
-  // destroyed automatically when _host_window is destroyed.
-  if (_host_window)
-    DestroyWindow(_host_window);
-  if (_magnifier_initialized)
-    _mag_uninitialize_func();
-  if (_mag_lib_handle)
-    free_system_library(_mag_lib_handle);
-  if (_desktop_dc)
-    ReleaseDC(NULL, _desktop_dc);
-
-  _inited = false;
+void record_desktop_mag::clean_up()
+{
+    // DestroyWindow must be called before MagUninitialize. _magnifier_window is
+    // destroyed automatically when _host_window is destroyed.
+    if (_host_window)
+        DestroyWindow(_host_window);
+    if (_magnifier_initialized)
+        _mag_uninitialize_func();
+    if (_mag_lib_handle)
+        free_system_library(_mag_lib_handle);
+    if (_desktop_dc)
+        ReleaseDC(NULL, _desktop_dc);
+
+    _inited = false;
 }
 
-void record_desktop_mag::record_func() {
-  int64_t pre_pts = 0;
-  int64_t dur = AV_TIME_BASE / _fps;
+void record_desktop_mag::record_func()
+{
+    int64_t pre_pts = 0;
+    int64_t dur = AV_TIME_BASE / _fps;
 
-  int ret = AE_NO;
+    int ret = AE_NO;
 
-  // must call this in a new thread, otherwise SetWindowPos will stuck before
-  // capture
-  if (!do_mag_initialize()) {
-    al_info("Failed to initialize ScreenCapturerWinMagnifier.");
-    if (_on_error)
-      _on_error(AE_NEED_INIT);
-
-    return;
-  }
+    // must call this in a new thread, otherwise SetWindowPos will stuck before
+    // capture
+    if (!do_mag_initialize()) {
+        al_info("Failed to initialize ScreenCapturerWinMagnifier.");
+        if (_on_error)
+            _on_error(AE_NEED_INIT);
 
-  while (_running) {
-    ret = do_mag_record();
-    if (ret != AE_NO) {
-      if (_on_error)
-        _on_error(ret);
-      break;
+        return;
     }
 
-    do_sleep(dur, pre_pts, _current_pts);
+    while (_running) {
+        ret = do_mag_record();
+        if (ret != AE_NO) {
+            if (_on_error)
+                _on_error(ret);
+            break;
+        }
 
-    pre_pts = _current_pts;
-  }
+        do_sleep(dur, pre_pts, _current_pts);
+
+        pre_pts = _current_pts;
+    }
 }
 
-void record_desktop_mag::do_sleep(int64_t dur, int64_t pre, int64_t now) {
-  int64_t delay = now - pre;
-  dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
+void record_desktop_mag::do_sleep(int64_t dur, int64_t pre, int64_t now)
+{
+    int64_t delay = now - pre;
+    dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
 
-  // al_debug("%lld", delay);
+    // al_debug("%lld", delay);
 
-  if (dur)
-    av_usleep(dur);
+    if (dur)
+        av_usleep(dur);
 }
 
-bool record_desktop_mag::do_mag_initialize() {
+bool record_desktop_mag::do_mag_initialize()
+{
 #if 0 // we can handle crash
       if (GetSystemMetrics(SM_CMONITORS) != 1) {
     // Do not try to use the magnifier in multi-screen setup (where the API
@@ -153,146 +167,174 @@ bool record_desktop_mag::do_mag_initialize() {
   }
 #endif
 
-  _desktop_dc = GetDC(nullptr);
-  _mag_lib_handle = load_system_library("Magnification.dll");
-  if (!_mag_lib_handle)
-    return false;
-  // Initialize Magnification API function pointers.
-  _mag_initialize_func = reinterpret_cast<MagInitializeFunc>(
-      GetProcAddress(_mag_lib_handle, "MagInitialize"));
-  _mag_uninitialize_func = reinterpret_cast<MagUninitializeFunc>(
-      GetProcAddress(_mag_lib_handle, "MagUninitialize"));
-  _mag_set_window_source_func = reinterpret_cast<MagSetWindowSourceFunc>(
-      GetProcAddress(_mag_lib_handle, "MagSetWindowSource"));
-  _mag_set_window_filter_list_func =
-      reinterpret_cast<MagSetWindowFilterListFunc>(
-          GetProcAddress(_mag_lib_handle, "MagSetWindowFilterList"));
-  _mag_set_image_scaling_callback_func =
-      reinterpret_cast<MagSetImageScalingCallbackFunc>(
-          GetProcAddress(_mag_lib_handle, "MagSetImageScalingCallback"));
-  if (!_mag_initialize_func || !_mag_uninitialize_func ||
-      !_mag_set_window_source_func || !_mag_set_window_filter_list_func ||
-      !_mag_set_image_scaling_callback_func) {
-    al_info(
-        "Failed to initialize ScreenCapturerWinMagnifier: library functions "
-        "missing.");
-    return false;
-  }
+    _desktop_dc = GetDC(nullptr);
+    _mag_lib_handle = load_system_library("Magnification.dll");
+    if (!_mag_lib_handle)
+        return false;
+    // Initialize Magnification API function pointers.
+    _mag_initialize_func = reinterpret_cast<MagInitializeFunc>(
+        GetProcAddress(_mag_lib_handle, "MagInitialize"));
+    _mag_uninitialize_func = reinterpret_cast<MagUninitializeFunc>(
+        GetProcAddress(_mag_lib_handle, "MagUninitialize"));
+    _mag_set_window_source_func = reinterpret_cast<MagSetWindowSourceFunc>(
+        GetProcAddress(_mag_lib_handle, "MagSetWindowSource"));
+    _mag_set_window_filter_list_func = reinterpret_cast<MagSetWindowFilterListFunc>(
+        GetProcAddress(_mag_lib_handle, "MagSetWindowFilterList"));
+    _mag_set_image_scaling_callback_func = reinterpret_cast<MagSetImageScalingCallbackFunc>(
+        GetProcAddress(_mag_lib_handle, "MagSetImageScalingCallback"));
+    if (!_mag_initialize_func || !_mag_uninitialize_func || !_mag_set_window_source_func
+        || !_mag_set_window_filter_list_func || !_mag_set_image_scaling_callback_func) {
+        al_info("Failed to initialize ScreenCapturerWinMagnifier: library functions "
+                "missing.");
+        return false;
+    }
 
-  BOOL result = _mag_initialize_func();
-  if (!result) {
-    al_info("Failed to initialize ScreenCapturerWinMagnifier: error from "
-            "MagInitialize %ld",
-            GetLastError());
-    return false;
-  }
-  HMODULE hInstance = nullptr;
-  result =
-      GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
-                             GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
-                         reinterpret_cast<char *>(&DefWindowProc), &hInstance);
-  if (!result) {
-    _mag_uninitialize_func();
-    al_info("Failed to initialize ScreenCapturerWinMagnifier: "
-            "error from GetModulehandleExA %ld",
-            GetLastError());
-    return false;
-  }
-  // Register the host window class. See the MSDN documentation of the
-  // Magnification API for more infomation.
-  WNDCLASSEXW wcex = {};
-  wcex.cbSize = sizeof(WNDCLASSEX);
-  wcex.lpfnWndProc = &DefWindowProc;
-  wcex.hInstance = hInstance;
-  wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
-  wcex.lpszClassName = kMagnifierHostClass;
-  // Ignore the error which may happen when the class is already registered.
-  RegisterClassExW(&wcex);
-  // Create the host window.
-  _host_window =
-      CreateWindowExW(WS_EX_LAYERED, kMagnifierHostClass, kHostWindowName, 0, 0,
-                      0, 0, 0, nullptr, nullptr, hInstance, nullptr);
-  if (!_host_window) {
-    _mag_uninitialize_func();
-    al_info("Failed to initialize ScreenCapturerWinMagnifier: "
-            "error from creating host window %ld",
-            GetLastError());
-    return false;
-  }
-  // Create the magnifier control.
-  _magnifier_window = CreateWindowW(kMagnifierWindowClass, kMagnifierWindowName,
-                                    WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
-                                    _host_window, nullptr, hInstance, nullptr);
-  if (!_magnifier_window) {
-    _mag_uninitialize_func();
-    al_info("Failed to initialize ScreenCapturerWinMagnifier: "
-            "error from creating magnifier window %ld",
-            GetLastError());
-    return false;
-  }
-  // Hide the host window.
-  ShowWindow(_host_window, SW_HIDE);
-  // Set the scaling callback to receive captured image.
-  result = _mag_set_image_scaling_callback_func(
-      _magnifier_window, &record_desktop_mag::on_mag_scaling_callback);
-  if (!result) {
-    _mag_uninitialize_func();
-    al_info("Failed to initialize ScreenCapturerWinMagnifier: "
-            "error from MagSetImageScalingCallback %ld",
-            GetLastError());
-    return false;
-  }
-  if (_excluded_window) {
-    result = _mag_set_window_filter_list_func(
-        _magnifier_window, MW_FILTERMODE_EXCLUDE, 1, &_excluded_window);
+    BOOL result = _mag_initialize_func();
     if (!result) {
-      _mag_uninitialize_func();
-      al_warn("Failed to initialize ScreenCapturerWinMagnifier: "
-              "error from MagSetWindowFilterList %ld",
-              GetLastError());
-      return false;
+        al_info("Failed to initialize ScreenCapturerWinMagnifier: error from "
+                "MagInitialize %ld",
+                GetLastError());
+        return false;
     }
-  }
-  _magnifier_initialized = true;
-  return true;
-}
-
-int record_desktop_mag::do_mag_record() {
-  if (!_magnifier_initialized) {
-    al_error("Magnifier initialization failed.");
-    return AE_NEED_INIT;
-  }
-
-  auto capture_image = [&](const RECORD_DESKTOP_RECT &rect) {
-    // Set the magnifier control to cover the captured rect. The content of the
-    // magnifier control will be the captured image.
-
-    BOOL result =
-        SetWindowPos(_magnifier_window, NULL, rect.left, rect.top,
-                     rect.right - rect.left, rect.bottom - rect.top, 0);
+    HMODULE hInstance = nullptr;
+    result = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+                                    | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                                reinterpret_cast<char *>(&DefWindowProc),
+                                &hInstance);
     if (!result) {
-      al_error("Failed to call SetWindowPos: %ld. Rect = {%d, %d, %d, %d}",
-               GetLastError(), rect.left, rect.top, rect.right, rect.bottom);
-      return false;
+        _mag_uninitialize_func();
+        al_info("Failed to initialize ScreenCapturerWinMagnifier: "
+                "error from GetModulehandleExA %ld",
+                GetLastError());
+        return false;
     }
-
-    _magnifier_capture_succeeded = false;
-    RECT native_rect = {rect.left, rect.top, rect.right, rect.bottom};
-    TlsSetValue(GetTlsIndex(), this);
-
-    // on_mag_data will be called via on_mag_scaling_callback and fill in the
-    // frame before _mag_set_window_source_func returns.
-    DWORD exception = 0;
-    result =
-        seh_mag_set_window_source(_magnifier_window, native_rect, exception);
+    // Register the host window class. See the MSDN documentation of the
+    // Magnification API for more infomation.
+    WNDCLASSEXW wcex = {};
+    wcex.cbSize = sizeof(WNDCLASSEX);
+    wcex.lpfnWndProc = &DefWindowProc;
+    wcex.hInstance = hInstance;
+    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
+    wcex.lpszClassName = kMagnifierHostClass;
+    // Ignore the error which may happen when the class is already registered.
+    RegisterClassExW(&wcex);
+    // Create the host window.
+    _host_window = CreateWindowExW(WS_EX_LAYERED,
+                                   kMagnifierHostClass,
+                                   kHostWindowName,
+                                   0,
+                                   0,
+                                   0,
+                                   0,
+                                   0,
+                                   nullptr,
+                                   nullptr,
+                                   hInstance,
+                                   nullptr);
+    if (!_host_window) {
+        _mag_uninitialize_func();
+        al_info("Failed to initialize ScreenCapturerWinMagnifier: "
+                "error from creating host window %ld",
+                GetLastError());
+        return false;
+    }
+    // Create the magnifier control.
+    _magnifier_window = CreateWindowW(kMagnifierWindowClass,
+                                      kMagnifierWindowName,
+                                      WS_CHILD | WS_VISIBLE,
+                                      0,
+                                      0,
+                                      0,
+                                      0,
+                                      _host_window,
+                                      nullptr,
+                                      hInstance,
+                                      nullptr);
+    if (!_magnifier_window) {
+        _mag_uninitialize_func();
+        al_info("Failed to initialize ScreenCapturerWinMagnifier: "
+                "error from creating magnifier window %ld",
+                GetLastError());
+        return false;
+    }
+    // Hide the host window.
+    ShowWindow(_host_window, SW_HIDE);
+    // Set the scaling callback to receive captured image.
+    result = _mag_set_image_scaling_callback_func(_magnifier_window,
+                                                  &record_desktop_mag::on_mag_scaling_callback);
     if (!result) {
-      al_error("Failed to call MagSetWindowSource: %ld Exception: %ld. Rect = {%d, %d, %d, %d}",
-               GetLastError(), exception, rect.left, rect.top, rect.right,
-               rect.bottom);
-      return false;
+        _mag_uninitialize_func();
+        al_info("Failed to initialize ScreenCapturerWinMagnifier: "
+                "error from MagSetImageScalingCallback %ld",
+                GetLastError());
+        return false;
+    }
+    if (_excluded_window) {
+        result = _mag_set_window_filter_list_func(_magnifier_window,
+                                                  MW_FILTERMODE_EXCLUDE,
+                                                  1,
+                                                  &_excluded_window);
+        if (!result) {
+            _mag_uninitialize_func();
+            al_warn("Failed to initialize ScreenCapturerWinMagnifier: "
+                    "error from MagSetWindowFilterList %ld",
+                    GetLastError());
+            return false;
+        }
+    }
+    _magnifier_initialized = true;
+    return true;
+}
+
+int record_desktop_mag::do_mag_record()
+{
+    if (!_magnifier_initialized) {
+        al_error("Magnifier initialization failed.");
+        return AE_NEED_INIT;
     }
-    return _magnifier_capture_succeeded;
-  };
+
+    auto capture_image = [&](const RECORD_DESKTOP_RECT &rect) {
+        // Set the magnifier control to cover the captured rect. The content of the
+        // magnifier control will be the captured image.
+
+        BOOL result = SetWindowPos(_magnifier_window,
+                                   NULL,
+                                   rect.left,
+                                   rect.top,
+                                   rect.right - rect.left,
+                                   rect.bottom - rect.top,
+                                   0);
+        if (!result) {
+            al_error("Failed to call SetWindowPos: %ld. Rect = {%d, %d, %d, %d}",
+                     GetLastError(),
+                     rect.left,
+                     rect.top,
+                     rect.right,
+                     rect.bottom);
+            return false;
+        }
+
+        _magnifier_capture_succeeded = false;
+        RECT native_rect = {rect.left, rect.top, rect.right, rect.bottom};
+        TlsSetValue(GetTlsIndex(), this);
+
+        // on_mag_data will be called via on_mag_scaling_callback and fill in the
+        // frame before _mag_set_window_source_func returns.
+        DWORD exception = 0;
+        result = seh_mag_set_window_source(_magnifier_window, native_rect, exception);
+        if (!result) {
+            al_error(
+                "Failed to call MagSetWindowSource: %ld Exception: %ld. Rect = {%d, %d, %d, %d}",
+                GetLastError(),
+                exception,
+                rect.left,
+                rect.top,
+                rect.right,
+                rect.bottom);
+            return false;
+        }
+        return _magnifier_capture_succeeded;
+    };
 
 #if 0
   // Switch to the desktop receiving user input if different from the current
@@ -312,78 +354,86 @@ int record_desktop_mag::do_mag_record() {
   DesktopRect rect = GetScreenRect(current_screen_id_, current_device_key_);
 #endif
 
-  // capture_image may fail in some situations, e.g. windows8 metro mode. So
-  // defer to the fallback capturer if magnifier capturer did not work.
-  if (!capture_image(_rect)) {
-    al_error("Magnifier capturer failed to capture a frame.");
-    return AE_ERROR;
-  }
+    // capture_image may fail in some situations, e.g. windows8 metro mode. So
+    // defer to the fallback capturer if magnifier capturer did not work.
+    if (!capture_image(_rect)) {
+        al_error("Magnifier capturer failed to capture a frame.");
+        return AE_ERROR;
+    }
 
-  return AE_NO;
+    return AE_NO;
 }
 
-void record_desktop_mag::set_exclude(HWND excluded_window) {
-  _excluded_window = excluded_window;
-  if (_excluded_window && _magnifier_initialized) {
-    _mag_set_window_filter_list_func(_magnifier_window, MW_FILTERMODE_EXCLUDE,
-                                     1, &_excluded_window);
-  }
+void record_desktop_mag::set_exclude(HWND excluded_window)
+{
+    _excluded_window = excluded_window;
+    if (_excluded_window && _magnifier_initialized) {
+        _mag_set_window_filter_list_func(_magnifier_window,
+                                         MW_FILTERMODE_EXCLUDE,
+                                         1,
+                                         &_excluded_window);
+    }
 }
 
-void record_desktop_mag::on_mag_data(void *data, const MAGIMAGEHEADER &header) {
-  const int kBytesPerPixel = 4;
-
-  int captured_bytes_per_pixel = header.cbSize / header.width / header.height;
-  if (header.format != GUID_WICPixelFormat32bppRGBA ||
-      header.width != static_cast<UINT>(_width) ||
-      header.height != static_cast<UINT>(_height) ||
-      header.stride != static_cast<UINT>(kBytesPerPixel * _width) ||
-      captured_bytes_per_pixel != kBytesPerPixel) {
-    al_warn("Output format does not match the captured format: width = %d, "
-            "height = %d, stride= %d, bpp = %d, pixel format RGBA ? %d.",
-            header.width, header.height, header.stride,
-            captured_bytes_per_pixel,
-            (header.format == GUID_WICPixelFormat32bppRGBA));
-    return;
-  }
+void record_desktop_mag::on_mag_data(void *data, const MAGIMAGEHEADER &header)
+{
+    const int kBytesPerPixel = 4;
+
+    int captured_bytes_per_pixel = header.cbSize / header.width / header.height;
+    if (header.format != GUID_WICPixelFormat32bppRGBA || header.width != static_cast<UINT>(_width)
+        || header.height != static_cast<UINT>(_height)
+        || header.stride != static_cast<UINT>(kBytesPerPixel * _width)
+        || captured_bytes_per_pixel != kBytesPerPixel) {
+        al_warn("Output format does not match the captured format: width = %d, "
+                "height = %d, stride= %d, bpp = %d, pixel format RGBA ? %d.",
+                header.width,
+                header.height,
+                header.stride,
+                captured_bytes_per_pixel,
+                (header.format == GUID_WICPixelFormat32bppRGBA));
+        return;
+    }
 
-  _current_pts = av_gettime_relative();
+    _current_pts = av_gettime_relative();
 
-  AVFrame *frame = av_frame_alloc();
-  frame->pts = _current_pts;
-  frame->pkt_dts = frame->pts;
+    AVFrame *frame = av_frame_alloc();
+    frame->pts = _current_pts;
+    frame->pkt_dts = frame->pts;
 
-  frame->width = _width;
-  frame->height = _height;
-  frame->format = AV_PIX_FMT_BGRA;
-  frame->pict_type = AV_PICTURE_TYPE_I;
-  frame->pkt_size = _width * _height * 4;
+    frame->width = _width;
+    frame->height = _height;
+    frame->format = AV_PIX_FMT_BGRA;
+    frame->pict_type = AV_PICTURE_TYPE_I;
+    frame->pkt_size = _width * _height * 4;
 
-  av_image_fill_arrays(frame->data, frame->linesize,
-                       reinterpret_cast<uint8_t *>(data), AV_PIX_FMT_BGRA,
-                       _width, _height, 1);
+    av_image_fill_arrays(frame->data,
+                         frame->linesize,
+                         reinterpret_cast<uint8_t *>(data),
+                         AV_PIX_FMT_BGRA,
+                         _width,
+                         _height,
+                         1);
 
-  if (_on_data)
-    _on_data(frame);
+    if (_on_data)
+        _on_data(frame);
 
-  av_frame_free(&frame);
+    av_frame_free(&frame);
 
-  _magnifier_capture_succeeded = true;
+    _magnifier_capture_succeeded = true;
 }
 
-bool record_desktop_mag::seh_mag_set_window_source(HWND hwnd, RECT rect,
-                                                   DWORD &exception) {
-  if (!_mag_set_window_source_func)
-    return false;
+bool record_desktop_mag::seh_mag_set_window_source(HWND hwnd, RECT rect, DWORD &exception)
+{
+    if (!_mag_set_window_source_func)
+        return false;
 
-  __try {
-    return _mag_set_window_source_func(hwnd, rect);
-  } __except (EXCEPTION_EXECUTE_HANDLER) {
-    exception = ::GetExceptionCode();
-    return false;
-  }
+    __try {
+        return _mag_set_window_source_func(hwnd, rect);
+    } __except (EXCEPTION_EXECUTE_HANDLER) {
+        exception = ::GetExceptionCode();
+        return false;
+    }
 
-  return false;
+    return false;
 }
-
-} // namespace am
+} // namespace am

+ 68 - 56
libs/Recorder/record_desktop_mag.h

@@ -10,84 +10,96 @@
 #include "record_desktop.h"
 
 namespace am {
-class record_desktop_mag : public record_desktop {
-  typedef BOOL(WINAPI *MagImageScalingCallback)(
-      HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata,
-      MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty);
-  typedef BOOL(WINAPI *MagInitializeFunc)(void);
-  typedef BOOL(WINAPI *MagUninitializeFunc)(void);
-  typedef BOOL(WINAPI *MagSetWindowSourceFunc)(HWND hwnd, RECT rect);
-  typedef BOOL(WINAPI *MagSetWindowFilterListFunc)(HWND hwnd,
-                                                   DWORD dwFilterMode,
-                                                   int count, HWND *pHWND);
-  typedef BOOL(WINAPI *MagSetImageScalingCallbackFunc)(
-      HWND hwnd, MagImageScalingCallback callback);
-
-  static BOOL WINAPI on_mag_scaling_callback(
-      HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata,
-      MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty);
+class record_desktop_mag : public record_desktop
+{
+    typedef BOOL(WINAPI *MagImageScalingCallback)(HWND hwnd,
+                                                  void *srcdata,
+                                                  MAGIMAGEHEADER srcheader,
+                                                  void *destdata,
+                                                  MAGIMAGEHEADER destheader,
+                                                  RECT unclipped,
+                                                  RECT clipped,
+                                                  HRGN dirty);
+    typedef BOOL(WINAPI *MagInitializeFunc)(void);
+    typedef BOOL(WINAPI *MagUninitializeFunc)(void);
+    typedef BOOL(WINAPI *MagSetWindowSourceFunc)(HWND hwnd, RECT rect);
+    typedef BOOL(WINAPI *MagSetWindowFilterListFunc)(HWND hwnd,
+                                                     DWORD dwFilterMode,
+                                                     int count,
+                                                     HWND *pHWND);
+    typedef BOOL(WINAPI *MagSetImageScalingCallbackFunc)(HWND hwnd,
+                                                         MagImageScalingCallback callback);
+
+    static BOOL WINAPI on_mag_scaling_callback(HWND hwnd,
+                                               void *srcdata,
+                                               MAGIMAGEHEADER srcheader,
+                                               void *destdata,
+                                               MAGIMAGEHEADER destheader,
+                                               RECT unclipped,
+                                               RECT clipped,
+                                               HRGN dirty);
 
 public:
-  record_desktop_mag();
-  ~record_desktop_mag() override;
+    record_desktop_mag();
+    ~record_desktop_mag() override;
 
-  int init(const RECORD_DESKTOP_RECT &rect, const int fps) override;
+    int init(const RECORD_DESKTOP_RECT &rect, const int fps) override;
 
-  int start() override;
-  int pause() override;
-  int resume() override;
-  int stop() override;
+    int start() override;
+    int pause() override;
+    int resume() override;
+    int stop() override;
 
-  void set_exclude(HWND excluded_window);
+    void set_exclude(HWND excluded_window);
 
 protected:
-  void clean_up() override;
+    void clean_up() override;
 
 private:
-  void record_func();
+    void record_func();
 
-  void do_sleep(int64_t dur, int64_t pre, int64_t now);
+    void do_sleep(int64_t dur, int64_t pre, int64_t now);
 
-  bool do_mag_initialize();
+    bool do_mag_initialize();
 
-  int do_mag_record();
+    int do_mag_record();
 
-  void on_mag_data(void *data, const MAGIMAGEHEADER &header);
+    void on_mag_data(void *data, const MAGIMAGEHEADER &header);
 
-  bool seh_mag_set_window_source(HWND hwnd, RECT rect, DWORD &exception);
+    bool seh_mag_set_window_source(HWND hwnd, RECT rect, DWORD &exception);
 
 private:
-  uint32_t _width = 0;
-  uint32_t _height = 0;
-  int64_t _current_pts = -1;
+    uint32_t _width = 0;
+    uint32_t _height = 0;
+    int64_t _current_pts = -1;
 
-  // Used to exclude window with specified window id.
-  HWND _excluded_window = NULL;
+    // Used to exclude window with specified window id.
+    HWND _excluded_window = NULL;
 
-  // Used for getting the screen dpi.
-  HDC _desktop_dc = NULL;
+    // Used for getting the screen dpi.
+    HDC _desktop_dc = NULL;
 
-  // Module handler
-  HMODULE _mag_lib_handle = NULL;
+    // Module handler
+    HMODULE _mag_lib_handle = NULL;
 
-  // Mag functions
-  MagInitializeFunc _mag_initialize_func = nullptr;
-  MagUninitializeFunc _mag_uninitialize_func = nullptr;
-  MagSetWindowSourceFunc _mag_set_window_source_func = nullptr;
-  MagSetWindowFilterListFunc _mag_set_window_filter_list_func = nullptr;
-  MagSetImageScalingCallbackFunc _mag_set_image_scaling_callback_func = nullptr;
+    // Mag functions
+    MagInitializeFunc _mag_initialize_func = nullptr;
+    MagUninitializeFunc _mag_uninitialize_func = nullptr;
+    MagSetWindowSourceFunc _mag_set_window_source_func = nullptr;
+    MagSetWindowFilterListFunc _mag_set_window_filter_list_func = nullptr;
+    MagSetImageScalingCallbackFunc _mag_set_image_scaling_callback_func = nullptr;
 
-  // The hidden window hosting the magnifier control.
-  HWND _host_window = NULL;
+    // The hidden window hosting the magnifier control.
+    HWND _host_window = NULL;
 
-  // The magnifier control that captures the screen.
-  HWND _magnifier_window = NULL;
+    // The magnifier control that captures the screen.
+    HWND _magnifier_window = NULL;
 
-  // True if the magnifier control has been successfully initialized.
-  bool _magnifier_initialized = false;
+    // True if the magnifier control has been successfully initialized.
+    bool _magnifier_initialized = false;
 
-  // True if the last OnMagImageScalingCallback was called and handled
-  // successfully. Reset at the beginning of each CaptureImage call.
-  bool _magnifier_capture_succeeded = true;
+    // True if the last OnMagImageScalingCallback was called and handled
+    // successfully. Reset at the beginning of each CaptureImage call.
+    bool _magnifier_capture_succeeded = true;
 };
-} // namespace am
+} // namespace am

+ 120 - 109
libs/Recorder/record_desktop_wgc.cpp

@@ -2,153 +2,164 @@
 
 #include "utils_string.h"
 
-#include "system_error.h"
 #include "error_define.h"
 #include "log_helper.h"
+#include "system_error.h"
 
-BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc,
-                            LPARAM data) {
-
-  MONITORINFOEX info_ex;
-  info_ex.cbSize = sizeof(MONITORINFOEX);
+BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc, LPARAM data)
+{
+    MONITORINFOEX info_ex;
+    info_ex.cbSize = sizeof(MONITORINFOEX);
 
-  GetMonitorInfo(hmonitor, &info_ex);
+    GetMonitorInfo(hmonitor, &info_ex);
 
-  if (info_ex.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER)
-    return true;
+    if (info_ex.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER)
+        return true;
 
-  if (info_ex.dwFlags & MONITORINFOF_PRIMARY) {
-    *(HMONITOR *)data = hmonitor;
-  }
+    if (info_ex.dwFlags & MONITORINFOF_PRIMARY) {
+        *(HMONITOR *) data = hmonitor;
+    }
 
-  return true;
+    return true;
 }
 
-HMONITOR GetPrimaryMonitor() {
-  HMONITOR hmonitor = nullptr;
+HMONITOR GetPrimaryMonitor()
+{
+    HMONITOR hmonitor = nullptr;
 
-  ::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&hmonitor);
+    ::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM) &hmonitor);
 
-  return hmonitor;
+    return hmonitor;
 }
 
 namespace am {
-
-
 record_desktop_wgc::record_desktop_wgc() {}
 
-record_desktop_wgc::~record_desktop_wgc() {
-  stop();
-  clean_up();
+record_desktop_wgc::~record_desktop_wgc()
+{
+    stop();
+    clean_up();
 }
 
-int record_desktop_wgc::init(const RECORD_DESKTOP_RECT &rect, const int fps) {
-  int error = AE_NO;
-  if (_inited == true)
-    return error;
+int record_desktop_wgc::init(const RECORD_DESKTOP_RECT &rect, const int fps)
+{
+    int error = AE_NO;
+    if (_inited == true)
+        return error;
+
+    _fps = fps;
+    _rect = rect;
+    _start_time = av_gettime_relative();
+    _time_base = {1, AV_TIME_BASE};
+    _pixel_fmt = AV_PIX_FMT_BGRA;
+
+    do {
+        if (!module_.is_supported()) {
+            error = AE_UNSUPPORT;
+            break;
+        }
+
+        session_ = module_.create_session();
+        if (!session_) {
+            error = AE_WGC_CREATE_CAPTURER_FAILED;
+            break;
+        }
+
+        session_->register_observer(this);
+
+        error = session_->initialize(GetPrimaryMonitor());
+
+        _inited = true;
+    } while (0);
+
+    if (error != AE_NO) {
+        al_debug("%s,last error:%s",
+                 err2str(error),
+                 system_error::error2str(GetLastError()).c_str());
+    }
 
-  _fps = fps;
-  _rect = rect;
-  _start_time = av_gettime_relative();
-  _time_base = {1, AV_TIME_BASE};
-  _pixel_fmt = AV_PIX_FMT_BGRA;
+    return error;
+}
 
-  do {
-    if (!module_.is_supported()) {
-      error = AE_UNSUPPORT;
-      break;
+int record_desktop_wgc::start()
+{
+    if (_running == true) {
+        al_warn("record desktop duplication is already running");
+        return AE_NO;
     }
 
-    session_ = module_.create_session();
-    if (!session_) {
-      error = AE_WGC_CREATE_CAPTURER_FAILED;
-      break;
+    if (_inited == false) {
+        return AE_NEED_INIT;
     }
 
-    session_->register_observer(this);
-
-    error = session_->initialize(GetPrimaryMonitor());
-
-    _inited = true;
-  } while (0);
-
-  if (error != AE_NO) {
-    al_debug("%s,last error:%s", err2str(error),
-             system_error::error2str(GetLastError()).c_str());
-  }
+    _running = true;
+    session_->start();
 
-  return error;
-}
-
-int record_desktop_wgc::start() {
-  if (_running == true) {
-    al_warn("record desktop duplication is already running");
     return AE_NO;
-  }
-
-  if (_inited == false) {
-    return AE_NEED_INIT;
-  }
-
-  _running = true;
-  session_->start();
-
-  return AE_NO;
 }
 
-int record_desktop_wgc::pause() {
-  _paused = true;
-  if (session_)
-    session_->pause();
-  return AE_NO;
+int record_desktop_wgc::pause()
+{
+    _paused = true;
+    if (session_)
+        session_->pause();
+    return AE_NO;
 }
 
-int record_desktop_wgc::resume() {
-  _paused = false;
-  if (session_)
-    session_->resume();
-  return AE_NO;
+int record_desktop_wgc::resume()
+{
+    _paused = false;
+    if (session_)
+        session_->resume();
+    return AE_NO;
 }
 
-int record_desktop_wgc::stop() {
-  _running = false;
+int record_desktop_wgc::stop()
+{
+    _running = false;
 
-  if (session_)
-    session_->stop();
+    if (session_)
+        session_->stop();
 
-  return AE_NO;
+    return AE_NO;
 }
 
-void record_desktop_wgc::on_frame(const wgc_session::wgc_session_frame &frame) {
-  al_debug("wgc on frame");
-  AVFrame *av_frame = av_frame_alloc();
-
-  av_frame->pts = av_gettime_relative();
-  av_frame->pkt_dts = av_frame->pts;
-  av_frame->pkt_pts = av_frame->pts;
-
-  av_frame->width = frame.width;
-  av_frame->height = frame.height;
-  av_frame->format = AV_PIX_FMT_BGRA;
-  av_frame->pict_type = AV_PICTURE_TYPE_NONE;
-  av_frame->pkt_size = frame.width * frame.height * 4;
-
-  av_image_fill_arrays(av_frame->data, av_frame->linesize, frame.data,
-                       AV_PIX_FMT_BGRA, frame.width, frame.height, 1);
-
-  if (_on_data)
-    _on_data(av_frame);
-
-  av_frame_free(&av_frame);
+void record_desktop_wgc::on_frame(const wgc_session::wgc_session_frame &frame)
+{
+    al_debug("wgc on frame");
+    AVFrame *av_frame = av_frame_alloc();
+
+    av_frame->pts = av_gettime_relative();
+    av_frame->pkt_dts = av_frame->pts;
+    av_frame->pkt_pts = av_frame->pts;
+
+    av_frame->width = frame.width;
+    av_frame->height = frame.height;
+    av_frame->format = AV_PIX_FMT_BGRA;
+    av_frame->pict_type = AV_PICTURE_TYPE_NONE;
+    av_frame->pkt_size = frame.width * frame.height * 4;
+
+    av_image_fill_arrays(av_frame->data,
+                         av_frame->linesize,
+                         frame.data,
+                         AV_PIX_FMT_BGRA,
+                         frame.width,
+                         frame.height,
+                         1);
+
+    if (_on_data)
+        _on_data(av_frame);
+
+    av_frame_free(&av_frame);
 }
 
-void record_desktop_wgc::clean_up() {
-  _inited = false;
+void record_desktop_wgc::clean_up()
+{
+    _inited = false;
 
-  if (session_)
-    session_->release();
+    if (session_)
+        session_->release();
 
-  session_ = nullptr;
+    session_ = nullptr;
 }
-
-} // namespace am
+} // namespace am

+ 46 - 44
libs/Recorder/record_desktop_wgc.h

@@ -6,62 +6,64 @@
 #include <Windows.h>
 
 namespace am {
-class record_desktop_wgc : public record_desktop,
-                           public wgc_session::wgc_session_observer {
-  class wgc_session_module {
-    using func_type_is_supported = bool (*)();
-    using func_type_create_session = wgc_session *(*)();
+class record_desktop_wgc : public record_desktop, public wgc_session::wgc_session_observer
+{
+    class wgc_session_module
+    {
+        using func_type_is_supported = bool (*)();
+        using func_type_create_session = wgc_session *(*) ();
 
-  public:
-    wgc_session_module() { 
-      module_ = ::LoadLibraryA("WGC.dll");
-      if (module_) {
-        func_is_supported_ = (func_type_is_supported)::GetProcAddress(
-            module_, "wgc_is_supported");
-        func_create_session_ = (func_type_create_session)::GetProcAddress(
-            module_, "wgc_create_session");
-      }
-    }
-    ~wgc_session_module() {
-      if (module_)
-        ::FreeModule(module_);
-    }
+    public:
+        wgc_session_module()
+        {
+            module_ = ::LoadLibraryA("WGC.dll");
+            if (module_) {
+                func_is_supported_ = (func_type_is_supported)::GetProcAddress(module_,
+                                                                              "wgc_is_supported");
+                func_create_session_
+                    = (func_type_create_session)::GetProcAddress(module_, "wgc_create_session");
+            }
+        }
+        ~wgc_session_module()
+        {
+            if (module_)
+                ::FreeModule(module_);
+        }
 
-    bool is_supported() const {
-      return func_create_session_ && func_is_supported_();
-    }
+        bool is_supported() const { return func_create_session_ && func_is_supported_(); }
 
-    wgc_session *create_session() const { 
-      if (!func_create_session_)
-        return nullptr;
+        wgc_session *create_session() const
+        {
+            if (!func_create_session_)
+                return nullptr;
 
-      return func_create_session_(); 
-    }
+            return func_create_session_();
+        }
 
-  private:
-    HMODULE module_ = nullptr;
-    func_type_is_supported func_is_supported_ = nullptr;
-    func_type_create_session func_create_session_ = nullptr;
-  };
+    private:
+        HMODULE module_ = nullptr;
+        func_type_is_supported func_is_supported_ = nullptr;
+        func_type_create_session func_create_session_ = nullptr;
+    };
 
 public:
-  record_desktop_wgc();
-  ~record_desktop_wgc();
+    record_desktop_wgc();
+    ~record_desktop_wgc();
 
-  int init(const RECORD_DESKTOP_RECT &rect, const int fps) override;
+    int init(const RECORD_DESKTOP_RECT &rect, const int fps) override;
 
-  int start() override;
-  int pause() override;
-  int resume() override;
-  int stop() override;
+    int start() override;
+    int pause() override;
+    int resume() override;
+    int stop() override;
 
-  void on_frame(const wgc_session::wgc_session_frame &frame) override;
+    void on_frame(const wgc_session::wgc_session_frame &frame) override;
 
 protected:
-  void clean_up() override;
+    void clean_up() override;
 
 private:
-  wgc_session *session_ = nullptr;
-  wgc_session_module module_;
+    wgc_session *session_ = nullptr;
+    wgc_session_module module_;
 };
-} // namespace am
+} // namespace am

+ 215 - 223
libs/Recorder/remuxer_ffmpeg.cpp

@@ -9,286 +9,278 @@
 #include "log_helper.h"
 
 namespace am {
-	static remuxer_ffmpeg *_g_instance = nullptr;
-	static std::mutex _g_mutex;
-
-	static void process_packet(AVPacket *pkt, AVStream *in_stream,
-		AVStream *out_stream)
-	{
-		pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base,
-			out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
-		pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base,
-			out_stream->time_base,
-			(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
-		pkt->duration = (int)av_rescale_q(pkt->duration, in_stream->time_base,
-			out_stream->time_base);
-		pkt->pos = -1;
-	}
-
-	static int remux_file(AVFormatContext *ctx_src, AVFormatContext *ctx_dst, REMUXER_PARAM *param)
-	{
-		AVPacket pkt;
-
-		int ret, throttle = 0, error = AE_NO;
-
-		for (;;) {
-			ret = av_read_frame(ctx_src, &pkt);
-			if (ret < 0) {
-				if (ret != AVERROR_EOF)
-					error = AE_FFMPEG_READ_FRAME_FAILED;
-				break;
-			}
-
-			if (param->cb_progress != NULL && throttle++ > 10) {
-				float progress = pkt.pos / (float)param->src_size * 100.f;
-				param->cb_progress(param->src, progress, 100);
-				throttle = 0;
-			}
-
-			process_packet(&pkt, ctx_src->streams[pkt.stream_index],
-				ctx_dst->streams[pkt.stream_index]);
-
-			ret = av_interleaved_write_frame(ctx_dst, &pkt);
-			av_packet_unref(&pkt);
-
-			// Sometimes the pts and dts will equal to last packet,
-			// don not know why,may the time base issue?
-			// So return -22 do not care for now
-			if (ret < 0 && ret != -22) {
-				error = AE_FFMPEG_WRITE_FRAME_FAILED;
-				break;
-			}
-		}
-
-		return error;
-	}
-
-	static int open_src(AVFormatContext **ctx, const char *path) {
-		int ret = avformat_open_input(ctx, path, NULL, NULL);
-		if (ret < 0) {
-			return AE_FFMPEG_OPEN_INPUT_FAILED;
-		}
-
-		ret = avformat_find_stream_info(*ctx, NULL);
-		if (ret < 0) {
-			return AE_FFMPEG_FIND_STREAM_FAILED;
-		}
+static remuxer_ffmpeg *_g_instance = nullptr;
+static std::mutex _g_mutex;
+
+static void process_packet(AVPacket *pkt, AVStream *in_stream, AVStream *out_stream)
+{
+    pkt->pts = av_rescale_q_rnd(pkt->pts,
+                                in_stream->time_base,
+                                out_stream->time_base,
+                                (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
+    pkt->dts = av_rescale_q_rnd(pkt->dts,
+                                in_stream->time_base,
+                                out_stream->time_base,
+                                (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
+    pkt->duration = (int) av_rescale_q(pkt->duration, in_stream->time_base, out_stream->time_base);
+    pkt->pos = -1;
+}
+
+static int remux_file(AVFormatContext *ctx_src, AVFormatContext *ctx_dst, REMUXER_PARAM *param)
+{
+    AVPacket pkt;
+
+    int ret, throttle = 0, error = AE_NO;
+
+    for (;;) {
+        ret = av_read_frame(ctx_src, &pkt);
+        if (ret < 0) {
+            if (ret != AVERROR_EOF)
+                error = AE_FFMPEG_READ_FRAME_FAILED;
+            break;
+        }
+
+        if (param->cb_progress != NULL && throttle++ > 10) {
+            float progress = pkt.pos / (float) param->src_size * 100.f;
+            param->cb_progress(param->src, progress, 100);
+            throttle = 0;
+        }
+
+        process_packet(&pkt, ctx_src->streams[pkt.stream_index], ctx_dst->streams[pkt.stream_index]);
+
+        ret = av_interleaved_write_frame(ctx_dst, &pkt);
+        av_packet_unref(&pkt);
+
+        // Sometimes the pts and dts will equal to last packet,
+        // don not know why,may the time base issue?
+        // So return -22 do not care for now
+        if (ret < 0 && ret != -22) {
+            error = AE_FFMPEG_WRITE_FRAME_FAILED;
+            break;
+        }
+    }
+
+    return error;
+}
+
+static int open_src(AVFormatContext **ctx, const char *path)
+{
+    int ret = avformat_open_input(ctx, path, NULL, NULL);
+    if (ret < 0) {
+        return AE_FFMPEG_OPEN_INPUT_FAILED;
+    }
+
+    ret = avformat_find_stream_info(*ctx, NULL);
+    if (ret < 0) {
+        return AE_FFMPEG_FIND_STREAM_FAILED;
+    }
 
 #ifdef _DEBUG
-		av_dump_format(*ctx, 0, path, false);
+    av_dump_format(*ctx, 0, path, false);
 #endif
-		return AE_NO;
-	}
-
-	int open_dst(AVFormatContext **ctx_dst, const char *path, AVFormatContext *ctx_src) {
-		int ret;
-
-		avformat_alloc_output_context2(ctx_dst, NULL, NULL,
-			path);
-		if (!*ctx_dst) {
-			return AE_FFMPEG_ALLOC_CONTEXT_FAILED;
-		}
-
-		for (unsigned i = 0; i < ctx_src->nb_streams; i++) {
-			AVStream *in_stream = ctx_src->streams[i];
-			AVStream *out_stream = avformat_new_stream(
-				*ctx_dst, in_stream->codec->codec);
-			if (!out_stream) {
-				return AE_FFMPEG_NEW_STREAM_FAILED;
-			}
+    return AE_NO;
+}
+
+int open_dst(AVFormatContext **ctx_dst, const char *path, AVFormatContext *ctx_src)
+{
+    int ret;
+
+    avformat_alloc_output_context2(ctx_dst, NULL, NULL, path);
+    if (!*ctx_dst) {
+        return AE_FFMPEG_ALLOC_CONTEXT_FAILED;
+    }
+
+    for (unsigned i = 0; i < ctx_src->nb_streams; i++) {
+        AVStream *in_stream = ctx_src->streams[i];
+        AVStream *out_stream = avformat_new_stream(*ctx_dst, in_stream->codec->codec);
+        if (!out_stream) {
+            return AE_FFMPEG_NEW_STREAM_FAILED;
+        }
 
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
-			AVCodecParameters *par = avcodec_parameters_alloc();
-			ret = avcodec_parameters_from_context(par, in_stream->codec);
-			if (ret == 0)
-				ret = avcodec_parameters_to_context(out_stream->codec,
-					par);
-			avcodec_parameters_free(&par);
+        AVCodecParameters *par = avcodec_parameters_alloc();
+        ret = avcodec_parameters_from_context(par, in_stream->codec);
+        if (ret == 0)
+            ret = avcodec_parameters_to_context(out_stream->codec, par);
+        avcodec_parameters_free(&par);
 #else
-			ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
+        ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
 #endif
 
-			if (ret < 0) {
-				return AE_FFMPEG_COPY_PARAMS_FAILED;
-			}
-			out_stream->time_base = out_stream->codec->time_base;
+        if (ret < 0) {
+            return AE_FFMPEG_COPY_PARAMS_FAILED;
+        }
+        out_stream->time_base = out_stream->codec->time_base;
 
-			av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
+        av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
 
-			out_stream->codec->codec_tag = 0;
-			if ((*ctx_dst)->oformat->flags & AVFMT_GLOBALHEADER)
-				out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-		}
+        out_stream->codec->codec_tag = 0;
+        if ((*ctx_dst)->oformat->flags & AVFMT_GLOBALHEADER)
+            out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+    }
 
 #ifndef _NDEBUG
-		av_dump_format(*ctx_dst, 0, path, true);
+    av_dump_format(*ctx_dst, 0, path, true);
 #endif
 
-		if (!((*ctx_dst)->oformat->flags & AVFMT_NOFILE)) {
-			ret = avio_open(&(*ctx_dst)->pb, path,
-				AVIO_FLAG_WRITE);
-			if (ret < 0) {
-				return AE_FFMPEG_OPEN_IO_FAILED;
-			}
-		}
-
-		return AE_NO;
-	}
-
-	static void remuxing(REMUXER_PARAM *param) {
-		al_debug("remuxing:%s", param->src);
+    if (!((*ctx_dst)->oformat->flags & AVFMT_NOFILE)) {
+        ret = avio_open(&(*ctx_dst)->pb, path, AVIO_FLAG_WRITE);
+        if (ret < 0) {
+            return AE_FFMPEG_OPEN_IO_FAILED;
+        }
+    }
 
-		int error = AE_NO;
+    return AE_NO;
+}
 
-		AVFormatContext *ctx_src = nullptr, *ctx_dst = nullptr;
+static void remuxing(REMUXER_PARAM *param)
+{
+    al_debug("remuxing:%s", param->src);
 
-		//call back start
-		if (param->cb_state)
-			param->cb_state(param->src, 1, AE_NO);
+    int error = AE_NO;
 
-		do {
-			error = open_src(&ctx_src, utils_string::ascii_utf8(param->src).c_str());
-			if (error != AE_NO) {
-				break;
-			}
+    AVFormatContext *ctx_src = nullptr, *ctx_dst = nullptr;
 
-			error = open_dst(&ctx_dst, utils_string::ascii_utf8(param->dst).c_str(), ctx_src);
-			if (error != AE_NO) {
-				break;
-			}
+    //call back start
+    if (param->cb_state)
+        param->cb_state(param->src, 1, AE_NO);
 
-			int ret = avformat_write_header(ctx_dst, NULL);
-			if (ret < 0) {
-				error = AE_FFMPEG_WRITE_HEADER_FAILED;
-				break;
-			}
+    do {
+        error = open_src(&ctx_src, utils_string::ascii_utf8(param->src).c_str());
+        if (error != AE_NO) {
+            break;
+        }
 
-			error = remux_file(ctx_src, ctx_dst, param);
-			if (error != AE_NO) {
-				av_write_trailer(ctx_dst);
-				break;
-			}
+        error = open_dst(&ctx_dst, utils_string::ascii_utf8(param->dst).c_str(), ctx_src);
+        if (error != AE_NO) {
+            break;
+        }
 
-			ret = av_write_trailer(ctx_dst);
-			if (ret < 0)
-				error = AE_FFMPEG_WRITE_TRAILER_FAILED;
+        int ret = avformat_write_header(ctx_dst, NULL);
+        if (ret < 0) {
+            error = AE_FFMPEG_WRITE_HEADER_FAILED;
+            break;
+        }
 
+        error = remux_file(ctx_src, ctx_dst, param);
+        if (error != AE_NO) {
+            av_write_trailer(ctx_dst);
+            break;
+        }
 
-		} while (0);
+        ret = av_write_trailer(ctx_dst);
+        if (ret < 0)
+            error = AE_FFMPEG_WRITE_TRAILER_FAILED;
 
+    } while (0);
 
-		if (ctx_src) {
-			avformat_close_input(&ctx_src);
-		}
+    if (ctx_src) {
+        avformat_close_input(&ctx_src);
+    }
 
-		if (ctx_dst && !(ctx_dst->oformat->flags & AVFMT_NOFILE))
-			avio_close(ctx_dst->pb);
+    if (ctx_dst && !(ctx_dst->oformat->flags & AVFMT_NOFILE))
+        avio_close(ctx_dst->pb);
 
-		if (ctx_dst)
-			avformat_free_context(ctx_dst);
+    if (ctx_dst)
+        avformat_free_context(ctx_dst);
 
-		al_debug("remux %s to %s end with error:%s",
-			param->src, param->dst, err2str(error));
+    al_debug("remux %s to %s end with error:%s", param->src, param->dst, err2str(error));
 
-		//call back end
-		if (param->cb_state)
-			param->cb_state(param->src, 0, error);
+    //call back end
+    if (param->cb_state)
+        param->cb_state(param->src, 0, error);
 
-		remuxer_ffmpeg::instance()->remove_remux(param->src);
-	}
+    remuxer_ffmpeg::instance()->remove_remux(param->src);
+}
 
-	remuxer_ffmpeg * remuxer_ffmpeg::instance()
-	{
-		std::lock_guard<std::mutex> lock(_g_mutex);
+remuxer_ffmpeg *remuxer_ffmpeg::instance()
+{
+    std::lock_guard<std::mutex> lock(_g_mutex);
 
-		if (_g_instance == nullptr) _g_instance = new remuxer_ffmpeg();
+    if (_g_instance == nullptr)
+        _g_instance = new remuxer_ffmpeg();
 
-		return _g_instance;
-	}
+    return _g_instance;
+}
 
-	void remuxer_ffmpeg::release()
-	{
-		std::lock_guard<std::mutex> lock(_g_mutex);
+void remuxer_ffmpeg::release()
+{
+    std::lock_guard<std::mutex> lock(_g_mutex);
 
-		if (_g_instance)
-			delete _g_instance;
+    if (_g_instance)
+        delete _g_instance;
 
-		_g_instance = nullptr;
-	}
+    _g_instance = nullptr;
+}
 
+int remuxer_ffmpeg::create_remux(const REMUXER_PARAM &param)
+{
+    std::lock_guard<std::mutex> lock(_g_mutex);
 
+    auto itr = _handlers.find(param.src);
+    if (itr != _handlers.end() && itr->second->fn.joinable() == true) {
+        return AE_REMUX_RUNNING;
+    }
 
-	int remuxer_ffmpeg::create_remux(const REMUXER_PARAM & param)
-	{
-		std::lock_guard<std::mutex> lock(_g_mutex);
-
-		auto itr = _handlers.find(param.src);
-		if (itr != _handlers.end() && itr->second->fn.joinable() == true) {
-			return AE_REMUX_RUNNING;
-		}
-
-
-		if (!strlen(param.src) || !strlen(param.dst) || !strcmp(param.src, param.dst))
-			return AE_REMUX_INVALID_INOUT;
+    if (!strlen(param.src) || !strlen(param.dst) || !strcmp(param.src, param.dst))
+        return AE_REMUX_INVALID_INOUT;
 
 #ifdef _MSC_VER
-		struct _stat64 st = { 0 };
-		_stat64(param.src, &st);
+    struct _stat64 st = {0};
+    _stat64(param.src, &st);
 #else
-		struct stat st = { 0 };
-		stat(param.src, &st);
+    struct stat st = {0};
+    stat(param.src, &st);
 #endif
 
-		if (!st.st_size) return AE_REMUX_NOT_EXIST;
-
-
-		if (itr != _handlers.end()) {
-			delete itr->second;
+    if (!st.st_size)
+        return AE_REMUX_NOT_EXIST;
 
-			_handlers.erase(itr);
-		}
+    if (itr != _handlers.end()) {
+        delete itr->second;
 
-		REMUXER_HANDLE *handle = new REMUXER_HANDLE;
+        _handlers.erase(itr);
+    }
 
-		memcpy(&(handle->param), &param, sizeof(REMUXER_PARAM));
+    REMUXER_HANDLE *handle = new REMUXER_HANDLE;
 
-		handle->param.running = true;
-		handle->param.src_size = st.st_size;
-		handle->fn = std::thread(remuxing, &handle->param);
+    memcpy(&(handle->param), &param, sizeof(REMUXER_PARAM));
 
-		_handlers[param.src] = handle;
+    handle->param.running = true;
+    handle->param.src_size = st.st_size;
+    handle->fn = std::thread(remuxing, &handle->param);
 
-		return AE_NO;
-	}
+    _handlers[param.src] = handle;
 
-	void remuxer_ffmpeg::remove_remux(std::string src)
-	{
-		std::lock_guard<std::mutex> lock(_g_mutex);
+    return AE_NO;
+}
 
-		auto itr = _handlers.find(src);
-		if (itr != _handlers.end()) {
-			itr->second->fn.detach();
+void remuxer_ffmpeg::remove_remux(std::string src)
+{
+    std::lock_guard<std::mutex> lock(_g_mutex);
 
-			delete itr->second;
-			_handlers.erase(itr);
-		}
-	}
+    auto itr = _handlers.find(src);
+    if (itr != _handlers.end()) {
+        itr->second->fn.detach();
 
-	void remuxer_ffmpeg::destroy_remux()
-	{
-		std::lock_guard<std::mutex> lock(_g_mutex);
+        delete itr->second;
+        _handlers.erase(itr);
+    }
+}
 
-		for (auto itr = _handlers.begin(); itr != _handlers.end(); itr++)
-		{
-			itr->second->param.running = false;
+void remuxer_ffmpeg::destroy_remux()
+{
+    std::lock_guard<std::mutex> lock(_g_mutex);
 
-			if (itr->second->fn.joinable())
-				itr->second->fn.join();
+    for (auto itr = _handlers.begin(); itr != _handlers.end(); itr++) {
+        itr->second->param.running = false;
 
-			delete itr->second;
+        if (itr->second->fn.joinable())
+            itr->second->fn.join();
 
-			_handlers.erase(itr);
-		}
-	}
+        delete itr->second;
 
-}
+        _handlers.erase(itr);
+    }
+}
+} // namespace am

+ 35 - 37
libs/Recorder/remuxer_ffmpeg.h

@@ -1,56 +1,54 @@
 #ifndef REMUXER_FFMPEG
 #define REMUXER_FFMPEG
 
-#include <map>
 #include <atomic>
 #include <functional>
-#include <thread>
+#include <map>
 #include <string>
+#include <thread>
 
 namespace am {
-	typedef void(*cb_remux_progress)(const char *, int, int);
-	typedef void(*cb_remux_state)(const char *, int, int);
-
-	typedef struct _REMUXER_PARAM {
-		char src[260];
-		char dst[260];
-		int64_t src_size;
-		std::atomic_bool running;
-		cb_remux_progress cb_progress;
-		cb_remux_state cb_state;
-	}REMUXER_PARAM;
-
-	typedef std::function<void(REMUXER_PARAM*)> thread_remuxing;
+typedef void (*cb_remux_progress)(const char *, int, int);
+typedef void (*cb_remux_state)(const char *, int, int);
 
-	typedef struct _REMUXER_HANDLE {
-		REMUXER_PARAM param;
-		std::thread fn;
-	}REMUXER_HANDLE;
-	
+typedef struct _REMUXER_PARAM
+{
+    char src[260];
+    char dst[260];
+    int64_t src_size;
+    std::atomic_bool running;
+    cb_remux_progress cb_progress;
+    cb_remux_state cb_state;
+} REMUXER_PARAM;
 
-	class remuxer_ffmpeg
-	{
-	private:
-		remuxer_ffmpeg(){}
-		
-		~remuxer_ffmpeg() { destroy_remux(); }
+typedef std::function<void(REMUXER_PARAM *)> thread_remuxing;
 
-	public:
-		static remuxer_ffmpeg *instance();
-		static void release();
+typedef struct _REMUXER_HANDLE
+{
+    REMUXER_PARAM param;
+    std::thread fn;
+} REMUXER_HANDLE;
 
-		int create_remux(const REMUXER_PARAM & param);
+class remuxer_ffmpeg
+{
+private:
+    remuxer_ffmpeg() {}
 
-		void remove_remux(std::string src);
+    ~remuxer_ffmpeg() { destroy_remux(); }
 
-		void destroy_remux();
+public:
+    static remuxer_ffmpeg *instance();
+    static void release();
 
-	private:
-		std::map<std::string, REMUXER_HANDLE*> _handlers;
-	};
+    int create_remux(const REMUXER_PARAM &param);
 
-}
+    void remove_remux(std::string src);
 
+    void destroy_remux();
 
+private:
+    std::map<std::string, REMUXER_HANDLE *> _handlers;
+};
+} // namespace am
 
-#endif // !REMUXER_FFMPEG
+#endif // !REMUXER_FFMPEG

+ 84 - 76
libs/Recorder/resample_pcm.cpp

@@ -1,72 +1,80 @@
 #include "resample_pcm.h"
 
-#include "log_helper.h"
 #include "error_define.h"
+#include "log_helper.h"
 
 namespace am {
-	resample_pcm::resample_pcm()
-	{
-		_sample_src = NULL;
-		_sample_dst = NULL;
-		_ctx = NULL;
-	}
-
-	resample_pcm::~resample_pcm()
-	{
-		cleanup();
-	}
-
-	int resample_pcm::init(const SAMPLE_SETTING * sample_src, const SAMPLE_SETTING * sample_dst, int * resapmled_frame_size)
-	{
-		int err = AE_NO;
-
-		do {
-			_sample_src = (SAMPLE_SETTING*)malloc(sizeof(SAMPLE_SETTING));
-			_sample_dst = (SAMPLE_SETTING*)malloc(sizeof(SAMPLE_SETTING));
-
-			memcpy(_sample_src, sample_src, sizeof(SAMPLE_SETTING));
-			memcpy(_sample_dst, sample_dst, sizeof(SAMPLE_SETTING));
-
-			_ctx = swr_alloc_set_opts(NULL,
-				_sample_dst->channel_layout, _sample_dst->fmt, _sample_dst->sample_rate,
-				_sample_src->channel_layout, _sample_src->fmt, _sample_src->sample_rate,
-				0, NULL);
-
-			if (_ctx == NULL) {
-				err = AE_RESAMPLE_INIT_FAILED;
-				break;
-			}
-
-			int ret = swr_init(_ctx);
-			if (ret < 0) {
-				err = AE_RESAMPLE_INIT_FAILED;
-				break;
-			}
-
-
-
-			*resapmled_frame_size = av_samples_get_buffer_size(NULL, _sample_dst->nb_channels, _sample_dst->nb_samples, _sample_dst->fmt, 1);
-
-		} while (0);
-
-		if (err != AE_NO) {
-			cleanup();
-			al_fatal("resample pcm init failed:%d", err);
-		}
-
-		return err;
-	}
-
-	int resample_pcm::convert(const uint8_t * src, int src_len, uint8_t * dst, int dst_len)
-	{
-
-		uint8_t *out[2] = { 0 };
-		out[0] = dst;
-		out[1] = dst + dst_len / 2;
-
-		const uint8_t *in1[2] = { src,NULL };
-
-		/*
+resample_pcm::resample_pcm()
+{
+    _sample_src = NULL;
+    _sample_dst = NULL;
+    _ctx = NULL;
+}
+
+resample_pcm::~resample_pcm()
+{
+    cleanup();
+}
+
+int resample_pcm::init(const SAMPLE_SETTING *sample_src,
+                       const SAMPLE_SETTING *sample_dst,
+                       int *resapmled_frame_size)
+{
+    int err = AE_NO;
+
+    do {
+        _sample_src = (SAMPLE_SETTING *) malloc(sizeof(SAMPLE_SETTING));
+        _sample_dst = (SAMPLE_SETTING *) malloc(sizeof(SAMPLE_SETTING));
+
+        memcpy(_sample_src, sample_src, sizeof(SAMPLE_SETTING));
+        memcpy(_sample_dst, sample_dst, sizeof(SAMPLE_SETTING));
+
+        _ctx = swr_alloc_set_opts(NULL,
+                                  _sample_dst->channel_layout,
+                                  _sample_dst->fmt,
+                                  _sample_dst->sample_rate,
+                                  _sample_src->channel_layout,
+                                  _sample_src->fmt,
+                                  _sample_src->sample_rate,
+                                  0,
+                                  NULL);
+
+        if (_ctx == NULL) {
+            err = AE_RESAMPLE_INIT_FAILED;
+            break;
+        }
+
+        int ret = swr_init(_ctx);
+        if (ret < 0) {
+            err = AE_RESAMPLE_INIT_FAILED;
+            break;
+        }
+
+        *resapmled_frame_size = av_samples_get_buffer_size(NULL,
+                                                           _sample_dst->nb_channels,
+                                                           _sample_dst->nb_samples,
+                                                           _sample_dst->fmt,
+                                                           1);
+
+    } while (0);
+
+    if (err != AE_NO) {
+        cleanup();
+        al_fatal("resample pcm init failed:%d", err);
+    }
+
+    return err;
+}
+
+int resample_pcm::convert(const uint8_t *src, int src_len, uint8_t *dst, int dst_len)
+{
+    uint8_t *out[2] = {0};
+    out[0] = dst;
+    out[1] = dst + dst_len / 2;
+
+    const uint8_t *in1[2] = {src, NULL};
+
+    /*
 		uint8_t *in[2] = { 0 };
 		in[0] = (uint8_t*)src;
 		in[1] = (uint8_t*)(src + src_len / 2);
@@ -80,17 +88,17 @@ namespace am {
 		avcodec_fill_audio_frame(sample_frame, _sample_dst->nb_channels, _sample_dst->fmt, src, src_len, 0);
 		*/
 
-		return swr_convert(_ctx, out, _sample_dst->nb_samples, in1, _sample_src->nb_samples);
-	}
-	void resample_pcm::cleanup()
-	{
-		if(_sample_src)
-			free(_sample_src);
+    return swr_convert(_ctx, out, _sample_dst->nb_samples, in1, _sample_src->nb_samples);
+}
+void resample_pcm::cleanup()
+{
+    if (_sample_src)
+        free(_sample_src);
 
-		if(_sample_dst)
-			free(_sample_dst);
+    if (_sample_dst)
+        free(_sample_dst);
 
-		if(_ctx)
-			swr_free(&_ctx);
-	}
-}
+    if (_ctx)
+        swr_free(&_ctx);
+}
+} // namespace am

+ 27 - 22
libs/Recorder/resample_pcm.h

@@ -6,28 +6,33 @@
 #include "headers_ffmpeg.h"
 
 namespace am {
-	typedef struct {
-		int nb_samples;
-		int64_t channel_layout;
-		int nb_channels;
-		AVSampleFormat fmt;
-		int sample_rate;
-	}SAMPLE_SETTING;
+typedef struct
+{
+    int nb_samples;
+    int64_t channel_layout;
+    int nb_channels;
+    AVSampleFormat fmt;
+    int sample_rate;
+} SAMPLE_SETTING;
 
-	class resample_pcm
-	{
-	public:
-		resample_pcm();
-		~resample_pcm();
+class resample_pcm
+{
+public:
+    resample_pcm();
+    ~resample_pcm();
 
-		int init(const SAMPLE_SETTING *sample_src, const SAMPLE_SETTING *sample_dst,__out int *resapmled_frame_size);
-		int convert(const uint8_t *src, int src_len, uint8_t *dst, int dst_len);
-	protected:
-		void cleanup();
-	private:
-		SwrContext *_ctx;
-		SAMPLE_SETTING *_sample_src;
-		SAMPLE_SETTING *_sample_dst;
-	};
-}
+    int init(const SAMPLE_SETTING *sample_src,
+             const SAMPLE_SETTING *sample_dst,
+             __out int *resapmled_frame_size);
+    int convert(const uint8_t *src, int src_len, uint8_t *dst, int dst_len);
+
+protected:
+    void cleanup();
+
+private:
+    SwrContext *_ctx;
+    SAMPLE_SETTING *_sample_src;
+    SAMPLE_SETTING *_sample_dst;
+};
+} // namespace am
 #endif

+ 67 - 73
libs/Recorder/ring_buffer.cpp

@@ -1,96 +1,90 @@
-#include "ring_buffer.h"
+// #include "ring_buffer.h"
 
-#include "error_define.h"
-#include "log_helper.h"
+// #include "error_define.h"
+// #include "log_helper.h"
 
-namespace am {
+// namespace am {
+// template<typename T>
+// ring_buffer<T>::ring_buffer(unsigned int size)
+// {
+//     _size = size;
+//     _head = _tail = 0;
 
-	template<typename T>
-	ring_buffer<T>::ring_buffer(unsigned int size)
-	{
-		_size = size;
-		_head = _tail = 0;
+//     _buf = new uint8_t[size];
+// }
 
-		_buf = new uint8_t[size];
-	}
+// template<typename T>
+// ring_buffer<T>::~ring_buffer()
+// {
+//     if (_buf)
+//         delete[] _buf;
+// }
 
-	template<typename T>
-	ring_buffer<T>::~ring_buffer()
-	{
-		if (_buf)
-			delete[] _buf;
-	}
+// template<typename T>
+// void ring_buffer<T>::put(const void *data, int len, const T &type)
+// {
+//     std::lock_guard<std::mutex> locker(_lock);
 
-	template<typename T>
-	void ring_buffer<T>::put(const void * data, int len, const T & type)
-	{
-		std::lock_guard<std::mutex> locker(_lock);
+//     if (_head + len <= _size) {
+//         memcpy(_buf + _head, data, len);
 
-		if (_head + len <= _size) {
-			memcpy(_buf + _head, data, len);
+//         _head += len;
+//     } else if (_head + len > _size) {
+//         int remain = len - (_size - _head);
+//         if (len - remain > 0)
+//             memcpy(_buf + _head, data, len - remain);
 
-			_head += len;
-		}
-		else if (_head + len > _size) {
-			int remain = len - (_size - _head);
-			if (len - remain > 0)
-				memcpy(_buf + _head, data, len - remain);
+//         if (remain > 0)
+//             memcpy(_buf, (unsigned char *) data + len - remain, remain);
 
-			if (remain > 0)
-				memcpy(_buf, (unsigned char*)data + len - remain, remain);
+//         _head = remain;
+//     }
 
-			_head = remain;
-		}
+//     struct ring_frame<T> frame;
+//     frame.len = len;
+//     frame.type = type;
 
-		struct ring_frame<T> frame;
-		frame.len = len;
-		frame.type = type;
+//     _frames.push(frame);
+// }
 
-		_frames.push(frame);
-	}
+// template<typename T>
+// int ring_buffer<T>::get(void *data, int len, T &type)
+// {
+//     std::lock_guard<std::mutex> locker(_lock);
 
-	template<typename T>
-	int ring_buffer<T>::get(void * data, int len, T & type)
-	{
-		std::lock_guard<std::mutex> locker(_lock);
+//     int retLen = 0;
 
-		int retLen = 0;
+//     if (_frames.size() <= 0) {
+//         retLen = 0;
+//         return retLen;
+//     }
 
-		if (_frames.size() <= 0) {
-			retLen = 0;
-			return retLen;
-		}
+//     struct ring_frame<T> frame = _frames.front();
+//     _frames.pop();
 
-		struct ring_frame<T> frame = _frames.front();
-		_frames.pop();
+//     if (frame.len > len) {
+//         al_error("ringbuff::get need larger buffer");
+//         return 0;
+//     }
 
-		if (frame.len > len) {
-			al_error("ringbuff::get need larger buffer");
-			return 0;
-		}
+//     type = frame.type retLen = frame.len;
 
-		type = frame.type
+//     if (_tail + frame.len <= _size) {
+//         memcpy(data, _buf + _tail, frame.len);
 
-		retLen = frame.len;
+//         _tail += frame.len;
+//     } else {
+//         int remain = frame.len - (_size - _tail);
 
-		if (_tail + frame.len <= _size) {
+//         if (frame.len - remain > 0)
+//             memcpy(data, _buf + _tail, frame.len - remain);
 
-			memcpy(data, _buf + _tail, frame.len);
+//         if (remain > 0)
+//             memcpy((unsigned char *) data + frame.len - remain, _buf, remain);
 
-			_tail += frame.len;
-		}
-		else {
-			int remain = frame.len - (_size - _tail);
+//         _tail = remain;
+//     }
 
-			if (frame.len - remain > 0)
-				memcpy(data, _buf + _tail, frame.len - remain);
-
-			if (remain > 0)
-				memcpy((unsigned char*)data + frame.len - remain, _buf, remain);
-
-			_tail = remain;
-		}
-
-		return retLen;
-	}
-}
+//     return retLen;
+// }
+// } // namespace am

+ 78 - 83
libs/Recorder/ring_buffer.h

@@ -4,117 +4,112 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <queue>
 #include <mutex>
+#include <queue>
 
 #include "error_define.h"
 #include "log_helper.h"
 
 namespace am {
+template<typename T>
+struct ring_frame
+{
+    T type;
+    int len;
+};
 
-	template <typename T>
-	struct ring_frame {
-		T type;
-		int len;
-	};
-
-	template <typename T>
-	class ring_buffer
-	{
-	public:
-		ring_buffer(unsigned int size = 1920 * 1080 * 4 * 10)
-		{
-			_size = size;
-			_head = _tail = 0;
-
-			_buf = new uint8_t[size];
-		}
-		~ring_buffer()
-		{
-			if (_buf)
-				delete[] _buf;
-		}
-
-		void put(const void *data, int len, const T &type)
-		{
-			std::lock_guard<std::mutex> locker(_lock);
-
-			if (_head + len <= _size) {
-				memcpy(_buf + _head, data, len);
+template<typename T>
+class ring_buffer
+{
+public:
+    ring_buffer(unsigned int size = 1920 * 1080 * 4 * 10)
+    {
+        _size = size;
+        _head = _tail = 0;
 
-				_head += len;
-			}
-			else if (_head + len > _size) {
-				int remain = len - (_size - _head);
-				if (len - remain > 0)
-					memcpy(_buf + _head, data, len - remain);
+        _buf = new uint8_t[size];
+    }
+    ~ring_buffer()
+    {
+        if (_buf)
+            delete[] _buf;
+    }
 
-				if (remain > 0)
-					memcpy(_buf, (unsigned char*)data + len - remain, remain);
+    void put(const void *data, int len, const T &type)
+    {
+        std::lock_guard<std::mutex> locker(_lock);
 
-				_head = remain;
-			}
+        if (_head + len <= _size) {
+            memcpy(_buf + _head, data, len);
 
-			struct ring_frame<T> frame;
-			frame.len = len;
-			frame.type = type;
+            _head += len;
+        } else if (_head + len > _size) {
+            int remain = len - (_size - _head);
+            if (len - remain > 0)
+                memcpy(_buf + _head, data, len - remain);
 
-			_frames.push(frame);
+            if (remain > 0)
+                memcpy(_buf, (unsigned char *) data + len - remain, remain);
 
-		}
+            _head = remain;
+        }
 
-		int get(void *data, int len, T &type)
-		{
-			std::lock_guard<std::mutex> locker(_lock);
+        struct ring_frame<T> frame;
+        frame.len = len;
+        frame.type = type;
 
-			int retLen = 0;
+        _frames.push(frame);
+    }
 
-			if (_frames.size() <= 0) {
-				retLen = 0;
-				return retLen;
-			}
+    int get(void *data, int len, T &type)
+    {
+        std::lock_guard<std::mutex> locker(_lock);
 
-			struct ring_frame<T> frame = _frames.front();
-			_frames.pop();
+        int retLen = 0;
 
-			if (frame.len > len) {
-				al_error("ringbuff::get need larger buffer");
-				return 0;
-			}
+        if (_frames.size() <= 0) {
+            retLen = 0;
+            return retLen;
+        }
 
-			type = frame.type;
+        struct ring_frame<T> frame = _frames.front();
+        _frames.pop();
 
-			retLen = frame.len;
+        if (frame.len > len) {
+            al_error("ringbuff::get need larger buffer");
+            return 0;
+        }
 
-			if (_tail + frame.len <= _size) {
+        type = frame.type;
 
-				memcpy(data, _buf + _tail, frame.len);
+        retLen = frame.len;
 
-				_tail += frame.len;
-			}
-			else {
-				int remain = frame.len - (_size - _tail);
+        if (_tail + frame.len <= _size) {
+            memcpy(data, _buf + _tail, frame.len);
 
-				if (frame.len - remain > 0)
-					memcpy(data, _buf + _tail, frame.len - remain);
+            _tail += frame.len;
+        } else {
+            int remain = frame.len - (_size - _tail);
 
-				if (remain > 0)
-					memcpy((unsigned char*)data + frame.len - remain, _buf, remain);
+            if (frame.len - remain > 0)
+                memcpy(data, _buf + _tail, frame.len - remain);
 
-				_tail = remain;
-			}
+            if (remain > 0)
+                memcpy((unsigned char *) data + frame.len - remain, _buf, remain);
 
-			return retLen;
-		}
+            _tail = remain;
+        }
 
-	private:
-		std::queue<ring_frame<T>> _frames;
-		unsigned int _size, _head, _tail;
+        return retLen;
+    }
 
-		uint8_t *_buf;
+private:
+    std::queue<ring_frame<T>> _frames;
+    unsigned int _size, _head, _tail;
 
-		std::mutex _lock;
-	};
+    uint8_t *_buf;
 
-}
-#endif
+    std::mutex _lock;
+};
+} // namespace am
+#endif

+ 70 - 68
libs/Recorder/sws_helper.cpp

@@ -4,94 +4,96 @@
 #include "log_helper.h"
 
 namespace am {
+sws_helper::sws_helper()
+{
+    _inited = false;
 
-	sws_helper::sws_helper()
-	{
-		_inited = false;
+    _frame = NULL;
 
-		_frame = NULL;
+    _buffer = NULL;
 
-		_buffer = NULL;
+    _ctx = NULL;
+}
 
-		_ctx = NULL;
-	}
+sws_helper::~sws_helper()
+{
+    cleanup();
+}
 
+int sws_helper::init(AVPixelFormat src_fmt,
+                     int src_width,
+                     int src_height,
+                     AVPixelFormat dst_fmt,
+                     int dst_width,
+                     int dst_height)
+{
+    if (_inited)
+        return AE_NO;
 
-	sws_helper::~sws_helper()
-	{
-		cleanup();
-	}
+    _ctx = sws_getContext(src_width,
+                          src_height,
+                          src_fmt,
+                          dst_width,
+                          dst_height,
+                          dst_fmt,
+                          SWS_BICUBIC,
+                          NULL,
+                          NULL,
+                          NULL);
 
-	int sws_helper::init(AVPixelFormat src_fmt, int src_width, int src_height, AVPixelFormat dst_fmt, int dst_width, int dst_height)
-	{
-		if (_inited)
-			return AE_NO;
+    if (!_ctx) {
+        return AE_FFMPEG_NEW_SWSCALE_FAILED;
+    }
 
-		_ctx = sws_getContext(
-			src_width,
-			src_height,
-			src_fmt,
-			dst_width,
-			dst_height,
-			dst_fmt,
-			SWS_BICUBIC,
-			NULL, NULL, NULL
-		);
+    _buffer_size = av_image_get_buffer_size(dst_fmt, dst_width, dst_height, 1);
+    _buffer = new uint8_t[_buffer_size];
 
-		if (!_ctx) {
-			return AE_FFMPEG_NEW_SWSCALE_FAILED;
-		}
+    _frame = av_frame_alloc();
 
-		_buffer_size = av_image_get_buffer_size(dst_fmt, dst_width, dst_height, 1);
-		_buffer = new uint8_t[_buffer_size];
+    av_image_fill_arrays(_frame->data, _frame->linesize, _buffer, dst_fmt, dst_width, dst_height, 1);
 
-		_frame = av_frame_alloc();
+    _inited = true;
 
-		av_image_fill_arrays(_frame->data, _frame->linesize, _buffer, dst_fmt, dst_width, dst_height, 1);
+    return AE_NO;
+}
 
-		_inited = true;
+int sws_helper::convert(const AVFrame *frame, uint8_t **out_data, int *len)
+{
+    int error = AE_NO;
+    if (!_inited || !_ctx || !_buffer)
+        return AE_NEED_INIT;
 
-		return AE_NO;
-	}
+    int ret = sws_scale(_ctx,
+                        (const uint8_t *const *) frame->data,
+                        frame->linesize,
+                        0,
+                        frame->height,
+                        _frame->data,
+                        _frame->linesize);
 
-	int sws_helper::convert(const AVFrame *frame, uint8_t ** out_data, int * len)
-	{
-		int error = AE_NO;
-		if (!_inited || !_ctx || !_buffer)
-			return AE_NEED_INIT;
+    *out_data = _buffer;
+    *len = _buffer_size;
 
-		int ret = sws_scale(
-			_ctx,
-			(const uint8_t *const *)frame->data,
-			frame->linesize,
-			0, frame->height,
-			_frame->data, _frame->linesize
-		);
+    return error;
+}
 
-		*out_data = _buffer;
-		*len = _buffer_size;
+void sws_helper::cleanup()
+{
+    _inited = false;
 
-		return error;
-	}
+    if (_ctx)
+        sws_freeContext(_ctx);
 
-	void sws_helper::cleanup()
-	{
-		_inited = false;
+    _ctx = NULL;
 
-		if (_ctx)
-			sws_freeContext(_ctx);
+    if (_frame)
+        av_frame_free(&_frame);
 
-		_ctx = NULL;
+    _frame = NULL;
 
-		if (_frame)
-			av_frame_free(&_frame);
+    if (_buffer)
+        delete[] _buffer;
 
-		_frame = NULL;
-
-		if (_buffer)
-			delete[] _buffer;
-
-		_buffer = NULL;
-	}
-
-}
+    _buffer = NULL;
+}
+} // namespace am

+ 22 - 22
libs/Recorder/sws_helper.h

@@ -5,32 +5,32 @@
 #include "headers_ffmpeg.h"
 
 namespace am {
+class sws_helper
+{
+public:
+    sws_helper();
+    ~sws_helper();
 
-	class sws_helper
-	{
-	public:
-		sws_helper();
-		~sws_helper();
-		
-		int init(
-			AVPixelFormat src_fmt,int src_width,int src_height,
-			AVPixelFormat dst_fmt,int dst_width,int dst_height
-		);
+    int init(AVPixelFormat src_fmt,
+             int src_width,
+             int src_height,
+             AVPixelFormat dst_fmt,
+             int dst_width,
+             int dst_height);
 
-		int convert(const AVFrame *frame, uint8_t ** out_data, int *len);
+    int convert(const AVFrame *frame, uint8_t **out_data, int *len);
 
-	private:
-		void cleanup();
+private:
+    void cleanup();
 
-	private:
-		std::atomic_bool _inited;
+private:
+    std::atomic_bool _inited;
 
-		AVFrame *_frame;
+    AVFrame *_frame;
 
-		uint8_t *_buffer;
-		int _buffer_size;
+    uint8_t *_buffer;
+    int _buffer_size;
 
-		struct SwsContext *_ctx;
-	};
-
-}
+    struct SwsContext *_ctx;
+};
+} // namespace am

+ 38 - 30
libs/Recorder/system_error.cpp

@@ -3,36 +3,44 @@
 #include <Windows.h>
 
 namespace am {
-
 const std::string& system_error::error2str(unsigned long error)
 {
-	DWORD system_locale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
-
-	HLOCAL local_buf = nullptr;
-
-	BOOL ret = FormatMessage(
-		FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
-		NULL, error, system_locale,(PSTR) &local_buf, 0, NULL);
-
-	if (!ret) {
-		HMODULE hnetmsg = LoadLibraryEx("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
-		if (hnetmsg != nullptr) {
-			ret = FormatMessage(
-				FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
-				hnetmsg, error, system_locale, (PSTR)&local_buf, 0, NULL);
-
-			FreeLibrary(hnetmsg);
-		}
-	}
-
-	std::string error_str;
-
-	if (ret) {
-		error_str = (LPCTSTR)LocalLock(local_buf);
-		LocalFree(local_buf);
-	}
-
-	return error_str;
+    DWORD system_locale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
+
+    HLOCAL local_buf = nullptr;
+
+    BOOL ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS
+                                  | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                              NULL,
+                              error,
+                              system_locale,
+                              (PSTR) &local_buf,
+                              0,
+                              NULL);
+
+    if (!ret) {
+        HMODULE hnetmsg = LoadLibraryExA("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
+        if (hnetmsg != nullptr) {
+            ret = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS
+                                     | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                                 hnetmsg,
+                                 error,
+                                 system_locale,
+                                 (PSTR) &local_buf,
+                                 0,
+                                 NULL);
+
+            FreeLibrary(hnetmsg);
+        }
+    }
+
+    std::string error_str;
+
+    if (ret) {
+        error_str = (char*) LocalLock(local_buf);
+        LocalFree(local_buf);
+    }
+
+    return error_str;
 }
-
-}
+} // namespace am

+ 4 - 5
libs/Recorder/system_error.h

@@ -3,10 +3,9 @@
 #include <string>
 
 namespace am {
-
-class system_error {
+class system_error
+{
 public:
-	static const std::string& error2str(unsigned long error);
+    static const std::string& error2str(unsigned long error);
 };
-
-}
+} // namespace am

+ 42 - 43
libs/Recorder/system_lib.cpp

@@ -3,46 +3,45 @@
 #include "log_helper.h"
 
 namespace am {
-
-	static char system_path[260] = { 0 };
-
-	static bool get_system_path() {
-
-		if (strlen(system_path) == 0) {
-			UINT ret = GetSystemDirectoryA(system_path, MAX_PATH);
-			if (!ret) {
-				al_fatal("failed to get system directory :%lu", GetLastError());
-				return false;
-			}
-		}
-
-		return true;
-	}
-
-	HMODULE load_system_library(const char * name)
-	{
-		if (get_system_path() == false) return NULL;
-
-		char base_path[MAX_PATH] = { 0 };
-		strcpy(base_path, system_path);
-		strcat(base_path, "\\");
-		strcat(base_path, name);
-
-		HMODULE module = GetModuleHandleA(base_path);
-		if (module)
-			return module;
-
-		module = LoadLibraryA(base_path);
-		if (!module) {
-			al_error("failed load system library :%lu", GetLastError());
-		}
-
-		return module;
-	}
-
-	void free_system_library(HMODULE handle)
-	{
-		FreeModule(handle);
-	}
-
-}
+static char system_path[260] = {0};
+
+static bool get_system_path()
+{
+    if (strlen(system_path) == 0) {
+        UINT ret = GetSystemDirectoryA(system_path, MAX_PATH);
+        if (!ret) {
+            al_fatal("failed to get system directory :%lu", GetLastError());
+            return false;
+        }
+    }
+
+    return true;
+}
+
+HMODULE load_system_library(const char *name)
+{
+    if (get_system_path() == false)
+        return NULL;
+
+    char base_path[MAX_PATH] = {0};
+    strcpy(base_path, system_path);
+    strcat(base_path, "\\");
+    strcat(base_path, name);
+
+    HMODULE module = GetModuleHandleA(base_path);
+    if (module)
+        return module;
+
+    module = LoadLibraryA(base_path);
+    if (!module) {
+        al_error("failed load system library :%lu", GetLastError());
+    }
+
+    return module;
+}
+
+void free_system_library(HMODULE handle)
+{
+    FreeModule(handle);
+}
+} // namespace am

+ 4 - 5
libs/Recorder/system_lib.h

@@ -2,9 +2,8 @@
 
 #include <Windows.h>
 
-namespace am{
-	HMODULE load_system_library(const char *name);
-	
-	void free_system_library(HMODULE handle);
+namespace am {
+HMODULE load_system_library(const char *name);
 
-}
+void free_system_library(HMODULE handle);
+} // namespace am

+ 26 - 27
libs/Recorder/system_time.cpp

@@ -3,30 +3,29 @@
 #include <Windows.h>
 
 namespace am {
-
-	static bool got_clockfreq = false;
-	static LARGE_INTEGER  clock_freq;
-
-	static uint64_t get_clockfreq() {
-		if (!got_clockfreq) {
-			QueryPerformanceFrequency(&clock_freq);
-			got_clockfreq = true;
-		}
-
-		return clock_freq.QuadPart;
-	}
-
-	uint64_t system_time::get_time_ns()
-	{
-		LARGE_INTEGER current_time;
-		double time_val;
-
-		QueryPerformanceCounter(&current_time);
-		time_val = (double)current_time.QuadPart;
-		time_val *= 1000000000.0;
-		time_val /= (double)get_clockfreq();
-
-		return (uint64_t)time_val;
-	}
-
-}
+static bool got_clockfreq = false;
+static LARGE_INTEGER clock_freq;
+
+static uint64_t get_clockfreq()
+{
+    if (!got_clockfreq) {
+        QueryPerformanceFrequency(&clock_freq);
+        got_clockfreq = true;
+    }
+
+    return clock_freq.QuadPart;
+}
+
+uint64_t system_time::get_time_ns()
+{
+    LARGE_INTEGER current_time;
+    double time_val;
+
+    QueryPerformanceCounter(&current_time);
+    time_val = (double) current_time.QuadPart;
+    time_val *= 1000000000.0;
+    time_val /= (double) get_clockfreq();
+
+    return (uint64_t) time_val;
+}
+} // namespace am

+ 10 - 11
libs/Recorder/system_time.h

@@ -4,16 +4,15 @@
 #include <stdint.h>
 
 namespace am {
+class system_time
+{
+private:
+    system_time() {};
+    ~system_time() {};
 
-	class system_time
-	{
-	private:
-		system_time() {};
-		~system_time() {};
-	public:
-		static uint64_t get_time_ns();
-	};
+public:
+    static uint64_t get_time_ns();
+};
+} // namespace am
 
-}
-
-#endif // !SYSTEM_TIME
+#endif // !SYSTEM_TIME

+ 126 - 137
libs/Recorder/system_version.cpp

@@ -2,17 +2,17 @@
 
 #include <Windows.h>
 
-#include "utils_string.h"
 #include "log_helper.h"
+#include "utils_string.h"
 
 #define WINVER_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
 
-typedef DWORD(WINAPI *get_file_version_info_size_w_t)(LPCWSTR module,
-	LPDWORD unused);
-typedef BOOL(WINAPI *get_file_version_info_w_t)(LPCWSTR module, DWORD unused,
-	DWORD len, LPVOID data);
-typedef BOOL(WINAPI *ver_query_value_w_t)(LPVOID data, LPCWSTR subblock,
-	LPVOID *buf, PUINT sizeout);
+typedef DWORD(WINAPI *get_file_version_info_size_w_t)(LPCWSTR module, LPDWORD unused);
+typedef BOOL(WINAPI *get_file_version_info_w_t)(LPCWSTR module,
+                                                DWORD unused,
+                                                DWORD len,
+                                                LPVOID data);
+typedef BOOL(WINAPI *ver_query_value_w_t)(LPVOID data, LPCWSTR subblock, LPVOID *buf, PUINT sizeout);
 
 static get_file_version_info_size_w_t get_file_version_info_size = NULL;
 static get_file_version_info_w_t get_file_version_info = NULL;
@@ -22,144 +22,133 @@ static bool ver_initialize_success = false;
 
 static bool initialize_version_functions(void)
 {
-	HMODULE ver = GetModuleHandleW(L"version");
-
-	ver_initialized = true;
-
-	if (!ver) {
-		ver = LoadLibraryW(L"version");
-		if (!ver) {
-			al_error("failed to load windows version library");
-			return false;
-		}
-	}
-
-	get_file_version_info_size =
-		(get_file_version_info_size_w_t)GetProcAddress(
-			ver, "GetFileVersionInfoSizeW");
-	get_file_version_info = (get_file_version_info_w_t)GetProcAddress(
-		ver, "GetFileVersionInfoW");
-	ver_query_value =
-		(ver_query_value_w_t)GetProcAddress(ver, "VerQueryValueW");
-
-	if (!get_file_version_info_size || !get_file_version_info ||
-		!ver_query_value) {
-		al_error("failed to load windows version functions");
-		return false;
-	}
-
-	ver_initialize_success = true;
-	return true;
+    HMODULE ver = GetModuleHandleW(L"version");
+
+    ver_initialized = true;
+
+    if (!ver) {
+        ver = LoadLibraryW(L"version");
+        if (!ver) {
+            al_error("failed to load windows version library");
+            return false;
+        }
+    }
+
+    get_file_version_info_size = (get_file_version_info_size_w_t)
+        GetProcAddress(ver, "GetFileVersionInfoSizeW");
+    get_file_version_info = (get_file_version_info_w_t) GetProcAddress(ver, "GetFileVersionInfoW");
+    ver_query_value = (ver_query_value_w_t) GetProcAddress(ver, "VerQueryValueW");
+
+    if (!get_file_version_info_size || !get_file_version_info || !ver_query_value) {
+        al_error("failed to load windows version functions");
+        return false;
+    }
+
+    ver_initialize_success = true;
+    return true;
 }
 
 namespace am {
+bool system_version::get_dll(const std::string tar, winversion_info *info)
+{
+    VS_FIXEDFILEINFO *file_info = NULL;
+    UINT len = 0;
+    BOOL success;
+    LPVOID data;
+    DWORD size;
+    std::wstring wtar = utils_string::ascii_unicode(tar);
+
+    if (!ver_initialized && !initialize_version_functions())
+        return false;
+    if (!ver_initialize_success)
+        return false;
+
+    size = get_file_version_info_size(wtar.c_str(), NULL);
+    if (!size) {
+        al_error("failed to get %s version info size", tar.c_str());
+        return false;
+    }
+
+    data = malloc(size);
+    if (!get_file_version_info(wtar.c_str(), 0, size, data)) {
+        al_error("failed to get %s version info", tar.c_str());
+        free(data);
+        return false;
+    }
+
+    success = ver_query_value(data, L"\\", (LPVOID *) &file_info, &len);
+    if (!success || !file_info || !len) {
+        al_error("failed to get %s version info value", tar.c_str());
+        free(data);
+        return false;
+    }
+
+    info->major = (int) HIWORD(file_info->dwFileVersionMS);
+    info->minor = (int) LOWORD(file_info->dwFileVersionMS);
+    info->build = (int) HIWORD(file_info->dwFileVersionLS);
+    info->revis = (int) LOWORD(file_info->dwFileVersionLS);
+
+    free(data);
+    return true;
+}
+
+void system_version::get_win(winversion_info *info)
+{
+    static winversion_info ver = {0};
+    static bool got_version = false;
+
+    if (!info)
+        return;
+
+    if (!got_version) {
+        get_dll("kernel32", &ver);
+        got_version = true;
+
+        if (ver.major == 10) {
+            HKEY key;
+            DWORD size, win10_revision;
+            LSTATUS status;
+
+            status = RegOpenKeyW(HKEY_LOCAL_MACHINE, WINVER_REG_KEY, &key);
+            if (status != ERROR_SUCCESS)
+                return;
+
+            size = sizeof(win10_revision);
+
+            status = RegQueryValueExW(key, L"UBR", NULL, NULL, (LPBYTE) &win10_revision, &size);
+            if (status == ERROR_SUCCESS)
+                ver.revis = (int) win10_revision > ver.revis ? (int) win10_revision : ver.revis;
+
+            RegCloseKey(key);
+        }
+    }
+
+    *info = ver;
+}
+
+bool system_version::is_win8_or_above()
+{
+    winversion_info info;
+
+    get_win(&info);
+
+    return info.major > 6 || (info.major == 6 && info.minor >= 2);
+}
 
-	bool system_version::get_dll(const std::string tar, winversion_info * info)
-	{
-		VS_FIXEDFILEINFO *file_info = NULL;
-		UINT len = 0;
-		BOOL success;
-		LPVOID data;
-		DWORD size;
-		std::wstring wtar = utils_string::ascii_unicode(tar);
-
-		if (!ver_initialized && !initialize_version_functions())
-			return false;
-		if (!ver_initialize_success)
-			return false;
-
-		size = get_file_version_info_size(wtar.c_str(), NULL);
-		if (!size) {
-			al_error("failed to get %s version info size",tar.c_str());
-			return false;
-		}
-
-		data = malloc(size);
-		if (!get_file_version_info(wtar.c_str(), 0, size, data)) {
-			al_error("failed to get %s version info", tar.c_str());
-			free(data);
-			return false;
-		}
-
-		success = ver_query_value(data, L"\\", (LPVOID *)&file_info, &len);
-		if (!success || !file_info || !len) {
-			al_error("failed to get %s version info value",tar.c_str());
-			free(data);
-			return false;
-		}
-
-		info->major = (int)HIWORD(file_info->dwFileVersionMS);
-		info->minor = (int)LOWORD(file_info->dwFileVersionMS);
-		info->build = (int)HIWORD(file_info->dwFileVersionLS);
-		info->revis = (int)LOWORD(file_info->dwFileVersionLS);
-
-		free(data);
-		return true;
-	}
-
-	void system_version::get_win(winversion_info * info)
-	{
-		static winversion_info ver = { 0 };
-		static bool got_version = false;
-
-		if (!info)
-			return;
-
-		if (!got_version) {
-			get_dll("kernel32", &ver);
-			got_version = true;
-
-			if (ver.major == 10) {
-				HKEY key;
-				DWORD size, win10_revision;
-				LSTATUS status;
-
-				status = RegOpenKeyW(HKEY_LOCAL_MACHINE, WINVER_REG_KEY,
-					&key);
-				if (status != ERROR_SUCCESS)
-					return;
-
-				size = sizeof(win10_revision);
-
-				status = RegQueryValueExW(key, L"UBR", NULL, NULL,
-					(LPBYTE)&win10_revision,
-					&size);
-				if (status == ERROR_SUCCESS)
-					ver.revis = (int)win10_revision > ver.revis
-					? (int)win10_revision
-					: ver.revis;
-
-				RegCloseKey(key);
-			}
-		}
-
-		*info = ver;
-	}
-
-	bool system_version::is_win8_or_above()
-	{
-		winversion_info info;
-
-		get_win(&info);
-
-
-		return info.major > 6 || (info.major == 6 && info.minor >= 2);
-	}
-
-	bool system_version::is_win10_or_above(int build_number) {
+bool system_version::is_win10_or_above(int build_number)
+{
     winversion_info info;
     get_win(&info);
     return info.major > 6 || (info.major == 6 && info.minor >= 2);
-  }
+}
 
-	bool system_version::is_32()
-	{
+bool system_version::is_32()
+{
 #if defined(_WIN64)
-		return false;
+    return false;
 #elif defined(_WIN32)
-		BOOL b64 = false;
-		return !(IsWow64Process(GetCurrentProcess(), &b64) && b64);
+    BOOL b64 = false;
+    return !(IsWow64Process(GetCurrentProcess(), &b64) && b64);
 #endif
-	}
-
-}
+}
+} // namespace am

+ 22 - 22
libs/Recorder/system_version.h

@@ -5,33 +5,33 @@
 #include <string>
 
 namespace am {
-	typedef struct _winversion_info {
-		int major;
-		int minor;
-		int build;
-		int revis;
-	}winversion_info;
+typedef struct _winversion_info
+{
+    int major;
+    int minor;
+    int build;
+    int revis;
+} winversion_info;
 
-	class system_version
-	{
-	private:
-		system_version();
+class system_version
+{
+private:
+    system_version();
 
-	public:
-		static bool get_dll(const std::string tar, winversion_info *info);
+public:
+    static bool get_dll(const std::string tar, winversion_info *info);
 
-		static void get_win(winversion_info *info);
+    static void get_win(winversion_info *info);
 
-		static bool is_win8_or_above();
+    static bool is_win8_or_above();
 
-		static bool is_win10_or_above(int build_number = -1);
+    static bool is_win10_or_above(int build_number = -1);
 
-		static bool is_32();
+    static bool is_32();
 
-	private:
-		std::string _target_file;
-	};
+private:
+    std::string _target_file;
+};
+} // namespace am
 
-}
-
-#endif
+#endif

+ 0 - 0
libs/Recorder/main.cpp → libs/Recorder/test_main.cpp


Datei-Diff unterdrückt, da er zu groß ist
+ 434 - 442
libs/Recorder/transcode_aac.cpp


+ 55 - 57
libs/Recorder/utils_string.cpp

@@ -7,60 +7,58 @@
 #endif
 
 namespace am {
-
-	std::wstring utils_string::ascii_unicode(const std::string & str)
-	{
-		int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
-
-		wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);
-
-		MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);
-
-		std::wstring ret_str = pUnicode;
-
-		free(pUnicode);
-
-		return ret_str;
-	}
-
-	std::string utils_string::unicode_ascii(const std::wstring & wstr)
-	{
-		int ansiiLen = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
-		char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
-		WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
-		std::string ret_str = pAssii;
-		free(pAssii);
-		return ret_str;
-	}
-
-	std::string utils_string::ascii_utf8(const std::string & str)
-	{
-		return unicode_utf8(ascii_unicode(str));
-	}
-
-	std::string utils_string::utf8_ascii(const std::string & utf8)
-	{
-		return unicode_ascii(utf8_unicode(utf8));
-	}
-
-	std::string utils_string::unicode_utf8(const std::wstring & wstr)
-	{
-		int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
-		char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
-		WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
-		std::string ret_str = pAssii;
-		free(pAssii);
-		return ret_str;
-	}
-
-	std::wstring utils_string::utf8_unicode(const std::string & utf8)
-	{
-		int unicodeLen = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, nullptr, 0);
-		wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);
-		MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, pUnicode, unicodeLen);
-		std::wstring ret_str = pUnicode;
-		free(pUnicode);
-		return ret_str;
-	}
-
-}
+std::wstring utils_string::ascii_unicode(const std::string &str)
+{
+    int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
+
+    wchar_t *pUnicode = (wchar_t *) malloc(sizeof(wchar_t) * unicodeLen);
+
+    MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);
+
+    std::wstring ret_str = pUnicode;
+
+    free(pUnicode);
+
+    return ret_str;
+}
+
+std::string utils_string::unicode_ascii(const std::wstring &wstr)
+{
+    int ansiiLen = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
+    char *pAssii = (char *) malloc(sizeof(char) * ansiiLen);
+    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
+    std::string ret_str = pAssii;
+    free(pAssii);
+    return ret_str;
+}
+
+std::string utils_string::ascii_utf8(const std::string &str)
+{
+    return unicode_utf8(ascii_unicode(str));
+}
+
+std::string utils_string::utf8_ascii(const std::string &utf8)
+{
+    return unicode_ascii(utf8_unicode(utf8));
+}
+
+std::string utils_string::unicode_utf8(const std::wstring &wstr)
+{
+    int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
+    char *pAssii = (char *) malloc(sizeof(char) * ansiiLen);
+    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
+    std::string ret_str = pAssii;
+    free(pAssii);
+    return ret_str;
+}
+
+std::wstring utils_string::utf8_unicode(const std::string &utf8)
+{
+    int unicodeLen = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, nullptr, 0);
+    wchar_t *pUnicode = (wchar_t *) malloc(sizeof(wchar_t) * unicodeLen);
+    MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, pUnicode, unicodeLen);
+    std::wstring ret_str = pUnicode;
+    free(pUnicode);
+    return ret_str;
+}
+} // namespace am

+ 11 - 13
libs/Recorder/utils_string.h

@@ -3,21 +3,19 @@
 #include <string>
 
 namespace am {
+class utils_string
+{
+public:
+    static std::wstring ascii_unicode(const std::string &str);
 
-	class utils_string
-	{
-	public:
-		static std::wstring ascii_unicode(const std::string & str);
+    static std::string unicode_ascii(const std::wstring &wstr);
 
-		static std::string unicode_ascii(const std::wstring &wstr);
+    static std::string ascii_utf8(const std::string &str);
 
-		static std::string ascii_utf8(const std::string & str);
+    static std::string utf8_ascii(const std::string &utf8);
 
-		static std::string utf8_ascii(const std::string &utf8);
+    static std::string unicode_utf8(const std::wstring &wstr);
 
-		static std::string  unicode_utf8(const std::wstring& wstr);
-
-		static std::wstring utf8_unicode(const std::string &utf8);
-	};
-
-}
+    static std::wstring utf8_unicode(const std::string &utf8);
+};
+} // namespace am

+ 2 - 0
libs/libs.pri

@@ -8,3 +8,5 @@ include($$PWD/jsonserializer/jsonserializer.pri)
 include($$PWD/advanceddockingsystem/advanceddockingsystem-lib.pri)
 include($$PWD/utils/utils.pri)
 
+
+include($$PWD/Recorder/Recorder.pri)

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.