zhuizhu пре 8 месеци
родитељ
комит
9b27c23126

+ 56 - 4
AvRecorder/recorder/audio_recorder.cpp

@@ -3,6 +3,8 @@
 #include "capturer/audio/audio_qt_capturer.h"
 #include "capturer/audio/wasapi_loopback_capturer.h"
 #include "qdebug.h"
+#include <algorithm>
+#include <mutex>
 
 AudioRecorder::AudioRecorder() {}
 
@@ -106,13 +108,56 @@ void AudioRecorder::SetVolumeScale(float scale, int mixIndex)
 
 bool AudioRecorder::LoadMuxer(AvMuxer& muxer)
 {
+    std::lock_guard<std::mutex> lock(_muxersMtx);
+    
+    // 检查是否已经加载过这个muxer
+    for (const auto& info : _muxers) {
+        if (info.muxer == &muxer) {
+            return true; // 已经加载过,直接返回成功
+        }
+    }
+    
+    int streamIndex = muxer.AddAudioStream(_param);
+    __CheckBool(streamIndex != -1);
+    
+    _muxers.emplace_back(&muxer, streamIndex);
+    
+    // 为了兼容性,保留原有的_infos逻辑(如果需要的话)
     for (auto&& info : _infos) {
-        info.muxer = &muxer;
+        if (info.muxer == nullptr) {
+            info.muxer = &muxer;
+            break;
+        }
     }
-    __CheckBool((_streamIndex = muxer.AddAudioStream(_param)) != -1);
+    
     return true;
 }
 
+bool AudioRecorder::UnloadMuxer(AvMuxer& muxer)
+{
+    std::lock_guard<std::mutex> lock(_muxersMtx);
+    
+    auto it = std::find_if(_muxers.begin(), _muxers.end(),
+                          [&muxer](const MuxerInfo& info) {
+                              return info.muxer == &muxer;
+                          });
+    
+    if (it != _muxers.end()) {
+        _muxers.erase(it);
+        
+        // 清理_infos中对应的muxer引用
+        for (auto&& info : _infos) {
+            if (info.muxer == &muxer) {
+                info.muxer = nullptr;
+            }
+        }
+        
+        return true;
+    }
+    
+    return false; // 没有找到对应的muxer
+}
+
 bool AudioRecorder::StartRecord()
 {
     _isRecord = true;
@@ -147,13 +192,20 @@ void AudioRecorder::PullAndProcessAudio()
             // 添加调试信息,显示数据大小
 
             auto frame = _mixer.Convert(index, (uint8_t*) buf, bytes);
-            if (frame && _isRecord && _streamIndex != -1) {
+            if (frame && _isRecord) {
                 int frameSize = _mixer.GetOutFrameSize();
                 if (_mixer.GetOutFrameSize() != frameSize) {
                     _mixer.SetOutFrameSize(frameSize);
                     continue;
                 }
-                _infos[index].muxer->Write(frame, _streamIndex);
+                
+                // 向所有已加载的muxer写入音频数据
+                {
+                    std::lock_guard<std::mutex> muxerLock(_muxersMtx);
+                    for (const auto& muxerInfo : _muxers) {
+                        muxerInfo.muxer->Write(frame, muxerInfo.streamIndex);
+                    }
+                }
             }
         }
     }

+ 10 - 0
AvRecorder/recorder/audio_recorder.h

@@ -20,6 +20,13 @@ public:
         int mixIndex;
         int* streamIndex = nullptr;
     };
+    
+    struct MuxerInfo
+    {
+        AvMuxer* muxer;
+        int streamIndex;
+        MuxerInfo(AvMuxer* m, int idx) : muxer(m), streamIndex(idx) {}
+    };
 
     bool Open(const std::vector<AudioCapturer::Type>& deviceTypes,
               Encoder<MediaType::AUDIO>::Param& param,
@@ -28,6 +35,7 @@ public:
               const uint32_t bitsPerSample = 32,
               const AVSampleFormat format = AUDIO_FMT);
     bool LoadMuxer(AvMuxer& muxer);
+    bool UnloadMuxer(AvMuxer& muxer);
     bool StartRecord();
     void StopRecord();
     void Close();
@@ -39,6 +47,8 @@ private:
     std::vector<IAudioCapturer*> m_audioCapturers;
     AudioMixer _mixer;
     std::vector<Info> _infos;
+    std::vector<MuxerInfo> _muxers;
+    std::mutex _muxersMtx;
     bool _isRecord = false;
     int _streamIndex;
     Encoder<MediaType::AUDIO>::Param _param;

+ 52 - 3
AvRecorder/recorder/video_recorder.cpp

@@ -2,6 +2,9 @@
 #include "avrecorder/capturer/video/VideoCaptureManager.h"
 #include <Windows.h>
 #include <capturer/finder.h>
+#include <vector>
+#include <algorithm>
+#include <mutex>
 using namespace avrecorder::video;
 
 bool VideoRecorder::Open(HWND srcHwnd, Encoder<MediaType::VIDEO>::Param& param, CaptureMethod method)
@@ -92,19 +95,65 @@ AVFrame* VideoRecorder::GetRenderFrame()
 
 bool VideoRecorder::LoadMuxer(AvMuxer& muxer)
 {
-    _muxer = &muxer;
-    __CheckBool((_streamIndex = muxer.AddVideoStream(_param)) != -1);
+    std::lock_guard<std::mutex> lock(_muxersMtx);
+    
+    // 检查是否已经加载过这个muxer
+    for (const auto& info : _muxers) {
+        if (info.muxer == &muxer) {
+            return true; // 已经加载过,直接返回成功
+        }
+    }
+    
+    int streamIndex = muxer.AddVideoStream(_param);
+    __CheckBool(streamIndex != -1);
+    
+    _muxers.emplace_back(&muxer, streamIndex);
     return true;
 }
 
+bool VideoRecorder::UnloadMuxer(AvMuxer& muxer)
+{
+    std::lock_guard<std::mutex> lock(_muxersMtx);
+    
+    auto it = std::find_if(_muxers.begin(), _muxers.end(),
+                          [&muxer](const MuxerInfo& info) {
+                              return info.muxer == &muxer;
+                          });
+    
+    if (it != _muxers.end()) {
+        _muxers.erase(it);
+        return true;
+    }
+    
+    return false; // 没有找到对应的muxer
+}
+
 bool VideoRecorder::StartRecord()
 {
+    std::lock_guard<std::mutex> lock(_muxersMtx);
+    
+    if (_muxers.empty()) {
+        return false; // 没有加载任何muxer
+    }
+    
     _totalPts = 0;
     _lossPts = 0;
     _lossHistory.clear();
     _muxTimer.Start(_param.fps, [this] {
         ++_totalPts;
-        bool loss = !_muxer->Write(_encodeFrame, _streamIndex);
+        bool anySuccess = false;
+        
+        // 向所有muxer写入数据
+        {
+            std::lock_guard<std::mutex> muxerLock(_muxersMtx);
+            for (const auto& info : _muxers) {
+                if (info.muxer->Write(_encodeFrame, info.streamIndex)) {
+                    anySuccess = true;
+                }
+            }
+        }
+        
+        bool loss = !anySuccess;
         if (loss)
             ++_lossPts;
         _lossHistory.push_back(loss);

+ 9 - 2
AvRecorder/recorder/video_recorder.h

@@ -15,6 +15,7 @@ public:
     bool Open(HWND srcHwnd, Encoder<MediaType::VIDEO>::Param& param, CaptureMethod method);
     bool Open(int monitorIdx, Encoder<MediaType::VIDEO>::Param& param, CaptureMethod method);
     bool LoadMuxer(AvMuxer& muxer);
+    bool UnloadMuxer(AvMuxer& muxer);
     bool StartRecord();
     void StopRecord();
     AVFrame* GetRenderFrame();
@@ -26,13 +27,19 @@ public:
     void SetCaptureSource(int monitorIdx, CaptureMethod method);
 
 private:
+    struct MuxerInfo {
+        AvMuxer* muxer;
+        int streamIndex;
+        MuxerInfo(AvMuxer* m, int idx) : muxer(m), streamIndex(idx) {}
+    };
+    
     static constexpr int kCanvasWidth = 1920;
     static constexpr int kCanvasHeight = 1080;
     bool _Open(Encoder<MediaType::VIDEO>::Param& param);
     VideoCaptureManager _capturer;
-    AvMuxer* _muxer = nullptr;
+    std::vector<MuxerInfo> _muxers;
+    std::mutex _muxersMtx;
     bool _isRecord = false;
-    int _streamIndex = -1;
     AVFrame* _encodeFrame = nullptr;
     AVFrame* _renderFrame = nullptr;
     Encoder<MediaType::VIDEO>::Param _param;

+ 58 - 5
AvRecorder/ui/av_recorder.cpp

@@ -163,7 +163,6 @@ void AvRecorder::initConnect()
             m_recordBtn->setEnabled(true);
             m_liveBtn->setText("开始直播");
         }
-        m_isLive = !m_isLive;
     });
     connect(m_microphoneWidget, &AudioWidget::SetVolumeScale, this, [this](float scale) {
         m_audioRecorder.SetVolumeScale(scale, MICROPHONE_INDEX);
@@ -408,6 +407,8 @@ bool AvRecorder::startStream(std::string_view path, std::string_view format)
     // m_captureComboBox->setEnabled(false); // 禁用采集源切换
     m_updateListBtn->setEnabled(false);
     m_captureMethodBox->setEnabled(false); // 禁用采集方式切换
+
+    m_isLive = !m_isLive;
     return true;
 }
 
@@ -415,10 +416,19 @@ void AvRecorder::stopStream()
 {
     m_audioRecorder.StopRecord();
     m_videoRecorder.StopRecord();
+    
+    // 从录制器中卸载直播muxer
+    m_audioRecorder.UnloadMuxer(m_avMuxer);
+    m_videoRecorder.UnloadMuxer(m_avMuxer);
+    
     m_avMuxer.Close();
 
     // 如果有同步录像,也需要关闭
     if (m_isSyncRecord) {
+        // 先从录制器中卸载同步录像muxer
+        m_audioRecorder.UnloadMuxer(m_recordMuxer);
+        m_videoRecorder.UnloadMuxer(m_recordMuxer);
+        
         m_recordMuxer.Close();
         m_isSyncRecord = false;
     }
@@ -431,6 +441,18 @@ void AvRecorder::stopStream()
 }
 bool AvRecorder::startSyncRecord()
 {
+    // 检查是否已经在同步录像
+    if (m_isSyncRecord) {
+        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('\\');
@@ -439,17 +461,48 @@ bool AvRecorder::startSyncRecord()
     fileName += QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss").toStdString()
                 + "_sync." + format;
 
-    __CheckBool(m_recordMuxer.Open(fileName, format));
-    __CheckBool(m_audioRecorder.LoadMuxer(m_recordMuxer));
-    __CheckBool(m_videoRecorder.LoadMuxer(m_recordMuxer));
-    __CheckBool(m_recordMuxer.WriteHeader());
+    // 打开同步录像的muxer
+    if (!m_recordMuxer.Open(fileName, format)) {
+        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";
+        m_audioRecorder.UnloadMuxer(m_recordMuxer);
+        m_videoRecorder.UnloadMuxer(m_recordMuxer);
+        m_recordMuxer.Close();
+        return false;
+    }
+    
     m_isSyncRecord = true;
+    qDebug() << "Sync recording started successfully: " << QString::fromStdString(fileName);
     return true;
 }
 
 void AvRecorder::stopSyncRecord()
 {
     if (m_isSyncRecord) {
+        // 先从录制器中卸载muxer
+        m_audioRecorder.UnloadMuxer(m_recordMuxer);
+        m_videoRecorder.UnloadMuxer(m_recordMuxer);
+        
+        // 然后关闭muxer
         m_recordMuxer.Close();
         m_isSyncRecord = false;
     }