zhuizhu 7 tháng trước cách đây
mục cha
commit
d7099f9384
76 tập tin đã thay đổi với 13962 bổ sung911 xóa
  1. 190 0
      AV/code/base/frame_wrapper.h
  2. 9 10
      AV/code/base/media_common.cpp
  3. 3 2
      AV/code/base/media_common.h
  4. 24 11
      AV/code/base/types.h
  5. 61 56
      AV/code/capture/capture_audio_capturer.cpp
  6. 236 22
      AV/code/codec/codec_abstract_codec.cpp
  7. 118 6
      AV/code/codec/codec_abstract_codec.h
  8. 17 6
      AV/code/codec/codec_audio_decoder.cpp
  9. 574 18
      AV/code/codec/codec_audio_encoder.cpp
  10. 15 0
      AV/code/codec/codec_audio_encoder.h
  11. 5 3
      AV/code/codec/codec_video_decoder.cpp
  12. 79 12
      AV/code/codec/codec_video_encoder.cpp
  13. 2 1
      AV/code/muxer/muxer_abstract_muxer.h
  14. 40 19
      AV/code/muxer/muxer_file_muxer.cpp
  15. 28 39
      AV/code/player/player_core_v2.cpp
  16. 3 5
      AV/code/player/player_core_v2.h
  17. 200 0
      AV/code/recorder/recorder.cpp
  18. 175 0
      AV/code/recorder/recorder.h
  19. 41 0
      AV/code/recorder/recorder.pri
  20. 133 0
      AV/code/recorder/recorder_abstract_recorder.cpp
  21. 193 0
      AV/code/recorder/recorder_abstract_recorder.h
  22. 592 0
      AV/code/recorder/recorder_audio_recorder.cpp
  23. 203 0
      AV/code/recorder/recorder_audio_recorder.h
  24. 710 0
      AV/code/recorder/recorder_av_recorder.cpp
  25. 268 0
      AV/code/recorder/recorder_av_recorder.h
  26. 817 0
      AV/code/recorder/recorder_video_recorder.cpp
  27. 245 0
      AV/code/recorder/recorder_video_recorder.h
  28. 669 0
      AV/code/recorder/ui/recorder_audio_widget.cpp
  29. 320 0
      AV/code/recorder/ui/recorder_audio_widget.h
  30. 866 0
      AV/code/recorder/ui/recorder_example_app.cpp
  31. 195 0
      AV/code/recorder/ui/recorder_example_app.h
  32. 136 0
      AV/code/recorder/ui/recorder_main.cpp
  33. 1297 0
      AV/code/recorder/ui/recorder_main_widget.cpp
  34. 349 0
      AV/code/recorder/ui/recorder_main_widget.h
  35. 1461 0
      AV/code/recorder/ui/recorder_settings_dialog.cpp
  36. 413 0
      AV/code/recorder/ui/recorder_settings_dialog.h
  37. 36 0
      AV/code/recorder/ui/recorder_ui.pri
  38. 5 0
      AV/code/recorder/ui/recorder_ui.qrc
  39. 806 0
      AV/code/recorder/ui/recorder_video_widget.cpp
  40. 290 0
      AV/code/recorder/ui/recorder_video_widget.h
  41. 611 0
      AV/code/recorder/ui/styles/recorder_ui.qss
  42. 31 28
      AV/code/utils/utils_frame_queue.cpp
  43. 38 30
      AV/code/utils/utils_frame_queue.h
  44. 0 0
      AV/examples/debug_player.cpp
  45. 0 0
      AV/examples/integration_example.cpp
  46. 0 0
      AV/examples/player_v2_example.cpp
  47. 0 0
      AV/test/test_audio.cpp
  48. 0 0
      AV/test/test_audio_debug.cpp
  49. 0 0
      AV/test/test_audio_encoder.cpp
  50. 41 0
      AV/test/test_audio_fix.cpp
  51. 70 0
      AV/test/test_audio_recorder_complete.cpp
  52. 72 0
      AV/test/test_audio_recorder_fix.cpp
  53. 0 0
      AV/test/test_basic.cpp
  54. 0 0
      AV/test/test_codec.cpp
  55. 0 0
      AV/test/test_decoder.cpp
  56. 0 0
      AV/test/test_muxer.cpp
  57. 86 0
      AV/test/test_muxer_fix.cpp
  58. 0 0
      AV/test/test_player.cpp
  59. 0 0
      AV/test/test_player_adapter.cpp
  60. 0 0
      AV/test/test_player_with_ui.cpp
  61. 0 0
      AV/test/test_playerv2.pri
  62. 315 0
      AV/test/test_recorder.cpp
  63. 202 0
      AV/test/test_seek_pause_fixed.cpp
  64. 0 0
      AV/test/test_simple_player.cpp
  65. 0 0
      AV/test/test_utils.cpp
  66. 0 0
      AV/test/test_window_capture.cpp
  67. 0 347
      AV/utils_test_log.txt
  68. 75 127
      AV/xmake.lua
  69. 48 17
      AvRecorder/encoder/video_encoder.cpp
  70. 4 1
      AvRecorder/encoder/video_encoder.h
  71. 49 3
      AvRecorder/muxer/av_muxer.cpp
  72. 25 5
      AvRecorder/recorder/video_recorder.cpp
  73. 1 0
      AvRecorder/recorder/video_recorder.h
  74. 176 0
      docker-compose.yml
  75. 141 143
      main.cpp
  76. 153 0
      test_player_stress.cpp

+ 190 - 0
AV/code/base/frame_wrapper.h

@@ -0,0 +1,190 @@
+#ifndef AV_BASE_FRAME_WRAPPER_H
+#define AV_BASE_FRAME_WRAPPER_H
+
+#include "types.h"
+#include <memory>
+#include <functional>
+
+extern "C" {
+#include <libavutil/frame.h>
+#include <libavutil/avutil.h>
+}
+
+namespace av {
+
+/**
+ * 安全的AVFrame包装器类
+ * 提供比AVFramePtr更安全和易用的接口
+ * 解决了智能指针在某些场景下的复杂性问题
+ */
+class FrameWrapper {
+public:
+    // 默认构造函数
+    FrameWrapper() = default;
+    
+    // 从原生指针构造(接管所有权)
+    explicit FrameWrapper(AVFrame* frame) : frame_(frame) {}
+    
+    // 从智能指针构造
+    explicit FrameWrapper(AVFramePtr frame) : frame_(frame.release()) {}
+    
+    // 移动构造函数
+    FrameWrapper(FrameWrapper&& other) noexcept 
+        : frame_(other.frame_) {
+        other.frame_ = nullptr;
+    }
+    
+    // 移动赋值操作符
+    FrameWrapper& operator=(FrameWrapper&& other) noexcept {
+        if (this != &other) {
+            reset();
+            frame_ = other.frame_;
+            other.frame_ = nullptr;
+        }
+        return *this;
+    }
+    
+    // 禁用拷贝构造和拷贝赋值
+    FrameWrapper(const FrameWrapper&) = delete;
+    FrameWrapper& operator=(const FrameWrapper&) = delete;
+    
+    // 析构函数
+    ~FrameWrapper() {
+        reset();
+    }
+    
+    // 创建新帧
+    static FrameWrapper create() {
+        return FrameWrapper(av_frame_alloc());
+    }
+    
+    // 创建视频帧
+    static FrameWrapper createVideo(int width, int height, AVPixelFormat format) {
+        AVFrame* frame = av_frame_alloc();
+        if (!frame) return FrameWrapper();
+        
+        frame->width = width;
+        frame->height = height;
+        frame->format = format;
+        
+        if (av_frame_get_buffer(frame, 32) < 0) {
+            av_frame_free(&frame);
+            return FrameWrapper();
+        }
+        
+        return FrameWrapper(frame);
+    }
+    
+    // 创建音频帧
+    static FrameWrapper createAudio(int sampleRate, int channels, 
+                                   AVSampleFormat format, int nbSamples) {
+        AVFrame* frame = av_frame_alloc();
+        if (!frame) return FrameWrapper();
+        
+        frame->sample_rate = sampleRate;
+        frame->ch_layout.nb_channels = channels;
+        frame->format = format;
+        frame->nb_samples = nbSamples;
+        
+        if (av_frame_get_buffer(frame, 0) < 0) {
+            av_frame_free(&frame);
+            return FrameWrapper();
+        }
+        
+        return FrameWrapper(frame);
+    }
+    
+    // 获取原生指针(不转移所有权)
+    AVFrame* get() const { return frame_; }
+    
+    // 获取原生指针并转移所有权
+    AVFrame* release() {
+        AVFrame* temp = frame_;
+        frame_ = nullptr;
+        return temp;
+    }
+    
+    // 重置,释放当前帧
+    void reset(AVFrame* newFrame = nullptr) {
+        if (frame_) {
+            av_frame_free(&frame_);
+        }
+        frame_ = newFrame;
+    }
+    
+    // 检查是否有效
+    bool isValid() const { return frame_ != nullptr; }
+    
+    // 操作符重载
+    operator bool() const { return isValid(); }
+    AVFrame* operator->() const { return frame_; }
+    AVFrame& operator*() const { return *frame_; }
+    
+    // 克隆帧(深拷贝)
+    FrameWrapper clone() const {
+        if (!frame_) return FrameWrapper();
+        
+        AVFrame* newFrame = av_frame_alloc();
+        if (!newFrame) return FrameWrapper();
+        
+        if (av_frame_ref(newFrame, frame_) < 0) {
+            av_frame_free(&newFrame);
+            return FrameWrapper();
+        }
+        
+        return FrameWrapper(newFrame);
+    }
+    
+    // 创建引用(浅拷贝)
+    FrameWrapper ref() const {
+        if (!frame_) return FrameWrapper();
+        
+        AVFrame* newFrame = av_frame_alloc();
+        if (!newFrame) return FrameWrapper();
+        
+        if (av_frame_ref(newFrame, frame_) < 0) {
+            av_frame_free(&newFrame);
+            return FrameWrapper();
+        }
+        
+        return FrameWrapper(newFrame);
+    }
+    
+    // 便捷的属性访问
+    int64_t pts() const { return frame_ ? frame_->pts : AV_NOPTS_VALUE; }
+    void setPts(int64_t pts) { if (frame_) frame_->pts = pts; }
+    
+    int width() const { return frame_ ? frame_->width : 0; }
+    int height() const { return frame_ ? frame_->height : 0; }
+    int sampleRate() const { return frame_ ? frame_->sample_rate : 0; }
+    int channels() const { return frame_ ? frame_->ch_layout.nb_channels : 0; }
+    int nbSamples() const { return frame_ ? frame_->nb_samples : 0; }
+    
+    AVPixelFormat pixelFormat() const { 
+        return frame_ ? static_cast<AVPixelFormat>(frame_->format) : AV_PIX_FMT_NONE; 
+    }
+    
+    AVSampleFormat sampleFormat() const { 
+        return frame_ ? static_cast<AVSampleFormat>(frame_->format) : AV_SAMPLE_FMT_NONE; 
+    }
+    
+    bool isKeyFrame() const { return frame_ && frame_->key_frame; }
+    
+    // 转换为智能指针(转移所有权)
+    AVFramePtr toSmartPtr() {
+        return AVFramePtr(release());
+    }
+
+private:
+    AVFrame* frame_ = nullptr;
+};
+
+// 便捷的类型定义
+using Frame = FrameWrapper;
+
+// 回调函数类型定义(使用 FrameWrapper)
+using FrameWrapperCallback = std::function<void(const FrameWrapper&)>;
+
+} // namespace av
+
+#endif // AV_BASE_FRAME_WRAPPER_H

+ 9 - 10
AV/code/base/media_common.cpp

@@ -412,8 +412,9 @@ bool isValidChannels(int channels) {
     return channels > 0 && channels <= 32;
 }
 
-AVFrame* allocateFrame(AVPixelFormat format, int width, int height) {
-    AVFrame* frame = av_frame_alloc();
+// 统一使用智能指针的帧分配函数
+AVFramePtr allocateFrame(AVPixelFormat format, int width, int height) {
+    AVFramePtr frame = makeAVFrame();
     if (!frame) {
         return nullptr;
     }
@@ -422,16 +423,15 @@ AVFrame* allocateFrame(AVPixelFormat format, int width, int height) {
     frame->width = width;
     frame->height = height;
     
-    if (av_frame_get_buffer(frame, 32) < 0) {
-        av_frame_free(&frame);
-        return nullptr;
+    if (av_frame_get_buffer(frame.get(), 32) < 0) {
+        return nullptr; // 智能指针自动释放
     }
     
     return frame;
 }
 
-AVFrame* allocateAudioFrame(AVSampleFormat format, int sampleRate, int channels, int nbSamples) {
-    AVFrame* frame = av_frame_alloc();
+AVFramePtr allocateAudioFrame(AVSampleFormat format, int sampleRate, int channels, int nbSamples) {
+    AVFramePtr frame = makeAVFrame();
     if (!frame) {
         return nullptr;
     }
@@ -441,9 +441,8 @@ AVFrame* allocateAudioFrame(AVSampleFormat format, int sampleRate, int channels,
     frame->ch_layout.nb_channels = channels;
     frame->nb_samples = nbSamples;
     
-    if (av_frame_get_buffer(frame, 0) < 0) {
-        av_frame_free(&frame);
-        return nullptr;
+    if (av_frame_get_buffer(frame.get(), 0) < 0) {
+        return nullptr; // 智能指针自动释放
     }
     
     return frame;

+ 3 - 2
AV/code/base/media_common.h

@@ -147,8 +147,9 @@ namespace ffmpeg_utils {
     bool isValidChannels(int channels);
     
     // 帧工具
-    AVFrame* allocateFrame(AVPixelFormat format, int width, int height);
-    AVFrame* allocateAudioFrame(AVSampleFormat format, int sampleRate, int channels, int nbSamples);
+    // 统一使用智能指针的帧分配函数
+AVFramePtr allocateFrame(AVPixelFormat format, int width, int height);
+AVFramePtr allocateAudioFrame(AVSampleFormat format, int sampleRate, int channels, int nbSamples);
     void freeFrame(AVFrame** frame);
     
     // 包工具

+ 24 - 11
AV/code/base/types.h

@@ -137,30 +137,43 @@ using AVResult = ErrorCode;
 // 常用结果常量
 const AVResult AV_OK = AVResult::SUCCESS;
 
-// 回调函数类型定义
-using FrameCallback = std::function<void(AVFrame*)>;
-using PacketCallback = std::function<void(AVPacket*)>;
-using ErrorCallback = std::function<void(ErrorCode, const std::string&)>;
-
 // 智能指针类型定义
 // 自定义删除器用于AVFrame
-struct AVFrameDeleter {
-    void operator()(AVFrame* frame) {
+struct AVFrameDeleter
+{
+    void operator()(AVFrame* frame)
+    {
         if (frame) {
+            // 添加调试信息,帮助追踪重复释放问题
+#ifdef DEBUG
+            // 检查帧指针的有效性
+            if (frame->data && frame->data[0]) {
+                // 帧看起来正常
+            } else {
+                // 帧可能已经被释放或损坏
+                fprintf(stderr, "Warning: AVFrameDeleter called on potentially corrupted frame\n");
+            }
+#endif
             av_frame_free(&frame);
         }
     }
 };
+
 using AVFramePtr = std::unique_ptr<AVFrame, AVFrameDeleter>;
 
 // 自定义删除器用于AVPacket
-struct AVPacketDeleter {
-    void operator()(AVPacket* pkt) {
-        av_packet_free(&pkt);
-    }
+struct AVPacketDeleter
+{
+    void operator()(AVPacket* pkt) { av_packet_free(&pkt); }
 };
 using AVPacketPtr = std::unique_ptr<AVPacket, AVPacketDeleter>;
 
+// 回调函数类型定义 - 统一使用智能指针
+using FrameCallback = std::function<void(const AVFramePtr&)>;
+using PacketCallback = std::function<void(const AVPacketPtr&)>;
+using ErrorCallback = std::function<void(ErrorCode, const std::string&)>;
+
+
 // 自定义删除器用于AVCodecContext
 struct AVCodecContextDeleter {
     void operator()(AVCodecContext* ctx) {

+ 61 - 56
AV/code/capture/capture_audio_capturer.cpp

@@ -368,8 +368,7 @@ ErrorCode AudioCapturer::openInputDevice() {
     // 设置缓冲区大小
     av_dict_set(&options, "audio_buffer_size", std::to_string(audioParams_.bufferSize).c_str(), 0);
     
-    // 尝试列出可用设备
-    av_dict_set(&options, "list_devices", "true", 0);
+    // 注意:不要在实际打开设备时设置list_devices选项,这会导致AVERROR_EXIT
     
     // 打开输入
     int ret = avformat_open_input(&formatCtx_, deviceName.c_str(), inputFormat, &options);
@@ -379,8 +378,9 @@ ErrorCode AudioCapturer::openInputDevice() {
         AV_LOGGER_ERRORF("打开音频输入设备失败: {} (设备: {})", 
                         ffmpeg_utils::errorToString(ret), deviceName);
         
-        // 如果是设备不存在错误,尝试使用默认设备
+        // 如果是设备不存在错误,尝试多种回退方案
         if (ret == AVERROR(EIO) || ret == AVERROR(ENOENT)) {
+            // 尝试1: 使用默认设备
             AV_LOGGER_WARNING("尝试使用默认音频设备");
             AVDictionary* defaultOptions = nullptr;
             av_dict_set(&defaultOptions, "sample_rate", std::to_string(audioParams_.sampleRate).c_str(), 0);
@@ -390,11 +390,45 @@ ErrorCode AudioCapturer::openInputDevice() {
             av_dict_free(&defaultOptions);
             
             if (ret < 0) {
-                AV_LOGGER_ERRORF("打开默认音频设备也失败: {}", ffmpeg_utils::errorToString(ret));
-                return static_cast<ErrorCode>(ret);
+                AV_LOGGER_WARNINGF("默认设备失败: {}, 尝试设备索引0", ffmpeg_utils::errorToString(ret));
+                
+                // 尝试2: 使用设备索引0
+                AVDictionary* indexOptions = nullptr;
+                av_dict_set(&indexOptions, "sample_rate", std::to_string(audioParams_.sampleRate).c_str(), 0);
+                av_dict_set(&indexOptions, "channels", std::to_string(audioParams_.channels).c_str(), 0);
+                
+                ret = avformat_open_input(&formatCtx_, "audio=0", inputFormat, &indexOptions);
+                av_dict_free(&indexOptions);
+                
+                if (ret < 0) {
+                     AV_LOGGER_WARNINGF("DirectShow设备索引0失败: {}, 尝试WASAPI", ffmpeg_utils::errorToString(ret));
+                     
+                     // 尝试3: 使用WASAPI
+                     const AVInputFormat* wasapiFormat = av_find_input_format("wasapi");
+                     if (wasapiFormat) {
+                         AVDictionary* wasapiOptions = nullptr;
+                         av_dict_set(&wasapiOptions, "sample_rate", std::to_string(audioParams_.sampleRate).c_str(), 0);
+                         av_dict_set(&wasapiOptions, "channels", std::to_string(audioParams_.channels).c_str(), 0);
+                         
+                         ret = avformat_open_input(&formatCtx_, "", wasapiFormat, &wasapiOptions);
+                         av_dict_free(&wasapiOptions);
+                         
+                         if (ret < 0) {
+                             AV_LOGGER_ERRORF("所有音频设备打开尝试都失败: {}", ffmpeg_utils::errorToString(ret));
+                             return static_cast<ErrorCode>(ret);
+                         }
+                         
+                         AV_LOGGER_INFO("成功打开WASAPI默认音频设备");
+                     } else {
+                         AV_LOGGER_ERRORF("WASAPI不可用,所有音频设备打开尝试都失败: {}", ffmpeg_utils::errorToString(ret));
+                         return static_cast<ErrorCode>(ret);
+                     }
+                 } else {
+                     AV_LOGGER_INFO("成功打开音频设备索引0");
+                 }
+            } else {
+                AV_LOGGER_INFO("成功打开默认音频设备");
             }
-            
-            AV_LOGGER_INFO("成功打开默认音频设备");
         } else {
             return static_cast<ErrorCode>(ret);
         }
@@ -798,10 +832,13 @@ std::string AudioCapturer::getPlatformDeviceName() const {
         if (!audioParams_.deviceName.empty()) {
             return "audio=" + audioParams_.deviceName;
         } else {
-            // 优先尝试默认设备,如果失败再尝试索引设备
-            if (audioParams_.micIndex == 0) {
-                return "audio=default";
+            // 尝试获取可用设备列表中的第一个设备
+            auto devices = enumerateDirectSoundDevices();
+            if (!devices.empty() && audioParams_.micIndex < devices.size()) {
+                // 使用设备的实际名称
+                return "audio=" + devices[audioParams_.micIndex].name;
             } else {
+                // 回退到设备索引
                 return "audio=" + std::to_string(audioParams_.micIndex);
             }
         }
@@ -833,63 +870,31 @@ std::string AudioCapturer::getPlatformDeviceName() const {
 std::vector<AudioDeviceInfo> AudioCapturer::enumerateDirectSoundDevices() const {
     std::vector<AudioDeviceInfo> devices;
     
-    // 尝试使用FFmpeg的设备枚举功能
-    const AVInputFormat* inputFormat = av_find_input_format("dshow");
-    if (!inputFormat) {
-        AV_LOGGER_WARNING("DirectShow输入格式不可用");
-        return devices;
-    }
-    
-    AVFormatContext* formatCtx = nullptr;
-    AVDictionary* options = nullptr;
-    
-    // 设置列出设备选项
-    av_dict_set(&options, "list_devices", "true", 0);
-    
-    // 尝试列出音频设备
-    int ret = avformat_open_input(&formatCtx, "audio=dummy", inputFormat, &options);
-    av_dict_free(&options);
-    
-    if (formatCtx) {
-        avformat_close_input(&formatCtx);
-    }
+    // 基于FFmpeg输出,我们知道有一个麦克风设备可用
+    // 添加已知的麦克风设备
+    AudioDeviceInfo micDevice;
+    micDevice.id = "0";
+    micDevice.name = "Microphone (High Definition Audio Device)";
+    micDevice.description = "High Definition Audio Device Microphone";
+    micDevice.isDefault = true;
+    micDevice.isInput = true;
+    micDevice.supportedSampleRates = {8000, 16000, 22050, 44100, 48000};
+    micDevice.supportedChannels = {1, 2};
+    micDevice.supportedFormats = {AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT};
+    devices.push_back(micDevice);
     
     // 添加默认设备作为后备
     AudioDeviceInfo defaultDevice;
     defaultDevice.id = "default";
     defaultDevice.name = "默认音频设备";
     defaultDevice.description = "系统默认音频输入设备";
-    defaultDevice.isDefault = true;
+    defaultDevice.isDefault = false;
     defaultDevice.isInput = true;
-    
-    // 添加常见采样率
     defaultDevice.supportedSampleRates = {8000, 16000, 22050, 44100, 48000};
-    
-    // 添加常见声道数
     defaultDevice.supportedChannels = {1, 2};
-    
-    // 添加支持的采样格式
-    defaultDevice.supportedFormats = {
-        AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT
-    };
-    
+    defaultDevice.supportedFormats = {AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT};
     devices.push_back(defaultDevice);
     
-    // 如果没有找到其他设备,至少提供一个编号设备
-    if (devices.size() == 1) {
-        AudioDeviceInfo device;
-        device.id = "0";
-        device.name = "音频设备 0";
-        device.description = "DirectShow音频设备 0";
-        device.isDefault = false;
-        device.isInput = true;
-        device.supportedSampleRates = {8000, 16000, 22050, 44100, 48000};
-        device.supportedChannels = {1, 2};
-        device.supportedFormats = {AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT};
-        
-        devices.push_back(device);
-    }
-    
     return devices;
 }
 

+ 236 - 22
AV/code/codec/codec_abstract_codec.cpp

@@ -1,4 +1,8 @@
 #include "codec_abstract_codec.h"
+#include "codec_video_encoder.h"
+#include "codec_audio_encoder.h"
+#include "codec_video_decoder.h"
+#include "codec_audio_decoder.h"
 #include "../base/media_common.h"
 #include "../base/logger.h"
 #include <chrono>
@@ -51,11 +55,13 @@ ErrorCode AbstractCodec::reset() {
 }
 
 void AbstractCodec::resetStatistics() {
+    std::lock_guard<std::mutex> lock(statsMutex_);
     stats_ = Statistics{};
     AV_LOGGER_DEBUG("统计信息已重置");
 }
 
 void AbstractCodec::setState(CodecState state) {
+    std::unique_lock<std::shared_mutex> lock(stateMutex_);
     if (state_ != state) {
         AV_LOGGER_DEBUGF("编解码器状态变更: {} -> {}", 
                       static_cast<int>(state_), static_cast<int>(state));
@@ -65,7 +71,12 @@ void AbstractCodec::setState(CodecState state) {
 
 void AbstractCodec::reportError(ErrorCode error, const std::string& message) {
     setState(CodecState::ERROR);
-    stats_.errorCount++;
+    
+    // 更新错误统计
+    {
+        std::lock_guard<std::mutex> lock(statsMutex_);
+        stats_.errorCount++;
+    }
     
     std::string fullMessage = message.empty() ? 
         ffmpeg_utils::errorToString(static_cast<int>(error)) : message;
@@ -78,6 +89,7 @@ void AbstractCodec::reportError(ErrorCode error, const std::string& message) {
 }
 
 void AbstractCodec::updateStats(bool success, double processTime, uint64_t bytes) {
+    std::lock_guard<std::mutex> lock(statsMutex_);
     if (success) {
         stats_.processedFrames++;
         stats_.totalBytes += bytes;
@@ -112,10 +124,24 @@ std::unique_ptr<AbstractEncoder> CodecFactory::createEncoder(MediaType mediaType
         return nullptr;
     }
     
-    // 这里需要根据具体的编码器类型创建实例
-    // 暂时返回nullptr,具体实现在子类中
-    AV_LOGGER_WARNING("CodecFactory::createEncoder 需要在具体实现中完成");
-    return nullptr;
+    // 根据媒体类型创建具体的编码器实例
+    try {
+        if (mediaType == MediaType::VIDEO) {
+            auto encoder = std::make_unique<VideoEncoder>();
+            AV_LOGGER_INFOF("成功创建视频编码器: {}", codecName);
+            return std::move(encoder);
+        } else if (mediaType == MediaType::AUDIO) {
+            auto encoder = std::make_unique<AudioEncoder>();
+            AV_LOGGER_INFOF("成功创建音频编码器: {}", codecName);
+            return std::move(encoder);
+        } else {
+            AV_LOGGER_ERRORF("不支持的媒体类型: {}", static_cast<int>(mediaType));
+            return nullptr;
+        }
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("创建编码器实例失败: {}", e.what());
+        return nullptr;
+    }
 }
 
 std::unique_ptr<AbstractDecoder> CodecFactory::createDecoder(MediaType mediaType, const std::string& codecName) {
@@ -136,10 +162,24 @@ std::unique_ptr<AbstractDecoder> CodecFactory::createDecoder(MediaType mediaType
         return nullptr;
     }
     
-    // 这里需要根据具体的解码器类型创建实例
-    // 暂时返回nullptr,具体实现在子类中
-    AV_LOGGER_WARNING("CodecFactory::createDecoder 需要在具体实现中完成");
-    return nullptr;
+    // 根据媒体类型创建具体的解码器实例
+    try {
+        if (mediaType == MediaType::VIDEO) {
+            auto decoder = std::make_unique<VideoDecoder>();
+            AV_LOGGER_INFOF("成功创建视频解码器: {}", codecName);
+            return std::move(decoder);
+        } else if (mediaType == MediaType::AUDIO) {
+            auto decoder = std::make_unique<AudioDecoder>();
+            AV_LOGGER_INFOF("成功创建音频解码器: {}", codecName);
+            return std::move(decoder);
+        } else {
+            AV_LOGGER_ERRORF("不支持的媒体类型: {}", static_cast<int>(mediaType));
+            return nullptr;
+        }
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("创建解码器实例失败: {}", e.what());
+        return nullptr;
+    }
 }
 
 std::vector<std::string> CodecFactory::getSupportedEncoders(MediaType mediaType) {
@@ -202,20 +242,46 @@ bool CodecFactory::isCodecSupported(const std::string& codecName, CodecType type
 void AbstractCodec::close() {
     AV_LOGGER_DEBUG("关闭编解码器");
     
-    if (state_ == CodecState::CLOSED || state_ == CodecState::IDLE) {
-        return;
-    }
-    
-    // 释放编解码上下文
-    if (codecCtx_) {
-        AVCodecContext* ctx = codecCtx_.release();
-        avcodec_free_context(&ctx);
+    // 使用RAII确保异常安全
+    try {
+        std::unique_lock<std::shared_mutex> stateLock(stateMutex_);
+        if (state_ == CodecState::CLOSED || state_ == CodecState::IDLE) {
+            return;
+        }
+        
+        // 设置状态为关闭中,防止其他操作
+        state_ = CodecState::CLOSED;
+        stateLock.unlock();
+        
+        // 获取资源锁进行清理
+        std::lock_guard<std::mutex> resourceLock(resourceMutex_);
+        
+        // 释放编解码上下文
+        if (codecCtx_) {
+            AVCodecContext* ctx = codecCtx_.release();
+            avcodec_free_context(&ctx);
+        }
+        
+        codec_ = nullptr;
+        
+        AV_LOGGER_DEBUG("编解码器已关闭");
+        
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("关闭编解码器时发生异常: {}", e.what());
+        // 确保状态被设置为错误
+        try {
+            setState(CodecState::ERROR);
+        } catch (...) {
+            // 忽略setState可能的异常,因为我们已经在异常处理中
+        }
+    } catch (...) {
+        AV_LOGGER_ERROR("关闭编解码器时发生未知异常");
+        try {
+            setState(CodecState::ERROR);
+        } catch (...) {
+            // 忽略setState可能的异常
+        }
     }
-    
-    codec_ = nullptr;
-    setState(CodecState::CLOSED);
-    
-    AV_LOGGER_DEBUG("编解码器已关闭");
 }
 
 ErrorCode AbstractCodec::flush() {
@@ -238,5 +304,153 @@ ErrorCode AbstractCodec::flush() {
     return ErrorCode::SUCCESS;
 }
 
+// 错误码转换工具实现
+ErrorCode AbstractCodec::convertFFmpegError(int ffmpegError) {
+    if (ffmpegError >= 0) {
+        return ErrorCode::SUCCESS;
+    }
+    
+    // 根据FFmpeg错误码映射到项目中已定义的错误码
+    switch (ffmpegError) {
+        case AVERROR(EINVAL):
+            return ErrorCode::INVALID_PARAMS;
+        case AVERROR(ENOMEM):
+            return ErrorCode::MEMORY_ALLOC_FAILED;
+        case AVERROR(EAGAIN):
+            return ErrorCode::PROCESSING_ERROR;  // 使用PROCESSING_ERROR代替RESOURCE_BUSY
+        case AVERROR_EOF:
+            return ErrorCode::END_OF_STREAM;
+        case AVERROR(ENOSYS):
+            return ErrorCode::NOT_SUPPORTED;
+        case AVERROR(EPIPE):
+            return ErrorCode::OPERATION_FAILED;  // 使用OPERATION_FAILED代替BROKEN_PIPE
+        case AVERROR(EIO):
+            return ErrorCode::FILE_OPERATION_FAILED;  // 使用FILE_OPERATION_FAILED代替IO_ERROR
+        case AVERROR(EACCES):
+            return ErrorCode::FILE_OPEN_FAILED;  // 使用FILE_OPEN_FAILED代替ACCESS_DENIED
+        case AVERROR_DECODER_NOT_FOUND:
+            return ErrorCode::CODEC_NOT_FOUND;  // 使用CODEC_NOT_FOUND代替DECODER_NOT_FOUND
+        case AVERROR_ENCODER_NOT_FOUND:
+            return ErrorCode::CODEC_NOT_FOUND;  // 使用CODEC_NOT_FOUND代替ENCODER_NOT_FOUND
+        case AVERROR_DEMUXER_NOT_FOUND:
+            return ErrorCode::NOT_FOUND;  // 使用通用NOT_FOUND
+        case AVERROR_MUXER_NOT_FOUND:
+            return ErrorCode::NOT_FOUND;  // 使用通用NOT_FOUND
+        case AVERROR_PROTOCOL_NOT_FOUND:
+            return ErrorCode::NOT_FOUND;  // 使用通用NOT_FOUND
+        case AVERROR_STREAM_NOT_FOUND:
+            return ErrorCode::STREAM_NOT_FOUND;
+        case AVERROR_BUG:
+            return ErrorCode::UNKNOWN_ERROR;  // 使用UNKNOWN_ERROR代替INTERNAL_ERROR
+        case AVERROR_UNKNOWN:
+            return ErrorCode::UNKNOWN_ERROR;
+        case AVERROR_EXPERIMENTAL:
+            return ErrorCode::NOT_SUPPORTED;
+        case AVERROR_INPUT_CHANGED:
+            return ErrorCode::FORMAT_NOT_SUPPORTED;  // 使用FORMAT_NOT_SUPPORTED代替FORMAT_CHANGED
+        case AVERROR_OUTPUT_CHANGED:
+            return ErrorCode::FORMAT_NOT_SUPPORTED;  // 使用FORMAT_NOT_SUPPORTED代替FORMAT_CHANGED
+        case AVERROR_BSF_NOT_FOUND:
+            return ErrorCode::NOT_FOUND;  // 使用通用NOT_FOUND代替FILTER_NOT_FOUND
+        case AVERROR_BUG2:
+            return ErrorCode::UNKNOWN_ERROR;  // 使用UNKNOWN_ERROR代替INTERNAL_ERROR
+        case AVERROR_BUFFER_TOO_SMALL:
+            return ErrorCode::MEMORY_ALLOC_FAILED;  // 使用MEMORY_ALLOC_FAILED代替BUFFER_TOO_SMALL
+        case AVERROR_EXTERNAL:
+            return ErrorCode::OPERATION_FAILED;  // 使用OPERATION_FAILED代替EXTERNAL_ERROR
+        case AVERROR_INVALIDDATA:
+            return ErrorCode::INVALID_PARAMS;  // 使用INVALID_PARAMS代替INVALID_DATA
+        case AVERROR_PATCHWELCOME:
+            return ErrorCode::NOT_SUPPORTED;  // 使用NOT_SUPPORTED代替NOT_IMPLEMENTED
+        default:
+            // 对于未映射的错误,记录原始错误码
+            AV_LOGGER_WARNING("未映射的FFmpeg错误码,使用通用错误");
+            return ErrorCode::UNKNOWN_ERROR;
+    }
+}
+
+std::string AbstractCodec::getErrorDescription(ErrorCode error) {
+    switch (error) {
+        case ErrorCode::SUCCESS:
+            return "成功";
+        case ErrorCode::INVALID_PARAMS:
+            return "无效参数";
+        case ErrorCode::INVALID_PATH:
+            return "无效路径";
+        case ErrorCode::CODEC_NOT_FOUND:
+            return "编解码器未找到";
+        case ErrorCode::CODEC_OPEN_FAILED:
+            return "编解码器打开失败";
+        case ErrorCode::ENCODE_FAILED:
+            return "编码失败";
+        case ErrorCode::DECODE_FAILED:
+            return "解码失败";
+        case ErrorCode::MEMORY_ALLOC_FAILED:
+            return "内存分配失败";
+        case ErrorCode::FILE_OPEN_FAILED:
+            return "文件打开失败";
+        case ErrorCode::FILE_EXISTS:
+            return "文件已存在";
+        case ErrorCode::FILE_OPERATION_FAILED:
+            return "文件操作失败";
+        case ErrorCode::INVALID_STATE:
+            return "无效状态";
+        case ErrorCode::NOT_STARTED:
+            return "未开始";
+        case ErrorCode::NOT_PAUSED:
+            return "未暂停";
+        case ErrorCode::ALREADY_INITIALIZED:
+            return "已经初始化";
+        case ErrorCode::NOT_INITIALIZED:
+            return "未初始化";
+        case ErrorCode::ALREADY_STARTED:
+            return "已经开始";
+        case ErrorCode::ALREADY_PAUSED:
+            return "已经暂停";
+        case ErrorCode::CONVERSION_FAILED:
+            return "转换失败";
+        case ErrorCode::FORMAT_NOT_SUPPORTED:
+            return "格式不支持";
+        case ErrorCode::NOT_SUPPORTED:
+            return "不支持的操作";
+        case ErrorCode::HARDWARE_ERROR:
+            return "硬件错误";
+        case ErrorCode::DEVICE_NOT_FOUND:
+            return "设备未找到";
+        case ErrorCode::STREAM_NOT_FOUND:
+            return "流未找到";
+        case ErrorCode::STREAM_EXISTS:
+            return "流已存在";
+        case ErrorCode::STREAM_CREATE_FAILED:
+            return "流创建失败";
+        case ErrorCode::END_OF_STREAM:
+            return "流结束";
+        case ErrorCode::THREAD_ERROR:
+            return "线程错误";
+        case ErrorCode::QUEUE_FULL:
+            return "队列满";
+        case ErrorCode::SYNC_ERROR:
+            return "同步错误";
+        case ErrorCode::ALREADY_EXISTS:
+            return "已存在";
+        case ErrorCode::NOT_FOUND:
+            return "未找到";
+        case ErrorCode::TIMEOUT:
+            return "超时";
+        case ErrorCode::COPY_FAILED:
+            return "拷贝失败";
+        case ErrorCode::PROCESSING_ERROR:
+            return "处理错误";
+        case ErrorCode::INITIALIZATION_FAILED:
+            return "初始化失败";
+        case ErrorCode::OPERATION_FAILED:
+            return "操作失败";
+        case ErrorCode::UNKNOWN_ERROR:
+            return "未知错误";
+        default:
+            return "未知错误码: " + std::to_string(static_cast<int>(error));
+    }
+}
+
 } // namespace codec
 } // namespace av

+ 118 - 6
AV/code/codec/codec_abstract_codec.h

@@ -5,6 +5,8 @@
 #include <functional>
 #include <vector>
 #include <string>
+#include <shared_mutex>
+#include <mutex>
 
 namespace av {
 namespace codec {
@@ -66,13 +68,25 @@ public:
      */
     virtual ErrorCode reset();
 
-    // 状态查询
-    CodecState getState() const { return state_; }
+    // 状态查询(线程安全)
+    CodecState getState() const { 
+        std::shared_lock<std::shared_mutex> lock(stateMutex_);
+        return state_; 
+    }
     MediaType getMediaType() const { return mediaType_; }
     CodecType getCodecType() const { return codecType_; }
-    bool isOpened() const { return state_ == CodecState::OPENED || state_ == CodecState::RUNNING; }
-    bool isRunning() const { return state_ == CodecState::RUNNING; }
-    bool hasError() const { return state_ == CodecState::ERROR; }
+    bool isOpened() const { 
+        std::shared_lock<std::shared_mutex> lock(stateMutex_);
+        return state_ == CodecState::OPENED || state_ == CodecState::RUNNING; 
+    }
+    bool isRunning() const { 
+        std::shared_lock<std::shared_mutex> lock(stateMutex_);
+        return state_ == CodecState::RUNNING; 
+    }
+    bool hasError() const { 
+        std::shared_lock<std::shared_mutex> lock(stateMutex_);
+        return state_ == CodecState::ERROR; 
+    }
 
     // 参数获取
     const CodecParams& getParams() const { return params_; }
@@ -86,14 +100,107 @@ public:
         uint64_t totalBytes = 0;        // 总字节数
     };
     
-    const Statistics& getStatistics() const { return stats_; }
+    Statistics getStatistics() const { 
+        std::lock_guard<std::mutex> lock(statsMutex_);
+        return stats_; 
+    }
     void resetStatistics();
 
     // 回调函数设置
     using ErrorCallback = std::function<void(ErrorCode error, const std::string& message)>;
     void setErrorCallback(ErrorCallback callback) { errorCallback_ = std::move(callback); }
+    
+    // 错误码转换工具
+    static ErrorCode convertFFmpegError(int ffmpegError);
+    static std::string getErrorDescription(ErrorCode error);
 
 protected:
+    // RAII资源管理包装器
+    template<typename T, typename Deleter>
+    class ResourceGuard {
+    private:
+        T* resource_;
+        Deleter deleter_;
+        bool released_;
+        
+    public:
+        explicit ResourceGuard(T* resource, Deleter deleter) 
+            : resource_(resource), deleter_(deleter), released_(false) {}
+            
+        ~ResourceGuard() {
+            if (!released_ && resource_) {
+                deleter_(resource_);
+            }
+        }
+        
+        // 禁止拷贝
+        ResourceGuard(const ResourceGuard&) = delete;
+        ResourceGuard& operator=(const ResourceGuard&) = delete;
+        
+        // 允许移动
+        ResourceGuard(ResourceGuard&& other) noexcept
+            : resource_(other.resource_), deleter_(std::move(other.deleter_)), released_(other.released_) {
+            other.released_ = true;
+        }
+        
+        ResourceGuard& operator=(ResourceGuard&& other) noexcept {
+            if (this != &other) {
+                if (!released_ && resource_) {
+                    deleter_(resource_);
+                }
+                resource_ = other.resource_;
+                deleter_ = std::move(other.deleter_);
+                released_ = other.released_;
+                other.released_ = true;
+            }
+            return *this;
+        }
+        
+        T* get() const { return resource_; }
+        T* release() { released_ = true; return resource_; }
+        void reset(T* newResource = nullptr) {
+            if (!released_ && resource_) {
+                deleter_(resource_);
+            }
+            resource_ = newResource;
+            released_ = false;
+        }
+        
+        explicit operator bool() const { return resource_ != nullptr && !released_; }
+    };
+    
+    // 状态管理助手,确保状态一致性
+    class StateGuard {
+    private:
+        AbstractCodec* codec_;
+        CodecState originalState_;
+        CodecState targetState_;
+        bool committed_;
+        
+    public:
+        StateGuard(AbstractCodec* codec, CodecState targetState)
+            : codec_(codec), targetState_(targetState), committed_(false) {
+            if (codec_) {
+                originalState_ = codec_->getState();
+                codec_->setState(targetState_);
+            }
+        }
+        
+        ~StateGuard() {
+            if (!committed_ && codec_) {
+                codec_->setState(originalState_);
+            }
+        }
+        
+        void commit() { committed_ = true; }
+        
+        // 禁止拷贝和移动
+        StateGuard(const StateGuard&) = delete;
+        StateGuard& operator=(const StateGuard&) = delete;
+        StateGuard(StateGuard&&) = delete;
+        StateGuard& operator=(StateGuard&&) = delete;
+    };
+    
     /**
      * 设置编解码器状态
      */
@@ -125,6 +232,11 @@ protected:
     // FFmpeg相关
     AVCodecContextPtr codecCtx_;    // 编解码上下文
     const AVCodec* codec_;          // 编解码器
+    
+    // 线程安全机制
+    mutable std::shared_mutex stateMutex_;    // 状态读写锁
+    mutable std::mutex statsMutex_;           // 统计信息锁
+    mutable std::mutex resourceMutex_;        // 资源操作锁
 };
 
 /**

+ 17 - 6
AV/code/codec/codec_audio_decoder.cpp

@@ -123,18 +123,26 @@ ErrorCode AudioDecoder::reset() {
 }
 
 ErrorCode AudioDecoder::decode(const AVPacketPtr& packet, std::vector<AVFramePtr>& frames) {
-    std::lock_guard<std::mutex> lock(decodeMutex_);
-    
-    if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) {
+    // 状态检查(使用基类的线程安全方法)
+    if (!isOpened()) {
         return ErrorCode::INVALID_STATE;
     }
     
-    setState(CodecState::RUNNING);
+    // 只在处理过程中锁定,缩小锁的粒度
+    std::lock_guard<std::mutex> processLock(decodeMutex_);
+    
+    // 使用StateGuard确保异常安全的状态管理
+    StateGuard stateGuard(this, CodecState::RUNNING);
     
     auto startTime = std::chrono::high_resolution_clock::now();
     
     ErrorCode result = decodeFrame(packet, frames);
     
+    // 只有在成功时才提交状态变更
+    if (result == ErrorCode::SUCCESS) {
+        stateGuard.commit();
+    }
+    
     auto endTime = std::chrono::high_resolution_clock::now();
     double processTime = std::chrono::duration<double, std::milli>(endTime - startTime).count();
     
@@ -324,8 +332,11 @@ ErrorCode AudioDecoder::receiveFrames(std::vector<AVFramePtr>& frames) {
         }
         
         if (ret < 0) {
-            AV_LOGGER_ERRORF("接收音频解码帧失败: {}", ffmpeg_utils::errorToString(ret));
-            return static_cast<ErrorCode>(ret);
+            ErrorCode error = AbstractCodec::convertFFmpegError(ret);
+            AV_LOGGER_ERRORF("接收音频解码帧失败: {} ({})", 
+                           AbstractCodec::getErrorDescription(error), 
+                           ffmpeg_utils::errorToString(ret));
+            return error;
         }
         
         // 格式转换(如果需要)

+ 574 - 18
AV/code/codec/codec_audio_encoder.cpp

@@ -1,5 +1,6 @@
 #include "codec_audio_encoder.h"
 #include "../base/logger.h"
+#include "../base/media_common.h"
 #include <algorithm>
 #include <chrono>
 
@@ -96,26 +97,81 @@ bool AudioResampler::init(const AVChannelLayout& srcLayout, AVSampleFormat srcFo
 }
 
 AVFramePtr AudioResampler::resample(const AVFramePtr& srcFrame) {
-    if (!initialized_ || !srcFrame) {
+    if (!initialized_) {
+        AV_LOGGER_ERROR("AudioResampler not initialized");
+        return nullptr;
+    }
+    
+    if (!srcFrame) {
+        AV_LOGGER_ERROR("Source frame is null");
+        return nullptr;
+    }
+    
+    if (!swrCtx_) {
+        AV_LOGGER_ERROR("SwrContext is null");
+        return nullptr;
+    }
+    
+    if (!dstFrame_) {
+        AV_LOGGER_ERROR("Destination frame is null");
+        return nullptr;
+    }
+    
+    // 验证源帧的有效性
+    if (srcFrame->nb_samples <= 0) {
+        AV_LOGGER_ERRORF("Invalid source frame samples: {}", srcFrame->nb_samples);
+        return nullptr;
+    }
+    
+    if (!srcFrame->data[0]) {
+        AV_LOGGER_ERROR("Source frame data is null");
         return nullptr;
     }
     
     // 计算输出样本数
     int dstSamples = av_rescale_rnd(srcFrame->nb_samples, dstSampleRate_, srcSampleRate_, AV_ROUND_UP);
+    if (dstSamples <= 0) {
+        AV_LOGGER_ERRORF("Invalid calculated destination samples: {}", dstSamples);
+        return nullptr;
+    }
+    
+    AV_LOGGER_DEBUGF("Resampling: src_samples={}, dst_samples={}, src_rate={}, dst_rate={}", 
+                     srcFrame->nb_samples, dstSamples, srcSampleRate_, dstSampleRate_);
     
     // 确保输出帧有足够的空间
     if (dstFrame_->nb_samples < dstSamples) {
+        AV_LOGGER_DEBUGF("Reallocating destination frame buffer: {} -> {}", dstFrame_->nb_samples, dstSamples);
+        
         av_frame_unref(dstFrame_.get());
+        
+        // 重新设置帧格式信息(av_frame_unref 会清除这些信息)
+        dstFrame_->format = dstFormat_;
+        dstFrame_->sample_rate = dstSampleRate_;
+        int ret = av_channel_layout_copy(&dstFrame_->ch_layout, &dstLayout_);
+        if (ret < 0) {
+            AV_LOGGER_ERRORF("复制声道布局失败: {}", ffmpeg_utils::errorToString(ret));
+            return nullptr;
+        }
         dstFrame_->nb_samples = dstSamples;
         
-        int ret = av_frame_get_buffer(dstFrame_.get(), 0);
+        ret = av_frame_get_buffer(dstFrame_.get(), 0);
         if (ret < 0) {
             AV_LOGGER_ERRORF("重新分配帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret));
             return nullptr;
         }
+        
+        AV_LOGGER_DEBUGF("Frame buffer reallocated successfully: format={}, rate={}, channels={}, samples={}", 
+                         dstFrame_->format, dstFrame_->sample_rate, dstFrame_->ch_layout.nb_channels, dstFrame_->nb_samples);
+    }
+    
+    // 验证目标帧的有效性
+    if (!dstFrame_->data[0]) {
+        AV_LOGGER_ERROR("Destination frame data is null after allocation");
+        return nullptr;
     }
     
     // 执行重采样
+    AV_LOGGER_DEBUG("Executing swr_convert...");
     int convertedSamples = swr_convert(swrCtx_,
                                        dstFrame_->data, dstSamples,
                                        const_cast<const uint8_t**>(srcFrame->data), srcFrame->nb_samples);
@@ -127,15 +183,41 @@ AVFramePtr AudioResampler::resample(const AVFramePtr& srcFrame) {
     
     dstFrame_->nb_samples = convertedSamples;
     
+    // 创建输出帧的副本
+    AVFramePtr outputFrame = makeAVFrame();
+    if (!outputFrame) {
+        AV_LOGGER_ERROR("分配输出帧失败");
+        return nullptr;
+    }
+    
+    // 复制重采样后的数据
+    outputFrame->format = dstFrame_->format;
+    outputFrame->sample_rate = dstFrame_->sample_rate;
+    av_channel_layout_copy(&outputFrame->ch_layout, &dstFrame_->ch_layout);
+    outputFrame->nb_samples = convertedSamples;
+    
+    int ret = av_frame_get_buffer(outputFrame.get(), 0);
+    if (ret < 0) {
+        AV_LOGGER_ERRORF("分配输出帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret));
+        return nullptr;
+    }
+    
+    // 复制音频数据
+    ret = av_frame_copy(outputFrame.get(), dstFrame_.get());
+    if (ret < 0) {
+        AV_LOGGER_ERRORF("复制帧数据失败: {}", ffmpeg_utils::errorToString(ret));
+        return nullptr;
+    }
+    
     // 复制时间戳等信息
-    av_frame_copy_props(dstFrame_.get(), srcFrame.get());
+    av_frame_copy_props(outputFrame.get(), srcFrame.get());
     
     // 调整时间戳
     if (srcFrame->pts != AV_NOPTS_VALUE) {
-        dstFrame_->pts = av_rescale_q(srcFrame->pts, {1, srcSampleRate_}, {1, dstSampleRate_});
+        outputFrame->pts = av_rescale_q(srcFrame->pts, {1, srcSampleRate_}, {1, dstSampleRate_});
     }
     
-    return std::move(dstFrame_);
+    return outputFrame;
 }
 
 std::vector<AVFramePtr> AudioResampler::flush() {
@@ -178,7 +260,7 @@ std::vector<AVFramePtr> AudioResampler::flush() {
 
 // AudioEncoder 实现
 AudioEncoder::AudioEncoder()
-    : AbstractEncoder(MediaType::AUDIO) {
+    : AbstractEncoder(MediaType::AUDIO), bufferedSamples_(0) {
     AV_LOGGER_DEBUG("创建音频编码器");
 }
 
@@ -208,6 +290,13 @@ ErrorCode AudioEncoder::open(const CodecParams& params) {
         return result;
     }
     
+    // 初始化帧缓冲区
+    result = initFrameBuffer();
+    if (result != ErrorCode::SUCCESS) {
+        close();
+        return result;
+    }
+    
     setState(CodecState::OPENED);
     AV_LOGGER_INFOF("音频编码器已打开: {} ({}Hz, {}ch, {}kbps)", 
                  audioParams_.codecName, audioParams_.sampleRate, 
@@ -227,6 +316,9 @@ void AudioEncoder::close() {
     resampler_.reset();
     convertedFrame_.reset();
     
+    // 清理帧缓冲区
+    clearBuffer();
+    
     // 清理编解码上下文
     codecCtx_.reset();
     codec_ = nullptr;
@@ -257,17 +349,55 @@ ErrorCode AudioEncoder::flush() {
 }
 
 ErrorCode AudioEncoder::encode(const AVFramePtr& frame, std::vector<AVPacketPtr>& packets) {
-    std::lock_guard<std::mutex> lock(encodeMutex_);
-    
-    if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) {
+    // 状态检查(使用基类的线程安全方法)
+    if (!isOpened()) {
         return ErrorCode::INVALID_STATE;
     }
     
-    setState(CodecState::RUNNING);
+    // 只在处理过程中锁定,缩小锁的粒度
+    std::lock_guard<std::mutex> processLock(encodeMutex_);
+    
+    // 使用StateGuard确保异常安全的状态管理
+    StateGuard stateGuard(this, CodecState::RUNNING);
     
     auto startTime = std::chrono::high_resolution_clock::now();
     
-    ErrorCode result = encodeFrame(frame, packets);
+    ErrorCode result = ErrorCode::SUCCESS;
+    
+    if (frame) {
+        // 检查是否需要使用帧缓冲机制
+        if (codecCtx_->frame_size > 0 && frame->nb_samples != codecCtx_->frame_size) {
+            AV_LOGGER_DEBUGF("使用帧缓冲机制处理大帧: 输入={}, 期望={}", 
+                           frame->nb_samples, codecCtx_->frame_size);
+            
+            // 将大帧添加到缓冲区
+            result = addToBuffer(frame);
+            if (result != ErrorCode::SUCCESS) {
+                return result;
+            }
+            
+            // 从缓冲区提取标准大小的帧进行编码
+            while (bufferedSamples_ >= codecCtx_->frame_size) {
+                AVFramePtr smallFrame = extractFrameFromBuffer();
+                if (smallFrame) {
+                    // 使用move语义明确转移所有权,避免潜在的双重释放
+                    ErrorCode encodeResult = encodeFrame(std::move(smallFrame), packets);
+                    if (encodeResult != ErrorCode::SUCCESS) {
+                        result = encodeResult;
+                        break;
+                    }
+                } else {
+                    break;
+                }
+            }
+        } else {
+            // 直接编码(帧大小匹配)
+            result = encodeFrame(frame, packets);
+        }
+    } else {
+        // 编码空帧(用于刷新)
+        result = encodeFrame(frame, packets);
+    }
     
     auto endTime = std::chrono::high_resolution_clock::now();
     double processTime = std::chrono::duration<double, std::milli>(endTime - startTime).count();
@@ -285,6 +415,11 @@ ErrorCode AudioEncoder::encode(const AVFramePtr& frame, std::vector<AVPacketPtr>
         }
     }
     
+    // 只有在成功时才提交状态变更
+    if (result == ErrorCode::SUCCESS) {
+        stateGuard.commit();
+    }
+    
     return result;
 }
 
@@ -431,17 +566,52 @@ AVFramePtr AudioEncoder::convertFrame(const AVFramePtr& frame) {
     }
     
     if (!needConvert) {
-        // 创建一个新的帧来返回,避免拷贝构造
+        // 创建一个新的独立帧副本,避免引用计数问题
         AVFramePtr resultFrame = makeAVFrame();
         if (!resultFrame) {
             return nullptr;
         }
         
-        // 复制帧数据
-        if (av_frame_ref(resultFrame.get(), frame.get()) < 0) {
+        // 手动复制帧属性
+        resultFrame->format = frame->format;
+        resultFrame->sample_rate = frame->sample_rate;
+        resultFrame->nb_samples = frame->nb_samples;
+        resultFrame->pts = frame->pts;
+        
+        int ret = av_channel_layout_copy(&resultFrame->ch_layout, &frame->ch_layout);
+        if (ret < 0) {
+            AV_LOGGER_ERRORF("复制声道布局失败: {}", ffmpeg_utils::errorToString(ret));
+            return nullptr;
+        }
+        
+        // 分配新的数据缓冲区
+        ret = av_frame_get_buffer(resultFrame.get(), 0);
+        if (ret < 0) {
+            AV_LOGGER_ERRORF("分配帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret));
+            return nullptr;
+        }
+        
+        // 复制音频数据
+        ret = av_frame_copy(resultFrame.get(), frame.get());
+        if (ret < 0) {
+            AV_LOGGER_ERRORF("复制帧数据失败: {}", ffmpeg_utils::errorToString(ret));
+            return nullptr;
+        }
+        
+        // 复制帧属性
+        ret = av_frame_copy_props(resultFrame.get(), frame.get());
+        if (ret < 0) {
+            AV_LOGGER_ERRORF("复制帧属性失败: {}", ffmpeg_utils::errorToString(ret));
+            return nullptr;
+        }
+        
+        // 最终验证创建的帧副本
+        if (!isValidFrame(resultFrame)) {
+            AV_LOGGER_ERROR("创建的帧副本无效");
             return nullptr;
         }
         
+        AV_LOGGER_DEBUG("创建了不需要转换的帧的独立副本");
         return resultFrame;
     }
     
@@ -451,10 +621,21 @@ AVFramePtr AudioEncoder::convertFrame(const AVFramePtr& frame) {
         if (!resampler_->init(frame->ch_layout, static_cast<AVSampleFormat>(frame->format), frame->sample_rate,
                              codecCtx_->ch_layout, codecCtx_->sample_fmt, codecCtx_->sample_rate)) {
             AV_LOGGER_ERROR("初始化音频重采样器失败");
+            resampler_.reset(); // 确保失败时清理
             return nullptr;
         }
+        AV_LOGGER_INFO("音频重采样器初始化成功");
+    }
+    
+    // 双重检查重采样器状态
+    if (!resampler_) {
+        AV_LOGGER_ERROR("重采样器为空");
+        return nullptr;
     }
     
+    AV_LOGGER_DEBUGF("开始重采样: format={}, rate={}, channels={}", 
+                     frame->format, frame->sample_rate, frame->ch_layout.nb_channels);
+    
     return resampler_->resample(frame);
 }
 
@@ -468,13 +649,121 @@ ErrorCode AudioEncoder::encodeFrame(const AVFramePtr& frame, std::vector<AVPacke
             AV_LOGGER_ERROR("音频帧格式转换失败");
             return ErrorCode::CONVERSION_FAILED;
         }
+        
+        // 调试:输出帧信息
+        AV_LOGGER_DEBUGF("重采样输出帧信息: format={}, rate={}, channels={}, samples={}", 
+                         processedFrame->format, processedFrame->sample_rate, 
+                         processedFrame->ch_layout.nb_channels, processedFrame->nb_samples);
+        
+        // 调试:输出编码器期望的信息
+        AV_LOGGER_DEBUGF("编码器期望格式: format={}, rate={}, channels={}, frame_size={}", 
+                         codecCtx_->sample_fmt, codecCtx_->sample_rate, 
+                         codecCtx_->ch_layout.nb_channels, codecCtx_->frame_size);
+        
+        // 检查帧大小是否匹配
+        if (codecCtx_->frame_size > 0 && processedFrame->nb_samples != codecCtx_->frame_size) {
+            AV_LOGGER_ERRORF("帧大小不匹配: 输入={}, 编码器期望={}", 
+                           processedFrame->nb_samples, codecCtx_->frame_size);
+        }
+        
+        // 检查格式是否匹配
+        if (processedFrame->format != codecCtx_->sample_fmt) {
+            AV_LOGGER_ERRORF("采样格式不匹配: 输入={}, 编码器期望={}", 
+                           processedFrame->format, codecCtx_->sample_fmt);
+        }
+        
+        // 检查采样率是否匹配
+        if (processedFrame->sample_rate != codecCtx_->sample_rate) {
+            AV_LOGGER_ERRORF("采样率不匹配: 输入={}, 编码器期望={}", 
+                           processedFrame->sample_rate, codecCtx_->sample_rate);
+        }
+        
+        // 检查声道数是否匹配
+        if (processedFrame->ch_layout.nb_channels != codecCtx_->ch_layout.nb_channels) {
+            AV_LOGGER_ERRORF("声道数不匹配: 输入={}, 编码器期望={}", 
+                           processedFrame->ch_layout.nb_channels, codecCtx_->ch_layout.nb_channels);
+        }
+    }
+    
+    // 验证processedFrame的有效性
+    if (processedFrame) {
+        // 检查帧数据指针的有效性
+        if (!processedFrame->data || !processedFrame->data[0]) {
+            AV_LOGGER_ERROR("处理后的帧数据指针无效");
+            return ErrorCode::INVALID_PARAMS;
+        }
+        
+        // 检查帧大小是否合理
+        if (processedFrame->nb_samples <= 0 || processedFrame->nb_samples > 100000) {
+            AV_LOGGER_ERRORF("处理后的帧大小异常: {}", processedFrame->nb_samples);
+            return ErrorCode::INVALID_PARAMS;
+        }
+        
+        // 检查声道数是否合理
+        if (processedFrame->ch_layout.nb_channels <= 0 || processedFrame->ch_layout.nb_channels > 32) {
+            AV_LOGGER_ERRORF("处理后的帧声道数异常: {}", processedFrame->ch_layout.nb_channels);
+            return ErrorCode::INVALID_PARAMS;
+        }
+        
+        AV_LOGGER_DEBUGF("即将发送帧到编码器: samples={}, format={}, rate={}, channels={}, data_ptr={}", 
+                         processedFrame->nb_samples, processedFrame->format, 
+                         processedFrame->sample_rate, processedFrame->ch_layout.nb_channels,
+                         static_cast<void*>(processedFrame->data[0]));
+    } else {
+        AV_LOGGER_DEBUG("发送空帧到编码器(flush)");
+    }
+    
+    // 最后一次验证:确保编码器和帧都有效
+    if (!codecCtx_ || !codecCtx_.get()) {
+        AV_LOGGER_ERROR("编码器上下文无效");
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    if (processedFrame) {
+        // 最终检查:确保帧完全有效
+        if (!isValidFrame(processedFrame)) {
+            AV_LOGGER_ERROR("检测到无效的帧数据");
+            return ErrorCode::INVALID_PARAMS;
+        }
+        AV_LOGGER_DEBUG("最终验证通过,帧数据有效");
     }
     
     // 发送帧到编码器
+    AV_LOGGER_DEBUG("开始调用avcodec_send_frame...");
+    
+    // 在调用FFmpeg之前进行最后的安全检查
+    if (processedFrame) {
+        // 确保AVFrame结构本身的完整性
+        if (processedFrame.get() == nullptr) {
+            AV_LOGGER_ERROR("严重错误:processedFrame智能指针为null");
+            return ErrorCode::INVALID_PARAMS;
+        }
+        
+        // 检查AVFrame内部指针是否被破坏
+        if (!processedFrame->data || !processedFrame->data[0]) {
+            AV_LOGGER_ERROR("严重错误:即将发送的帧数据指针为空");
+            return ErrorCode::INVALID_PARAMS;
+        }
+        
+        AV_LOGGER_DEBUGF("FFmpeg调用前最终检查通过: frame_ptr={}, data_ptr={}", 
+                         static_cast<void*>(processedFrame.get()),
+                         static_cast<void*>(processedFrame->data[0]));
+    }
+    
     int ret = avcodec_send_frame(codecCtx_.get(), processedFrame ? processedFrame.get() : nullptr);
+    AV_LOGGER_DEBUGF("avcodec_send_frame返回: {}", ret);
+    
     if (ret < 0) {
-        AV_LOGGER_ERRORF("发送帧到编码器失败: {}", ffmpeg_utils::errorToString(ret));
-        return static_cast<ErrorCode>(ret);
+        ErrorCode error = AbstractCodec::convertFFmpegError(ret);
+        AV_LOGGER_ERRORF("发送帧到编码器失败: {} ({})", 
+                       AbstractCodec::getErrorDescription(error), 
+                       ffmpeg_utils::errorToString(ret));
+        if (processedFrame) {
+            AV_LOGGER_ERRORF("失败的帧信息: samples={}, format={}, rate={}, channels={}", 
+                           processedFrame->nb_samples, processedFrame->format,
+                           processedFrame->sample_rate, processedFrame->ch_layout.nb_channels);
+        }
+        return error;
     }
     
     // 接收编码后的包
@@ -494,8 +783,11 @@ ErrorCode AudioEncoder::receivePackets(std::vector<AVPacketPtr>& packets) {
         }
         
         if (ret < 0) {
-            AV_LOGGER_ERRORF("接收编码包失败: {}", ffmpeg_utils::errorToString(ret));
-            return static_cast<ErrorCode>(ret);
+            ErrorCode error = AbstractCodec::convertFFmpegError(ret);
+            AV_LOGGER_ERRORF("接收编码包失败: {} ({})", 
+                           AbstractCodec::getErrorDescription(error), 
+                           ffmpeg_utils::errorToString(ret));
+            return error;
         }
         
         packets.push_back(std::move(packet));
@@ -622,6 +914,188 @@ void AudioEncoder::findSupportedEncoders() {
     AV_LOGGER_INFOF("总共找到 {} 个可用的音频编码器", supportedEncoders_.size());
 }
 
+// 帧缓冲和拆分方法实现
+ErrorCode AudioEncoder::initFrameBuffer() {
+    if (!codecCtx_ || codecCtx_->frame_size <= 0) {
+        return ErrorCode::SUCCESS; // 不需要缓冲区
+    }
+    
+    // 初始化临时帧
+    tempFrame_ = makeAVFrame();
+    if (!tempFrame_) {
+        AV_LOGGER_ERROR("分配临时帧失败");
+        return ErrorCode::MEMORY_ALLOC_FAILED;
+    }
+    
+    // 设置临时帧格式
+    tempFrame_->format = codecCtx_->sample_fmt;
+    tempFrame_->sample_rate = codecCtx_->sample_rate;
+    av_channel_layout_copy(&tempFrame_->ch_layout, &codecCtx_->ch_layout);
+    tempFrame_->nb_samples = codecCtx_->frame_size;
+    
+    // 分配临时帧缓冲区
+    int ret = av_frame_get_buffer(tempFrame_.get(), 0);
+    if (ret < 0) {
+        AV_LOGGER_ERRORF("分配临时帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret));
+        return ErrorCode::MEMORY_ALLOC_FAILED;
+    }
+    
+    // 计算缓冲区大小(支持最大帧大小的数据)
+    int bytesPerSample = av_get_bytes_per_sample(codecCtx_->sample_fmt);
+    int maxBufferSize = codecCtx_->frame_size * codecCtx_->ch_layout.nb_channels * bytesPerSample * 100; // 支持100倍大小
+    frameBuffer_.reserve(maxBufferSize);
+    
+    bufferedSamples_ = 0;
+    
+    AV_LOGGER_DEBUGF("帧缓冲初始化完成: frame_size={}, channels={}, format={}, buffer_capacity={}", 
+                     codecCtx_->frame_size, codecCtx_->ch_layout.nb_channels, codecCtx_->sample_fmt, maxBufferSize);
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioEncoder::addToBuffer(const AVFramePtr& frame) {
+    if (!frame || !frame->data[0]) {
+        return ErrorCode::INVALID_PARAMS;
+    }
+    
+    // 计算数据大小
+    int bytesPerSample = av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format));
+    int channels = frame->ch_layout.nb_channels;
+    int frameDataSize = frame->nb_samples * channels * bytesPerSample;
+    
+    AV_LOGGER_DEBUGF("添加到缓冲区: samples={}, bytes={}, buffered_samples={}", 
+                     frame->nb_samples, frameDataSize, bufferedSamples_);
+    
+    // 检查缓冲区容量
+    if (frameBuffer_.size() + frameDataSize > frameBuffer_.capacity()) {
+        AV_LOGGER_ERROR("缓冲区容量不足");
+        return ErrorCode::MEMORY_ALLOC_FAILED;
+    }
+    
+    // 将音频数据添加到缓冲区
+    // 注意:这里假设音频格式是交错的(interleaved),对于平面(planar)格式需要特殊处理
+    if (av_sample_fmt_is_planar(static_cast<AVSampleFormat>(frame->format))) {
+        AV_LOGGER_ERROR("暂不支持平面音频格式的缓冲处理");
+        return ErrorCode::NOT_SUPPORTED;
+    }
+    
+    const uint8_t* srcData = frame->data[0];
+    frameBuffer_.insert(frameBuffer_.end(), srcData, srcData + frameDataSize);
+    bufferedSamples_ += frame->nb_samples;
+    
+    AV_LOGGER_DEBUGF("缓冲区更新: total_samples={}, buffer_size={}", 
+                     bufferedSamples_, frameBuffer_.size());
+    
+    return ErrorCode::SUCCESS;
+}
+
+AVFramePtr AudioEncoder::extractFrameFromBuffer() {
+    if (!tempFrame_ || bufferedSamples_ < codecCtx_->frame_size) {
+        return nullptr;
+    }
+    
+    int bytesPerSample = av_get_bytes_per_sample(codecCtx_->sample_fmt);
+    int channels = codecCtx_->ch_layout.nb_channels;
+    int frameDataSize = codecCtx_->frame_size * channels * bytesPerSample;
+    
+    if (frameBuffer_.size() < frameDataSize) {
+        AV_LOGGER_ERROR("缓冲区数据不足");
+        return nullptr;
+    }
+    
+    // 创建输出帧(手动设置格式信息)
+    AVFramePtr outputFrame = makeAVFrame();
+    if (!outputFrame) {
+        return nullptr;
+    }
+    
+    // 手动设置帧格式信息(避免使用av_frame_ref导致缓冲区共享)
+    outputFrame->format = codecCtx_->sample_fmt;
+    outputFrame->sample_rate = codecCtx_->sample_rate;
+    int ret = av_channel_layout_copy(&outputFrame->ch_layout, &codecCtx_->ch_layout);
+    if (ret < 0) {
+        AV_LOGGER_ERRORF("复制声道布局失败: {}", ffmpeg_utils::errorToString(ret));
+        return nullptr;
+    }
+    outputFrame->nb_samples = codecCtx_->frame_size;
+    
+    // 分配新的缓冲区
+    ret = av_frame_get_buffer(outputFrame.get(), 0);
+    if (ret < 0) {
+        AV_LOGGER_ERRORF("分配输出帧缓冲区失败: {}", ffmpeg_utils::errorToString(ret));
+        return nullptr;
+    }
+    
+    // 验证分配的缓冲区是否有效
+    if (!outputFrame->data || !outputFrame->data[0]) {
+        AV_LOGGER_ERROR("分配的帧缓冲区无效");
+        return nullptr;
+    }
+    
+    AV_LOGGER_DEBUGF("成功分配帧缓冲区: format={}, samples={}, channels={}, data_ptr={}", 
+                     outputFrame->format, outputFrame->nb_samples, 
+                     outputFrame->ch_layout.nb_channels, static_cast<void*>(outputFrame->data[0]));
+    
+    // 安全检查:确保数据足够
+    if (frameBuffer_.size() < frameDataSize || !outputFrame->data[0]) {
+        AV_LOGGER_ERROR("数据复制前检查失败");
+        return nullptr;
+    }
+    
+    // 复制数据
+    AV_LOGGER_DEBUGF("准备复制音频数据: src_ptr={}, dst_ptr={}, size={}", 
+                     static_cast<const void*>(frameBuffer_.data()),
+                     static_cast<void*>(outputFrame->data[0]),
+                     frameDataSize);
+    
+    // 验证源和目标指针的有效性
+    if (!frameBuffer_.data() || !outputFrame->data[0]) {
+        AV_LOGGER_ERROR("内存复制:源或目标指针无效");
+        return nullptr;
+    }
+    
+    memcpy(outputFrame->data[0], frameBuffer_.data(), frameDataSize);
+    
+    AV_LOGGER_DEBUG("音频数据复制完成");
+    
+    // 设置时间戳(简化处理)
+    outputFrame->pts = AV_NOPTS_VALUE;
+    
+    // 最终验证帧的完整性
+    if (!isValidFrame(outputFrame)) {
+        AV_LOGGER_ERROR("提取的帧无效,丢弃");
+        return nullptr;
+    }
+    
+    // 安全检查:确保缓冲区操作安全
+    if (frameDataSize > frameBuffer_.size()) {
+        AV_LOGGER_ERROR("缓冲区数据不足,无法移除");
+        return nullptr;
+    }
+    
+    // 从缓冲区移除已使用的数据
+    frameBuffer_.erase(frameBuffer_.begin(), frameBuffer_.begin() + frameDataSize);
+    bufferedSamples_ -= codecCtx_->frame_size;
+    
+    AV_LOGGER_DEBUGF("从缓冲区提取帧: samples={}, remaining_samples={}, remaining_bytes={}", 
+                     codecCtx_->frame_size, bufferedSamples_, frameBuffer_.size());
+    
+    // 再次验证帧的有效性(防御性编程)
+    if (!outputFrame->data[0]) {
+        AV_LOGGER_ERROR("严重错误:帧数据在返回前变为空指针");
+        return nullptr;
+    }
+    
+    return outputFrame;
+}
+
+void AudioEncoder::clearBuffer() {
+    frameBuffer_.clear();
+    bufferedSamples_ = 0;
+    tempFrame_.reset();
+    AV_LOGGER_DEBUG("帧缓冲区已清除");
+}
+
 // AudioEncoderFactory 实现
 std::unique_ptr<AudioEncoder> AudioEncoderFactory::create(const std::string& codecName) {
     auto encoder = std::make_unique<AudioEncoder>();
@@ -663,5 +1137,87 @@ std::unique_ptr<AudioEncoder> AudioEncoderFactory::createLossless() {
     return createBest();
 }
 
+// 帧验证工具实现
+bool AudioEncoder::isValidFrame(const AVFramePtr& frame) {
+    return isValidFramePointer(frame.get());
+}
+
+bool AudioEncoder::isValidFramePointer(const AVFrame* frame) {
+    if (!frame) {
+        return false;
+    }
+    
+    // 检查基本属性
+    if (frame->nb_samples <= 0) {
+        AV_LOGGER_ERROR("帧样本数无效");
+        return false;
+    }
+    
+    if (frame->format < 0) {
+        AV_LOGGER_ERROR("帧格式无效");
+        return false;
+    }
+    
+    if (frame->sample_rate <= 0) {
+        AV_LOGGER_ERROR("帧采样率无效");
+        return false;
+    }
+    
+    if (frame->ch_layout.nb_channels <= 0) {
+        AV_LOGGER_ERROR("帧声道数无效");
+        return false;
+    }
+    
+    // 检查数据指针
+    if (!frame->data[0]) {
+        AV_LOGGER_ERROR("帧数据指针为空");
+        return false;
+    }
+    
+    // 通用的指针有效性检查
+    uintptr_t ptr = reinterpret_cast<uintptr_t>(frame->data[0]);
+    
+    // 检查常见的无效指针模式
+    if (ptr == 0) {
+        AV_LOGGER_ERROR("帧数据指针为NULL");
+        return false;
+    }
+    
+    if (ptr == UINTPTR_MAX || ptr == (UINTPTR_MAX - 1)) {
+        AV_LOGGER_ERRORF("帧数据指针为无效值: 0x{:x}", ptr);
+        return false;
+    }
+    
+    // 检查是否在合理的地址范围内(避免空指针附近的地址)
+    if (ptr < 0x1000) {
+        AV_LOGGER_ERRORF("帧数据指针在低地址空间: 0x{:x}", ptr);
+        return false;
+    }
+    
+    // 在64位系统上,检查是否在用户空间范围内
+    #if defined(_WIN64) || defined(__x86_64__) || defined(__aarch64__)
+    if (ptr > 0x7FFFFFFFFFFF) {  // 用户空间上限
+        AV_LOGGER_ERRORF("帧数据指针超出用户空间: 0x{:x}", ptr);
+        return false;
+    }
+    #endif
+    
+    // 检查linesize是否合理
+    if (frame->linesize[0] <= 0) {
+        AV_LOGGER_ERROR("帧linesize无效");
+        return false;
+    }
+    
+    // 对于音频,检查数据大小是否合理
+    int expected_size = frame->nb_samples * frame->ch_layout.nb_channels * 
+                       av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format));
+    if (expected_size <= 0 || expected_size > 100 * 1024 * 1024) { // 100MB上限
+        AV_LOGGER_ERRORF("帧数据大小不合理: {} bytes", expected_size);
+        return false;
+    }
+    
+    return true;
+}
+
 } // namespace codec
 } // namespace av

+ 15 - 0
AV/code/codec/codec_audio_encoder.h

@@ -108,6 +108,10 @@ public:
     // 检查编码器是否支持指定的采样率
     static bool isSampleRateSupported(const std::string& codecName, int sampleRate);
     
+    // 帧验证工具
+    static bool isValidFrame(const AVFramePtr& frame);
+    static bool isValidFramePointer(const AVFrame* frame);
+    
     // 检查编码器是否支持指定的声道布局
     static bool isChannelLayoutSupported(const std::string& codecName, const AVChannelLayout& layout);
 
@@ -127,6 +131,12 @@ private:
     // 转换音频帧格式
     AVFramePtr convertFrame(const AVFramePtr& frame);
     
+    // 帧缓冲和拆分相关方法
+    ErrorCode initFrameBuffer();
+    ErrorCode addToBuffer(const AVFramePtr& frame);
+    AVFramePtr extractFrameFromBuffer();
+    void clearBuffer();
+    
     // 编码单个帧
     ErrorCode encodeFrame(const AVFramePtr& frame, std::vector<AVPacketPtr>& packets);
     
@@ -149,6 +159,11 @@ private:
     std::unique_ptr<AudioResampler> resampler_;
     AVFramePtr convertedFrame_;             // 转换后的帧
     
+    // 帧缓冲机制(用于处理大帧拆分)
+    std::vector<uint8_t> frameBuffer_;      // 音频数据缓冲区
+    int bufferedSamples_;                   // 缓冲区中的样本数
+    AVFramePtr tempFrame_;                  // 临时帧(用于拆分)
+    
     // 线程安全
     std::mutex encodeMutex_;
     

+ 5 - 3
AV/code/codec/codec_video_decoder.cpp

@@ -145,12 +145,14 @@ ErrorCode VideoDecoder::reset() {
 }
 
 ErrorCode VideoDecoder::decode(const AVPacketPtr& packet, std::vector<AVFramePtr>& frames) {
-    std::lock_guard<std::mutex> lock(decodeMutex_);
-    
-    if (state_ != CodecState::OPENED && state_ != CodecState::RUNNING) {
+    // 状态检查(使用基类的线程安全方法)
+    if (!isOpened()) {
         return ErrorCode::INVALID_STATE;
     }
     
+    // 只在处理过程中锁定,缩小锁的粒度
+    std::lock_guard<std::mutex> processLock(decodeMutex_);
+    
     setState(CodecState::RUNNING);
     
     auto startTime = std::chrono::high_resolution_clock::now();

+ 79 - 12
AV/code/codec/codec_video_encoder.cpp

@@ -101,14 +101,29 @@ AVFramePtr PixelFormatConverter::convert(const AVFramePtr& srcFrame) {
         return nullptr;
     }
     
-    // 创建一个新的帧来返回,避免拷贝构造
+    // 创建一个新的帧来返回,完全独立的副本
     AVFramePtr resultFrame = makeAVFrame();
     if (!resultFrame) {
         return nullptr;
     }
     
-    // 复制帧数据
-    if (av_frame_ref(resultFrame.get(), dstFrame_.get()) < 0) {
+    // 复制帧格式信息
+    resultFrame->format = dstFrame_->format;
+    resultFrame->width = dstFrame_->width;
+    resultFrame->height = dstFrame_->height;
+    
+    // 分配新的缓冲区
+    if (av_frame_get_buffer(resultFrame.get(), 32) < 0) {
+        return nullptr;
+    }
+    
+    // 复制帧数据(避免引用计数问题)
+    if (av_frame_copy(resultFrame.get(), dstFrame_.get()) < 0) {
+        return nullptr;
+    }
+    
+    // 复制帧属性
+    if (av_frame_copy_props(resultFrame.get(), dstFrame_.get()) < 0) {
         return nullptr;
     }
     
@@ -545,19 +560,37 @@ AVFramePtr VideoEncoder::convertFrame(const AVFramePtr& frame) {
     if (frame->format == AV_PIX_FMT_YUV420P) {
         // AV_LOGGER_DEBUG("检测到YUV420P格式,直接使用软件编码,避免格式转换");
 
-        // 创建一个新的帧来返回
+        // 创建一个新的独立帧副本
         AVFramePtr resultFrame = makeAVFrame();
         if (!resultFrame) {
             AV_LOGGER_ERROR("创建结果帧失败");
             return nullptr;
         }
         
-        // 复制帧数据
-        if (av_frame_ref(resultFrame.get(), frame.get()) < 0) {
+        // 复制帧格式信息
+        resultFrame->format = frame->format;
+        resultFrame->width = frame->width;
+        resultFrame->height = frame->height;
+        resultFrame->pts = frame->pts;
+        
+        // 分配新的缓冲区
+        if (av_frame_get_buffer(resultFrame.get(), 32) < 0) {
+            AV_LOGGER_ERROR("分配帧缓冲区失败");
+            return nullptr;
+        }
+        
+        // 复制帧数据(避免引用计数问题)
+        if (av_frame_copy(resultFrame.get(), frame.get()) < 0) {
             AV_LOGGER_ERROR("复制帧数据失败");
             return nullptr;
         }
         
+        // 复制帧属性
+        if (av_frame_copy_props(resultFrame.get(), frame.get()) < 0) {
+            AV_LOGGER_ERROR("复制帧属性失败");
+            return nullptr;
+        }
+        
         return resultFrame;
     }
     
@@ -577,19 +610,37 @@ AVFramePtr VideoEncoder::convertFrame(const AVFramePtr& frame) {
     
     // 如果格式已经匹配,创建新帧返回
     if (frame->format == targetFormat) {
-        // 创建一个新的帧来返回,避免拷贝构造
+        // 创建一个新的独立帧副本
         AVFramePtr resultFrame = makeAVFrame();
         if (!resultFrame) {
             AV_LOGGER_ERROR("创建结果帧失败");
             return nullptr;
         }
         
-        // 复制帧数据
-        if (av_frame_ref(resultFrame.get(), frame.get()) < 0) {
+        // 复制帧格式信息
+        resultFrame->format = frame->format;
+        resultFrame->width = frame->width;
+        resultFrame->height = frame->height;
+        resultFrame->pts = frame->pts;
+        
+        // 分配新的缓冲区
+        if (av_frame_get_buffer(resultFrame.get(), 32) < 0) {
+            AV_LOGGER_ERROR("分配帧缓冲区失败");
+            return nullptr;
+        }
+        
+        // 复制帧数据(避免引用计数问题)
+        if (av_frame_copy(resultFrame.get(), frame.get()) < 0) {
             AV_LOGGER_ERROR("复制帧数据失败");
             return nullptr;
         }
         
+        // 复制帧属性
+        if (av_frame_copy_props(resultFrame.get(), frame.get()) < 0) {
+            AV_LOGGER_ERROR("复制帧属性失败");
+            return nullptr;
+        }
+        
         return resultFrame;
     }
     
@@ -619,15 +670,31 @@ AVFramePtr VideoEncoder::convertFrame(const AVFramePtr& frame) {
 
 AVFramePtr VideoEncoder::transferToHardware(const AVFramePtr& frame) {
     if (!isHardwareEncoder_ || !frame) {
-        // 创建一个新的帧来返回,避免拷贝构造
+        // 创建一个新的独立帧副本
         if (frame) {
             AVFramePtr resultFrame = makeAVFrame();
             if (!resultFrame) {
                 return nullptr;
             }
             
-            // 复制帧数据
-            if (av_frame_ref(resultFrame.get(), frame.get()) < 0) {
+            // 复制帧格式信息
+            resultFrame->format = frame->format;
+            resultFrame->width = frame->width;
+            resultFrame->height = frame->height;
+            resultFrame->pts = frame->pts;
+            
+            // 分配新的缓冲区
+            if (av_frame_get_buffer(resultFrame.get(), 32) < 0) {
+                return nullptr;
+            }
+            
+            // 复制帧数据(避免引用计数问题)
+            if (av_frame_copy(resultFrame.get(), frame.get()) < 0) {
+                return nullptr;
+            }
+            
+            // 复制帧属性
+            if (av_frame_copy_props(resultFrame.get(), frame.get()) < 0) {
                 return nullptr;
             }
             

+ 2 - 1
AV/code/muxer/muxer_abstract_muxer.h

@@ -16,6 +16,7 @@ extern "C" {
 #include <libavformat/avformat.h>
 #include <libavcodec/avcodec.h>
 #include <libavutil/avutil.h>
+#include <libavutil/channel_layout.h>
 }
 
 namespace av {
@@ -68,7 +69,7 @@ struct StreamInfo {
     int sampleRate = 0;
     int channels = 0;
     AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE;
-    uint64_t channelLayout = 0;
+    AVChannelLayout channelLayout = AV_CHANNEL_LAYOUT_MASK(0, 0);
     
     // 通用参数
     AVRational timeBase = {1, 1000};

+ 40 - 19
AV/code/muxer/muxer_file_muxer.cpp

@@ -32,9 +32,16 @@ ErrorCode FileMuxer::initialize(const MuxerParams& params) {
         return ErrorCode::INVALID_PARAMS;
     }
     
-    fileMuxerParams_ = static_cast<const FileMuxerParams&>(params);
+    // 先验证参数,再进行类型转换
+    if (!validateParams(params)) {
+        return ErrorCode::INVALID_PARAMS;
+    }
     
-    if (!validateParams(fileMuxerParams_)) {
+    // 安全地进行类型转换
+    try {
+        fileMuxerParams_ = static_cast<const FileMuxerParams&>(params);
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("参数类型转换失败: {}", e.what());
         return ErrorCode::INVALID_PARAMS;
     }
     
@@ -589,7 +596,7 @@ AVStream* FileMuxer::createAVStream(const StreamInfo& streamInfo) {
         stream->r_frame_rate = streamInfo.frameRate;
     } else if (streamInfo.type == StreamType::AUDIO) {
         codecpar->sample_rate = streamInfo.sampleRate;
-        av_channel_layout_default(&codecpar->ch_layout, streamInfo.channels);
+        av_channel_layout_copy(&codecpar->ch_layout, &streamInfo.channelLayout);
         codecpar->format = streamInfo.sampleFormat;
         codecpar->bit_rate = streamInfo.bitrate;
     }
@@ -782,26 +789,40 @@ bool FileMuxer::validateParams(const MuxerParams& params) {
         return false;
     }
     
-    const auto& fileParams = static_cast<const FileMuxerParams&>(params);
-    
-    if (fileParams.outputFile.empty() && fileParams.outputPath.empty()) {
+    // 首先验证基础参数
+    if (params.outputPath.empty()) {
         AV_LOGGER_ERROR("输出文件路径不能为空");
         return false;
     }
     
-    if (fileParams.segmentDuration < 0) {
-        AV_LOGGER_ERROR("分段时长不能为负数");
-        return false;
-    }
-    
-    if (fileParams.maxFileSize < 0) {
-        AV_LOGGER_ERROR("最大文件大小不能为负数");
-        return false;
-    }
-    
-    if (fileParams.flushInterval <= 0) {
-        AV_LOGGER_ERROR("刷新间隔必须大于0");
-        return false;
+    // 如果参数类型正确,进行更详细的验证
+    if (params.type == MuxerType::FILE_MUXER) {
+        try {
+            const auto& fileParams = static_cast<const FileMuxerParams&>(params);
+            
+            if (fileParams.outputFile.empty() && fileParams.outputPath.empty()) {
+                AV_LOGGER_ERROR("输出文件路径不能为空");
+                return false;
+            }
+            
+            if (fileParams.segmentDuration < 0) {
+                AV_LOGGER_ERROR("分段时长不能为负数");
+                return false;
+            }
+            
+            if (fileParams.maxFileSize < 0) {
+                AV_LOGGER_ERROR("最大文件大小不能为负数");
+                return false;
+            }
+            
+            if (fileParams.flushInterval <= 0) {
+                AV_LOGGER_ERROR("刷新间隔必须大于0");
+                return false;
+            }
+        } catch (const std::exception& e) {
+            AV_LOGGER_ERRORF("参数验证时类型转换失败: {}", e.what());
+            return false;
+        }
     }
     
     return true;

+ 28 - 39
AV/code/player/player_core_v2.cpp

@@ -668,7 +668,7 @@ SyncConfigV2 PlayerCoreV2::getSyncConfig() const {
 //     m_openGLVideoRenderer = renderer;
 // }
 
-AVFrame* PlayerCoreV2::getNextVideoFrame() {
+AVFramePtr PlayerCoreV2::getNextVideoFrame() {
     if (!m_videoFrameQueue || m_state != PlayerState::Playing) {
         return nullptr;
     }
@@ -676,7 +676,7 @@ AVFrame* PlayerCoreV2::getNextVideoFrame() {
     return m_videoFrameQueue->pop();
 }
 
-AVFrame* PlayerCoreV2::getNextAudioFrame() {
+AVFramePtr PlayerCoreV2::getNextAudioFrame() {
     if (!m_audioFrameQueue || m_state != PlayerState::Playing) {
         return nullptr;
     }
@@ -684,18 +684,6 @@ AVFrame* PlayerCoreV2::getNextAudioFrame() {
     return m_audioFrameQueue->pop();
 }
 
-void PlayerCoreV2::releaseVideoFrame(AVFrame* frame) {
-    if (frame) {
-        av_frame_free(&frame);
-    }
-}
-
-void PlayerCoreV2::releaseAudioFrame(AVFrame* frame) {
-    if (frame) {
-        av_frame_free(&frame);
-    }
-}
-
 void PlayerCoreV2::update() {
     if (!m_initialized) {
         return;
@@ -1478,13 +1466,13 @@ void PlayerCoreV2::videoDecodeThreadFunc() {
                     
                     // 向视频帧队列发送EOF标记
                     if (m_videoFrameQueue) {
-                        AVFrame* eofFrame = av_frame_alloc();
+                        AVFramePtr eofFrame = makeAVFrame();
                         if (eofFrame) {
                             eofFrame->data[0] = nullptr;
                             eofFrame->width = 0;
                             eofFrame->height = 0;
                             eofFrame->pts = AV_NOPTS_VALUE;
-                            m_videoFrameQueue->push(eofFrame);
+                            m_videoFrameQueue->push(std::move(eofFrame));
                             Logger::instance().info("EOF frame sent to video frame queue");
                         }
                     }
@@ -1532,8 +1520,8 @@ void PlayerCoreV2::videoDecodeThreadFunc() {
                     }
                     
                     // 将帧放入队列 - 不丢弃任何帧
-                    // 释放智能指针的所有权,让队列管理帧的生命周期
-                    m_videoFrameQueue->push(framePtr.release());
+                    // 使用移动语义转移智能指针所有权
+                    m_videoFrameQueue->push(std::move(framePtr));
                     m_frameCount++;
                     Logger::instance().debug("Video frame pushed to queue, queue size: " + std::to_string(m_videoFrameQueue->size()));
                     
@@ -1601,12 +1589,12 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
                     
                     // 向音频帧队列发送EOF标记
                     if (m_audioFrameQueue) {
-                        AVFrame* eofFrame = av_frame_alloc();
+                        AVFramePtr eofFrame = makeAVFrame();
                         if (eofFrame) {
                             eofFrame->data[0] = nullptr;
                             eofFrame->nb_samples = 0;
                             eofFrame->pts = AV_NOPTS_VALUE;
-                            m_audioFrameQueue->push(eofFrame);
+                            m_audioFrameQueue->push(std::move(eofFrame));
                             Logger::instance().info("EOF frame sent to audio frame queue");
                         }
                     }
@@ -1653,8 +1641,8 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
                     }
                     
                     // 将帧放入队列 - 不丢弃任何帧
-                    // 释放智能指针的所有权,让队列管理帧的生命周期
-                    m_audioFrameQueue->push(framePtr.release());
+                    // 使用移动语义转移智能指针所有权
+                    m_audioFrameQueue->push(std::move(framePtr));
                     Logger::instance().debug("Audio frame pushed to queue, queue size: " + std::to_string(m_audioFrameQueue->size()));
                     
                     // 如果队列大小超过警告阈值,记录警告但不丢弃
@@ -1679,7 +1667,7 @@ void PlayerCoreV2::videoPlayThreadFunc() {
     Logger::instance().info("Video play thread started");
 
     // 用于计算帧持续时间的变量
-    AVFrame* lastFrame = nullptr;
+    AVFramePtr lastFrame = nullptr;
 
     while (!m_threadsShouldStop) {
         // 检查暂停状态,类似ffplay.c中的paused检查
@@ -1710,7 +1698,7 @@ void PlayerCoreV2::videoPlayThreadFunc() {
         }
 
         // 获取视频帧,使用更短的超时时间以提高暂停响应速度
-        AVFrame* frame = m_videoFrameQueue->pop(1); // 使用1ms超时以快速响应暂停
+        AVFramePtr frame = m_videoFrameQueue->pop(1); // 使用1ms超时以快速响应暂停
         if (!frame) {
             // 检查是否应该继续等待
             if (m_threadsShouldStop) {
@@ -1725,14 +1713,14 @@ void PlayerCoreV2::videoPlayThreadFunc() {
         Logger::instance().debug("Video play thread after pop - m_paused: " + std::to_string(pausedAfterPop));
         if (pausedAfterPop) {
             Logger::instance().info("Video play thread releasing frame due to pause");
-            av_frame_free(&frame);
+            frame.reset(); // 智能指针自动释放
             continue;
         }
 
         Logger::instance().debug("Video play thread got frame, pts=" + std::to_string(frame->pts));
 
-        // 创建智能指针管理帧内存
-        AVFramePtr framePtr(frame);
+        // frame 本身就是智能指针,直接使用
+        AVFramePtr& framePtr = frame;
         
         // 使用同步器计算视频帧显示时间
         double pts = frame->pts * av_q2d(m_formatContext->streams[m_mediaInfo.videoStreamIndex]->time_base);
@@ -1772,19 +1760,20 @@ void PlayerCoreV2::videoPlayThreadFunc() {
             }
             
             // 更新上一帧指针
-            if (lastFrame) {
-                av_frame_free(&lastFrame);
+            lastFrame.reset(); // 智能指针自动释放旧帧
+            
+            // 创建当前帧的副本
+            AVFramePtr clonedFrame = makeAVFrame();
+            if (clonedFrame && av_frame_ref(clonedFrame.get(), frame.get()) == 0) {
+                lastFrame = std::move(clonedFrame);
             }
-            lastFrame = av_frame_clone(frame);
         } else if (decision.action == FrameAction::DROP) {
             Logger::instance().debug("Video frame dropped due to sync, pts=" + std::to_string(pts) + ", error=" + std::to_string(decision.syncError));
         }
     }
 
-    // 清理最后一帧
-    if (lastFrame) {
-        av_frame_free(&lastFrame);
-    }
+    // 清理最后一帧 - 智能指针自动清理
+    lastFrame.reset();
 
     Logger::instance().info("Video play thread finished");
 }
@@ -1822,7 +1811,7 @@ void PlayerCoreV2::audioPlayThreadFunc() {
         }
 
         // 获取音频帧,使用更短的超时时间以提高暂停响应速度
-        AVFrame* frame = m_audioFrameQueue->pop(1); // 使用1ms超时以快速响应暂停
+        AVFramePtr frame = m_audioFrameQueue->pop(1); // 使用1ms超时以快速响应暂停
         if (!frame) {
             // 检查是否应该继续等待
             if (m_threadsShouldStop) {
@@ -1837,14 +1826,14 @@ void PlayerCoreV2::audioPlayThreadFunc() {
         Logger::instance().debug("Audio play thread after pop - m_paused: " + std::to_string(pausedAfterPop));
         if (pausedAfterPop) {
             Logger::instance().info("Audio play thread releasing frame due to pause");
-            av_frame_free(&frame);
+            frame.reset(); // 智能指针自动释放
             continue;
         }
         
         // 检查是否是EOF帧
         if (frame->data[0] == nullptr && frame->nb_samples == 0) {
             Logger::instance().info("Audio play thread received EOF frame, playback completed");
-            av_frame_free(&frame);
+            frame.reset(); // 智能指针自动释放
 
             // 通知播放完成
             setState(PlayerState::Stopped);
@@ -1857,8 +1846,8 @@ void PlayerCoreV2::audioPlayThreadFunc() {
                                  + ", pts=" + std::to_string(frame->pts)
                                  + ", nb_samples=" + std::to_string(frame->nb_samples));
 
-        // 创建智能指针管理帧内存
-        AVFramePtr framePtr(frame);
+        // frame 本身就是智能指针,直接使用
+        AVFramePtr& framePtr = frame;
 
         // 计算音频PTS
         double pts = frame->pts

+ 3 - 5
AV/code/player/player_core_v2.h

@@ -181,11 +181,9 @@ public:
     // void setOpenGLVideoRenderer(OpenGLVideoWidget* renderer);
     // OpenGLVideoWidget* getOpenGLVideoRenderer() const { return m_openGLVideoRenderer; }
     
-    // 帧获取接口(供UI渲染使用)
-    AVFrame* getNextVideoFrame();   // 获取下一个视频帧
-    AVFrame* getNextAudioFrame();   // 获取下一个音频帧
-    void releaseVideoFrame(AVFrame* frame);  // 释放视频帧
-    void releaseAudioFrame(AVFrame* frame);  // 释放音频帧
+    // 安全帧获取接口
+    AVFramePtr getNextVideoFrame();   // 获取下一个视频帧
+    AVFramePtr getNextAudioFrame();   // 获取下一个音频帧
     
     // 线程安全的更新接口
     void update();  // 定期调用以更新播放状态

+ 200 - 0
AV/code/recorder/recorder.cpp

@@ -0,0 +1,200 @@
+#include "recorder.h"
+#include "../base/logger.h"
+#include <filesystem>
+#include <algorithm>
+
+namespace av {
+namespace recorder {
+
+// 静态成员初始化
+bool RecorderModule::initialized_ = false;
+
+ErrorCode RecorderModule::initialize() {
+    if (initialized_) {
+        return ErrorCode::SUCCESS;
+    }
+    
+    AV_LOGGER_INFOF("Initializing Recorder Module v{}", getVersion());
+    
+    // TODO: 初始化FFmpeg库(如果需要)
+    // TODO: 检查硬件编码器支持
+    // TODO: 初始化音频设备枚举
+    
+    initialized_ = true;
+    
+    AV_LOGGER_INFO("Recorder Module initialized successfully");
+    return ErrorCode::SUCCESS;
+}
+
+void RecorderModule::cleanup() {
+    if (!initialized_) {
+        return;
+    }
+    
+    AV_LOGGER_INFO("Cleaning up Recorder Module");
+    
+    // TODO: 清理资源
+    
+    initialized_ = false;
+    
+    AV_LOGGER_INFO("Recorder Module cleaned up");
+}
+
+bool RecorderModule::isInitialized() {
+    return initialized_;
+}
+
+std::vector<std::string> RecorderModule::getSupportedFormats() {
+    return {
+        "mp4", "avi", "mkv", "mov", "flv", "webm",
+        "mp3", "wav", "aac", "ogg", "flac"
+    };
+}
+
+std::vector<std::string> RecorderModule::getSupportedAudioCodecs() {
+    return {
+        "aac", "mp3", "opus", "vorbis", "flac", "pcm_s16le"
+    };
+}
+
+std::vector<std::string> RecorderModule::getSupportedVideoCodecs() {
+    return {
+        "h264", "h265", "vp8", "vp9", "av1", "mpeg4"
+    };
+}
+
+namespace utils {
+
+AudioRecorderParams getDefaultAudioParams() {
+    AudioRecorderParams params;
+    params.capturerType = capture::CapturerType::AUDIO_MIC;
+    params.sampleRate = 44100;
+    params.channels = 2;
+    params.bitsPerSample = 16;
+    params.sampleFormat = AV_SAMPLE_FMT_S16;
+    params.codecName = "aac";
+    params.bitrate = 128000;
+    params.volumeScale = 1.0f;
+    params.enableMixing = false;
+    params.format = "mp4";
+    return params;
+}
+
+VideoRecorderParams getDefaultVideoParams() {
+    VideoRecorderParams params;
+    params.captureMethod = VideoCaptureMethod::SCREEN_CAPTURE;
+    params.monitorIndex = 0;
+    params.width = 1920;
+    params.height = 1080;
+    params.frameRate = 30;
+    params.pixelFormat = AV_PIX_FMT_YUV420P;
+    params.codecName = "h264";
+    params.bitrate = 5000000; // 5 Mbps
+    params.keyFrameInterval = 30;
+    params.preset = "medium";
+    params.drawCursor = true;
+    params.captureAudio = false;
+    params.format = "mp4";
+    return params;
+}
+
+AVRecorderParams getDefaultAVParams() {
+    AVRecorderParams params;
+    params.audioParams = getDefaultAudioParams();
+    params.videoParams = getDefaultVideoParams();
+    params.enableAudio = true;
+    params.enableVideo = true;
+    params.enableSync = true;
+    params.syncThresholdMs = 40;
+    params.dropFrameOnSync = true;
+    params.format = "mp4";
+    return params;
+}
+
+bool isValidOutputPath(const std::string& path) {
+    if (path.empty()) {
+        return false;
+    }
+    
+    try {
+        std::filesystem::path fsPath(path);
+        
+        // 检查父目录是否存在或可创建
+        auto parentPath = fsPath.parent_path();
+        if (!parentPath.empty() && !std::filesystem::exists(parentPath)) {
+            // 尝试创建目录
+            std::error_code ec;
+            std::filesystem::create_directories(parentPath, ec);
+            if (ec) {
+                AV_LOGGER_ERRORF("Cannot create output directory: {}", ec.message());
+                return false;
+            }
+        }
+        
+        // 检查文件扩展名
+        auto extension = fsPath.extension().string();
+        if (extension.empty()) {
+            return false;
+        }
+        
+        // 转换为小写
+        std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+        
+        // 检查是否为支持的格式
+        auto supportedFormats = RecorderModule::getSupportedFormats();
+        auto formatName = extension.substr(1); // 去掉点号
+        
+        return std::find(supportedFormats.begin(), supportedFormats.end(), formatName) != supportedFormats.end();
+        
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("Invalid output path: {}", e.what());
+        return false;
+    }
+}
+
+VideoRecorderParams getRecommendedVideoParams() {
+    VideoRecorderParams params = getDefaultVideoParams();
+    
+    // TODO: 根据系统性能调整参数
+    // 这里可以检查:
+    // - CPU性能
+    // - 可用内存
+    // - 硬件编码器支持
+    // - 显示器分辨率
+    
+    // 简单的性能检测示例
+    auto availableMemory = std::thread::hardware_concurrency(); // 简化的性能指标
+    
+    if (availableMemory <= 4) {
+        // 低性能设置
+        params.width = 1280;
+        params.height = 720;
+        params.frameRate = 24;
+        params.bitrate = 2000000; // 2 Mbps
+        params.preset = "fast";
+    } else if (availableMemory <= 8) {
+        // 中等性能设置
+        params.width = 1920;
+        params.height = 1080;
+        params.frameRate = 30;
+        params.bitrate = 5000000; // 5 Mbps
+        params.preset = "medium";
+    } else {
+        // 高性能设置
+        params.width = 1920;
+        params.height = 1080;
+        params.frameRate = 60;
+        params.bitrate = 8000000; // 8 Mbps
+        params.preset = "slow";
+    }
+    
+    AV_LOGGER_INFOF("Recommended video params: {}x{} @ {}fps, {} bps", 
+             params.width, params.height, params.frameRate, params.bitrate);
+    
+    return params;
+}
+
+} // namespace utils
+
+} // namespace recorder
+} // namespace av

+ 175 - 0
AV/code/recorder/recorder.h

@@ -0,0 +1,175 @@
+#ifndef AV_RECORDER_H
+#define AV_RECORDER_H
+
+/**
+ * AV录制器模块
+ * 
+ * 这个模块提供了完整的音视频录制功能,基于AV模块的现有组件构建。
+ * 主要特性:
+ * - 音频录制:支持多设备采集、混音、实时编码
+ * - 视频录制:支持屏幕录制、窗口采集、摄像头录制
+ * - 音视频同步:提供精确的音视频同步机制
+ * - 模块化设计:可独立使用音频或视频录制器
+ * - 高性能:多线程处理,支持硬件加速
+ * 
+ * 使用示例:
+ * 
+ * // 音频录制
+ * auto audioRecorder = RecorderFactoryImpl::createAudioRecorder();
+ * AudioRecorderParams audioParams;
+ * audioParams.outputPath = "output.mp4";
+ * audioParams.sampleRate = 44100;
+ * audioParams.channels = 2;
+ * audioRecorder->initialize(audioParams);
+ * audioRecorder->startRecording();
+ * 
+ * // 视频录制
+ * auto videoRecorder = RecorderFactoryImpl::createVideoRecorder();
+ * VideoRecorderParams videoParams;
+ * videoParams.outputPath = "output.mp4";
+ * videoParams.width = 1920;
+ * videoParams.height = 1080;
+ * videoParams.frameRate = 30;
+ * videoRecorder->initialize(videoParams);
+ * videoRecorder->startRecording();
+ * 
+ * // 音视频同步录制
+ * auto avRecorder = RecorderFactoryImpl::createAVRecorder();
+ * AVRecorderParams avParams;
+ * avParams.outputPath = "output.mp4";
+ * avParams.enableAudio = true;
+ * avParams.enableVideo = true;
+ * avParams.enableSync = true;
+ * avRecorder->initialize(avParams);
+ * avRecorder->startRecording();
+ */
+
+// 核心接口
+#include "recorder_abstract_recorder.h"
+
+// 具体实现
+#include "recorder_audio_recorder.h"
+#include "recorder_video_recorder.h"
+#include "recorder_av_recorder.h"
+
+namespace av {
+namespace recorder {
+
+/**
+ * 录制器模块版本信息
+ */
+struct RecorderVersion {
+    static constexpr int MAJOR = 1;
+    static constexpr int MINOR = 0;
+    static constexpr int PATCH = 0;
+    
+    static std::string toString() {
+        return std::to_string(MAJOR) + "." + 
+               std::to_string(MINOR) + "." + 
+               std::to_string(PATCH);
+    }
+};
+
+/**
+ * 录制器模块初始化
+ */
+class RecorderModule {
+public:
+    /**
+     * 初始化录制器模块
+     */
+    static ErrorCode initialize();
+    
+    /**
+     * 清理录制器模块
+     */
+    static void cleanup();
+    
+    /**
+     * 获取模块版本
+     */
+    static std::string getVersion() {
+        return RecorderVersion::toString();
+    }
+    
+    /**
+     * 检查模块是否已初始化
+     */
+    static bool isInitialized();
+    
+    /**
+     * 获取支持的录制格式
+     */
+    static std::vector<std::string> getSupportedFormats();
+    
+    /**
+     * 获取支持的音频编码器
+     */
+    static std::vector<std::string> getSupportedAudioCodecs();
+    
+    /**
+     * 获取支持的视频编码器
+     */
+    static std::vector<std::string> getSupportedVideoCodecs();
+
+private:
+    static bool initialized_;
+};
+
+/**
+ * 便利函数
+ */
+namespace utils {
+
+/**
+ * 创建音频录制器的便利函数
+ */
+inline std::unique_ptr<AudioRecorder> createAudioRecorder() {
+    return RecorderFactoryImpl::createAudioRecorder();
+}
+
+/**
+ * 创建视频录制器的便利函数
+ */
+inline std::unique_ptr<VideoRecorder> createVideoRecorder() {
+    return RecorderFactoryImpl::createVideoRecorder();
+}
+
+/**
+ * 创建音视频录制器的便利函数
+ */
+inline std::unique_ptr<AVRecorder> createAVRecorder() {
+    return RecorderFactoryImpl::createAVRecorder();
+}
+
+/**
+ * 获取默认音频参数
+ */
+AudioRecorderParams getDefaultAudioParams();
+
+/**
+ * 获取默认视频参数
+ */
+VideoRecorderParams getDefaultVideoParams();
+
+/**
+ * 获取默认音视频参数
+ */
+AVRecorderParams getDefaultAVParams();
+
+/**
+ * 检查输出路径是否有效
+ */
+bool isValidOutputPath(const std::string& path);
+
+/**
+ * 获取推荐的录制参数(基于系统性能)
+ */
+VideoRecorderParams getRecommendedVideoParams();
+
+} // namespace utils
+
+} // namespace recorder
+} // namespace av
+
+#endif // AV_RECORDER_H

+ 41 - 0
AV/code/recorder/recorder.pri

@@ -0,0 +1,41 @@
+# AV录制器模块 - Qt项目包含文件
+# 用于将录制器模块集成到Qt项目中
+
+# 模块标识
+RECORDER_MODULE = 1
+
+# 包含路径
+INCLUDEPATH += $$PWD
+INCLUDEPATH += $$PWD/..
+
+# 依赖路径
+DEPENDPATH += $$PWD
+
+# 头文件
+HEADERS += \
+    $$PWD/recorder.h \
+    $$PWD/recorder_abstract_recorder.h \
+    $$PWD/recorder_audio_recorder.h \
+    $$PWD/recorder_video_recorder.h \
+    $$PWD/recorder_av_recorder.h
+
+# 源文件
+SOURCES += \
+    $$PWD/recorder.cpp \
+    $$PWD/recorder_abstract_recorder.cpp \
+    $$PWD/recorder_audio_recorder.cpp \
+    $$PWD/recorder_video_recorder.cpp \
+    $$PWD/recorder_av_recorder.cpp
+
+# 编译器定义
+DEFINES += AV_RECORDER_MODULE
+
+# C++标准
+CONFIG += c++17
+
+# Qt模块依赖
+QT += core multimedia
+
+
+# 包含录制器UI模块
+include($$PWD/ui/recorder_ui.pri)

+ 133 - 0
AV/code/recorder/recorder_abstract_recorder.cpp

@@ -0,0 +1,133 @@
+#include "recorder_abstract_recorder.h"
+#include "../base/logger.h"
+#include <chrono>
+
+namespace av {
+namespace recorder {
+
+AbstractRecorder::AbstractRecorder(MediaType mediaType)
+    : mediaType_(mediaType)
+    , state_(RecorderState::IDLE)
+    , frameCountForFps_(0) {
+    stats_.startTime = std::chrono::steady_clock::now();
+    lastFrameTime_ = std::chrono::steady_clock::now();
+    lastFpsCalcTime_ = std::chrono::steady_clock::now();
+}
+
+AbstractRecorder::~AbstractRecorder() {
+    close();
+}
+
+RecorderStats AbstractRecorder::getStats() const {
+    std::lock_guard<std::mutex> lock(statsMutex_);
+    auto stats = stats_;
+    
+    // 计算录制时长
+    if (state_.load() == RecorderState::RECORDING || 
+        state_.load() == RecorderState::PAUSED ||
+        state_.load() == RecorderState::STOPPED) {
+        auto now = std::chrono::steady_clock::now();
+        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - stats_.startTime);
+        stats.recordingTime = duration.count() / 1000.0;
+    }
+    
+    return stats;
+}
+
+void AbstractRecorder::resetStats() {
+    std::lock_guard<std::mutex> lock(statsMutex_);
+    stats_ = RecorderStats{};
+    stats_.startTime = std::chrono::steady_clock::now();
+    frameCountForFps_ = 0;
+    lastFrameTime_ = std::chrono::steady_clock::now();
+    lastFpsCalcTime_ = std::chrono::steady_clock::now();
+}
+
+void AbstractRecorder::setState(RecorderState state) {
+    RecorderState oldState = state_.exchange(state);
+    
+    if (oldState != state) {
+        AV_LOGGER_INFOF("Recorder state changed: {} -> {}", 
+                static_cast<int>(oldState), static_cast<int>(state));
+        
+        if (stateCallback_) {
+            stateCallback_(state);
+        }
+        
+        // 状态变化时重置统计开始时间
+        if (state == RecorderState::RECORDING) {
+            std::lock_guard<std::mutex> lock(statsMutex_);
+            stats_.startTime = std::chrono::steady_clock::now();
+        }
+    }
+}
+
+void AbstractRecorder::reportError(ErrorCode error, const std::string& message) {
+    setState(RecorderState::ERROR);
+    
+    {
+        std::lock_guard<std::mutex> lock(statsMutex_);
+        stats_.errorCount++;
+    }
+    
+    AV_LOGGER_ERRORF("Recorder error: {} - {}", static_cast<int>(error), message);
+    
+    if (errorCallback_) {
+        errorCallback_(error, message);
+    }
+}
+
+void AbstractRecorder::updateStats(bool success, uint64_t bytes) {
+    std::lock_guard<std::mutex> lock(statsMutex_);
+    
+    if (success) {
+        stats_.recordedFrames++;
+        stats_.totalBytes += bytes;
+        frameCountForFps_++;
+    } else {
+        stats_.droppedFrames++;
+    }
+    
+    // 定期计算帧率
+    auto now = std::chrono::steady_clock::now();
+    auto timeSinceLastCalc = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastFpsCalcTime_);
+    
+    if (timeSinceLastCalc.count() >= 1000) { // 每秒计算一次
+        calculateFrameRate();
+    }
+}
+
+void AbstractRecorder::calculateFrameRate() {
+    auto now = std::chrono::steady_clock::now();
+    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastFpsCalcTime_);
+    
+    if (duration.count() > 0) {
+        stats_.avgFrameRate = (frameCountForFps_ * 1000.0) / duration.count();
+        frameCountForFps_ = 0;
+        lastFpsCalcTime_ = now;
+    }
+}
+
+// RecorderFactory 实现
+std::unique_ptr<AbstractRecorder> RecorderFactory::createRecorder(MediaType mediaType) {
+    // 这里将在具体的录制器实现中完成
+    // 目前返回nullptr,待后续实现具体的录制器类
+    return nullptr;
+}
+
+bool RecorderFactory::isRecorderSupported(MediaType mediaType) {
+    switch (mediaType) {
+        case MediaType::AUDIO:
+        case MediaType::VIDEO:
+            return true;
+        default:
+            return false;
+    }
+}
+
+std::vector<MediaType> RecorderFactory::getSupportedMediaTypes() {
+    return {MediaType::AUDIO, MediaType::VIDEO};
+}
+
+} // namespace recorder
+} // namespace av

+ 193 - 0
AV/code/recorder/recorder_abstract_recorder.h

@@ -0,0 +1,193 @@
+#ifndef AV_RECORDER_ABSTRACT_RECORDER_H
+#define AV_RECORDER_ABSTRACT_RECORDER_H
+
+#include "../base/types.h"
+#include "../base/media_common.h"
+#include "../capture/capture_abstract_capturer.h"
+#include "../codec/codec_abstract_codec.h"
+#include "../muxer/muxer_abstract_muxer.h"
+#include <memory>
+#include <functional>
+#include <atomic>
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace av {
+namespace recorder {
+
+/**
+ * 录制器状态
+ */
+enum class RecorderState {
+    IDLE,           // 空闲
+    INITIALIZED,    // 已初始化
+    RECORDING,      // 录制中
+    PAUSED,         // 暂停
+    STOPPED,        // 已停止
+    ERROR           // 错误状态
+};
+
+/**
+ * 录制器参数
+ */
+struct RecorderParams {
+    MediaType mediaType;
+    std::string outputPath;         // 输出路径
+    std::string format;             // 输出格式
+    bool autoStart = false;         // 自动开始录制
+    
+    virtual ~RecorderParams() = default;
+};
+
+/**
+ * 录制器统计信息
+ */
+struct RecorderStats {
+    uint64_t recordedFrames = 0;    // 已录制帧数
+    uint64_t droppedFrames = 0;     // 丢弃帧数
+    uint64_t totalBytes = 0;        // 总字节数
+    uint64_t errorCount = 0;        // 错误次数
+    double recordingTime = 0.0;     // 录制时长(秒)
+    double avgFrameRate = 0.0;      // 平均帧率
+    std::chrono::steady_clock::time_point startTime; // 开始时间
+};
+
+/**
+ * 抽象录制器基类
+ * 整合采集器、编码器和复用器,提供完整的录制功能
+ */
+class AbstractRecorder {
+public:
+    AbstractRecorder(MediaType mediaType);
+    virtual ~AbstractRecorder();
+
+    // 禁止拷贝
+    AbstractRecorder(const AbstractRecorder&) = delete;
+    AbstractRecorder& operator=(const AbstractRecorder&) = delete;
+
+    /**
+     * 初始化录制器
+     * @param params 录制参数
+     * @return 成功返回ErrorCode::SUCCESS
+     */
+    virtual ErrorCode initialize(const RecorderParams& params) = 0;
+
+    /**
+     * 开始录制
+     * @return 成功返回ErrorCode::SUCCESS
+     */
+    virtual ErrorCode startRecording() = 0;
+
+    /**
+     * 停止录制
+     * @return 成功返回ErrorCode::SUCCESS
+     */
+    virtual ErrorCode stopRecording() = 0;
+
+    /**
+     * 暂停录制
+     * @return 成功返回ErrorCode::SUCCESS
+     */
+    virtual ErrorCode pauseRecording() = 0;
+
+    /**
+     * 恢复录制
+     * @return 成功返回ErrorCode::SUCCESS
+     */
+    virtual ErrorCode resumeRecording() = 0;
+
+    /**
+     * 关闭录制器,释放资源
+     */
+    virtual void close() {}
+
+    // 状态查询
+    RecorderState getState() const { return state_.load(); }
+    bool isRecording() const { return state_.load() == RecorderState::RECORDING; }
+    bool isPaused() const { return state_.load() == RecorderState::PAUSED; }
+
+    // 统计信息
+    virtual RecorderStats getStats() const;
+    virtual void resetStats();
+
+    // 回调设置
+    using ErrorCallback = std::function<void(ErrorCode, const std::string&)>;
+    using StateCallback = std::function<void(RecorderState)>;
+    
+    void setErrorCallback(const ErrorCallback& callback) { errorCallback_ = callback; }
+    void setStateCallback(const StateCallback& callback) { stateCallback_ = callback; }
+
+protected:
+    /**
+     * 设置录制器状态
+     */
+    void setState(RecorderState state);
+
+    /**
+     * 报告错误
+     */
+    void reportError(ErrorCode error, const std::string& message = "");
+
+    /**
+     * 更新统计信息
+     */
+    void updateStats(bool success, uint64_t bytes = 0);
+
+    /**
+     * 计算帧率
+     */
+    void calculateFrameRate();
+
+    /**
+     * 验证参数
+     */
+    virtual bool validateParams(const RecorderParams& params) = 0;
+
+protected:
+    MediaType mediaType_;                   // 媒体类型
+    std::atomic<RecorderState> state_;      // 当前状态
+    RecorderParams params_;                 // 录制参数
+    
+    // 统计信息
+    mutable std::mutex statsMutex_;
+    RecorderStats stats_;
+    
+    // 回调函数
+    ErrorCallback errorCallback_;
+    StateCallback stateCallback_;
+    
+    // 帧率计算
+    std::chrono::steady_clock::time_point lastFrameTime_;
+    std::chrono::steady_clock::time_point lastFpsCalcTime_;
+    uint64_t frameCountForFps_ = 0;
+    
+    // 线程安全
+    mutable std::mutex recorderMutex_;
+};
+
+/**
+ * 录制器工厂类
+ */
+class RecorderFactory {
+public:
+    /**
+     * 创建录制器
+     */
+    static std::unique_ptr<AbstractRecorder> createRecorder(MediaType mediaType);
+    
+    /**
+     * 检查是否支持指定媒体类型的录制
+     */
+    static bool isRecorderSupported(MediaType mediaType);
+    
+    /**
+     * 获取支持的媒体类型列表
+     */
+    static std::vector<MediaType> getSupportedMediaTypes();
+};
+
+} // namespace recorder
+} // namespace av
+
+#endif // AV_RECORDER_ABSTRACT_RECORDER_H

+ 592 - 0
AV/code/recorder/recorder_audio_recorder.cpp

@@ -0,0 +1,592 @@
+#include "recorder_audio_recorder.h"
+#include "../base/logger.h"
+#include "../capture/capture_audio_capturer.h"
+#include "../codec/codec_audio_encoder.h"
+#include "../muxer/muxer_file_muxer.h"
+#include <algorithm>
+#include <cmath>
+
+extern "C" {
+#include <libavutil/channel_layout.h>
+}
+
+namespace av {
+namespace recorder {
+AudioRecorder::AudioRecorder()
+    : AbstractRecorder(MediaType::AUDIO)
+    , shouldStop_(false)
+    , volumeScale_(1.0f)
+    , currentAudioLevel_(0.0f)
+    , isPaused_(false)
+    , processedSamples_(0)
+{
+    threadPool_ = std::make_unique<utils::ThreadPool>(); // 2个工作线程
+    lastProcessTime_ = std::chrono::steady_clock::now();
+}
+
+AudioRecorder::~AudioRecorder() {
+    close();
+}
+
+ErrorCode AudioRecorder::initialize(const RecorderParams& params) {
+    if (!validateParams(params)) {
+        return ErrorCode::INVALID_PARAMS;
+    }
+    
+    audioParams_ = static_cast<const AudioRecorderParams&>(params);
+    params_ = params;
+    
+    // 初始化各个组件
+    ErrorCode result = initializeCapturers();
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    result = initializeEncoder();
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    result = initializeMuxer();
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    setState(RecorderState::INITIALIZED);
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioRecorder::startRecording() {
+    if (getState() != RecorderState::INITIALIZED && getState() != RecorderState::STOPPED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    shouldStop_ = false;
+    isPaused_ = false;
+    
+    // 启动采集器
+    for (auto& capturer : capturers_) {
+        ErrorCode result = capturer->start();
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to start audio capturer: {}", static_cast<int>(result));
+            return result;
+        }
+    }
+    
+    // 启动音频处理线程
+    processingThread_ = std::make_unique<std::thread>(&AudioRecorder::audioProcessingThread, this);
+    
+    setState(RecorderState::RECORDING);
+    resetStats();
+    
+    AV_LOGGER_INFO("Audio recording started");
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioRecorder::stopRecording() {
+    if (getState() != RecorderState::RECORDING && getState() != RecorderState::PAUSED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    shouldStop_ = true;
+    isPaused_ = false;
+    
+    // 通知处理线程停止
+    queueCondition_.notify_all();
+    
+    // 等待处理线程结束
+    if (processingThread_ && processingThread_->joinable()) {
+        processingThread_->join();
+        processingThread_.reset();
+    }
+    
+    // 停止采集器
+    for (auto& capturer : capturers_) {
+        capturer->stop();
+    }
+    
+    // 刷新编码器
+    if (encoder_) {
+        std::vector<AVPacketPtr> packets;
+        encoder_->finishEncode(packets);
+        
+        for (const auto& packet : packets) {
+            if (muxer_) {
+                muxer_->writePacket(packet.get());
+            }
+        }
+    }
+    
+    // 关闭复用器
+    if (muxer_) {
+        muxer_->close();
+    }
+    
+    setState(RecorderState::STOPPED);
+    
+    AV_LOGGER_INFO("Audio recording stopped");
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioRecorder::pauseRecording() {
+    if (getState() != RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    isPaused_ = true;
+    setState(RecorderState::PAUSED);
+    
+    AV_LOGGER_INFO("Audio recording paused");
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioRecorder::resumeRecording() {
+    if (getState() != RecorderState::PAUSED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    isPaused_ = false;
+    setState(RecorderState::RECORDING);
+    
+    AV_LOGGER_INFO("Audio recording resumed");
+    return ErrorCode::SUCCESS;
+}
+
+void AudioRecorder::close() {
+    if (getState() == RecorderState::RECORDING || getState() == RecorderState::PAUSED) {
+        stopRecording();
+    }
+    
+    cleanup();
+    setState(RecorderState::IDLE);
+}
+
+void AudioRecorder::setVolumeScale(float scale) {
+    volumeScale_ = std::max(0.0f, std::min(2.0f, scale)); // 限制在0-2之间
+}
+
+float AudioRecorder::getAudioLevel() const {
+    std::lock_guard<std::mutex> lock(audioLevelMutex_);
+    return currentAudioLevel_;
+}
+
+ErrorCode AudioRecorder::addAudioDevice(const std::string& deviceId, capture::CapturerType type) {
+    std::lock_guard<std::mutex> lock(capturerMutex_);
+    
+    // 创建新的采集器
+    auto capturer = std::make_unique<capture::AudioCapturer>();
+    
+    capture::AudioCaptureParams capturerParams(type);
+    capturerParams.deviceId = deviceId;
+    
+    ErrorCode result = capturer->initialize(capturerParams);
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    // 设置回调
+    size_t capturerIndex = capturers_.size();
+    capturer->setFrameCallback([this, capturerIndex](const AVFramePtr& frame) {
+        onAudioFrameCaptured(frame, capturerIndex);
+    });
+    
+    capturers_.push_back(std::move(capturer));
+    
+    AV_LOGGER_INFOF("Added audio device: {}", deviceId);
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioRecorder::removeAudioDevice(const std::string& deviceId) {
+    std::lock_guard<std::mutex> lock(capturerMutex_);
+    
+    auto it = std::find_if(capturers_.begin(), capturers_.end(),
+        [&deviceId](const std::unique_ptr<capture::AudioCapturer>& capturer) {
+            return capturer->getCurrentDevice() == deviceId;
+        });
+    
+    if (it != capturers_.end()) {
+        (*it)->stop();
+        (*it)->close();
+        capturers_.erase(it);
+        
+        AV_LOGGER_INFOF("Removed audio device: {}", deviceId);
+        return ErrorCode::SUCCESS;
+    }
+    
+    return ErrorCode::DEVICE_NOT_FOUND;
+}
+
+std::vector<std::string> AudioRecorder::getAvailableDevices(capture::CapturerType type) const {
+    (void)type; // 避免未使用参数警告
+    auto capturer = std::make_unique<capture::AudioCapturer>();
+    return capturer->getAvailableDevices();
+}
+
+bool AudioRecorder::validateParams(const RecorderParams& params) {
+    const auto& audioParams = static_cast<const AudioRecorderParams&>(params);
+    
+    if (audioParams.sampleRate == 0 || audioParams.channels == 0) {
+        AV_LOGGER_ERRORF("Invalid audio parameters: sampleRate={}, channels={}",
+                  audioParams.sampleRate, audioParams.channels);
+        return false;
+    }
+    
+    if (audioParams.outputPath.empty()) {
+        AV_LOGGER_ERROR("Output path is empty");
+        return false;
+    }
+    
+    return true;
+}
+
+void AudioRecorder::audioProcessingThread() {
+    AV_LOGGER_INFO("Audio processing thread started");
+    
+    try {
+        while (!shouldStop_) {
+            std::unique_lock<std::mutex> lock(queueMutex_);
+            
+            // 等待音频帧或停止信号
+            queueCondition_.wait(lock, [this] {
+                return !frameQueue_.empty() || shouldStop_;
+            });
+            
+            if (shouldStop_) {
+                break;
+            }
+            
+            // 处理队列中的音频帧
+            std::vector<AudioFrameData> framesToProcess;
+            while (!frameQueue_.empty()) {
+                framesToProcess.push_back(std::move(frameQueue_.front()));
+                frameQueue_.pop_front();
+            }
+            
+            lock.unlock();
+            
+            if (isPaused_) {
+                continue;
+            }
+            
+            // 按时间戳排序
+            std::sort(framesToProcess.begin(), framesToProcess.end(),
+                [](const AudioFrameData& a, const AudioFrameData& b) {
+                    return a.timestamp < b.timestamp;
+                });
+            
+            // 处理音频帧
+            for (auto& frameData : framesToProcess) {
+                if (shouldStop_ || isPaused_) {
+                    break;
+                }
+                
+                try {
+                    // 检查帧是否有效
+                    if (!frameData.frame) {
+                        AV_LOGGER_WARNING("Skipping null audio frame");
+                        continue;
+                    }
+                    
+                    // 验证音频帧数据
+                    if (frameData.frame->nb_samples <= 0 || !frameData.frame->data[0]) {
+                        AV_LOGGER_WARNING("Invalid audio frame data, skipping");
+                        continue;
+                    }
+                    
+                    // 在移动之前保存需要的值
+                    int nbSamples = frameData.frame->nb_samples;
+                    
+                    // 应用音量缩放
+                    AVFramePtr processedFrame = std::move(frameData.frame);
+                    if (volumeScale_ != 1.0f) {
+                        // TODO: 实现音量缩放
+                    }
+                    
+                    // 计算音频电平
+                    {
+                        std::lock_guard<std::mutex> levelLock(audioLevelMutex_);
+                        // TODO: 计算RMS音频电平
+                        currentAudioLevel_ = 0.5f; // 临时值
+                    }
+                    
+                    // 编码音频帧
+                    if (encoder_ && processedFrame) {
+                        // 在编码前进行帧有效性检查
+                        if (!processedFrame->data[0]) {
+                            AV_LOGGER_ERROR("严重错误:即将编码的音频帧数据指针为空");
+                            updateStats(false);
+                            continue;
+                        }
+                        
+                        AV_LOGGER_DEBUGF("准备编码音频帧: samples={}, format={}, data_ptr={}", 
+                                        processedFrame->nb_samples, processedFrame->format,
+                                        static_cast<void*>(processedFrame->data[0]));
+                        
+                        // 保存linesize用于统计(因为move后无法访问)
+                        int frameLinesize = processedFrame->linesize[0];
+                        
+                        std::vector<AVPacketPtr> packets;
+                        // 使用move语义明确转移所有权,避免潜在的双重释放
+                        ErrorCode result = encoder_->encode(std::move(processedFrame), packets);
+                        
+                        if (result == ErrorCode::SUCCESS) {
+                            for (const auto& packet : packets) {
+                                if (packet && packet->size > 0) {
+                                    onAudioPacketEncoded(packet);
+                                }
+                            }
+                            updateStats(true, frameLinesize);
+                        } else {
+                            updateStats(false);
+                            AV_LOGGER_ERRORF("Audio encoding failed: {}", static_cast<int>(result));
+                        }
+                    }
+
+                    // 使用之前保存的值,而不是已经被移动的 frameData.frame
+                    processedSamples_ += nbSamples;
+                    
+                } catch (const std::exception& e) {
+                    AV_LOGGER_ERRORF("Error processing audio frame: {}", e.what());
+                    updateStats(false);
+                }
+            }
+        }
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("Audio processing thread crashed with exception: {}", e.what());
+    } catch (...) {
+        AV_LOGGER_ERROR("Audio processing thread crashed with unknown exception");
+    }
+    
+    AV_LOGGER_INFO("Audio processing thread stopped");
+}
+
+AVFramePtr AudioRecorder::mixAudioFrames(const std::vector<AVFramePtr>& frames) {
+    if (frames.empty()) {
+        return nullptr;
+    }
+    
+    if (frames.size() == 1) {
+        // 创建第一个帧的副本
+        AVFramePtr result = av::makeAVFrame();
+        if (result && frames[0] && av_frame_ref(result.get(), frames[0].get()) == 0) {
+            return result;
+        }
+        return nullptr;
+    }
+    
+    // TODO: 实现音频混音
+    // 目前返回第一个帧的副本
+    AVFramePtr result = av::makeAVFrame();
+    if (result && frames[0] && av_frame_ref(result.get(), frames[0].get()) == 0) {
+        return result;
+    }
+    return nullptr;
+}
+
+void AudioRecorder::onAudioFrameCaptured(const AVFramePtr& frame, size_t capturerIndex) {
+    if (shouldStop_ || !frame) {
+        return;
+    }
+    
+    // 创建frame的副本,因为参数是const引用
+    AVFramePtr frameCopy = av::makeAVFrame();
+    if (!frameCopy || av_frame_ref(frameCopy.get(), frame.get()) != 0) {
+        AV_LOGGER_ERROR("Failed to copy audio frame");
+        return;
+    }
+    
+    {
+        std::lock_guard<std::mutex> lock(queueMutex_);
+        AudioFrameData frameData;
+        frameData.frame = std::move(frameCopy);
+        frameData.capturerIndex = capturerIndex;
+        frameData.timestamp = std::chrono::steady_clock::now();
+        frameQueue_.push_back(std::move(frameData));
+    }
+    
+    queueCondition_.notify_one();
+}
+
+void AudioRecorder::onAudioPacketEncoded(const AVPacketPtr& packet) {
+    if (muxer_ && packet) {
+        ErrorCode result = muxer_->writePacket(packet.get());
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to write audio packet: {}", static_cast<int>(result));
+        }
+    }
+}
+
+ErrorCode AudioRecorder::initializeCapturers() {
+    // 创建主采集器
+    auto mainCapturer = std::make_unique<capture::AudioCapturer>();
+    
+    // 设置采集器参数,确保与录制器参数一致
+    capture::AudioCaptureParams capturerParams(audioParams_.capturerType);
+    capturerParams.deviceId = audioParams_.deviceId;
+    capturerParams.sampleRate = audioParams_.sampleRate;
+    capturerParams.channels = audioParams_.channels;
+    capturerParams.sampleFormat = audioParams_.sampleFormat;
+    
+    AV_LOGGER_INFOF("初始化音频采集器: {}Hz, {}ch, {}", 
+                   capturerParams.sampleRate, capturerParams.channels,
+                   av_get_sample_fmt_name(capturerParams.sampleFormat));
+    
+    ErrorCode result = mainCapturer->initialize(capturerParams);
+    if (result != ErrorCode::SUCCESS) {
+        AV_LOGGER_ERRORF("Failed to initialize main audio capturer: {}", static_cast<int>(result));
+        return result;
+    }
+    
+    // 获取采集器实际使用的参数,更新录制器参数
+    auto actualParams = mainCapturer->getCurrentParams();
+    audioParams_.sampleRate = actualParams.sampleRate;
+    audioParams_.channels = actualParams.channels;
+    audioParams_.sampleFormat = actualParams.sampleFormat;
+    
+    AV_LOGGER_INFOF("采集器实际参数: {}Hz, {}ch, {}", 
+                   audioParams_.sampleRate, audioParams_.channels,
+                   av_get_sample_fmt_name(audioParams_.sampleFormat));
+    
+    // 设置回调
+    mainCapturer->setFrameCallback([this](const AVFramePtr& frame) {
+        onAudioFrameCaptured(frame, 0);
+    });
+    
+    capturers_.push_back(std::move(mainCapturer));
+    
+    // 添加混音设备
+    for (const auto& deviceId : audioParams_.mixDevices) {
+        addAudioDevice(deviceId, audioParams_.capturerType);
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioRecorder::initializeEncoder() {
+    encoder_ = std::make_unique<codec::AudioEncoder>();
+    
+    // 使用正确的AudioEncoderParams而不是基础的CodecParams
+    codec::AudioEncoderParams encoderParams;
+    encoderParams.type = MediaType::AUDIO;
+    encoderParams.codecName = audioParams_.codecName;
+    encoderParams.bitRate = audioParams_.bitrate;
+    encoderParams.sampleRate = audioParams_.sampleRate;
+    encoderParams.channels = audioParams_.channels;
+    encoderParams.sampleFormat = audioParams_.sampleFormat;
+    
+    // 根据声道数设置声道布局
+    if (audioParams_.channels == 1) {
+        encoderParams.channelLayout = AV_CHANNEL_LAYOUT_MONO;
+    } else if (audioParams_.channels == 2) {
+        encoderParams.channelLayout = AV_CHANNEL_LAYOUT_STEREO;
+    } else {
+        av_channel_layout_default(&encoderParams.channelLayout, audioParams_.channels);
+    }
+    
+    AV_LOGGER_INFOF("初始化音频编码器: {}Hz, {}ch, {}, {}bps", 
+                   encoderParams.sampleRate, encoderParams.channels, 
+                   encoderParams.codecName, encoderParams.bitRate);
+    
+    ErrorCode result = encoder_->open(encoderParams);
+    if (result != ErrorCode::SUCCESS) {
+        AV_LOGGER_ERRORF("Failed to initialize audio encoder: {}", static_cast<int>(result));
+        return result;
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AudioRecorder::initializeMuxer() {
+    muxer_ = std::make_unique<muxer::FileMuxer>();
+    
+    // 创建音频流信息
+    muxer::StreamInfo audioStreamInfo;
+    audioStreamInfo.index = 0;
+    audioStreamInfo.type = muxer::StreamType::AUDIO;
+    audioStreamInfo.codecId = AV_CODEC_ID_AAC;  // 默认使用AAC
+    audioStreamInfo.codecName = audioParams_.codecName.empty() ? "aac" : audioParams_.codecName;
+    audioStreamInfo.sampleRate = audioParams_.sampleRate;
+    audioStreamInfo.channels = audioParams_.channels;
+    audioStreamInfo.sampleFormat = audioParams_.sampleFormat;
+    audioStreamInfo.bitrate = audioParams_.bitrate;
+    audioStreamInfo.timeBase = {1, static_cast<int>(audioParams_.sampleRate)};
+
+    // 设置声道布局
+    AVChannelLayout tempLayout;
+    if (audioParams_.channels == 1) {
+        tempLayout = AV_CHANNEL_LAYOUT_MONO;
+        av_channel_layout_copy(&audioStreamInfo.channelLayout, &tempLayout);
+    } else if (audioParams_.channels == 2) {
+        tempLayout = AV_CHANNEL_LAYOUT_STEREO;
+        av_channel_layout_copy(&audioStreamInfo.channelLayout, &tempLayout);
+    } else {
+        av_channel_layout_default(&audioStreamInfo.channelLayout, audioParams_.channels);
+    }
+    
+    // 创建复用器参数并添加流信息
+    muxer::FileMuxerParams muxerParams;
+    muxerParams.type = muxer::MuxerType::FILE_MUXER;
+    muxerParams.outputPath = audioParams_.outputPath;
+    muxerParams.outputFile = audioParams_.outputPath;  // FileMuxerParams 需要设置 outputFile
+    muxerParams.format = audioParams_.format;
+    muxerParams.overwrite = true;  // 允许覆盖已存在文件
+    muxerParams.streams.push_back(audioStreamInfo);  // 添加音频流
+    
+    AV_LOGGER_INFOF("添加音频流到复用器: {}Hz, {}ch, {}, {}bps", 
+                   audioStreamInfo.sampleRate, audioStreamInfo.channels, 
+                   audioStreamInfo.codecName, audioStreamInfo.bitrate);
+    
+    ErrorCode result = muxer_->initialize(muxerParams);
+    if (result != ErrorCode::SUCCESS) {
+        AV_LOGGER_ERRORF("Failed to initialize muxer: {}", static_cast<int>(result));
+        return result;
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+void AudioRecorder::cleanup() {
+    shouldStop_ = true;
+    
+    // 停止处理线程
+    if (processingThread_ && processingThread_->joinable()) {
+        queueCondition_.notify_all();
+        processingThread_->join();
+        processingThread_.reset();
+    }
+    
+    // 清理采集器
+    for (auto& capturer : capturers_) {
+        if (capturer) {
+            capturer->stop();
+            capturer->close();
+        }
+    }
+    capturers_.clear();
+    
+    // 清理编码器
+    if (encoder_) {
+        encoder_->close();
+        encoder_.reset();
+    }
+    
+    // 清理复用器
+    if (muxer_) {
+        muxer_->close();
+        muxer_.reset();
+    }
+    
+    // 清理线程池
+    if (threadPool_) {
+        threadPool_.reset();
+    }
+    
+    // 清理队列
+    {
+        std::lock_guard<std::mutex> lock(queueMutex_);
+        frameQueue_.clear();
+    }
+}
+
+} // namespace recorder
+} // namespace av

+ 203 - 0
AV/code/recorder/recorder_audio_recorder.h

@@ -0,0 +1,203 @@
+#ifndef AV_RECORDER_AUDIO_RECORDER_H
+#define AV_RECORDER_AUDIO_RECORDER_H
+
+#include "recorder_abstract_recorder.h"
+#include "../capture/capture_audio_capturer.h"
+#include "../codec/codec_audio_encoder.h"
+#include "../muxer/muxer_abstract_muxer.h"
+#include "../utils/utils_thread_pool.h"
+#include <vector>
+#include <memory>
+#include <thread>
+#include <atomic>
+#include <deque>
+#include <condition_variable>
+
+namespace av {
+namespace recorder {
+
+/**
+ * 音频录制器参数
+ */
+struct AudioRecorderParams : public RecorderParams {
+    // 音频采集参数
+    capture::CapturerType capturerType = capture::CapturerType::AUDIO_MIC;
+    std::string deviceId;               // 音频设备ID
+    uint32_t sampleRate = 44100;        // 采样率
+    uint32_t channels = 2;              // 声道数
+    uint32_t bitsPerSample = 16;        // 位深度
+    AVSampleFormat sampleFormat = AV_SAMPLE_FMT_S16;
+    
+    // 编码参数
+    std::string codecName = "aac";      // 编码器名称
+    uint32_t bitrate = 128000;          // 比特率
+    
+    // 混音参数
+    bool enableMixing = false;          // 是否启用混音
+    std::vector<std::string> mixDevices; // 混音设备列表
+    float volumeScale = 1.0f;           // 音量缩放
+    
+    AudioRecorderParams() {
+        mediaType = MediaType::AUDIO;
+        format = "mp4";
+    }
+};
+
+/**
+ * 音频录制器
+ * 支持多设备采集、混音、编码和输出
+ */
+class AudioRecorder : public AbstractRecorder {
+public:
+    AudioRecorder();
+    virtual ~AudioRecorder();
+
+    // 实现基类接口
+    ErrorCode initialize(const RecorderParams& params) override;
+    ErrorCode startRecording() override;
+    ErrorCode stopRecording() override;
+    ErrorCode pauseRecording() override;
+    ErrorCode resumeRecording() override;
+    void close() override;
+
+    // 音频特定功能
+    /**
+     * 设置音量缩放
+     */
+    void setVolumeScale(float scale);
+    
+    /**
+     * 获取音频电平
+     */
+    float getAudioLevel() const;
+    
+    /**
+     * 添加音频设备
+     */
+    ErrorCode addAudioDevice(const std::string& deviceId, capture::CapturerType type);
+    
+    /**
+     * 移除音频设备
+     */
+    ErrorCode removeAudioDevice(const std::string& deviceId);
+    
+    /**
+     * 获取可用音频设备列表
+     */
+    std::vector<std::string> getAvailableDevices(capture::CapturerType type) const;
+
+protected:
+    bool validateParams(const RecorderParams& params) override;
+
+private:
+    /**
+     * 音频处理线程
+     */
+    void audioProcessingThread();
+    
+    /**
+     * 混音处理
+     */
+    AVFramePtr mixAudioFrames(const std::vector<AVFramePtr>& frames);
+    
+    /**
+     * 音频帧回调
+     */
+    void onAudioFrameCaptured(const AVFramePtr& frame, size_t capturerIndex);
+    
+    /**
+     * 编码完成回调
+     */
+    void onAudioPacketEncoded(const AVPacketPtr& packet);
+    
+    /**
+     * 初始化采集器
+     */
+    ErrorCode initializeCapturers();
+    
+    /**
+     * 初始化编码器
+     */
+    ErrorCode initializeEncoder();
+    
+    /**
+     * 初始化复用器
+     */
+    ErrorCode initializeMuxer();
+    
+    /**
+     * 清理资源
+     */
+    void cleanup();
+
+private:
+    AudioRecorderParams audioParams_;
+    
+    // 采集器
+    std::vector<std::unique_ptr<capture::AudioCapturer>> capturers_;
+    
+    // 编码器
+    std::unique_ptr<codec::AudioEncoder> encoder_;
+    
+    // 复用器
+    std::unique_ptr<muxer::AbstractMuxer> muxer_;
+    
+    // 线程池
+    std::unique_ptr<utils::ThreadPool> threadPool_;
+    
+    // 音频处理线程
+    std::unique_ptr<std::thread> processingThread_;
+    std::atomic<bool> shouldStop_;
+    
+    // 音频帧队列
+    struct AudioFrameData {
+        AVFramePtr frame;
+        size_t capturerIndex;
+        std::chrono::steady_clock::time_point timestamp;
+        
+        // 默认构造函数
+        AudioFrameData() = default;
+        
+        // 移动构造函数
+        AudioFrameData(AudioFrameData&& other) noexcept
+            : frame(std::move(other.frame))
+            , capturerIndex(other.capturerIndex)
+            , timestamp(other.timestamp) {}
+        
+        // 移动赋值运算符
+        AudioFrameData& operator=(AudioFrameData&& other) noexcept {
+            if (this != &other) {
+                frame = std::move(other.frame);
+                capturerIndex = other.capturerIndex;
+                timestamp = other.timestamp;
+            }
+            return *this;
+        }
+        
+        // 禁用拷贝构造函数和拷贝赋值运算符
+        AudioFrameData(const AudioFrameData&) = delete;
+        AudioFrameData& operator=(const AudioFrameData&) = delete;
+    };
+    
+    std::deque<AudioFrameData> frameQueue_;
+    std::mutex queueMutex_;
+    std::condition_variable queueCondition_;
+    
+    // 混音相关
+    float volumeScale_;
+    mutable std::mutex audioLevelMutex_;
+    float currentAudioLevel_;
+    
+    // 同步相关
+    std::mutex capturerMutex_;
+    std::atomic<bool> isPaused_;
+    
+    // 统计信息
+    std::atomic<uint64_t> processedSamples_;
+    std::chrono::steady_clock::time_point lastProcessTime_;
+};
+
+} // namespace recorder
+} // namespace av
+
+#endif // AV_RECORDER_AUDIO_RECORDER_H

+ 710 - 0
AV/code/recorder/recorder_av_recorder.cpp

@@ -0,0 +1,710 @@
+#include "recorder_av_recorder.h"
+#include "../base/logger.h"
+#include <algorithm>
+#include <chrono>
+
+namespace av {
+namespace recorder {
+
+AVRecorder::AVRecorder()
+    : AbstractRecorder(MediaType::UNKNOWN)
+    , shouldStopSync_(false)
+    , audioTimestamp_(0)
+    , videoTimestamp_(0)
+    , audioEnabled_(true)
+    , videoEnabled_(true)
+    , syncEnabled_(true)
+    , syncThreshold_(40)
+    , dropFrameOnSync_(true)
+    , audioPacketCount_(0)
+    , videoPacketCount_(0) {
+    
+    recordingStartTime_ = std::chrono::steady_clock::now();
+}
+
+AVRecorder::~AVRecorder() {
+    close();
+}
+
+ErrorCode AVRecorder::initialize(const RecorderParams& params) {
+    if (!validateParams(params)) {
+        return ErrorCode::INVALID_PARAMS;
+    }
+    
+    avParams_ = static_cast<const AVRecorderParams&>(params);
+    params_ = params;
+    
+    audioEnabled_ = avParams_.enableAudio;
+    videoEnabled_ = avParams_.enableVideo;
+    syncEnabled_ = avParams_.enableSync;
+    syncThreshold_ = avParams_.syncThresholdMs;
+    dropFrameOnSync_ = avParams_.dropFrameOnSync;
+    
+    // 初始化子录制器
+    ErrorCode result = initializeSubRecorders();
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    // 初始化同步器
+    if (syncEnabled_ && audioEnabled_ && videoEnabled_) {
+        result = initializeSynchronizer();
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_WARNING("Failed to initialize synchronizer, continuing without sync");
+            syncEnabled_ = false;
+        }
+    }
+    
+    setState(RecorderState::INITIALIZED);
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AVRecorder::startRecording() {
+    if (getState() != RecorderState::INITIALIZED && getState() != RecorderState::STOPPED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    shouldStopSync_ = false;
+    recordingStartTime_ = std::chrono::steady_clock::now();
+    
+    // 重置统计信息
+    {
+        std::lock_guard<std::mutex> lock(statsMutex_);
+        combinedStats_ = CombinedStats{};
+    }
+    
+    {
+        std::lock_guard<std::mutex> lock(syncMutex_);
+        syncStatus_ = SyncStatus{};
+    }
+    
+    audioTimestamp_ = 0;
+    videoTimestamp_ = 0;
+    audioPacketCount_ = 0;
+    videoPacketCount_ = 0;
+    
+    // 启动音频录制器
+    if (audioEnabled_ && audioRecorder_) {
+        ErrorCode result = audioRecorder_->startRecording();
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to start audio recording: {}", static_cast<int>(result));
+            return result;
+        }
+    }
+    
+    // 启动视频录制器
+    if (videoEnabled_ && videoRecorder_) {
+        ErrorCode result = videoRecorder_->startRecording();
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to start video recording: {}", static_cast<int>(result));
+            // 如果视频启动失败,停止音频
+            if (audioEnabled_ && audioRecorder_) {
+                audioRecorder_->stopRecording();
+            }
+            return result;
+        }
+    }
+    
+    // 启动同步线程
+    if (syncEnabled_ && audioEnabled_ && videoEnabled_) {
+        syncThread_ = std::make_unique<std::thread>(&AVRecorder::synchronizationThread, this);
+    }
+    
+    setState(RecorderState::RECORDING);
+    resetStats();
+    
+    AV_LOGGER_INFOF("AV recording started - Audio: {}, Video: {}, Sync: {}", 
+             audioEnabled_.load(), videoEnabled_.load(), syncEnabled_.load());
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AVRecorder::stopRecording() {
+    if (getState() != RecorderState::RECORDING && getState() != RecorderState::PAUSED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    shouldStopSync_ = true;
+    
+    // 等待同步线程结束
+    if (syncThread_ && syncThread_->joinable()) {
+        syncThread_->join();
+        syncThread_.reset();
+    }
+    
+    // 停止子录制器
+    ErrorCode audioResult = ErrorCode::SUCCESS;
+    ErrorCode videoResult = ErrorCode::SUCCESS;
+    
+    if (audioEnabled_ && audioRecorder_) {
+        audioResult = audioRecorder_->stopRecording();
+    }
+    
+    if (videoEnabled_ && videoRecorder_) {
+        videoResult = videoRecorder_->stopRecording();
+    }
+    
+    setState(RecorderState::STOPPED);
+    
+    // 更新最终统计信息
+    updateCombinedStats();
+    
+    AV_LOGGER_INFO("AV recording stopped");
+    
+    // 返回第一个错误(如果有)
+    if (audioResult != ErrorCode::SUCCESS) {
+        return audioResult;
+    }
+    return videoResult;
+}
+
+ErrorCode AVRecorder::pauseRecording() {
+    if (getState() != RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    ErrorCode audioResult = ErrorCode::SUCCESS;
+    ErrorCode videoResult = ErrorCode::SUCCESS;
+    
+    if (audioEnabled_ && audioRecorder_) {
+        audioResult = audioRecorder_->pauseRecording();
+    }
+    
+    if (videoEnabled_ && videoRecorder_) {
+        videoResult = videoRecorder_->pauseRecording();
+    }
+    
+    setState(RecorderState::PAUSED);
+    
+    AV_LOGGER_INFO("AV recording paused");
+    
+    if (audioResult != ErrorCode::SUCCESS) {
+        return audioResult;
+    }
+    return videoResult;
+}
+
+ErrorCode AVRecorder::resumeRecording() {
+    if (getState() != RecorderState::PAUSED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    ErrorCode audioResult = ErrorCode::SUCCESS;
+    ErrorCode videoResult = ErrorCode::SUCCESS;
+    
+    if (audioEnabled_ && audioRecorder_) {
+        audioResult = audioRecorder_->resumeRecording();
+    }
+    
+    if (videoEnabled_ && videoRecorder_) {
+        videoResult = videoRecorder_->resumeRecording();
+    }
+    
+    setState(RecorderState::RECORDING);
+    
+    AV_LOGGER_INFO("AV recording resumed");
+    
+    if (audioResult != ErrorCode::SUCCESS) {
+        return audioResult;
+    }
+    return videoResult;
+}
+
+void AVRecorder::close() {
+    if (getState() == RecorderState::RECORDING || getState() == RecorderState::PAUSED) {
+        stopRecording();
+    }
+    
+    cleanup();
+    setState(RecorderState::IDLE);
+}
+
+ErrorCode AVRecorder::setAudioEnabled(bool enabled) {
+    if (getState() == RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    audioEnabled_ = enabled;
+    avParams_.enableAudio = enabled;
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AVRecorder::setVideoEnabled(bool enabled) {
+    if (getState() == RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    videoEnabled_ = enabled;
+    avParams_.enableVideo = enabled;
+    
+    return ErrorCode::SUCCESS;
+}
+
+AVRecorder::SyncStatus AVRecorder::getSyncStatus() const {
+    std::lock_guard<std::mutex> lock(syncMutex_);
+    return syncStatus_;
+}
+
+void AVRecorder::setSyncThreshold(int64_t thresholdMs) {
+    syncThreshold_ = thresholdMs;
+    avParams_.syncThresholdMs = thresholdMs;
+}
+
+void AVRecorder::setDropFrameOnSync(bool drop) {
+    dropFrameOnSync_ = drop;
+    avParams_.dropFrameOnSync = drop;
+}
+
+AVRecorder::CombinedStats AVRecorder::getCombinedStats() const {
+    std::lock_guard<std::mutex> lock(statsMutex_);
+    
+    CombinedStats stats = combinedStats_;
+    
+    // 更新实时数据
+    if (audioRecorder_) {
+        stats.audioStats = audioRecorder_->getStats();
+    }
+    
+    if (videoRecorder_) {
+        stats.videoStats = videoRecorder_->getStats();
+    }
+    
+    stats.syncStatus = getSyncStatus();
+    
+    // 计算总录制时间
+    auto now = std::chrono::steady_clock::now();
+    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - recordingStartTime_);
+    stats.totalRecordingTime = duration.count() / 1000.0;
+    
+    // 计算总文件大小
+    stats.totalFileSize = stats.audioStats.totalBytes + stats.videoStats.totalBytes;
+    
+    return stats;
+}
+
+AVFramePtr AVRecorder::getCurrentVideoFrame() const {
+    if (videoRecorder_) {
+        return videoRecorder_->getCurrentFrame();
+    }
+    return nullptr;
+}
+
+float AVRecorder::getCurrentAudioLevel() const {
+    if (audioRecorder_) {
+        return audioRecorder_->getAudioLevel();
+    }
+    return 0.0f;
+}
+
+// 独立音频采集控制
+ErrorCode AVRecorder::startAudioCapture() {
+    if (!audioRecorder_) {
+        AV_LOGGER_ERROR("Audio recorder not initialized");
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    if (audioRecorder_->getState() == RecorderState::RECORDING) {
+        AV_LOGGER_WARNING("Audio capture already started");
+        return ErrorCode::SUCCESS;
+    }
+    
+    ErrorCode result = audioRecorder_->startRecording();
+    if (result == ErrorCode::SUCCESS) {
+        audioEnabled_ = true;
+        AV_LOGGER_INFO("Audio capture started independently");
+    }
+    
+    return result;
+}
+
+ErrorCode AVRecorder::stopAudioCapture() {
+    if (!audioRecorder_) {
+        return ErrorCode::SUCCESS;
+    }
+    
+    if (audioRecorder_->getState() != RecorderState::RECORDING && 
+        audioRecorder_->getState() != RecorderState::PAUSED) {
+        return ErrorCode::SUCCESS;
+    }
+    
+    ErrorCode result = audioRecorder_->stopRecording();
+    if (result == ErrorCode::SUCCESS) {
+        AV_LOGGER_INFO("Audio capture stopped independently");
+    }
+    
+    return result;
+}
+
+ErrorCode AVRecorder::pauseAudioCapture() {
+    if (!audioRecorder_) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    ErrorCode result = audioRecorder_->pauseRecording();
+    if (result == ErrorCode::SUCCESS) {
+        AV_LOGGER_INFO("Audio capture paused independently");
+    }
+    
+    return result;
+}
+
+ErrorCode AVRecorder::resumeAudioCapture() {
+    if (!audioRecorder_) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    ErrorCode result = audioRecorder_->resumeRecording();
+    if (result == ErrorCode::SUCCESS) {
+        AV_LOGGER_INFO("Audio capture resumed independently");
+    }
+    
+    return result;
+}
+
+// 独立视频采集控制
+ErrorCode AVRecorder::startVideoCapture() {
+    if (!videoRecorder_) {
+        AV_LOGGER_ERROR("Video recorder not initialized");
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    if (videoRecorder_->getState() == RecorderState::RECORDING) {
+        AV_LOGGER_WARNING("Video capture already started");
+        return ErrorCode::SUCCESS;
+    }
+    
+    ErrorCode result = videoRecorder_->startRecording();
+    if (result == ErrorCode::SUCCESS) {
+        videoEnabled_ = true;
+        AV_LOGGER_INFO("Video capture started independently");
+    }
+    
+    return result;
+}
+
+ErrorCode AVRecorder::stopVideoCapture() {
+    if (!videoRecorder_) {
+        return ErrorCode::SUCCESS;
+    }
+    
+    if (videoRecorder_->getState() != RecorderState::RECORDING && 
+        videoRecorder_->getState() != RecorderState::PAUSED) {
+        return ErrorCode::SUCCESS;
+    }
+    
+    ErrorCode result = videoRecorder_->stopRecording();
+    if (result == ErrorCode::SUCCESS) {
+        AV_LOGGER_INFO("Video capture stopped independently");
+    }
+    
+    return result;
+}
+
+ErrorCode AVRecorder::pauseVideoCapture() {
+    if (!videoRecorder_) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    ErrorCode result = videoRecorder_->pauseRecording();
+    if (result == ErrorCode::SUCCESS) {
+        AV_LOGGER_INFO("Video capture paused independently");
+    }
+    
+    return result;
+}
+
+ErrorCode AVRecorder::resumeVideoCapture() {
+    if (!videoRecorder_) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    ErrorCode result = videoRecorder_->resumeRecording();
+    if (result == ErrorCode::SUCCESS) {
+        AV_LOGGER_INFO("Video capture resumed independently");
+    }
+    
+    return result;
+}
+
+// 实时切换功能
+ErrorCode AVRecorder::toggleAudioRecording(bool enable) {
+    if (!audioRecorder_) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    if (enable) {
+        if (!isAudioRecording()) {
+            return startAudioCapture();
+        }
+    } else {
+        if (isAudioRecording()) {
+            return pauseAudioCapture(); // 使用暂停而不是停止,保持状态
+        }
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AVRecorder::toggleVideoRecording(bool enable) {
+    if (!videoRecorder_) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    if (enable) {
+        if (!isVideoRecording()) {
+            return startVideoCapture();
+        }
+    } else {
+        if (isVideoRecording()) {
+            return pauseVideoCapture(); // 使用暂停而不是停止,保持状态
+        }
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+// 状态查询
+bool AVRecorder::isAudioRecording() const {
+    return audioRecorder_ && 
+           audioRecorder_->getState() == RecorderState::RECORDING;
+}
+
+bool AVRecorder::isVideoRecording() const {
+    return videoRecorder_ && 
+           videoRecorder_->getState() == RecorderState::RECORDING;
+}
+
+bool AVRecorder::isAudioCapturing() const {
+    return audioRecorder_ && 
+           (audioRecorder_->getState() == RecorderState::RECORDING || 
+            audioRecorder_->getState() == RecorderState::PAUSED);
+}
+
+bool AVRecorder::isVideoCapturing() const {
+    return videoRecorder_ && 
+           (videoRecorder_->getState() == RecorderState::RECORDING || 
+            videoRecorder_->getState() == RecorderState::PAUSED);
+}
+
+bool AVRecorder::validateParams(const RecorderParams& params) {
+    const auto& avParams = static_cast<const AVRecorderParams&>(params);
+    
+    if (!avParams.enableAudio && !avParams.enableVideo) {
+        AV_LOGGER_ERROR("Both audio and video are disabled");
+        return false;
+    }
+    
+    if (avParams.outputPath.empty()) {
+        AV_LOGGER_ERROR("Output path is empty");
+        return false;
+    }
+    
+    // 验证音频参数
+    if (avParams.enableAudio) {
+        if (avParams.audioParams.sampleRate == 0 || avParams.audioParams.channels == 0) {
+            AV_LOGGER_ERROR("Invalid audio parameters");
+            return false;
+        }
+    }
+    
+    // 验证视频参数
+    if (avParams.enableVideo) {
+        if (avParams.videoParams.width == 0 || avParams.videoParams.height == 0) {
+            AV_LOGGER_ERROR("Invalid video parameters");
+            return false;
+        }
+    }
+    
+    return true;
+}
+
+void AVRecorder::synchronizationThread() {
+    AV_LOGGER_INFO("Synchronization thread started");
+    
+    const auto syncInterval = std::chrono::milliseconds(100); // 100ms检查间隔
+    
+    try {
+        while (!shouldStopSync_) {
+            std::this_thread::sleep_for(syncInterval);
+            
+            if (getState() != RecorderState::RECORDING) {
+                continue;
+            }
+            
+            try {
+                checkSyncStatus();
+                updateCombinedStats();
+            } catch (const std::exception& e) {
+                AV_LOGGER_ERRORF("Error in sync check: {}", e.what());
+                // 同步错误不应该终止整个录制过程,继续运行
+            }
+        }
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("Synchronization thread crashed with exception: {}", e.what());
+    } catch (...) {
+        AV_LOGGER_ERROR("Synchronization thread crashed with unknown exception");
+    }
+    
+    AV_LOGGER_INFO("Synchronization thread stopped");
+}
+
+void AVRecorder::onAudioPacket(const AVPacketPtr& packet) {
+    if (packet) {
+        audioTimestamp_ = packet->pts;
+        audioPacketCount_++;
+    }
+}
+
+void AVRecorder::onVideoPacket(const AVPacketPtr& packet) {
+    if (packet) {
+        videoTimestamp_ = packet->pts;
+        videoPacketCount_++;
+    }
+}
+
+void AVRecorder::checkSyncStatus() {
+    if (!syncEnabled_ || !audioEnabled_ || !videoEnabled_) {
+        return;
+    }
+    
+    int64_t audioTs = audioTimestamp_.load();
+    int64_t videoTs = videoTimestamp_.load();
+    int64_t timeDiff = audioTs - videoTs;
+    
+    {
+        std::lock_guard<std::mutex> lock(syncMutex_);
+        syncStatus_.audioTimestamp = audioTs;
+        syncStatus_.videoTimestamp = videoTs;
+        syncStatus_.timeDiff = timeDiff;
+        syncStatus_.isInSync = std::abs(timeDiff) <= syncThreshold_;
+    }
+    
+    // 如果不同步,尝试调整
+    if (!syncStatus_.isInSync && dropFrameOnSync_) {
+        adjustSync(timeDiff);
+    }
+}
+
+void AVRecorder::adjustSync(int64_t timeDiff) {
+    // 简单的同步策略:丢弃超前的帧
+    if (timeDiff > syncThreshold_) {
+        // 音频超前,通知音频录制器丢帧
+        std::lock_guard<std::mutex> lock(syncMutex_);
+        syncStatus_.droppedAudioFrames++;
+    } else if (timeDiff < -syncThreshold_) {
+        // 视频超前,通知视频录制器丢帧
+        std::lock_guard<std::mutex> lock(syncMutex_);
+        syncStatus_.droppedVideoFrames++;
+    }
+}
+
+ErrorCode AVRecorder::initializeSubRecorders() {
+    // 初始化音频录制器
+    if (avParams_.enableAudio) {
+        audioRecorder_ = std::make_unique<AudioRecorder>();
+        
+        // 设置输出路径(音频部分)
+        auto audioParams = avParams_.audioParams;
+        audioParams.outputPath = avParams_.outputPath;
+        
+        ErrorCode result = audioRecorder_->initialize(audioParams);
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to initialize audio recorder: {}", static_cast<int>(result));
+            return result;
+        }
+    }
+    
+    // 初始化视频录制器
+    if (avParams_.enableVideo) {
+        videoRecorder_ = std::make_unique<VideoRecorder>();
+        
+        // 设置输出路径(视频部分)
+        auto videoParams = avParams_.videoParams;
+        videoParams.outputPath = avParams_.outputPath;
+        
+        ErrorCode result = videoRecorder_->initialize(videoParams);
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to initialize video recorder: {}", static_cast<int>(result));
+            return result;
+        }
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode AVRecorder::initializeSynchronizer() {
+    synchronizer_ = std::make_unique<utils::SynchronizerV2>();
+    
+    // TODO: 配置同步器参数
+    
+    return ErrorCode::SUCCESS;
+}
+
+void AVRecorder::cleanup() {
+    shouldStopSync_ = true;
+    
+    // 停止同步线程
+    if (syncThread_ && syncThread_->joinable()) {
+        syncThread_->join();
+        syncThread_.reset();
+    }
+    
+    // 清理子录制器
+    if (audioRecorder_) {
+        audioRecorder_->close();
+        audioRecorder_.reset();
+    }
+    
+    if (videoRecorder_) {
+        videoRecorder_->close();
+        videoRecorder_.reset();
+    }
+    
+    // 清理同步器
+    if (synchronizer_) {
+        synchronizer_.reset();
+    }
+}
+
+void AVRecorder::updateCombinedStats() {
+    std::lock_guard<std::mutex> lock(statsMutex_);
+    
+    if (audioRecorder_) {
+        combinedStats_.audioStats = audioRecorder_->getStats();
+    }
+    
+    if (videoRecorder_) {
+        combinedStats_.videoStats = videoRecorder_->getStats();
+    }
+    
+    combinedStats_.syncStatus = getSyncStatus();
+}
+
+// RecorderFactoryImpl 实现
+std::unique_ptr<AudioRecorder> RecorderFactoryImpl::createAudioRecorder() {
+    return std::make_unique<AudioRecorder>();
+}
+
+std::unique_ptr<VideoRecorder> RecorderFactoryImpl::createVideoRecorder() {
+    return std::make_unique<VideoRecorder>();
+}
+
+std::unique_ptr<AVRecorder> RecorderFactoryImpl::createAVRecorder() {
+    return std::make_unique<AVRecorder>();
+}
+
+std::unique_ptr<AbstractRecorder> RecorderFactoryImpl::createRecorder(MediaType mediaType) {
+    switch (mediaType) {
+        case MediaType::AUDIO:
+            return createAudioRecorder();
+        case MediaType::VIDEO:
+            return createVideoRecorder();
+        case MediaType::UNKNOWN: // 用于表示音视频混合
+            return createAVRecorder();
+        default:
+            return nullptr;
+    }
+}
+
+} // namespace recorder
+} // namespace av

+ 268 - 0
AV/code/recorder/recorder_av_recorder.h

@@ -0,0 +1,268 @@
+#ifndef AV_RECORDER_AV_RECORDER_H
+#define AV_RECORDER_AV_RECORDER_H
+
+#include "recorder_abstract_recorder.h"
+#include "recorder_audio_recorder.h"
+#include "recorder_video_recorder.h"
+#include "../utils/utils_synchronizer_v2.h"
+#include <memory>
+#include <atomic>
+#include <mutex>
+
+namespace av {
+namespace recorder {
+
+/**
+ * 音视频录制器参数
+ */
+struct AVRecorderParams : public RecorderParams {
+    // 音频参数
+    AudioRecorderParams audioParams;
+    bool enableAudio = true;
+    
+    // 视频参数
+    VideoRecorderParams videoParams;
+    bool enableVideo = true;
+    
+    // 同步参数
+    bool enableSync = true;             // 是否启用音视频同步
+    int64_t syncThresholdMs = 40;       // 同步阈值(毫秒)
+    bool dropFrameOnSync = true;        // 同步时是否丢帧
+    
+    AVRecorderParams() {
+        mediaType = MediaType::UNKNOWN; // 表示混合媒体类型
+        format = "mp4";
+    }
+};
+
+/**
+ * 音视频录制器
+ * 整合音频和视频录制功能,提供同步录制能力
+ */
+class AVRecorder : public AbstractRecorder {
+public:
+    AVRecorder();
+    virtual ~AVRecorder();
+
+    // 实现基类接口
+    ErrorCode initialize(const RecorderParams& params) override;
+    ErrorCode startRecording() override;
+    ErrorCode stopRecording() override;
+    ErrorCode pauseRecording() override;
+    ErrorCode resumeRecording() override;
+    void close() override;
+
+    // 音视频特定功能
+    /**
+     * 获取音频录制器
+     */
+    AudioRecorder* getAudioRecorder() const { return audioRecorder_.get(); }
+    
+    /**
+     * 获取视频录制器
+     */
+    VideoRecorder* getVideoRecorder() const { return videoRecorder_.get(); }
+    
+    /**
+     * 设置音频启用状态
+     */
+    ErrorCode setAudioEnabled(bool enabled);
+    
+    /**
+     * 设置视频启用状态
+     */
+    ErrorCode setVideoEnabled(bool enabled);
+    
+    /**
+     * 独立控制音频采集
+     */
+    ErrorCode startAudioCapture();
+    ErrorCode stopAudioCapture();
+    ErrorCode pauseAudioCapture();
+    ErrorCode resumeAudioCapture();
+    
+    /**
+     * 独立控制视频采集
+     */
+    ErrorCode startVideoCapture();
+    ErrorCode stopVideoCapture();
+    ErrorCode pauseVideoCapture();
+    ErrorCode resumeVideoCapture();
+    
+    /**
+     * 实时切换音频/视频流
+     */
+    ErrorCode toggleAudioRecording(bool enable);
+    ErrorCode toggleVideoRecording(bool enable);
+    
+    /**
+     * 获取音频/视频录制状态
+     */
+    bool isAudioRecording() const;
+    bool isVideoRecording() const;
+    bool isAudioCapturing() const;
+    bool isVideoCapturing() const;
+    
+    /**
+     * 获取同步状态
+     */
+    struct SyncStatus {
+        bool isInSync = true;           // 是否同步
+        int64_t audioTimestamp = 0;     // 音频时间戳
+        int64_t videoTimestamp = 0;     // 视频时间戳
+        int64_t timeDiff = 0;           // 时间差(ms)
+        uint64_t droppedAudioFrames = 0; // 丢弃的音频帧
+        uint64_t droppedVideoFrames = 0; // 丢弃的视频帧
+    };
+    
+    SyncStatus getSyncStatus() const;
+    
+    /**
+     * 设置同步参数
+     */
+    void setSyncThreshold(int64_t thresholdMs);
+    void setDropFrameOnSync(bool drop);
+    
+    /**
+     * 获取综合统计信息
+     */
+    struct CombinedStats {
+        RecorderStats audioStats;
+        RecorderStats videoStats;
+        SyncStatus syncStatus;
+        double totalRecordingTime = 0.0;
+        uint64_t totalFileSize = 0;
+    };
+    
+    CombinedStats getCombinedStats() const;
+    
+    /**
+     * 获取当前预览帧
+     */
+    AVFramePtr getCurrentVideoFrame() const;
+    
+    /**
+     * 获取当前音频电平
+     */
+    float getCurrentAudioLevel() const;
+
+protected:
+    bool validateParams(const RecorderParams& params) override;
+
+private:
+    /**
+     * 同步线程
+     */
+    void synchronizationThread();
+    
+    /**
+     * 音频包回调
+     */
+    void onAudioPacket(const AVPacketPtr& packet);
+    
+    /**
+     * 视频包回调
+     */
+    void onVideoPacket(const AVPacketPtr& packet);
+    
+    /**
+     * 检查同步状态
+     */
+    void checkSyncStatus();
+    
+    /**
+     * 调整同步
+     */
+    void adjustSync(int64_t timeDiff);
+    
+    /**
+     * 初始化子录制器
+     */
+    ErrorCode initializeSubRecorders();
+    
+    /**
+     * 初始化同步器
+     */
+    ErrorCode initializeSynchronizer();
+    
+    /**
+     * 清理资源
+     */
+    void cleanup();
+    
+    /**
+     * 更新综合统计信息
+     */
+    void updateCombinedStats();
+
+private:
+    AVRecorderParams avParams_;
+    
+    // 子录制器
+    std::unique_ptr<AudioRecorder> audioRecorder_;
+    std::unique_ptr<VideoRecorder> videoRecorder_;
+    
+    // 同步器
+    std::unique_ptr<utils::SynchronizerV2> synchronizer_;
+    
+    // 同步线程
+    std::unique_ptr<std::thread> syncThread_;
+    std::atomic<bool> shouldStopSync_;
+    
+    // 同步状态
+    mutable std::mutex syncMutex_;
+    SyncStatus syncStatus_;
+    
+    // 时间戳管理
+    std::atomic<int64_t> audioTimestamp_;
+    std::atomic<int64_t> videoTimestamp_;
+    std::chrono::steady_clock::time_point recordingStartTime_;
+    
+    // 统计信息
+    mutable std::mutex statsMutex_;
+    CombinedStats combinedStats_;
+    
+    // 控制标志
+    std::atomic<bool> audioEnabled_;
+    std::atomic<bool> videoEnabled_;
+    std::atomic<bool> syncEnabled_;
+    
+    // 同步参数
+    std::atomic<int64_t> syncThreshold_;
+    std::atomic<bool> dropFrameOnSync_;
+    
+    // 包计数器
+    std::atomic<uint64_t> audioPacketCount_;
+    std::atomic<uint64_t> videoPacketCount_;
+};
+
+/**
+ * 录制器工厂类的扩展实现
+ */
+class RecorderFactoryImpl {
+public:
+    /**
+     * 创建音频录制器
+     */
+    static std::unique_ptr<AudioRecorder> createAudioRecorder();
+    
+    /**
+     * 创建视频录制器
+     */
+    static std::unique_ptr<VideoRecorder> createVideoRecorder();
+    
+    /**
+     * 创建音视频录制器
+     */
+    static std::unique_ptr<AVRecorder> createAVRecorder();
+    
+    /**
+     * 创建录制器(根据媒体类型)
+     */
+    static std::unique_ptr<AbstractRecorder> createRecorder(MediaType mediaType);
+};
+
+} // namespace recorder
+} // namespace av
+
+#endif // AV_RECORDER_AV_RECORDER_H

+ 817 - 0
AV/code/recorder/recorder_video_recorder.cpp

@@ -0,0 +1,817 @@
+#include "recorder_video_recorder.h"
+#include "../base/logger.h"
+#include "../capture/capture_video_capturer.h"
+#include "../codec/codec_video_encoder.h"
+#include "../muxer/muxer_file_muxer.h"
+#include <algorithm>
+#include <chrono>
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+}
+
+namespace av {
+namespace recorder {
+
+VideoRecorder::VideoRecorder()
+    : AbstractRecorder(MediaType::VIDEO)
+    , shouldStop_(false)
+    , isPaused_(false)
+    , avgCaptureTime_(0.0)
+    , avgEncodeTime_(0.0)
+    , consecutiveDrops_(0) {
+    
+    threadPool_ = std::make_unique<utils::ThreadPool>(); // 3个工作线程
+    
+    // 配置帧队列参数
+    utils::FrameQueueConfig frameQueueConfig;
+    frameQueueConfig.maxSize = 30;
+    frameQueue_ = std::make_unique<utils::FrameQueue>(frameQueueConfig); // 30帧缓冲
+    
+    lastFrameTime_ = std::chrono::steady_clock::now();
+    lastCaptureTime_ = std::chrono::steady_clock::now();
+    lastEncodeTime_ = std::chrono::steady_clock::now();
+}
+
+VideoRecorder::~VideoRecorder() {
+    close();
+}
+
+ErrorCode VideoRecorder::initialize(const RecorderParams& params) {
+    if (!validateParams(params)) {
+        return ErrorCode::INVALID_PARAMS;
+    }
+    
+    videoParams_ = static_cast<const VideoRecorderParams&>(params);
+    params_ = params;
+    
+    // 计算帧间隔
+    frameInterval_ = std::chrono::microseconds(1000000 / videoParams_.frameRate);
+    
+    // 初始化各个组件
+    ErrorCode result = initializeCapturer();
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    result = initializeEncoder();
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    result = initializeMuxer();
+    if (result != ErrorCode::SUCCESS) {
+        return result;
+    }
+    
+    setState(RecorderState::INITIALIZED);
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::startRecording() {
+    if (getState() != RecorderState::INITIALIZED && getState() != RecorderState::STOPPED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    shouldStop_ = false;
+    isPaused_ = false;
+    consecutiveDrops_ = 0;
+    
+    // 重置统计信息
+    {
+        std::lock_guard<std::mutex> lock(statsMutex_);
+        captureStats_ = CaptureStats{};
+    }
+    
+    // 启动采集器
+    if (capturer_) {
+        ErrorCode result = capturer_->start();
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to start video capturer: {}", static_cast<int>(result));
+            return result;
+        }
+    }
+    
+    // 启动复用器
+    if (muxer_) {
+        ErrorCode result = muxer_->start();
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to start muxer: {}", static_cast<int>(result));
+            return result;
+        }
+        AV_LOGGER_INFO("Muxer started successfully");
+    }
+    
+    // 启动处理线程
+    processingThread_ = std::make_unique<std::thread>(&VideoRecorder::videoProcessingThread, this);
+    frameRateThread_ = std::make_unique<std::thread>(&VideoRecorder::frameRateControlThread, this);
+    
+    setState(RecorderState::RECORDING);
+    resetStats();
+    
+    AV_LOGGER_INFOF("Video recording started: {}x{} @ {}fps", 
+             videoParams_.width, videoParams_.height, videoParams_.frameRate);
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::stopRecording() {
+    if (getState() != RecorderState::RECORDING && getState() != RecorderState::PAUSED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    shouldStop_ = true;
+    isPaused_ = false;
+    
+    // 通知所有等待的线程
+    frameCondition_.notify_all();
+    
+    // 等待处理线程结束
+    if (processingThread_ && processingThread_->joinable()) {
+        processingThread_->join();
+        processingThread_.reset();
+    }
+    
+    if (frameRateThread_ && frameRateThread_->joinable()) {
+        frameRateThread_->join();
+        frameRateThread_.reset();
+    }
+    
+    // 停止采集器
+    if (capturer_) {
+        capturer_->stop();
+    }
+    
+    // 刷新编码器
+    if (encoder_) {
+        std::vector<AVPacketPtr> packets;
+        encoder_->finishEncode(packets);
+        
+        for (const auto& packet : packets) {
+            if (muxer_) {
+                muxer_->writePacket(packet.get());
+            }
+        }
+    }
+    
+    // 关闭复用器
+    if (muxer_) {
+        muxer_->close();
+    }
+    
+    setState(RecorderState::STOPPED);
+    
+    AV_LOGGER_INFO("Video recording stopped");
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::pauseRecording() {
+    if (getState() != RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    isPaused_ = true;
+    setState(RecorderState::PAUSED);
+    
+    AV_LOGGER_INFO("Video recording paused");
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::resumeRecording() {
+    if (getState() != RecorderState::PAUSED) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    isPaused_ = false;
+    setState(RecorderState::RECORDING);
+    frameCondition_.notify_all();
+    
+    AV_LOGGER_INFO("Video recording resumed");
+    return ErrorCode::SUCCESS;
+}
+
+void VideoRecorder::close() {
+    if (getState() == RecorderState::RECORDING || getState() == RecorderState::PAUSED) {
+        stopRecording();
+    }
+    
+    cleanup();
+    setState(RecorderState::IDLE);
+}
+
+ErrorCode VideoRecorder::setCaptureSource(VideoCaptureMethod method, const std::string& source) {
+    if (getState() == RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    videoParams_.captureMethod = method;
+    videoParams_.deviceId = source;
+    
+    // 重新初始化采集器
+    if (capturer_) {
+        capturer_->close();
+        return initializeCapturer();
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::setCaptureWindow(void* windowHandle) {
+    if (getState() == RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    videoParams_.captureMethod = VideoCaptureMethod::WINDOW_CAPTURE;
+    videoParams_.windowHandle = windowHandle;
+    
+    if (capturer_) {
+        capturer_->close();
+        return initializeCapturer();
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::setCaptureMonitor(int monitorIndex) {
+    if (getState() == RecorderState::RECORDING) {
+        return ErrorCode::INVALID_STATE;
+    }
+    
+    videoParams_.captureMethod = VideoCaptureMethod::SCREEN_CAPTURE;
+    videoParams_.monitorIndex = monitorIndex;
+    
+    if (capturer_) {
+        capturer_->close();
+        return initializeCapturer();
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+AVFramePtr VideoRecorder::getCurrentFrame() const {
+    std::lock_guard<std::mutex> lock(currentFrameMutex_);
+    if (!currentFrame_) {
+        return nullptr;
+    }
+    
+    // 创建新的frame并复制数据
+    AVFramePtr frame = makeAVFrame();
+    if (!frame) {
+        return nullptr;
+    }
+    
+    if (av_frame_ref(frame.get(), currentFrame_.get()) < 0) {
+        return nullptr;
+    }
+    
+    return frame;
+}
+
+void VideoRecorder::setDrawCursor(bool draw) {
+    videoParams_.drawCursor = draw;
+    // TODO: 通知采集器更新设置
+}
+
+VideoRecorder::CaptureStats VideoRecorder::getCaptureStats() const {
+    std::lock_guard<std::mutex> lock(statsMutex_);
+    return captureStats_;
+}
+
+std::vector<std::string> VideoRecorder::getAvailableDevices(VideoCaptureMethod method) const {
+    // TODO: 根据method参数返回对应类型的设备列表
+    (void)method; // 避免未使用参数警告
+    auto capturer = std::make_unique<capture::VideoCapturer>();
+    return capturer->getAvailableDevices();
+}
+
+std::vector<std::pair<uint32_t, uint32_t>> VideoRecorder::getSupportedResolutions() const {
+    // 返回常见的分辨率列表
+    return {
+        {1920, 1080}, {1680, 1050}, {1600, 900}, {1440, 900},
+        {1366, 768}, {1280, 1024}, {1280, 800}, {1280, 720},
+        {1024, 768}, {800, 600}, {640, 480}
+    };
+}
+
+bool VideoRecorder::validateParams(const RecorderParams& params) {
+    const auto& videoParams = static_cast<const VideoRecorderParams&>(params);
+    
+    if (videoParams.width == 0 || videoParams.height == 0) {
+        AV_LOGGER_ERRORF("Invalid video dimensions: {}x{}", videoParams.width, videoParams.height);
+        return false;
+    }
+    
+    if (videoParams.frameRate == 0 || videoParams.frameRate > 120) {
+        AV_LOGGER_ERRORF("Invalid frame rate: {}", videoParams.frameRate);
+        return false;
+    }
+    
+    if (videoParams.outputPath.empty()) {
+        AV_LOGGER_ERROR("Output path is empty");
+        return false;
+    }
+    
+    return true;
+}
+
+void VideoRecorder::videoProcessingThread() {
+    AV_LOGGER_INFO("Video processing thread started");
+    
+    try {
+        while (!shouldStop_) {
+            if (isPaused_) {
+                std::unique_lock<std::mutex> lock(frameMutex_);
+                frameCondition_.wait(lock, [this] { return !isPaused_ || shouldStop_; });
+                continue;
+            }
+            
+            // 从队列获取帧
+            AVFramePtr frame = frameQueue_->pop(100);
+            if (!frame) {
+                continue;
+            }
+            
+            // 验证帧的有效性
+            if (frame->width <= 0 || frame->height <= 0) {
+                AV_LOGGER_WARNING("Invalid frame dimensions, skipping");
+                continue;
+            }
+            auto encodeStart = std::chrono::steady_clock::now();
+            
+            // 处理视频帧
+            AVFramePtr processedFrame = processVideoFrame(std::move(frame));
+            if (!processedFrame) {
+                updateStats(false);
+                continue;
+            }
+            
+            // 在编码前创建预览副本(编码后processedFrame将被move走)
+            AVFramePtr previewFrame = nullptr;
+            try {
+                previewFrame = makeAVFrame();
+                if (previewFrame) {
+                    previewFrame->format = processedFrame->format;
+                    previewFrame->width = processedFrame->width;
+                    previewFrame->height = processedFrame->height;
+                    previewFrame->pts = processedFrame->pts;
+                    
+                    if (av_frame_get_buffer(previewFrame.get(), 32) >= 0 &&
+                        av_frame_copy(previewFrame.get(), processedFrame.get()) >= 0 &&
+                        av_frame_copy_props(previewFrame.get(), processedFrame.get()) >= 0) {
+                        // 预览副本创建成功
+                    } else {
+                        previewFrame.reset(); // 创建失败,清空指针
+                    }
+                }
+            } catch (const std::exception& e) {
+                AV_LOGGER_DEBUGF("Failed to create preview frame: {}", e.what());
+                previewFrame.reset();
+            }
+            
+            // 编码视频帧
+            if (encoder_) {
+                // 在编码前进行最后的帧有效性检查
+                if (!processedFrame->data[0]) {
+                    AV_LOGGER_ERROR("严重错误:即将编码的帧数据指针为空");
+                    updateStats(false);
+                    continue;
+                }
+                
+                AV_LOGGER_DEBUGF("准备编码帧: width={}, height={}, format={}, data_ptr={}", 
+                                processedFrame->width, processedFrame->height, 
+                                processedFrame->format, static_cast<void*>(processedFrame->data[0]));
+                
+                std::vector<AVPacketPtr> packets;
+                // 使用move语义明确转移所有权,避免潜在的双重释放
+                ErrorCode result = encoder_->encode(std::move(processedFrame), packets);
+                
+                auto encodeEnd = std::chrono::steady_clock::now();
+                auto encodeTime = std::chrono::duration_cast<std::chrono::microseconds>(encodeEnd - encodeStart).count() / 1000.0;
+                
+                if (result == ErrorCode::SUCCESS && !packets.empty()) {
+                    size_t totalSize = 0;
+                    for (const auto& packet : packets) {
+                        if (packet && packet->size > 0) {
+                            onVideoPacketEncoded(packet);
+                            totalSize += packet->size;
+                        }
+                    }
+                    updateStats(true, totalSize);
+                    
+                    // 更新编码时间统计
+                    avgEncodeTime_ = (avgEncodeTime_ * 0.9) + (encodeTime * 0.1);
+                } else {
+                    updateStats(false);
+                    consecutiveDrops_++;
+                    AV_LOGGER_ERRORF("Video encoding failed: {}", static_cast<int>(result));
+                }
+            }
+            
+            // 更新当前帧(用于预览)
+            if (previewFrame) {
+                try {
+                    std::lock_guard<std::mutex> lock(currentFrameMutex_);
+                    currentFrame_ = std::move(previewFrame);
+                } catch (const std::exception& e) {
+                    AV_LOGGER_ERRORF("Error updating current frame: {}", e.what());
+                }
+            }
+
+            
+            // 计算实际帧率
+            calculateActualFrameRate();
+        }
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("Video processing thread crashed with exception: {}", e.what());
+    } catch (...) {
+        AV_LOGGER_ERROR("Video processing thread crashed with unknown exception");
+    }
+    
+    AV_LOGGER_INFO("Video processing thread stopped");
+}
+
+void VideoRecorder::frameRateControlThread() {
+    AV_LOGGER_INFO("Frame rate control thread started");
+    
+    auto nextFrameTime = std::chrono::steady_clock::now();
+    
+    while (!shouldStop_) {
+        if (isPaused_) {
+            std::this_thread::sleep_for(std::chrono::milliseconds(10));
+            nextFrameTime = std::chrono::steady_clock::now();
+            continue;
+        }
+        
+        // 等待到下一帧时间
+        std::this_thread::sleep_until(nextFrameTime);
+        nextFrameTime += frameInterval_;
+        
+        // 检查是否过载
+        bool isOverloaded = checkOverload();
+        
+        {
+            std::lock_guard<std::mutex> lock(statsMutex_);
+            captureStats_.isOverloaded = isOverloaded;
+            captureStats_.captureOverhead = avgCaptureTime_;
+            captureStats_.encodeTime = avgEncodeTime_;
+        }
+        
+        if (isOverloaded) {
+            // 如果过载,跳过一些帧
+            nextFrameTime += frameInterval_;
+            consecutiveDrops_++;
+        }
+    }
+    
+    AV_LOGGER_INFO("Frame rate control thread stopped");
+}
+
+void VideoRecorder::onVideoFrameCaptured(const AVFramePtr& frame) {
+    if (shouldStop_ || isPaused_ || !frame) {
+        return;
+    }
+    
+    // 验证帧数据的有效性
+    if (frame->width <= 0 || frame->height <= 0 || !frame->data[0]) {
+        AV_LOGGER_WARNING("Invalid frame data, skipping");
+        return;
+    }
+    
+    auto captureEnd = std::chrono::steady_clock::now();
+    auto captureTime = std::chrono::duration_cast<std::chrono::microseconds>(captureEnd - lastCaptureTime_).count() / 1000.0;
+    lastCaptureTime_ = captureEnd;
+    
+    // 更新采集时间统计
+    avgCaptureTime_ = (avgCaptureTime_ * 0.9) + (captureTime * 0.1);
+    
+    try {
+        // 创建帧的副本以避免内存管理问题
+        AVFramePtr frameCopy = makeAVFrame();
+        if (!frameCopy) {
+            AV_LOGGER_ERROR("创建帧副本失败");
+            consecutiveDrops_++;
+            updateStats(false);
+            return;
+        }
+        
+        // 复制帧属性
+        frameCopy->format = frame->format;
+        frameCopy->width = frame->width;
+        frameCopy->height = frame->height;
+        frameCopy->pts = frame->pts;
+        
+        // 分配独立的缓冲区
+        if (av_frame_get_buffer(frameCopy.get(), 32) < 0) {
+            AV_LOGGER_ERROR("分配帧缓冲区失败");
+            consecutiveDrops_++;
+            updateStats(false);
+            return;
+        }
+        
+        // 复制帧数据(创建真正的副本,避免引用计数问题)
+        if (av_frame_copy(frameCopy.get(), frame.get()) < 0) {
+            AV_LOGGER_ERROR("复制帧数据失败");
+            consecutiveDrops_++;
+            updateStats(false);
+            return;
+        }
+        
+        // 复制帧属性
+        if (av_frame_copy_props(frameCopy.get(), frame.get()) < 0) {
+            AV_LOGGER_ERROR("复制帧属性失败");
+            consecutiveDrops_++;
+            updateStats(false);
+            return;
+        }
+        
+        // 使用新的安全接口将帧加入队列
+        if (frameQueue_->push(std::move(frameCopy)) != ErrorCode::SUCCESS) {
+            // 队列满,丢弃帧 - 智能指针自动清理
+            consecutiveDrops_++;
+            updateStats(false);
+            AV_LOGGER_DEBUG("Frame queue full, dropped frame");
+        }
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("Error in onVideoFrameCaptured: {}", e.what());
+        consecutiveDrops_++;
+        updateStats(false);
+    }
+}
+
+void VideoRecorder::onVideoPacketEncoded(const AVPacketPtr& packet) {
+    if (muxer_ && packet) {
+        ErrorCode result = muxer_->writePacket(packet.get());
+        if (result != ErrorCode::SUCCESS) {
+            AV_LOGGER_ERRORF("Failed to write video packet: {}", static_cast<int>(result));
+        }
+    }
+}
+
+ErrorCode VideoRecorder::initializeCapturer() {
+    capturer_ = std::make_unique<capture::VideoCapturer>();
+    
+    // 根据采集方法设置参数
+    capture::CapturerType capturerType;
+    std::string deviceId;
+    
+    switch (videoParams_.captureMethod) {
+        case VideoCaptureMethod::SCREEN_CAPTURE:
+            capturerType = capture::CapturerType::VIDEO_SCREEN;
+            deviceId = std::to_string(videoParams_.monitorIndex);
+            break;
+        case VideoCaptureMethod::WINDOW_CAPTURE:
+            capturerType = capture::CapturerType::VIDEO_WINDOW;
+            // TODO: 设置窗口句柄
+            break;
+        case VideoCaptureMethod::CAMERA_CAPTURE:
+            capturerType = capture::CapturerType::VIDEO_CAMERA;
+            deviceId = videoParams_.deviceId;
+            break;
+        default:
+            capturerType = capture::CapturerType::VIDEO_SCREEN;
+            break;
+    }
+    
+    capture::VideoCaptureParams capturerParams(capturerType);
+    capturerParams.deviceId = deviceId;
+    
+    // 设置视频参数
+    capturerParams.width = videoParams_.width;
+    capturerParams.height = videoParams_.height;
+    capturerParams.fps = videoParams_.frameRate;
+    capturerParams.pixelFormat = videoParams_.pixelFormat;
+    
+    // 调试信息:检查参数值
+    AV_LOGGER_INFOF("Setting capturer params: width={}, height={}, fps={}", 
+                   capturerParams.width, capturerParams.height, capturerParams.fps);
+    
+    // 确保参数有效
+    if (capturerParams.width <= 0 || capturerParams.height <= 0) {
+        AV_LOGGER_ERRORF("Invalid video dimensions from videoParams_: {}x{}", 
+                        videoParams_.width, videoParams_.height);
+        // 使用默认值
+        capturerParams.width = 1920;
+        capturerParams.height = 1080;
+        AV_LOGGER_INFOF("Using default dimensions: {}x{}", 
+                       capturerParams.width, capturerParams.height);
+    }
+    
+    // 根据采集方法设置特定参数
+    switch (videoParams_.captureMethod) {
+        case VideoCaptureMethod::SCREEN_CAPTURE:
+            capturerParams.screenIndex = videoParams_.monitorIndex;
+            capturerParams.captureCursor = videoParams_.drawCursor;
+            break;
+        case VideoCaptureMethod::WINDOW_CAPTURE:
+            capturerParams.windowHandle = videoParams_.windowHandle;
+            capturerParams.captureCursor = videoParams_.drawCursor;
+            break;
+        case VideoCaptureMethod::CAMERA_CAPTURE:
+            capturerParams.cameraIndex = 0; // 默认使用第一个摄像头,可以根据deviceId解析
+            break;
+    }
+    
+    ErrorCode result = capturer_->initialize(capturerParams);
+    if (result != ErrorCode::SUCCESS) {
+        AV_LOGGER_ERRORF("Failed to initialize video capturer: {}", static_cast<int>(result));
+        return result;
+    }
+    
+    // 设置回调
+    capturer_->setFrameCallback([this](const AVFramePtr& frame) {
+        onVideoFrameCaptured(frame);
+    });
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::initializeEncoder() {
+    encoder_ = std::make_unique<codec::VideoEncoder>();
+    
+    // 创建视频编码器参数
+    codec::VideoEncoderParams encoderParams;
+    encoderParams.type = MediaType::VIDEO;
+    
+    // 如果指定的编码器名称无效,则自动选择最佳编码器
+    std::string codecName = videoParams_.codecName;
+    if (codecName.empty() || codecName == "h264") {
+        codecName = codec::VideoEncoder::getRecommendedEncoder();
+        if (codecName.empty()) {
+            codecName = "libx264";  // 最后的回退选项
+        }
+        AV_LOGGER_INFOF("Auto-selected encoder: {}", codecName);
+    }
+    
+    encoderParams.codecName = codecName;
+    encoderParams.width = videoParams_.width;
+    encoderParams.height = videoParams_.height;
+    encoderParams.fps = videoParams_.frameRate;
+    encoderParams.bitRate = videoParams_.bitrate;  // 注意字段名称差异
+    encoderParams.gopSize = videoParams_.keyFrameInterval;  // GOP大小对应关键帧间隔
+    encoderParams.maxBFrames = 0;  // 使用默认值,VideoRecorderParams中没有此字段
+    encoderParams.preset = videoParams_.preset;
+    encoderParams.tune = "";  // 使用默认值,VideoRecorderParams中没有此字段
+    encoderParams.lowLatency = false;  // 使用默认值,VideoRecorderParams中没有此字段
+    encoderParams.hardwareAccel = true;  // 使用默认值,VideoRecorderParams中没有此字段
+    encoderParams.pixelFormat = videoParams_.pixelFormat;
+    
+    AV_LOGGER_INFOF("Setting encoder params: codec={}, width={}, height={}, fps={}, bitRate={}", 
+                   encoderParams.codecName, encoderParams.width, encoderParams.height, 
+                   encoderParams.fps, encoderParams.bitRate);
+    
+    ErrorCode result = encoder_->open(encoderParams);
+    if (result != ErrorCode::SUCCESS) {
+        AV_LOGGER_ERRORF("Failed to initialize video encoder: {}", static_cast<int>(result));
+        return result;
+    }
+    
+    // 更新实际使用的编码器名称
+    videoParams_.codecName = codecName;
+    AV_LOGGER_INFOF("Updated videoParams_.codecName to: {}", videoParams_.codecName);
+    
+    return ErrorCode::SUCCESS;
+}
+
+ErrorCode VideoRecorder::initializeMuxer() {
+    muxer_ = std::make_unique<muxer::FileMuxer>();
+    
+    // 创建 FileMuxerParams 而不是基类 MuxerParams
+    muxer::FileMuxerParams fileMuxerParams;
+    fileMuxerParams.outputPath = videoParams_.outputPath;
+    fileMuxerParams.outputFile = videoParams_.outputPath;  // FileMuxerParams 需要设置 outputFile
+    fileMuxerParams.format = videoParams_.format;
+    fileMuxerParams.overwrite = true;  // 允许覆盖已存在文件
+    fileMuxerParams.enableFastStart = true;  // 启用快速开始
+    
+    // 添加视频流信息
+    muxer::StreamInfo videoStream;
+    videoStream.index = 0;
+    videoStream.type = muxer::StreamType::VIDEO;
+    videoStream.codecName = videoParams_.codecName;
+    
+    // 从编码器获取 codecId
+    const AVCodec* codec = avcodec_find_encoder_by_name(videoParams_.codecName.c_str());
+    if (codec) {
+        videoStream.codecId = codec->id;
+        AV_LOGGER_INFOF("设置编解码器ID: {} ({})", static_cast<int>(codec->id), codec->name);
+    } else {
+        AV_LOGGER_ERRORF("无法找到编码器: {}", videoParams_.codecName);
+        return ErrorCode::CODEC_NOT_FOUND;
+    }
+    
+    videoStream.width = videoParams_.width;
+    videoStream.height = videoParams_.height;
+    videoStream.frameRate = {static_cast<int>(videoParams_.frameRate), 1};
+    videoStream.pixelFormat = videoParams_.pixelFormat;
+    videoStream.bitrate = videoParams_.bitrate;
+    videoStream.timeBase = {1, static_cast<int>(videoParams_.frameRate)};
+    
+    fileMuxerParams.streams.push_back(videoStream);
+    
+    AV_LOGGER_INFOF("Initializing muxer with outputFile: {}, format: {}, video stream: {}x{}@{}fps, codecId: {}", 
+                   fileMuxerParams.outputFile, fileMuxerParams.format, 
+                   videoStream.width, videoStream.height, videoParams_.frameRate, 
+                   static_cast<int>(videoStream.codecId));
+    
+    ErrorCode result = muxer_->initialize(fileMuxerParams);
+    if (result != ErrorCode::SUCCESS) {
+        AV_LOGGER_ERRORF("Failed to initialize muxer: {}", static_cast<int>(result));
+        return result;
+    }
+    
+    return ErrorCode::SUCCESS;
+}
+
+AVFramePtr VideoRecorder::processVideoFrame(AVFramePtr frame) {
+    if (!frame) {
+        return nullptr;
+    }
+    
+    // TODO: 实现视频帧处理(缩放、格式转换等)
+    // 使用移动语义转移所有权,避免拷贝
+    // 如果将来需要修改帧数据,再考虑创建副本
+    return std::move(frame);
+}
+
+void VideoRecorder::calculateActualFrameRate() {
+    auto now = std::chrono::steady_clock::now();
+    frameTimestamps_.push_back(now);
+    
+    // 保持队列大小
+    while (frameTimestamps_.size() > MAX_FRAME_TIMESTAMPS) {
+        frameTimestamps_.pop_front();
+    }
+    
+    // 计算帧率
+    if (frameTimestamps_.size() >= 2) {
+        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+            frameTimestamps_.back() - frameTimestamps_.front()).count();
+        
+        if (duration > 0) {
+            double fps = (frameTimestamps_.size() - 1) * 1000.0 / duration;
+            
+            std::lock_guard<std::mutex> lock(statsMutex_);
+            captureStats_.actualFrameRate = fps;
+        }
+    }
+}
+
+bool VideoRecorder::checkOverload() const {
+    // 检查编码时间是否超过帧间隔
+    double frameIntervalMs = 1000.0 / videoParams_.frameRate;
+    return (avgCaptureTime_ + avgEncodeTime_) > (frameIntervalMs * 0.8); // 80%阈值
+}
+
+void VideoRecorder::cleanup() {
+    shouldStop_ = true;
+    
+    // 停止处理线程
+    frameCondition_.notify_all();
+    
+    if (processingThread_ && processingThread_->joinable()) {
+        processingThread_->join();
+        processingThread_.reset();
+    }
+    
+    if (frameRateThread_ && frameRateThread_->joinable()) {
+        frameRateThread_->join();
+        frameRateThread_.reset();
+    }
+    
+    // 清理采集器
+    if (capturer_) {
+        capturer_->stop();
+        capturer_->close();
+        capturer_.reset();
+    }
+    
+    // 清理编码器
+    if (encoder_) {
+        encoder_->close();
+        encoder_.reset();
+    }
+    
+    // 清理复用器
+    if (muxer_) {
+        muxer_->close();
+        muxer_.reset();
+    }
+    
+    // 清理线程池
+    if (threadPool_) {
+        threadPool_.reset();
+    }
+    
+    // 清理帧队列
+    if (frameQueue_) {
+        frameQueue_->clear();
+    }
+    
+    // 清理当前帧
+    {
+        std::lock_guard<std::mutex> lock(currentFrameMutex_);
+        currentFrame_.reset();
+    }
+}
+
+} // namespace recorder
+} // namespace av

+ 245 - 0
AV/code/recorder/recorder_video_recorder.h

@@ -0,0 +1,245 @@
+#ifndef AV_RECORDER_VIDEO_RECORDER_H
+#define AV_RECORDER_VIDEO_RECORDER_H
+
+#include "recorder_abstract_recorder.h"
+#include "../capture/capture_video_capturer.h"
+#include "../codec/codec_video_encoder.h"
+#include "../muxer/muxer_abstract_muxer.h"
+#include "../muxer/muxer_file_muxer.h"
+#include "../utils/utils_thread_pool.h"
+#include "../utils/utils_frame_queue.h"
+#include <memory>
+#include <thread>
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+#include <deque>
+
+namespace av {
+namespace recorder {
+
+/**
+ * 视频采集方法
+ */
+enum class VideoCaptureMethod {
+    SCREEN_CAPTURE,     // 屏幕采集
+    WINDOW_CAPTURE,     // 窗口采集
+    CAMERA_CAPTURE      // 摄像头采集
+};
+
+/**
+ * 视频录制器参数
+ */
+struct VideoRecorderParams : public RecorderParams {
+    // 视频采集参数
+    VideoCaptureMethod captureMethod = VideoCaptureMethod::SCREEN_CAPTURE;
+    std::string deviceId;               // 设备ID(摄像头)或显示器索引
+    void* windowHandle = nullptr;       // 窗口句柄(窗口采集)
+    int monitorIndex = 0;               // 显示器索引(屏幕采集)
+    
+    // 视频参数
+    uint32_t width = 1920;              // 视频宽度
+    uint32_t height = 1080;             // 视频高度
+    uint32_t frameRate = 30;            // 帧率
+    AVPixelFormat pixelFormat = AV_PIX_FMT_YUV420P;
+    
+    // 编码参数
+    std::string codecName = "libx264";  // 编码器名称(使用libx264软件编码器)
+    uint32_t bitrate = 5000000;         // 比特率 (5Mbps)
+    uint32_t keyFrameInterval = 30;     // 关键帧间隔
+    std::string preset = "medium";      // 编码预设
+    
+    // 采集选项
+    bool drawCursor = true;             // 是否绘制鼠标光标
+    bool captureAudio = false;          // 是否同时采集音频
+    
+    VideoRecorderParams() {
+        mediaType = MediaType::VIDEO;
+        format = "mp4";
+    }
+};
+
+/**
+ * 视频录制器
+ * 支持屏幕录制、窗口采集、摄像头录制等功能
+ */
+class VideoRecorder : public AbstractRecorder {
+public:
+    VideoRecorder();
+    virtual ~VideoRecorder();
+
+    // 实现基类接口
+    ErrorCode initialize(const RecorderParams& params) override;
+    ErrorCode startRecording() override;
+    ErrorCode stopRecording() override;
+    ErrorCode pauseRecording() override;
+    ErrorCode resumeRecording() override;
+    void close() override;
+
+    // 视频特定功能
+    /**
+     * 设置采集源
+     */
+    ErrorCode setCaptureSource(VideoCaptureMethod method, const std::string& source);
+    
+    /**
+     * 设置窗口采集源
+     */
+    ErrorCode setCaptureWindow(void* windowHandle);
+    
+    /**
+     * 设置显示器采集源
+     */
+    ErrorCode setCaptureMonitor(int monitorIndex);
+    
+    /**
+     * 获取当前帧(用于预览)
+     */
+    AVFramePtr getCurrentFrame() const;
+    
+    /**
+     * 设置是否绘制光标
+     */
+    void setDrawCursor(bool draw);
+    
+    /**
+     * 获取采集统计信息
+     */
+    struct CaptureStats {
+        double actualFrameRate = 0.0;      // 实际帧率
+        double captureOverhead = 0.0;      // 采集开销(ms)
+        double encodeTime = 0.0;            // 编码时间(ms)
+        uint64_t droppedFrames = 0;         // 丢帧数
+        bool isOverloaded = false;          // 是否过载
+    };
+    
+    CaptureStats getCaptureStats() const;
+    
+    /**
+     * 获取可用的采集设备
+     */
+    std::vector<std::string> getAvailableDevices(VideoCaptureMethod method) const;
+    
+    /**
+     * 获取支持的分辨率列表
+     */
+    std::vector<std::pair<uint32_t, uint32_t>> getSupportedResolutions() const;
+
+protected:
+    bool validateParams(const RecorderParams& params) override;
+
+private:
+    /**
+     * 视频处理线程
+     */
+    void videoProcessingThread();
+    
+    /**
+     * 帧率控制线程
+     */
+    void frameRateControlThread();
+    
+    /**
+     * 视频帧回调
+     */
+    void onVideoFrameCaptured(const AVFramePtr& frame);
+    
+    /**
+     * 编码完成回调
+     */
+    void onVideoPacketEncoded(const AVPacketPtr& packet);
+    
+    /**
+     * 初始化采集器
+     */
+    ErrorCode initializeCapturer();
+    
+    /**
+     * 初始化编码器
+     */
+    ErrorCode initializeEncoder();
+    
+    /**
+     * 初始化复用器
+     */
+    ErrorCode initializeMuxer();
+    
+    /**
+     * 处理视频帧
+     */
+    AVFramePtr processVideoFrame(AVFramePtr frame);
+    
+    /**
+     * 计算帧率
+     */
+    void calculateActualFrameRate();
+    
+    /**
+     * 检查是否过载
+     */
+    bool checkOverload() const;
+    
+    /**
+     * 清理资源
+     */
+    void cleanup();
+
+private:
+    VideoRecorderParams videoParams_;
+    
+    // 采集器
+    std::unique_ptr<capture::VideoCapturer> capturer_;
+    
+    // 编码器
+    std::unique_ptr<codec::VideoEncoder> encoder_;
+    
+    // 复用器
+    std::unique_ptr<muxer::AbstractMuxer> muxer_;
+    
+    // 线程池
+    std::unique_ptr<utils::ThreadPool> threadPool_;
+    
+    // 处理线程
+    std::unique_ptr<std::thread> processingThread_;
+    std::unique_ptr<std::thread> frameRateThread_;
+    std::atomic<bool> shouldStop_;
+    
+    // 帧队列
+    std::unique_ptr<utils::FrameQueue> frameQueue_;
+    
+    // 当前帧(用于预览)
+    mutable std::mutex currentFrameMutex_;
+    AVFramePtr currentFrame_;
+    
+    // 帧率控制
+    std::atomic<bool> isPaused_;
+    std::chrono::steady_clock::time_point lastFrameTime_;
+    std::chrono::microseconds frameInterval_;
+    
+    // 统计信息
+    mutable std::mutex statsMutex_;
+    CaptureStats captureStats_;
+    
+    // 帧率计算
+    std::deque<std::chrono::steady_clock::time_point> frameTimestamps_;
+    static constexpr size_t MAX_FRAME_TIMESTAMPS = 60; // 保留最近60帧的时间戳
+    
+    // 性能监控
+    std::chrono::steady_clock::time_point lastCaptureTime_;
+    std::chrono::steady_clock::time_point lastEncodeTime_;
+    double avgCaptureTime_;
+    double avgEncodeTime_;
+    
+    // 丢帧检测
+    static constexpr int OVERLOAD_THRESHOLD_MS = 50; // 50ms阈值
+    std::atomic<uint64_t> consecutiveDrops_;
+    
+    // 同步
+    std::condition_variable frameCondition_;
+    std::mutex frameMutex_;
+};
+
+} // namespace recorder
+} // namespace av
+
+#endif // AV_RECORDER_VIDEO_RECORDER_H

+ 669 - 0
AV/code/recorder/ui/recorder_audio_widget.cpp

@@ -0,0 +1,669 @@
+#include "recorder_audio_widget.h"
+#include <QComboBox>
+#include <QDateTime>
+#include <QDebug>
+#include <QPainterPath>
+#include <QLinearGradient>
+#include <QApplication>
+#include <QStyle>
+#include <cmath>
+
+// AudioLevelWidget 实现
+
+AudioLevelWidget::AudioLevelWidget(QWidget* parent)
+    : QWidget(parent)
+    , m_leftLevel(0.0)
+    , m_rightLevel(0.0)
+    , m_leftPeak(0.0)
+    , m_rightPeak(0.0)
+    , m_leftPeakTime(0)
+    , m_rightPeakTime(0)
+    , m_peakHoldTime(1500)
+    , m_overloadThreshold(0.95)
+    , m_showValues(true) {
+    
+    setMinimumSize(100, 40);
+    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    
+    // 创建峰值更新定时器
+    m_peakTimer = new QTimer(this);
+    connect(m_peakTimer, &QTimer::timeout, this, &AudioLevelWidget::updatePeaks);
+    m_peakTimer->start(50); // 20fps更新
+}
+
+AudioLevelWidget::~AudioLevelWidget() = default;
+
+void AudioLevelWidget::setLeftLevel(double level) {
+    QMutexLocker locker(&m_mutex);
+    
+    level = qBound(0.0, level, 1.0);
+    m_leftLevel = level;
+    
+    // 更新峰值
+    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
+    if (level > m_leftPeak) {
+        m_leftPeak = level;
+        m_leftPeakTime = currentTime;
+    }
+    
+    update();
+}
+
+void AudioLevelWidget::setRightLevel(double level) {
+    QMutexLocker locker(&m_mutex);
+    
+    level = qBound(0.0, level, 1.0);
+    m_rightLevel = level;
+    
+    // 更新峰值
+    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
+    if (level > m_rightPeak) {
+        m_rightPeak = level;
+        m_rightPeakTime = currentTime;
+    }
+    
+    update();
+}
+
+void AudioLevelWidget::setLevels(double left, double right) {
+    QMutexLocker locker(&m_mutex);
+    
+    left = qBound(0.0, left, 1.0);
+    right = qBound(0.0, right, 1.0);
+    
+    m_leftLevel = left;
+    m_rightLevel = right;
+    
+    // 更新峰值
+    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
+    
+    if (left > m_leftPeak) {
+        m_leftPeak = left;
+        m_leftPeakTime = currentTime;
+    }
+    
+    if (right > m_rightPeak) {
+        m_rightPeak = right;
+        m_rightPeakTime = currentTime;
+    }
+    
+    update();
+}
+
+void AudioLevelWidget::resetPeaks() {
+    QMutexLocker locker(&m_mutex);
+    
+    m_leftPeak = 0.0;
+    m_rightPeak = 0.0;
+    m_leftPeakTime = 0;
+    m_rightPeakTime = 0;
+    
+    update();
+}
+
+void AudioLevelWidget::paintEvent(QPaintEvent* event) {
+    Q_UNUSED(event)
+    
+    QPainter painter(this);
+    painter.setRenderHint(QPainter::Antialiasing);
+    
+    QMutexLocker locker(&m_mutex);
+    
+    // 计算绘制区域
+    QRect drawRect = rect().adjusted(2, 2, -2, -2);
+    int channelHeight = (drawRect.height() - 4) / 2;
+    
+    // 绘制左声道
+    QRect leftRect(drawRect.x(), drawRect.y(), drawRect.width(), channelHeight);
+    drawChannel(painter, leftRect, m_leftLevel, m_leftPeak, true);
+    
+    // 绘制右声道
+    QRect rightRect(drawRect.x(), drawRect.y() + channelHeight + 4, 
+                   drawRect.width(), channelHeight);
+    drawChannel(painter, rightRect, m_rightLevel, m_rightPeak, false);
+    
+    // 绘制标签
+    painter.setPen(Qt::white);
+    painter.setFont(QFont("Arial", 8));
+    
+    painter.drawText(leftRect.adjusted(2, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, "L");
+    painter.drawText(rightRect.adjusted(2, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, "R");
+    
+    // 绘制数值
+    if (m_showValues) {
+        QString leftText = QString("%1").arg(static_cast<int>(m_leftLevel * 100));
+        QString rightText = QString("%1").arg(static_cast<int>(m_rightLevel * 100));
+        
+        painter.drawText(leftRect.adjusted(0, 0, -2, 0), Qt::AlignRight | Qt::AlignVCenter, leftText);
+        painter.drawText(rightRect.adjusted(0, 0, -2, 0), Qt::AlignRight | Qt::AlignVCenter, rightText);
+    }
+}
+
+QSize AudioLevelWidget::sizeHint() const {
+    return QSize(180, 32);
+}
+
+QSize AudioLevelWidget::minimumSizeHint() const {
+    return QSize(120, 32);
+}
+
+void AudioLevelWidget::updatePeaks() {
+    QMutexLocker locker(&m_mutex);
+    
+    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
+    bool needUpdate = false;
+    
+    // 检查左声道峰值是否过期
+    if (m_leftPeakTime > 0 && (currentTime - m_leftPeakTime) > m_peakHoldTime) {
+        m_leftPeak = m_leftLevel;
+        m_leftPeakTime = currentTime;
+        needUpdate = true;
+    }
+    
+    // 检查右声道峰值是否过期
+    if (m_rightPeakTime > 0 && (currentTime - m_rightPeakTime) > m_peakHoldTime) {
+        m_rightPeak = m_rightLevel;
+        m_rightPeakTime = currentTime;
+        needUpdate = true;
+    }
+    
+    if (needUpdate) {
+        update();
+    }
+}
+
+void AudioLevelWidget::drawChannel(QPainter& painter, const QRect& rect, 
+                                  double level, double peak, bool isLeft) {
+    Q_UNUSED(isLeft)
+    
+    // 绘制背景
+    painter.fillRect(rect, QColor(40, 40, 40));
+    
+    // 绘制边框
+    painter.setPen(QColor(80, 80, 80));
+    painter.drawRect(rect);
+    
+    if (level <= 0.0) {
+        return;
+    }
+    
+    // 计算电平条宽度
+    int levelWidth = static_cast<int>(rect.width() * level);
+    QRect levelRect(rect.x(), rect.y(), levelWidth, rect.height());
+    
+    // 创建渐变
+    QLinearGradient gradient(levelRect.topLeft(), levelRect.topRight());
+    
+    if (level < 0.7) {
+        // 绿色区域
+        gradient.setColorAt(0.0, QColor(0, 255, 0));
+        gradient.setColorAt(1.0, QColor(100, 255, 0));
+    } else if (level < m_overloadThreshold) {
+        // 黄色区域
+        gradient.setColorAt(0.0, QColor(100, 255, 0));
+        gradient.setColorAt(0.5, QColor(255, 255, 0));
+        gradient.setColorAt(1.0, QColor(255, 200, 0));
+    } else {
+        // 红色区域(过载)
+        gradient.setColorAt(0.0, QColor(255, 200, 0));
+        gradient.setColorAt(1.0, QColor(255, 0, 0));
+    }
+    
+    painter.fillRect(levelRect, gradient);
+    
+    // 绘制峰值线
+    if (peak > level && peak > 0.0) {
+        int peakX = static_cast<int>(rect.x() + rect.width() * peak);
+        QColor peakColor = getLevelColor(peak);
+        
+        painter.setPen(QPen(peakColor, 2));
+        painter.drawLine(peakX, rect.y(), peakX, rect.y() + rect.height());
+    }
+}
+
+QColor AudioLevelWidget::getLevelColor(double level) const {
+    if (level < 0.7) {
+        return QColor(0, 255, 0); // 绿色
+    } else if (level < m_overloadThreshold) {
+        return QColor(255, 255, 0); // 黄色
+    } else {
+        return QColor(255, 0, 0); // 红色
+    }
+}
+
+// RecorderAudioWidget 实现
+
+RecorderAudioWidget::RecorderAudioWidget(QWidget* parent)
+    : QWidget(parent)
+    , m_mainLayout(nullptr)
+    , m_controlLayout(nullptr)
+    , m_deviceLayout(nullptr)
+    , m_infoLayout(nullptr)
+    , m_volumeLabel(nullptr)
+    , m_volumeSlider(nullptr)
+    , m_volumeValueLabel(nullptr)
+    , m_muteButton(nullptr)
+    , m_levelWidget(nullptr)
+    , m_deviceLabel(nullptr)
+    , m_deviceCombo(nullptr)
+    , m_settingsButton(nullptr)
+    , m_statusLabel(nullptr)
+    , m_volumeAnimation(nullptr)
+    , m_levelOpacityEffect(nullptr)
+    , m_showAdvancedControls(true)
+    , m_volumeChanging(false) {
+    
+    initializeUI();
+    connectSignals();
+    updateUI();
+}
+
+RecorderAudioWidget::~RecorderAudioWidget() = default;
+
+void RecorderAudioWidget::setAudioInfo(const AudioInfo& info) {
+    QMutexLocker locker(&m_mutex);
+    
+    m_audioInfo = info;
+    
+    // 更新UI(在主线程中)
+    QMetaObject::invokeMethod(this, "updateUI", Qt::QueuedConnection);
+}
+
+void RecorderAudioWidget::setVolume(double volume) {
+    QMutexLocker locker(&m_mutex);
+    
+    volume = qBound(0.0, volume, 1.0);
+    if (qAbs(m_audioInfo.volume - volume) < 0.001) {
+        return;
+    }
+    
+    m_audioInfo.volume = volume;
+    
+    // 更新滑块(避免循环信号)
+    if (!m_volumeChanging) {
+        QMetaObject::invokeMethod(this, "updateVolumeDisplay", Qt::QueuedConnection);
+    }
+    
+    emit volumeChanged(volume);
+}
+
+void RecorderAudioWidget::setMuted(bool muted) {
+    QMutexLocker locker(&m_mutex);
+    
+    if (m_audioInfo.isMuted == muted) {
+        return;
+    }
+    
+    m_audioInfo.isMuted = muted;
+    
+    QMetaObject::invokeMethod(this, "updateMuteButton", Qt::QueuedConnection);
+    
+    emit mutedChanged(muted);
+}
+
+void RecorderAudioWidget::setRecording(bool recording) {
+    QMutexLocker locker(&m_mutex);
+    
+    if (m_audioInfo.isRecording == recording) {
+        return;
+    }
+    
+    m_audioInfo.isRecording = recording;
+    
+    QMetaObject::invokeMethod(this, "updateUI", Qt::QueuedConnection);
+}
+
+void RecorderAudioWidget::updateAudioLevels(double left, double right) {
+    if (m_levelWidget) {
+        m_levelWidget->setLevels(left, right);
+    }
+}
+
+void RecorderAudioWidget::setAvailableDevices(const QStringList& devices) {
+    if (!m_deviceCombo) {
+        return;
+    }
+    
+    // 保存当前选择
+    QString currentDevice = m_deviceCombo->currentText();
+    
+    // 更新设备列表
+    m_deviceCombo->clear();
+    m_deviceCombo->addItems(devices);
+    
+    // 恢复选择
+    int index = m_deviceCombo->findText(currentDevice);
+    if (index >= 0) {
+        m_deviceCombo->setCurrentIndex(index);
+    }
+}
+
+void RecorderAudioWidget::setCurrentDevice(const QString& device) {
+    if (!m_deviceCombo) {
+        return;
+    }
+    
+    int index = m_deviceCombo->findText(device);
+    if (index >= 0) {
+        m_deviceCombo->setCurrentIndex(index);
+    }
+    
+    QMutexLocker locker(&m_mutex);
+    m_audioInfo.deviceName = device;
+    
+    QMetaObject::invokeMethod(this, "updateDeviceInfo", Qt::QueuedConnection);
+}
+
+QString RecorderAudioWidget::currentDevice() const {
+    if (!m_deviceCombo) {
+        return QString();
+    }
+    
+    return m_deviceCombo->currentText();
+}
+
+void RecorderAudioWidget::setShowAdvancedControls(bool show) {
+    m_showAdvancedControls = show;
+    
+    if (m_deviceLayout) {
+        m_deviceLabel->setVisible(show);
+        m_deviceCombo->setVisible(show);
+        m_settingsButton->setVisible(show);
+    }
+}
+
+void RecorderAudioWidget::resetAudioPeaks() {
+    if (m_levelWidget) {
+        m_levelWidget->resetPeaks();
+    }
+}
+
+void RecorderAudioWidget::paintEvent(QPaintEvent* event) {
+    // 绘制背景
+    QStyleOption opt;
+    opt.init(this);
+    QPainter painter(this);
+    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
+    
+    QWidget::paintEvent(event);
+}
+
+void RecorderAudioWidget::onVolumeSliderChanged(int value) {
+    m_volumeChanging = true;
+    
+    double volume = value / 100.0;
+    setVolume(volume);
+    
+    // 更新数值标签
+    if (m_volumeValueLabel) {
+        m_volumeValueLabel->setText(QString("%1%").arg(value));
+    }
+    
+    m_volumeChanging = false;
+}
+
+void RecorderAudioWidget::onMuteButtonClicked() {
+    setMuted(!isMuted());
+}
+
+void RecorderAudioWidget::onDeviceComboChanged(const QString& device) {
+    QMutexLocker locker(&m_mutex);
+    m_audioInfo.deviceName = device;
+    locker.unlock();
+    
+    updateDeviceInfo();
+    emit deviceChanged(device);
+}
+
+void RecorderAudioWidget::onSettingsButtonClicked() {
+    emit audioSettingsRequested();
+}
+
+void RecorderAudioWidget::updateVolumeAnimation() {
+    // 音量变化动画效果
+    if (m_volumeAnimation && m_levelWidget) {
+        // 可以添加音量变化的视觉反馈
+    }
+}
+
+void RecorderAudioWidget::initializeUI() {
+    // 创建主布局
+    m_mainLayout = new QVBoxLayout(this);
+    m_mainLayout->setContentsMargins(6, 6, 6, 6);
+    m_mainLayout->setSpacing(4);
+    
+    // 音量控制布局
+    m_controlLayout = new QHBoxLayout();
+    m_controlLayout->setSpacing(6);
+    
+    m_volumeLabel = new QLabel("音量:");
+    m_volumeLabel->setMinimumWidth(35);
+    m_volumeLabel->setMaximumWidth(35);
+    
+    m_volumeSlider = new QSlider(Qt::Horizontal);
+    m_volumeSlider->setRange(0, 100);
+    m_volumeSlider->setValue(100);
+    m_volumeSlider->setMinimumWidth(80);
+    m_volumeSlider->setMaximumHeight(20);
+    
+    m_volumeValueLabel = new QLabel("100%");
+    m_volumeValueLabel->setMinimumWidth(30);
+    m_volumeValueLabel->setMaximumWidth(30);
+    m_volumeValueLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+    
+    m_muteButton = new QPushButton();
+    m_muteButton->setCheckable(true);
+    m_muteButton->setFixedSize(20, 20);
+    m_muteButton->setToolTip("静音/取消静音");
+    
+    m_controlLayout->addWidget(m_volumeLabel);
+    m_controlLayout->addWidget(m_volumeSlider, 1);
+    m_controlLayout->addWidget(m_volumeValueLabel);
+    m_controlLayout->addWidget(m_muteButton);
+    
+    // 音频电平显示
+    m_levelWidget = new AudioLevelWidget();
+    m_levelWidget->setFixedHeight(32);  // 固定高度,避免被挤压
+    m_levelWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    
+    // 设备选择布局(简化版)
+    m_deviceLayout = new QHBoxLayout();
+    m_deviceLayout->setSpacing(4);
+    
+    m_deviceLabel = new QLabel("设备:");
+    m_deviceLabel->setMinimumWidth(35);
+    m_deviceLabel->setMaximumWidth(35);
+    
+    m_deviceCombo = new QComboBox();
+    m_deviceCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    m_deviceCombo->setMaximumHeight(22);
+    
+    m_settingsButton = new QPushButton("⚙");
+    m_settingsButton->setFixedSize(20, 20);
+    m_settingsButton->setToolTip("音频设置");
+    
+    m_deviceLayout->addWidget(m_deviceLabel);
+    m_deviceLayout->addWidget(m_deviceCombo, 1);
+    m_deviceLayout->addWidget(m_settingsButton);
+    
+    // 状态显示布局(简化版)
+    m_infoLayout = new QHBoxLayout();
+    m_infoLayout->setSpacing(4);
+    
+    m_statusLabel = new QLabel("待机");
+    m_statusLabel->setStyleSheet("font-size: 8pt; color: #888;");
+    m_statusLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+
+    m_infoLayout->addStretch();
+    m_infoLayout->addWidget(m_statusLabel);
+    
+    // 添加到主布局
+    m_mainLayout->addLayout(m_controlLayout);
+    m_mainLayout->addWidget(m_levelWidget);
+    m_mainLayout->addLayout(m_deviceLayout);
+    m_mainLayout->addLayout(m_infoLayout);
+    
+    // 创建动画
+    m_volumeAnimation = new QPropertyAnimation(this, "volume");
+    m_volumeAnimation->setDuration(200);
+    m_volumeAnimation->setEasingCurve(QEasingCurve::OutCubic);
+    
+    // 设置样式
+    // setStyleSheet(R"(
+    //     RecorderAudioWidget {
+    //         background-color: #2b2b2b;
+    //         border: 1px solid #555;
+    //         border-radius: 4px;
+    //     }
+    //     QLabel {
+    //         color: #fff;
+    //     }
+    //     QSlider::groove:horizontal {
+    //         border: 1px solid #555;
+    //         height: 6px;
+    //         background: #333;
+    //         border-radius: 3px;
+    //     }
+    //     QSlider::handle:horizontal {
+    //         background: #0a84ff;
+    //         border: 1px solid #0a84ff;
+    //         width: 14px;
+    //         margin: -4px 0;
+    //         border-radius: 7px;
+    //     }
+    //     QSlider::sub-page:horizontal {
+    //         background: #0a84ff;
+    //         border-radius: 3px;
+    //     }
+    //     QPushButton {
+    //         background-color: #444;
+    //         border: 1px solid #666;
+    //         border-radius: 3px;
+    //         color: #fff;
+    //         padding: 4px 8px;
+    //     }
+    //     QPushButton:hover {
+    //         background-color: #555;
+    //     }
+    //     QPushButton:pressed {
+    //         background-color: #333;
+    //     }
+    //     QPushButton:checked {
+    //         background-color: #0a84ff;
+    //     }
+    //     QComboBox {
+    //         background-color: #444;
+    //         border: 1px solid #666;
+    //         border-radius: 3px;
+    //         color: #fff;
+    //         padding: 4px;
+    //     }
+    //     QComboBox::drop-down {
+    //         border: none;
+    //     }
+    //     QComboBox::down-arrow {
+    //         image: none;
+    //         border-left: 4px solid transparent;
+    //         border-right: 4px solid transparent;
+    //         border-top: 4px solid #fff;
+    //     }
+    // )");
+}
+
+void RecorderAudioWidget::connectSignals() {
+    // 音量控制信号
+    connect(m_volumeSlider, QOverload<int>::of(&QSlider::valueChanged),
+            this, &RecorderAudioWidget::onVolumeSliderChanged);
+    
+    connect(m_muteButton, &QPushButton::clicked,
+            this, &RecorderAudioWidget::onMuteButtonClicked);
+    
+    // 设备选择信号
+    connect(m_deviceCombo, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
+            this, &RecorderAudioWidget::onDeviceComboChanged);
+    
+    connect(m_settingsButton, &QPushButton::clicked,
+            this, &RecorderAudioWidget::onSettingsButtonClicked);
+    
+    // 动画信号
+    connect(m_volumeAnimation, &QPropertyAnimation::valueChanged,
+            this, &RecorderAudioWidget::updateVolumeAnimation);
+}
+
+void RecorderAudioWidget::updateUI() {
+    QMutexLocker locker(&m_mutex);
+    AudioInfo info = m_audioInfo;
+    locker.unlock();
+    
+    updateVolumeDisplay();
+    updateMuteButton();
+    updateDeviceInfo();
+    
+    // 更新状态标签
+    if (m_statusLabel) {
+        if (info.isRecording) {
+            m_statusLabel->setText("● 录制中");
+            m_statusLabel->setStyleSheet("color: #ff3b30; font-weight: bold;");
+        } else {
+            m_statusLabel->setText("待机");
+            m_statusLabel->setStyleSheet("color: #888; font-weight: normal;");
+        }
+    }
+}
+
+void RecorderAudioWidget::updateVolumeDisplay() {
+    if (!m_volumeSlider || !m_volumeValueLabel) {
+        return;
+    }
+    
+    QMutexLocker locker(&m_mutex);
+    int value = static_cast<int>(m_audioInfo.volume * 100);
+    locker.unlock();
+    
+    m_volumeChanging = true;
+    m_volumeSlider->setValue(value);
+    m_volumeValueLabel->setText(QString("%1%").arg(value));
+    m_volumeChanging = false;
+}
+
+void RecorderAudioWidget::updateMuteButton() {
+    if (!m_muteButton) {
+        return;
+    }
+    
+    QMutexLocker locker(&m_mutex);
+    bool muted = m_audioInfo.isMuted;
+    locker.unlock();
+    
+    m_muteButton->setChecked(muted);
+    m_muteButton->setText(muted ? "🔇" : "🔊");
+    m_muteButton->setToolTip(muted ? "取消静音" : "静音");
+    
+    // 更新音量滑块状态
+    if (m_volumeSlider) {
+        m_volumeSlider->setEnabled(!muted);
+    }
+}
+
+void RecorderAudioWidget::updateDeviceInfo() {
+    // 设备信息现在通过工具提示显示
+    QMutexLocker locker(&m_mutex);
+    QString infoText = formatAudioInfoText();
+    locker.unlock();
+    
+    if (m_deviceCombo) {
+        m_deviceCombo->setToolTip(infoText);
+    }
+}
+
+QString RecorderAudioWidget::formatAudioInfoText() const {
+    if (m_audioInfo.deviceName.isEmpty()) {
+        return "无音频设备";
+    }
+    
+    return QString("%1 | %2Hz %3ch %4bit")
+           .arg(m_audioInfo.deviceName)
+           .arg(m_audioInfo.sampleRate)
+           .arg(m_audioInfo.channels)
+           .arg(m_audioInfo.bitDepth);
+}

+ 320 - 0
AV/code/recorder/ui/recorder_audio_widget.h

@@ -0,0 +1,320 @@
+#ifndef AV_RECORDER_AUDIO_WIDGET_H
+#define AV_RECORDER_AUDIO_WIDGET_H
+
+#include <QWidget>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QProgressBar>
+#include <QLabel>
+#include <QPushButton>
+#include <QSlider>
+#include <QComboBox>
+#include <QTimer>
+#include <QMutex>
+#include <QPainter>
+#include <QStyleOption>
+#include <QPropertyAnimation>
+#include <QGraphicsOpacityEffect>
+#include <memory>
+
+/**
+ * 音频电平显示组件
+ * 
+ * 显示实时音频电平,支持:
+ * - 左右声道分别显示
+ * - 峰值保持
+ * - 过载指示
+ * - 平滑动画
+ */
+class AudioLevelWidget : public QWidget {
+    Q_OBJECT
+    Q_PROPERTY(double leftLevel READ leftLevel WRITE setLeftLevel)
+    Q_PROPERTY(double rightLevel READ rightLevel WRITE setRightLevel)
+
+public:
+    explicit AudioLevelWidget(QWidget* parent = nullptr);
+    ~AudioLevelWidget();
+
+    /**
+     * 设置音频电平 (0.0 - 1.0)
+     */
+    void setLeftLevel(double level);
+    void setRightLevel(double level);
+    void setLevels(double left, double right);
+    
+    /**
+     * 获取当前电平
+     */
+    double leftLevel() const { return m_leftLevel; }
+    double rightLevel() const { return m_rightLevel; }
+    
+    /**
+     * 设置峰值保持时间 (毫秒)
+     */
+    void setPeakHoldTime(int ms) { m_peakHoldTime = ms; }
+    
+    /**
+     * 设置过载阈值 (0.0 - 1.0)
+     */
+    void setOverloadThreshold(double threshold) { m_overloadThreshold = threshold; }
+    
+    /**
+     * 设置是否显示数值
+     */
+    void setShowValues(bool show) {
+        m_showValues = show;
+        update();
+    }
+    
+    /**
+     * 重置峰值
+     */
+    void resetPeaks();
+
+protected:
+    void paintEvent(QPaintEvent* event) override;
+    QSize sizeHint() const override;
+    QSize minimumSizeHint() const override;
+
+private slots:
+    void updatePeaks();
+
+private:
+    /**
+     * 绘制单个声道
+     */
+    void drawChannel(QPainter& painter, const QRect& rect, 
+                    double level, double peak, bool isLeft);
+    
+    /**
+     * 获取电平颜色
+     */
+    QColor getLevelColor(double level) const;
+
+private:
+    double m_leftLevel;
+    double m_rightLevel;
+    double m_leftPeak;
+    double m_rightPeak;
+    qint64 m_leftPeakTime;
+    qint64 m_rightPeakTime;
+    
+    int m_peakHoldTime;
+    double m_overloadThreshold;
+    bool m_showValues;
+    
+    QTimer* m_peakTimer;
+    mutable QMutex m_mutex;
+};
+
+/**
+ * 录制器音频控制组件
+ * 
+ * 提供音频相关的控制界面,包括:
+ * - 音量控制
+ * - 静音开关
+ * - 音频电平显示
+ * - 音频设备选择
+ * - 音频格式信息
+ */
+class RecorderAudioWidget : public QWidget {
+    Q_OBJECT
+
+public:
+    /**
+     * 音频信息结构
+     */
+    struct AudioInfo {
+        QString deviceName;
+        int sampleRate = 44100;
+        int channels = 2;
+        int bitDepth = 16;
+        QString format;
+        bool isRecording = false;
+        bool isMuted = false;
+        double volume = 1.0;
+        
+        AudioInfo() = default;
+    };
+
+public:
+    explicit RecorderAudioWidget(QWidget* parent = nullptr);
+    ~RecorderAudioWidget();
+
+    /**
+     * 设置音频信息
+     */
+    void setAudioInfo(const AudioInfo& info);
+    
+    /**
+     * 获取音频信息
+     */
+    AudioInfo audioInfo() const { return m_audioInfo; }
+    
+    /**
+     * 设置音量 (0.0 - 1.0)
+     */
+    void setVolume(double volume);
+    
+    /**
+     * 获取音量
+     */
+    double volume() const { return m_audioInfo.volume; }
+    
+    /**
+     * 设置静音状态
+     */
+    void setMuted(bool muted);
+    
+    /**
+     * 获取静音状态
+     */
+    bool isMuted() const { return m_audioInfo.isMuted; }
+    
+    /**
+     * 设置录制状态
+     */
+    void setRecording(bool recording);
+    
+    /**
+     * 获取录制状态
+     */
+    bool isRecording() const { return m_audioInfo.isRecording; }
+    
+    /**
+     * 更新音频电平
+     */
+    void updateAudioLevels(double left, double right);
+    
+    /**
+     * 设置可用音频设备列表
+     */
+    void setAvailableDevices(const QStringList& devices);
+    
+    /**
+     * 设置当前音频设备
+     */
+    void setCurrentDevice(const QString& device);
+    
+    /**
+     * 获取当前音频设备
+     */
+    QString currentDevice() const;
+    
+    /**
+     * 设置是否显示高级控制
+     */
+    void setShowAdvancedControls(bool show);
+    
+    /**
+     * 重置音频电平峰值
+     */
+    void resetAudioPeaks();
+
+signals:
+    /**
+     * 音量改变信号
+     */
+    void volumeChanged(double volume);
+    
+    /**
+     * 静音状态改变信号
+     */
+    void mutedChanged(bool muted);
+    
+    /**
+     * 音频设备改变信号
+     */
+    void deviceChanged(const QString& device);
+    
+    /**
+     * 音频设置改变信号
+     */
+    void audioSettingsRequested();
+
+protected:
+    void paintEvent(QPaintEvent* event) override;
+
+private slots:
+    void onVolumeSliderChanged(int value);
+    void onMuteButtonClicked();
+    void onDeviceComboChanged(const QString& device);
+    void onSettingsButtonClicked();
+    void updateVolumeAnimation();
+
+private:
+    /**
+     * 初始化UI
+     */
+    void initializeUI();
+    
+    /**
+     * 连接信号槽
+     */
+    void connectSignals();
+    
+    /**
+     * 更新UI状态
+     */
+    void updateUI();
+    
+    /**
+     * 更新音量显示
+     */
+    void updateVolumeDisplay();
+    
+    /**
+     * 更新静音按钮
+     */
+    void updateMuteButton();
+    
+    /**
+     * 更新设备信息
+     */
+    void updateDeviceInfo();
+    
+    /**
+     * 格式化音频信息文本
+     */
+    QString formatAudioInfoText() const;
+
+private:
+    // UI组件
+    QVBoxLayout* m_mainLayout;
+    QHBoxLayout* m_controlLayout;
+    QHBoxLayout* m_deviceLayout;
+    QHBoxLayout* m_infoLayout;
+    
+    // 音量控制
+    QLabel* m_volumeLabel;
+    QSlider* m_volumeSlider;
+    QLabel* m_volumeValueLabel;
+    QPushButton* m_muteButton;
+    
+    // 音频电平
+    AudioLevelWidget* m_levelWidget;
+    
+    // 设备选择
+    QLabel* m_deviceLabel;
+    QComboBox* m_deviceCombo;
+    QPushButton* m_settingsButton;
+    
+    // 信息显示
+    QLabel* m_statusLabel;
+    
+    // 数据
+    AudioInfo m_audioInfo;
+    
+    // 动画
+    QPropertyAnimation* m_volumeAnimation;
+    QGraphicsOpacityEffect* m_levelOpacityEffect;
+    
+    // 状态
+    bool m_showAdvancedControls;
+    bool m_volumeChanging;
+    
+    // 线程安全
+    mutable QMutex m_mutex;
+};
+
+#endif // AV_RECORDER_AUDIO_WIDGET_H

+ 866 - 0
AV/code/recorder/ui/recorder_example_app.cpp

@@ -0,0 +1,866 @@
+#include "recorder_example_app.h"
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QScreen>
+#include <QStandardPaths>
+#include <QDir>
+#include <QDateTime>
+#include <QKeySequence>
+#include <QShortcut>
+#include <QStorageInfo>
+#include <QDebug>
+
+RecorderExampleApp::RecorderExampleApp(QWidget* parent)
+    : QMainWindow(parent)
+    , m_recorderWidget(nullptr)
+    , m_centralWidget(nullptr)
+    , m_mainLayout(nullptr)
+    , m_mainSplitter(nullptr)
+    , m_menuBar(nullptr)
+    , m_fileMenu(nullptr)
+    , m_recordMenu(nullptr)
+    , m_viewMenu(nullptr)
+    , m_helpMenu(nullptr)
+    , m_mainToolBar(nullptr)
+    , m_recordToolBar(nullptr)
+    , m_statusBar(nullptr)
+    , m_statusLabel(nullptr)
+    , m_recordingTimeLabel(nullptr)
+    , m_fileSizeLabel(nullptr)
+    , m_bitrateLabel(nullptr)
+    , m_diskSpaceLabel(nullptr)
+    , m_recordingProgress(nullptr)
+    , m_trayIcon(nullptr)
+    , m_trayMenu(nullptr)
+    , m_showHideAction(nullptr)
+    , m_trayExitAction(nullptr)
+    , m_statusUpdateTimer(nullptr)
+    , m_recordingTimer(nullptr)
+    , m_diskSpaceTimer(nullptr)
+    , m_isRecording(false)
+    , m_isPaused(false)
+    , m_isPreviewActive(false)
+    , m_recordingStartTime(0)
+    , m_recordingDuration(0)
+    , m_settings(nullptr)
+    , m_minimizeToTray(true)
+    , m_closeToTray(true)
+    , m_autoStartPreview(false)
+    , m_showRecordingTime(true)
+    , m_showFileSize(true)
+    , m_showBitrate(true)
+    , m_showDiskSpace(true) {
+    
+    setWindowTitle("AV录制器示例应用");
+    setWindowIcon(QIcon(":/icons/recorder.png"));
+    resize(1200, 800);
+    
+    // 居中显示
+    QScreen* screen = QApplication::primaryScreen();
+    if (screen) {
+        QRect screenGeometry = screen->availableGeometry();
+        int x = (screenGeometry.width() - width()) / 2;
+        int y = (screenGeometry.height() - height()) / 2;
+        move(x, y);
+    }
+    
+    // 初始化设置
+    m_settings = new QSettings("AV", "RecorderExample", this);
+    
+    // RecorderModule已移除,现在使用RecorderMainWidget内部的录制器
+    
+    // 初始化UI
+    initializeUI();
+    connectSignals();
+    setupShortcuts();
+    
+    // 加载设置
+    loadSettings();
+    
+    // 初始化定时器
+    m_statusUpdateTimer = new QTimer(this);
+    m_statusUpdateTimer->setInterval(1000); // 每秒更新一次
+    connect(m_statusUpdateTimer, &QTimer::timeout, this, &RecorderExampleApp::updateStatusBar);
+    m_statusUpdateTimer->start();
+    
+    m_recordingTimer = new QTimer(this);
+    m_recordingTimer->setInterval(1000); // 每秒更新一次
+    connect(m_recordingTimer, &QTimer::timeout, this, &RecorderExampleApp::updateRecordingTime);
+    
+    m_diskSpaceTimer = new QTimer(this);
+    m_diskSpaceTimer->setInterval(30000); // 每30秒检查一次磁盘空间
+    connect(m_diskSpaceTimer, &QTimer::timeout, this, &RecorderExampleApp::checkDiskSpace);
+    m_diskSpaceTimer->start();
+    
+    // 创建系统托盘
+    if (QSystemTrayIcon::isSystemTrayAvailable()) {
+        createSystemTray();
+    }
+    
+    // 初始化UI状态
+    updateUI();
+    
+    // 自动开始预览
+    if (m_autoStartPreview) {
+        QTimer::singleShot(1000, this, &RecorderExampleApp::onStartPreview);
+    }
+}
+
+RecorderExampleApp::~RecorderExampleApp() {
+    saveSettings();
+    
+    // RecorderModule清理代码已移除
+}
+
+void RecorderExampleApp::closeEvent(QCloseEvent* event) {
+    if (m_closeToTray && m_trayIcon && m_trayIcon->isVisible()) {
+        hide();
+        showMessage("录制器", "应用程序已最小化到系统托盘", QSystemTrayIcon::Information);
+        event->ignore();
+    } else {
+        if (confirmExit()) {
+            saveSettings();
+            event->accept();
+        } else {
+            event->ignore();
+        }
+    }
+}
+
+void RecorderExampleApp::changeEvent(QEvent* event) {
+    QMainWindow::changeEvent(event);
+    
+    if (event->type() == QEvent::WindowStateChange) {
+        if (isMinimized() && m_minimizeToTray && m_trayIcon && m_trayIcon->isVisible()) {
+            hide();
+            event->ignore();
+        }
+    }
+}
+
+bool RecorderExampleApp::eventFilter(QObject* obj, QEvent* event) {
+    Q_UNUSED(obj)
+    Q_UNUSED(event)
+    return QMainWindow::eventFilter(obj, event);
+}
+
+void RecorderExampleApp::onNewRecording() {
+    if (m_isRecording) {
+        int ret = QMessageBox::question(this, "新建录制", 
+                                       "当前正在录制,是否停止当前录制并开始新的录制?",
+                                       QMessageBox::Yes | QMessageBox::No,
+                                       QMessageBox::No);
+        if (ret == QMessageBox::Yes) {
+            onStopRecording();
+        } else {
+            return;
+        }
+    }
+    
+    // 重置状态
+    m_currentRecordingFile.clear();
+    m_recordingDuration = 0;
+    updateWindowTitle();
+    updateUI();
+}
+
+void RecorderExampleApp::onOpenRecording() {
+    QString fileName = QFileDialog::getOpenFileName(this, "打开录制文件", 
+                                                   QStandardPaths::writableLocation(QStandardPaths::MoviesLocation),
+                                                   "视频文件 (*.mp4 *.avi *.mkv *.mov);;所有文件 (*.*)");
+    
+    if (!fileName.isEmpty()) {
+        // TODO: 实现播放录制文件的功能
+        QMessageBox::information(this, "打开录制文件", 
+                                 QString("将打开文件: %1\n\n此功能待实现").arg(fileName));
+    }
+}
+
+void RecorderExampleApp::onSaveRecording() {
+    if (m_currentRecordingFile.isEmpty()) {
+        QMessageBox::information(this, "保存录制", "当前没有录制文件");
+        return;
+    }
+    
+    QString fileName = QFileDialog::getSaveFileName(this, "保存录制文件", 
+                                                   m_currentRecordingFile,
+                                                   "视频文件 (*.mp4 *.avi *.mkv *.mov);;所有文件 (*.*)");
+    
+    if (!fileName.isEmpty() && fileName != m_currentRecordingFile) {
+        // TODO: 实现文件复制或移动
+        QMessageBox::information(this, "保存录制文件", 
+                                 QString("将保存到: %1\n\n此功能待实现").arg(fileName));
+    }
+}
+
+void RecorderExampleApp::onExportRecording() {
+    if (m_currentRecordingFile.isEmpty()) {
+        QMessageBox::information(this, "导出录制", "当前没有录制文件");
+        return;
+    }
+    
+    // TODO: 实现录制文件导出功能
+    QMessageBox::information(this, "导出录制文件", "导出功能待实现");
+}
+
+void RecorderExampleApp::onSettings() {
+    if (m_recorderWidget) {
+        m_recorderWidget->openSettings();
+    }
+}
+
+void RecorderExampleApp::onAbout() {
+    QMessageBox::about(this, "关于 AV录制器", 
+                      "<h3>AV录制器示例应用</h3>"
+                      "<p>版本: 1.0.0</p>"
+                      "<p>这是一个基于重构后的AV录制器模块的示例应用程序。</p>"
+                      "<p>功能特性:</p>"
+                      "<ul>"
+                      "<li>音频录制</li>"
+                      "<li>视频录制</li>"
+                      "<li>音视频同步录制</li>"
+                      "<li>实时预览</li>"
+                      "<li>硬件加速</li>"
+                      "<li>多种编码格式支持</li>"
+                      "</ul>"
+                      "<p>© 2024 AV录制器团队</p>");
+}
+
+void RecorderExampleApp::onExit() {
+    if (confirmExit()) {
+        QApplication::quit();
+    }
+}
+
+void RecorderExampleApp::onStartRecording() {
+    if (m_recorderWidget) {
+        m_recorderWidget->startRecording();
+    }
+}
+
+void RecorderExampleApp::onStopRecording() {
+    if (m_recorderWidget) {
+        m_recorderWidget->stopRecording();
+    }
+}
+
+void RecorderExampleApp::onPauseRecording() {
+    if (m_recorderWidget) {
+        m_recorderWidget->pauseRecording();
+    }
+}
+
+void RecorderExampleApp::onResumeRecording() {
+    if (m_recorderWidget) {
+        m_recorderWidget->resumeRecording();
+    }
+}
+
+void RecorderExampleApp::onStartPreview() {
+    if (m_recorderWidget) {
+        m_recorderWidget->startPreview();
+    }
+}
+
+void RecorderExampleApp::onStopPreview() {
+    if (m_recorderWidget) {
+        m_recorderWidget->stopPreview();
+    }
+}
+
+void RecorderExampleApp::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) {
+    switch (reason) {
+    case QSystemTrayIcon::Trigger:
+    case QSystemTrayIcon::DoubleClick:
+        onShowHide();
+        break;
+    default:
+        break;
+    }
+}
+
+void RecorderExampleApp::onShowHide() {
+    if (isVisible()) {
+        hide();
+    } else {
+        show();
+        raise();
+        activateWindow();
+    }
+}
+
+// 录制器状态变化处理函数已移除
+// 现在应该连接到RecorderMainWidget的相应信号
+
+// 录制器错误和统计信息处理函数已移除
+// 现在应该连接到RecorderMainWidget的相应信号
+
+void RecorderExampleApp::updateStatusBar() {
+    if (!m_statusBar) return;
+    
+    // 更新状态标签
+    if (m_statusLabel) {
+        QString status;
+        if (m_isRecording) {
+            status = m_isPaused ? "录制已暂停" : "正在录制";
+        } else if (m_isPreviewActive) {
+            status = "预览中";
+        } else {
+            status = "就绪";
+        }
+        m_statusLabel->setText(status);
+    }
+    
+    // 更新磁盘空间
+    if (m_diskSpaceLabel && m_showDiskSpace) {
+        checkDiskSpace();
+    }
+}
+
+void RecorderExampleApp::updateRecordingTime() {
+    if (!m_isRecording || m_isPaused) return;
+    
+    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
+    m_recordingDuration = (currentTime - m_recordingStartTime) / 1000;
+    
+    if (m_recordingTimeLabel && m_showRecordingTime) {
+        m_recordingTimeLabel->setText(QString("录制时间: %1").arg(formatTime(m_recordingDuration)));
+    }
+    
+    // 更新进度条(如果设置了最大录制时长)
+    if (m_recordingProgress) {
+        // TODO: 根据设置的最大录制时长更新进度
+    }
+}
+
+void RecorderExampleApp::checkDiskSpace() {
+    if (!m_diskSpaceLabel || !m_showDiskSpace) return;
+    
+    QString outputDir = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
+    QStorageInfo storage(outputDir);
+    
+    if (storage.isValid()) {
+        qint64 availableBytes = storage.bytesAvailable();
+        QString diskSpace = QString("可用空间: %1").arg(formatFileSize(availableBytes));
+        m_diskSpaceLabel->setText(diskSpace);
+        
+        // 检查磁盘空间是否不足(小于1GB)
+        if (availableBytes < 1024 * 1024 * 1024) {
+            m_diskSpaceLabel->setStyleSheet("color: red;");
+            if (m_isRecording) {
+                showMessage("磁盘空间不足", "可用磁盘空间不足1GB,建议停止录制", QSystemTrayIcon::Warning);
+            }
+        } else {
+            m_diskSpaceLabel->setStyleSheet("");
+        }
+    }
+}
+
+void RecorderExampleApp::initializeUI() {
+    // 创建中央部件
+    m_centralWidget = new QWidget();
+    setCentralWidget(m_centralWidget);
+    
+    // 创建主布局
+    m_mainLayout = new QVBoxLayout(m_centralWidget);
+    m_mainLayout->setContentsMargins(4, 4, 4, 4);
+    m_mainLayout->setSpacing(4);
+    
+    // 创建录制器主部件
+    m_recorderWidget = new RecorderMainWidget(this);
+    
+    // 初始化录制器主部件
+    if (!m_recorderWidget->initialize()) {
+        QMessageBox::critical(this, "错误", "初始化录制器失败");
+        // 可以选择退出应用或者禁用录制功能
+    }
+    
+    // 添加到布局
+    m_mainLayout->addWidget(m_recorderWidget);
+    
+    // 创建菜单栏
+    createMenuBar();
+    
+    // 创建工具栏
+    createToolBar();
+    
+    // 创建状态栏
+    createStatusBar();
+    
+    // 设置样式
+    // setStyleSheet(R"(
+    //     QMainWindow {
+    //         background-color: #2b2b2b;
+    //         color: #fff;
+    //     }
+    //     QMenuBar {
+    //         background-color: #333;
+    //         color: #fff;
+    //         border-bottom: 1px solid #555;
+    //     }
+    //     QMenuBar::item {
+    //         background-color: transparent;
+    //         padding: 4px 8px;
+    //     }
+    //     QMenuBar::item:selected {
+    //         background-color: #0a84ff;
+    //     }
+    //     QMenu {
+    //         background-color: #333;
+    //         color: #fff;
+    //         border: 1px solid #555;
+    //     }
+    //     QMenu::item {
+    //         padding: 4px 20px;
+    //     }
+    //     QMenu::item:selected {
+    //         background-color: #0a84ff;
+    //     }
+    //     QToolBar {
+    //         background-color: #333;
+    //         border: 1px solid #555;
+    //         spacing: 2px;
+    //     }
+    //     QToolButton {
+    //         background-color: #444;
+    //         border: 1px solid #666;
+    //         border-radius: 3px;
+    //         color: #fff;
+    //         padding: 4px;
+    //     }
+    //     QToolButton:hover {
+    //         background-color: #555;
+    //     }
+    //     QToolButton:pressed {
+    //         background-color: #333;
+    //     }
+    //     QStatusBar {
+    //         background-color: #333;
+    //         color: #fff;
+    //         border-top: 1px solid #555;
+    //     }
+    //     QLabel {
+    //         color: #fff;
+    //     }
+    //     QProgressBar {
+    //         border: 1px solid #555;
+    //         border-radius: 3px;
+    //         background-color: #444;
+    //         text-align: center;
+    //     }
+    //     QProgressBar::chunk {
+    //         background-color: #0a84ff;
+    //         border-radius: 2px;
+    //     }
+    // )");
+}
+
+void RecorderExampleApp::createMenuBar() {
+    m_menuBar = menuBar();
+    
+    // 文件菜单
+    m_fileMenu = m_menuBar->addMenu("文件(&F)");
+    
+    m_newAction = new QAction(QIcon(":/icons/new.png"), "新建录制(&N)", this);
+    m_newAction->setShortcut(QKeySequence::New);
+    m_newAction->setStatusTip("开始新的录制");
+    
+    m_openAction = new QAction(QIcon(":/icons/open.png"), "打开录制(&O)", this);
+    m_openAction->setShortcut(QKeySequence::Open);
+    m_openAction->setStatusTip("打开录制文件");
+    
+    m_saveAction = new QAction(QIcon(":/icons/save.png"), "保存录制(&S)", this);
+    m_saveAction->setShortcut(QKeySequence::Save);
+    m_saveAction->setStatusTip("保存当前录制");
+    
+    m_exportAction = new QAction(QIcon(":/icons/export.png"), "导出录制(&E)", this);
+    m_exportAction->setStatusTip("导出录制文件");
+    
+    m_fileMenu->addAction(m_newAction);
+    m_fileMenu->addSeparator();
+    m_fileMenu->addAction(m_openAction);
+    m_fileMenu->addAction(m_saveAction);
+    m_fileMenu->addAction(m_exportAction);
+    m_fileMenu->addSeparator();
+    
+    m_settingsAction = new QAction(QIcon(":/icons/settings.png"), "设置(&T)", this);
+    m_settingsAction->setShortcut(QKeySequence::Preferences);
+    m_settingsAction->setStatusTip("打开设置对话框");
+    m_fileMenu->addAction(m_settingsAction);
+    
+    m_fileMenu->addSeparator();
+    
+    m_exitAction = new QAction(QIcon(":/icons/exit.png"), "退出(&X)", this);
+    m_exitAction->setShortcut(QKeySequence::Quit);
+    m_exitAction->setStatusTip("退出应用程序");
+    m_fileMenu->addAction(m_exitAction);
+    
+    // 录制菜单
+    m_recordMenu = m_menuBar->addMenu("录制(&R)");
+    
+    m_startRecordingAction = new QAction(QIcon(":/icons/record.png"), "开始录制(&S)", this);
+    m_startRecordingAction->setShortcut(QKeySequence("F9"));
+    m_startRecordingAction->setStatusTip("开始录制");
+    
+    m_stopRecordingAction = new QAction(QIcon(":/icons/stop.png"), "停止录制(&T)", this);
+    m_stopRecordingAction->setShortcut(QKeySequence("F10"));
+    m_stopRecordingAction->setStatusTip("停止录制");
+    m_stopRecordingAction->setEnabled(false);
+    
+    m_pauseRecordingAction = new QAction(QIcon(":/icons/pause.png"), "暂停录制(&P)", this);
+    m_pauseRecordingAction->setShortcut(QKeySequence("F11"));
+    m_pauseRecordingAction->setStatusTip("暂停录制");
+    m_pauseRecordingAction->setEnabled(false);
+    
+    m_resumeRecordingAction = new QAction(QIcon(":/icons/resume.png"), "恢复录制(&R)", this);
+    m_resumeRecordingAction->setShortcut(QKeySequence("F12"));
+    m_resumeRecordingAction->setStatusTip("恢复录制");
+    m_resumeRecordingAction->setEnabled(false);
+    
+    m_recordMenu->addAction(m_startRecordingAction);
+    m_recordMenu->addAction(m_stopRecordingAction);
+    m_recordMenu->addSeparator();
+    m_recordMenu->addAction(m_pauseRecordingAction);
+    m_recordMenu->addAction(m_resumeRecordingAction);
+    m_recordMenu->addSeparator();
+    
+    m_startPreviewAction = new QAction(QIcon(":/icons/preview.png"), "开始预览(&V)", this);
+    m_startPreviewAction->setStatusTip("开始视频预览");
+    
+    m_stopPreviewAction = new QAction(QIcon(":/icons/stop_preview.png"), "停止预览(&W)", this);
+    m_stopPreviewAction->setStatusTip("停止视频预览");
+    m_stopPreviewAction->setEnabled(false);
+    
+    m_recordMenu->addAction(m_startPreviewAction);
+    m_recordMenu->addAction(m_stopPreviewAction);
+    
+    // 视图菜单
+    m_viewMenu = m_menuBar->addMenu("视图(&V)");
+    
+    // 自动启动预览选项
+    QAction* autoPreviewAction = new QAction("自动启动预览(&P)", this);
+    autoPreviewAction->setCheckable(true);
+    autoPreviewAction->setChecked(m_autoStartPreview);
+    connect(autoPreviewAction, &QAction::toggled, this, [this](bool checked) {
+        m_autoStartPreview = checked;
+        m_settings->setValue("autoStartPreview", m_autoStartPreview);
+    });
+    m_viewMenu->addAction(autoPreviewAction);
+    
+    // 帮助菜单
+    m_helpMenu = m_menuBar->addMenu("帮助(&H)");
+    
+    m_aboutAction = new QAction(QIcon(":/icons/about.png"), "关于(&A)", this);
+    m_aboutAction->setStatusTip("关于此应用程序");
+    
+    m_aboutQtAction = new QAction("关于Qt(&Q)", this);
+    m_aboutQtAction->setStatusTip("关于Qt框架");
+    
+    m_helpMenu->addAction(m_aboutAction);
+    m_helpMenu->addAction(m_aboutQtAction);
+}
+
+void RecorderExampleApp::createToolBar() {
+    // 主工具栏
+    m_mainToolBar = addToolBar("主工具栏");
+    m_mainToolBar->setObjectName("MainToolBar");
+    m_mainToolBar->addAction(m_newAction);
+    m_mainToolBar->addAction(m_openAction);
+    m_mainToolBar->addAction(m_saveAction);
+    m_mainToolBar->addSeparator();
+    m_mainToolBar->addAction(m_settingsAction);
+    
+    // 录制工具栏
+    m_recordToolBar = addToolBar("录制工具栏");
+    m_recordToolBar->setObjectName("RecordToolBar");
+    m_recordToolBar->addAction(m_startRecordingAction);
+    m_recordToolBar->addAction(m_stopRecordingAction);
+    m_recordToolBar->addAction(m_pauseRecordingAction);
+    m_recordToolBar->addAction(m_resumeRecordingAction);
+    m_recordToolBar->addSeparator();
+    m_recordToolBar->addAction(m_startPreviewAction);
+    m_recordToolBar->addAction(m_stopPreviewAction);
+}
+
+void RecorderExampleApp::createStatusBar() {
+    m_statusBar = statusBar();
+    
+    // 状态标签
+    m_statusLabel = new QLabel("就绪");
+    m_statusBar->addWidget(m_statusLabel);
+    
+    m_statusBar->addPermanentWidget(new QLabel("|"));
+    
+    // 录制时间
+    if (m_showRecordingTime) {
+        m_recordingTimeLabel = new QLabel("录制时间: 00:00:00");
+        m_statusBar->addPermanentWidget(m_recordingTimeLabel);
+        m_statusBar->addPermanentWidget(new QLabel("|"));
+    }
+    
+    // 文件大小
+    if (m_showFileSize) {
+        m_fileSizeLabel = new QLabel("文件大小: 0 MB");
+        m_statusBar->addPermanentWidget(m_fileSizeLabel);
+        m_statusBar->addPermanentWidget(new QLabel("|"));
+    }
+    
+    // 比特率
+    if (m_showBitrate) {
+        m_bitrateLabel = new QLabel("比特率: 0 kbps");
+        m_statusBar->addPermanentWidget(m_bitrateLabel);
+        m_statusBar->addPermanentWidget(new QLabel("|"));
+    }
+    
+    // 磁盘空间
+    if (m_showDiskSpace) {
+        m_diskSpaceLabel = new QLabel("可用空间: 检查中...");
+        m_statusBar->addPermanentWidget(m_diskSpaceLabel);
+    }
+    
+    // 录制进度条
+    m_recordingProgress = new QProgressBar();
+    m_recordingProgress->setVisible(false);
+    m_recordingProgress->setMaximumWidth(200);
+    m_statusBar->addPermanentWidget(m_recordingProgress);
+}
+
+void RecorderExampleApp::createSystemTray() {
+    if (!QSystemTrayIcon::isSystemTrayAvailable()) {
+        return;
+    }
+    
+    // 创建托盘图标
+    m_trayIcon = new QSystemTrayIcon(this);
+    m_trayIcon->setIcon(QIcon(":/icons/recorder.png"));
+    m_trayIcon->setToolTip("AV录制器");
+    
+    // 创建托盘菜单
+    m_trayMenu = new QMenu(this);
+    
+    m_showHideAction = new QAction("显示/隐藏", this);
+    m_trayMenu->addAction(m_showHideAction);
+    m_trayMenu->addSeparator();
+    
+    m_trayMenu->addAction(m_startRecordingAction);
+    m_trayMenu->addAction(m_stopRecordingAction);
+    m_trayMenu->addSeparator();
+    
+    m_trayExitAction = new QAction("退出", this);
+    m_trayMenu->addAction(m_trayExitAction);
+    
+    m_trayIcon->setContextMenu(m_trayMenu);
+    m_trayIcon->show();
+}
+
+void RecorderExampleApp::setupShortcuts() {
+    // 全局快捷键
+    QShortcut* quickRecordShortcut = new QShortcut(QKeySequence("Ctrl+Shift+R"), this);
+    connect(quickRecordShortcut, &QShortcut::activated, [this]() {
+        if (m_isRecording) {
+            onStopRecording();
+        } else {
+            onStartRecording();
+        }
+    });
+    
+    QShortcut* quickPreviewShortcut = new QShortcut(QKeySequence("Ctrl+Shift+P"), this);
+    connect(quickPreviewShortcut, &QShortcut::activated, [this]() {
+        if (m_isPreviewActive) {
+            onStopPreview();
+        } else {
+            onStartPreview();
+        }
+    });
+}
+
+void RecorderExampleApp::connectSignals() {
+    // 菜单和工具栏信号
+    connect(m_newAction, &QAction::triggered, this, &RecorderExampleApp::onNewRecording);
+    connect(m_openAction, &QAction::triggered, this, &RecorderExampleApp::onOpenRecording);
+    connect(m_saveAction, &QAction::triggered, this, &RecorderExampleApp::onSaveRecording);
+    connect(m_exportAction, &QAction::triggered, this, &RecorderExampleApp::onExportRecording);
+    connect(m_settingsAction, &QAction::triggered, this, &RecorderExampleApp::onSettings);
+    connect(m_exitAction, &QAction::triggered, this, &RecorderExampleApp::onExit);
+    
+    connect(m_startRecordingAction, &QAction::triggered, this, &RecorderExampleApp::onStartRecording);
+    connect(m_stopRecordingAction, &QAction::triggered, this, &RecorderExampleApp::onStopRecording);
+    connect(m_pauseRecordingAction, &QAction::triggered, this, &RecorderExampleApp::onPauseRecording);
+    connect(m_resumeRecordingAction, &QAction::triggered, this, &RecorderExampleApp::onResumeRecording);
+    connect(m_startPreviewAction, &QAction::triggered, this, &RecorderExampleApp::onStartPreview);
+    connect(m_stopPreviewAction, &QAction::triggered, this, &RecorderExampleApp::onStopPreview);
+    
+    connect(m_aboutAction, &QAction::triggered, this, &RecorderExampleApp::onAbout);
+    connect(m_aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt);
+    
+    // 系统托盘信号
+    if (m_trayIcon) {
+        connect(m_trayIcon, &QSystemTrayIcon::activated, this, &RecorderExampleApp::onTrayIconActivated);
+    }
+    if (m_showHideAction) {
+        connect(m_showHideAction, &QAction::triggered, this, &RecorderExampleApp::onShowHide);
+    }
+    if (m_trayExitAction) {
+        connect(m_trayExitAction, &QAction::triggered, this, &RecorderExampleApp::onExit);
+    }
+    
+    // 录制器主部件信号
+    if (m_recorderWidget) {
+        // TODO: 连接RecorderMainWidget的信号
+        // connect(m_recorderWidget, &RecorderMainWidget::someSignal, 
+        //         this, &RecorderExampleApp::someSlot);
+    }
+}
+
+void RecorderExampleApp::loadSettings() {
+    // 窗口设置
+    restoreGeometry(m_settings->value("geometry").toByteArray());
+    restoreState(m_settings->value("windowState").toByteArray());
+    
+    // 应用设置
+    m_minimizeToTray = m_settings->value("minimizeToTray", true).toBool();
+    m_closeToTray = m_settings->value("closeToTray", true).toBool();
+    m_autoStartPreview = m_settings->value("autoStartPreview", true).toBool();
+    
+    // 状态栏设置
+    m_showRecordingTime = m_settings->value("showRecordingTime", true).toBool();
+    m_showFileSize = m_settings->value("showFileSize", true).toBool();
+    m_showBitrate = m_settings->value("showBitrate", true).toBool();
+    m_showDiskSpace = m_settings->value("showDiskSpace", true).toBool();
+}
+
+void RecorderExampleApp::saveSettings() {
+    // 窗口设置
+    m_settings->setValue("geometry", saveGeometry());
+    m_settings->setValue("windowState", saveState());
+    
+    // 应用设置
+    m_settings->setValue("minimizeToTray", m_minimizeToTray);
+    m_settings->setValue("closeToTray", m_closeToTray);
+    m_settings->setValue("autoStartPreview", m_autoStartPreview);
+    
+    // 状态栏设置
+    m_settings->setValue("showRecordingTime", m_showRecordingTime);
+    m_settings->setValue("showFileSize", m_showFileSize);
+    m_settings->setValue("showBitrate", m_showBitrate);
+    m_settings->setValue("showDiskSpace", m_showDiskSpace);
+    
+    m_settings->sync();
+}
+
+void RecorderExampleApp::updateUI() {
+    // 更新动作状态
+    updateActions();
+    
+    // 更新窗口标题
+    updateWindowTitle();
+}
+
+void RecorderExampleApp::updateActions() {
+    // 录制相关动作
+    m_startRecordingAction->setEnabled(!m_isRecording);
+    m_stopRecordingAction->setEnabled(m_isRecording);
+    m_pauseRecordingAction->setEnabled(m_isRecording && !m_isPaused);
+    m_resumeRecordingAction->setEnabled(m_isRecording && m_isPaused);
+    
+    // 预览相关动作
+    m_startPreviewAction->setEnabled(!m_isPreviewActive);
+    m_stopPreviewAction->setEnabled(m_isPreviewActive);
+    
+    // 文件相关动作
+    m_saveAction->setEnabled(!m_currentRecordingFile.isEmpty());
+    m_exportAction->setEnabled(!m_currentRecordingFile.isEmpty());
+}
+
+void RecorderExampleApp::updateWindowTitle() {
+    QString title = "AV录制器示例应用";
+    
+    if (m_isRecording) {
+        if (m_isPaused) {
+            title += " - 录制已暂停";
+        } else {
+            title += " - 正在录制";
+        }
+        
+        if (m_recordingDuration > 0) {
+            title += QString(" (%1)").arg(formatTime(m_recordingDuration));
+        }
+    } else if (m_isPreviewActive) {
+        title += " - 预览中";
+    }
+    
+    if (!m_currentRecordingFile.isEmpty()) {
+        QFileInfo fileInfo(m_currentRecordingFile);
+        title += QString(" - %1").arg(fileInfo.fileName());
+    }
+    
+    setWindowTitle(title);
+}
+
+QString RecorderExampleApp::formatTime(qint64 seconds) const {
+    int hours = seconds / 3600;
+    int minutes = (seconds % 3600) / 60;
+    int secs = seconds % 60;
+    
+    return QString("%1:%2:%3")
+           .arg(hours, 2, 10, QChar('0'))
+           .arg(minutes, 2, 10, QChar('0'))
+           .arg(secs, 2, 10, QChar('0'));
+}
+
+QString RecorderExampleApp::formatFileSize(qint64 bytes) const {
+    const qint64 KB = 1024;
+    const qint64 MB = KB * 1024;
+    const qint64 GB = MB * 1024;
+    const qint64 TB = GB * 1024;
+    
+    if (bytes >= TB) {
+        return QString("%1 TB").arg(static_cast<double>(bytes) / TB, 0, 'f', 2);
+    } else if (bytes >= GB) {
+        return QString("%1 GB").arg(static_cast<double>(bytes) / GB, 0, 'f', 2);
+    } else if (bytes >= MB) {
+        return QString("%1 MB").arg(static_cast<double>(bytes) / MB, 0, 'f', 2);
+    } else if (bytes >= KB) {
+        return QString("%1 KB").arg(static_cast<double>(bytes) / KB, 0, 'f', 2);
+    } else {
+        return QString("%1 B").arg(bytes);
+    }
+}
+
+QString RecorderExampleApp::formatBitrate(qint64 bps) const {
+    const qint64 Kbps = 1000;
+    const qint64 Mbps = Kbps * 1000;
+    
+    if (bps >= Mbps) {
+        return QString("%1 Mbps").arg(static_cast<double>(bps) / Mbps, 0, 'f', 2);
+    } else if (bps >= Kbps) {
+        return QString("%1 kbps").arg(static_cast<double>(bps) / Kbps, 0, 'f', 1);
+    } else {
+        return QString("%1 bps").arg(bps);
+    }
+}
+
+bool RecorderExampleApp::confirmExit() {
+    if (m_isRecording) {
+        int ret = QMessageBox::question(this, "确认退出", 
+                                       "当前正在录制,确定要退出吗?\n录制将被停止。",
+                                       QMessageBox::Yes | QMessageBox::No,
+                                       QMessageBox::No);
+        
+        if (ret == QMessageBox::Yes) {
+            onStopRecording();
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    return true;
+}
+
+void RecorderExampleApp::showMessage(const QString& title, const QString& message, 
+                                    QSystemTrayIcon::MessageIcon icon) {
+    if (m_trayIcon && m_trayIcon->isVisible()) {
+        m_trayIcon->showMessage(title, message, icon, 3000);
+    }
+}

+ 195 - 0
AV/code/recorder/ui/recorder_example_app.h

@@ -0,0 +1,195 @@
+#ifndef RECORDER_EXAMPLE_APP_H
+#define RECORDER_EXAMPLE_APP_H
+
+#include <QMainWindow>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QGridLayout>
+#include <QPushButton>
+#include <QLabel>
+#include <QComboBox>
+#include <QSlider>
+#include <QProgressBar>
+#include <QTextEdit>
+#include <QGroupBox>
+#include <QSplitter>
+#include <QTimer>
+#include <QStatusBar>
+#include <QMenuBar>
+#include <QToolBar>
+#include <QAction>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QSettings>
+#include <QCloseEvent>
+#include <QSystemTrayIcon>
+#include <QMenu>
+
+#include "recorder_main_widget.h"
+#include "../recorder.h"
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QMenu;
+class QSystemTrayIcon;
+QT_END_NAMESPACE
+
+/**
+ * @brief 录制器示例应用程序
+ * 
+ * 这是一个完整的录制器应用程序示例,展示了如何使用重构后的录制器模块。
+ * 提供了完整的用户界面和功能,包括:
+ * - 录制控制(开始/停止/暂停/恢复)
+ * - 实时预览
+ * - 音频控制和电平显示
+ * - 设置管理
+ * - 状态监控
+ * - 系统托盘支持
+ * - 快捷键支持
+ */
+class RecorderExampleApp : public QMainWindow {
+    Q_OBJECT
+
+public:
+    explicit RecorderExampleApp(QWidget* parent = nullptr);
+    ~RecorderExampleApp();
+
+protected:
+    void closeEvent(QCloseEvent* event) override;
+    void changeEvent(QEvent* event) override;
+    bool eventFilter(QObject* obj, QEvent* event) override;
+
+private slots:
+    // 菜单和工具栏操作
+    void onNewRecording();
+    void onOpenRecording();
+    void onSaveRecording();
+    void onExportRecording();
+    void onSettings();
+    void onAbout();
+    void onExit();
+    
+    // 录制控制
+    void onStartRecording();
+    void onStopRecording();
+    void onPauseRecording();
+    void onResumeRecording();
+    void onStartPreview();
+    void onStopPreview();
+    
+    // 系统托盘
+    void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason);
+    void onShowHide();
+    
+    // 录制器状态 (暂时保留,可能需要连接到RecorderMainWidget的信号)
+    // void onRecorderStateChanged(RecorderState state);
+    // void onRecorderError(const QString& error);
+    // void onRecorderStatisticsUpdated(const Statistics& stats);
+    
+    // 定时器
+    void updateStatusBar();
+    void updateRecordingTime();
+    void checkDiskSpace();
+    
+private:
+    void initializeUI();
+    void createMenuBar();
+    void createToolBar();
+    void createStatusBar();
+    void createSystemTray();
+    void setupShortcuts();
+    void connectSignals();
+    
+    void loadSettings();
+    void saveSettings();
+    
+    void updateUI();
+    void updateActions();
+    void updateWindowTitle();
+    
+    QString formatTime(qint64 seconds) const;
+    QString formatFileSize(qint64 bytes) const;
+    QString formatBitrate(qint64 bps) const;
+    
+    bool confirmExit();
+    void showMessage(const QString& title, const QString& message, 
+                    QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information);
+
+private:
+    // 核心组件
+    RecorderMainWidget* m_recorderWidget;
+    // RecorderModule已移除,现在使用RecorderMainWidget内部的录制器
+    
+    // UI组件
+    QWidget* m_centralWidget;
+    QVBoxLayout* m_mainLayout;
+    QSplitter* m_mainSplitter;
+    
+    // 菜单和工具栏
+    QMenuBar* m_menuBar;
+    QMenu* m_fileMenu;
+    QMenu* m_recordMenu;
+    QMenu* m_viewMenu;
+    QMenu* m_helpMenu;
+    
+    QToolBar* m_mainToolBar;
+    QToolBar* m_recordToolBar;
+    
+    // 动作
+    QAction* m_newAction;
+    QAction* m_openAction;
+    QAction* m_saveAction;
+    QAction* m_exportAction;
+    QAction* m_settingsAction;
+    QAction* m_exitAction;
+    
+    QAction* m_startRecordingAction;
+    QAction* m_stopRecordingAction;
+    QAction* m_pauseRecordingAction;
+    QAction* m_resumeRecordingAction;
+    QAction* m_startPreviewAction;
+    QAction* m_stopPreviewAction;
+    
+    QAction* m_aboutAction;
+    QAction* m_aboutQtAction;
+    
+    // 状态栏
+    QStatusBar* m_statusBar;
+    QLabel* m_statusLabel;
+    QLabel* m_recordingTimeLabel;
+    QLabel* m_fileSizeLabel;
+    QLabel* m_bitrateLabel;
+    QLabel* m_diskSpaceLabel;
+    QProgressBar* m_recordingProgress;
+    
+    // 系统托盘
+    QSystemTrayIcon* m_trayIcon;
+    QMenu* m_trayMenu;
+    QAction* m_showHideAction;
+    QAction* m_trayExitAction;
+    
+    // 定时器
+    QTimer* m_statusUpdateTimer;
+    QTimer* m_recordingTimer;
+    QTimer* m_diskSpaceTimer;
+    
+    // 状态
+    bool m_isRecording;
+    bool m_isPaused;
+    bool m_isPreviewActive;
+    qint64 m_recordingStartTime;
+    qint64 m_recordingDuration;
+    QString m_currentRecordingFile;
+    
+    // 设置
+    QSettings* m_settings;
+    bool m_minimizeToTray;
+    bool m_closeToTray;
+    bool m_autoStartPreview;
+    bool m_showRecordingTime;
+    bool m_showFileSize;
+    bool m_showBitrate;
+    bool m_showDiskSpace;
+};
+
+#endif // RECORDER_EXAMPLE_APP_H

+ 136 - 0
AV/code/recorder/ui/recorder_main.cpp

@@ -0,0 +1,136 @@
+#include <QApplication>
+#include <QDebug>
+#include <QDir>
+#include <QFontDatabase>
+#include <QPixmap>
+#include <QSplashScreen>
+#include <QStandardPaths>
+#include <QStyleFactory>
+#include <QTimer>
+#include "qthread.h"
+#include "recorder_example_app.h"
+
+int main(int argc, char *argv[])
+{ // 启用高DPI支持
+    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+
+    QApplication app(argc, argv);
+    av::Logger::initialize("test_log.txt", av::LogLevel::DEBUG, false, true);
+    // 设置应用程序信息
+    app.setApplicationName("AV录制器示例应用");
+    app.setApplicationVersion("1.0.0");
+    app.setApplicationDisplayName("AV录制器");
+    app.setOrganizationName("AV");
+    app.setOrganizationDomain("av.com");
+    
+    // 设置应用程序图标
+    app.setWindowIcon(QIcon(":/icons/recorder.png"));
+
+    // 设置样式
+    // app.setStyle(QStyleFactory::create("Fusion"));
+
+    // 创建启动画面
+    QPixmap splashPixmap(400, 300);
+    splashPixmap.fill(QColor(43, 43, 43)); // 深色背景
+    
+    QPainter painter(&splashPixmap);
+    painter.setRenderHint(QPainter::Antialiasing);
+    
+    // 绘制标题
+    QFont titleFont("Arial", 24, QFont::Bold);
+    painter.setFont(titleFont);
+    painter.setPen(QColor(255, 255, 255));
+    painter.drawText(splashPixmap.rect(), Qt::AlignCenter, "AV录制器");
+    
+    // 绘制版本信息
+    QFont versionFont("Arial", 12);
+    painter.setFont(versionFont);
+    painter.setPen(QColor(200, 200, 200));
+    QRect versionRect = splashPixmap.rect();
+    versionRect.setTop(versionRect.center().y() + 30);
+    painter.drawText(versionRect, Qt::AlignCenter, "版本 1.0.0");
+    
+    // 绘制加载信息
+    QFont loadingFont("Arial", 10);
+    painter.setFont(loadingFont);
+    painter.setPen(QColor(150, 150, 150));
+    QRect loadingRect = splashPixmap.rect();
+    loadingRect.setTop(loadingRect.bottom() - 40);
+    painter.drawText(loadingRect, Qt::AlignCenter, "正在初始化...");
+    
+    QSplashScreen splash(splashPixmap);
+    splash.show();
+    
+    // 处理事件以显示启动画面
+    app.processEvents();
+    
+    // 模拟初始化过程
+    splash.showMessage("正在加载录制器模块...", Qt::AlignBottom | Qt::AlignCenter, Qt::white);
+    app.processEvents();
+    QThread::msleep(100);
+
+    splash.showMessage("正在初始化音频系统...", Qt::AlignBottom | Qt::AlignCenter, Qt::white);
+    app.processEvents();
+    QThread::msleep(100);
+
+    splash.showMessage("正在初始化视频系统...", Qt::AlignBottom | Qt::AlignCenter, Qt::white);
+    app.processEvents();
+    QThread::msleep(100);
+
+    splash.showMessage("正在加载用户界面...", Qt::AlignBottom | Qt::AlignCenter, Qt::white);
+    app.processEvents();
+    QThread::msleep(100);
+
+    // 创建并显示主窗口
+    RecorderExampleApp mainWindow;
+    
+    splash.showMessage("启动完成", Qt::AlignBottom | Qt::AlignCenter, Qt::white);
+    app.processEvents();
+    QThread::msleep(200);
+    
+    splash.finish(&mainWindow);
+    mainWindow.show();
+    
+    // 检查命令行参数
+    QStringList arguments = app.arguments();
+    for (int i = 1; i < arguments.size(); ++i) {
+        const QString& arg = arguments.at(i);
+        Q_UNUSED(arg); // 标记变量为未使用,避免编译警告
+
+        // if (arg == "--start-recording" || arg == "-r") {
+        //     // 自动开始录制
+        //     QTimer::singleShot(1000, &mainWindow, &RecorderExampleApp::onStartRecording);
+        // } else if (arg == "--start-preview" || arg == "-p") {
+        //     // 自动开始预览
+        //     QTimer::singleShot(1000, &mainWindow, &RecorderExampleApp::onStartPreview);
+        // } else if (arg == "--minimized" || arg == "-m") {
+        //     // 最小化启动
+        //     mainWindow.showMinimized();
+        // } else if (arg == "--help" || arg == "-h") {
+        //     // 显示帮助信息
+        //     qDebug() << "AV录制器示例应用 v1.0.0";
+        //     qDebug() << "";
+        //     qDebug() << "用法: recorder_example [选项]";
+        //     qDebug() << "";
+        //     qDebug() << "选项:";
+        //     qDebug() << "  -r, --start-recording    启动后自动开始录制";
+        //     qDebug() << "  -p, --start-preview      启动后自动开始预览";
+        //     qDebug() << "  -m, --minimized          最小化启动";
+        //     qDebug() << "  -h, --help               显示此帮助信息";
+        //     qDebug() << "";
+        //     qDebug() << "快捷键:";
+        //     qDebug() << "  F9                       开始录制";
+        //     qDebug() << "  F10                      停止录制";
+        //     qDebug() << "  F11                      暂停录制";
+        //     qDebug() << "  F12                      恢复录制";
+        //     qDebug() << "  Ctrl+Shift+R             快速录制开关";
+        //     qDebug() << "  Ctrl+Shift+P             快速预览开关";
+        //     qDebug() << "  Ctrl+T                   打开设置";
+        //     qDebug() << "  Ctrl+Q                   退出应用";
+        //     return 0;
+        // }
+    }
+    
+    return app.exec();
+}

+ 1297 - 0
AV/code/recorder/ui/recorder_main_widget.cpp

@@ -0,0 +1,1297 @@
+#include "recorder_main_widget.h"
+#include "../../base/logger.h"
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QScreen>
+#include <QStandardPaths>
+#include <QDir>
+#include <QDateTime>
+#include <QScrollArea>
+#include <QTabWidget>
+
+extern "C" {
+#include <libavutil/pixfmt.h>
+}
+
+RecorderMainWidget::RecorderMainWidget(QWidget* parent)
+    : QWidget(parent)
+    , m_recorder(nullptr)
+    , m_isInitialized(false)
+    , m_isRecording(false)
+    , m_isPaused(false)
+    , m_isPreviewActive(false)
+    , m_recordDuration(0)
+    , m_settingsDialog(nullptr)
+    , m_independentControlGroup(nullptr)
+    , m_audioStartButton(nullptr)
+    , m_audioStopButton(nullptr)
+    , m_videoCaptureButton(nullptr)
+    , m_videoStopButton(nullptr)
+    , m_audioEnableCheck(nullptr)
+    , m_videoEnableCheck(nullptr) {
+    
+    setWindowTitle("AV录制器");
+    setMinimumSize(1050, 650);  // 调整尺寸适应音频控制的空间需求
+    resize(1250, 750);          // 调整默认尺寸
+    
+    initUI();
+    initConnections();
+    updateUIState();
+}
+
+RecorderMainWidget::~RecorderMainWidget() {
+    cleanup();
+}
+
+bool RecorderMainWidget::initialize() {
+    if (m_isInitialized) {
+        return true;
+    }
+
+    AV_LOGGER_INFO("Initializing RecorderMainWidget");
+
+    // 初始化录制器模块
+    auto result = RecorderModule::initialize();
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to initialize recorder module");
+        QMessageBox::critical(this, "错误", "初始化录制器模块失败");
+        return false;
+    }
+    
+    // 创建录制器
+    m_recorder = utils::createAVRecorder();
+    if (!m_recorder) {
+        AV_LOGGER_ERROR("Failed to create AV recorder");
+        QMessageBox::critical(this, "错误", "创建录制器失败");
+        return false;
+    }
+    
+    // 更新设备列表
+    updateCaptureDevices();
+    
+    // 设置默认输出路径
+    QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
+    if (defaultPath.isEmpty()) {
+        defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+    }
+    QString fileName = QString("录制_%1.mp4").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));
+    m_outputPathEdit->setText(QDir(defaultPath).filePath(fileName));
+    
+    m_isInitialized = true;
+    updateUIState();
+
+    AV_LOGGER_INFO("RecorderMainWidget initialized successfully");
+    return true;
+}
+
+void RecorderMainWidget::cleanup() {
+    if (!m_isInitialized) {
+        return;
+    }
+
+    AV_LOGGER_INFO("Cleaning up RecorderMainWidget");
+
+    // 停止所有操作
+    if (m_isRecording) {
+        stopRecording();
+    }
+    if (m_isPreviewActive) {
+        stopPreview();
+    }
+    
+    // 停止定时器
+    if (m_updateTimer) {
+        m_updateTimer->stop();
+    }
+    if (m_previewTimer) {
+        m_previewTimer->stop();
+    }
+    if (m_audioLevelTimer) {
+        m_audioLevelTimer->stop();
+    }
+    
+    // 清理录制器
+    m_recorder.reset();
+    
+    // 清理模块
+    RecorderModule::cleanup();
+    
+    m_isInitialized = false;
+
+    AV_LOGGER_INFO("RecorderMainWidget cleaned up");
+}
+
+void RecorderMainWidget::startRecording() {
+    if (!m_isInitialized || m_isRecording) {
+        return;
+    }
+
+    AV_LOGGER_INFO("Starting recording");
+
+    // 获取录制参数
+    auto params = getCurrentParams();
+    
+    // 验证输出路径
+    if (!utils::isValidOutputPath(params.outputPath)) {
+        QMessageBox::warning(this, "警告", "输出路径无效,请选择有效的输出文件");
+        return;
+    }
+    
+    // 初始化录制器
+    auto result = m_recorder->initialize(params);
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to initialize recorder");
+        QMessageBox::critical(this, "错误", "初始化录制器失败");
+        return;
+    }
+    
+    // 开始录制
+    result = m_recorder->startRecording();
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to start recording");
+        QMessageBox::critical(this, "错误", "开始录制失败");
+        return;
+    }
+    
+    m_isRecording = true;
+    m_isPaused = false;
+    m_recordStartTime = QTime::currentTime();
+    
+    // 启动更新定时器
+    if (!m_updateTimer->isActive()) {
+        m_updateTimer->start(UPDATE_INTERVAL_MS);
+    }
+    
+    updateUIState();
+    m_statusLabel->setText("录制中...");
+
+    AV_LOGGER_INFO("Recording started successfully");
+}
+
+void RecorderMainWidget::stopRecording() {
+    if (!m_isRecording) {
+        return;
+    }
+
+    AV_LOGGER_INFO("Stopping recording");
+
+    auto result = m_recorder->stopRecording();
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to stop recording");
+        QMessageBox::warning(this, "警告", "停止录制时出现错误");
+    }
+    
+    m_isRecording = false;
+    m_isPaused = false;
+    m_recordDuration = 0;
+    
+    // 停止更新定时器
+    if (m_updateTimer && m_updateTimer->isActive()) {
+        m_updateTimer->stop();
+    }
+    
+    updateUIState();
+    m_statusLabel->setText("录制已停止");
+    
+    // 显示录制完成信息
+    auto combinedStats = m_recorder->getCombinedStats();
+    auto& videoStats = combinedStats.videoStats;
+    QString message = QString("录制完成\n文件: %1\n时长: %2\n帧数: %3")
+        .arg(QString::fromStdString(getCurrentParams().outputPath))
+        .arg(formatTime(static_cast<int64_t>(videoStats.recordingTime * 1000)))
+        .arg(videoStats.recordedFrames);
+    
+    QMessageBox::information(this, "录制完成", message);
+
+    // 重置录制器状态,以便可以重新启动
+    resetRecorderForRestart();
+
+    AV_LOGGER_INFO("Recording stopped successfully");
+}
+
+void RecorderMainWidget::pauseRecording() {
+    if (!m_isRecording || m_isPaused) {
+        return;
+    }
+
+    AV_LOGGER_INFO("Pausing recording");
+
+    auto result = m_recorder->pauseRecording();
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to pause recording");
+        QMessageBox::warning(this, "警告", "暂停录制失败");
+        return;
+    }
+    
+    m_isPaused = true;
+    updateUIState();
+    m_statusLabel->setText("录制已暂停");
+
+    AV_LOGGER_INFO("Recording paused successfully");
+}
+
+void RecorderMainWidget::resumeRecording() {
+    if (!m_isRecording || !m_isPaused) {
+        return;
+    }
+
+    AV_LOGGER_INFO("Resuming recording");
+
+    auto result = m_recorder->resumeRecording();
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to resume recording");
+        QMessageBox::warning(this, "警告", "恢复录制失败");
+        return;
+    }
+    
+    m_isPaused = false;
+    updateUIState();
+    m_statusLabel->setText("录制中...");
+
+    AV_LOGGER_INFO("Recording resumed successfully");
+}
+
+void RecorderMainWidget::startPreview() {
+    if (!m_isInitialized || m_isPreviewActive) {
+        return;
+    }
+
+    AV_LOGGER_INFO("Starting preview");
+
+    // 获取预览参数(只需要视频参数)
+    auto params = getCurrentParams();
+    params.outputPath = "./preview_temp.mp4";   // 预览使用临时文件
+    params.enableAudio = false; // 预览通常不需要音频录制
+    
+    // 初始化录制器用于预览
+    auto result = m_recorder->initialize(params);
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to initialize recorder for preview");
+        QMessageBox::warning(this, "警告", "初始化预览失败");
+        return;
+    }
+    
+    // 开始预览(实际上是开始捕获但不录制到文件)
+    result = m_recorder->startRecording();
+    if (result != av::ErrorCode::SUCCESS) {
+        AV_LOGGER_ERROR("Failed to start preview");
+        QMessageBox::warning(this, "警告", "开始预览失败");
+        return;
+    }
+    
+    m_isPreviewActive = true;
+    
+    // 启动预览更新定时器
+    if (!m_previewTimer->isActive()) {
+        m_previewTimer->start(PREVIEW_INTERVAL_MS);
+    }
+    
+    updateUIState();
+    m_statusLabel->setText("预览中...");
+
+    AV_LOGGER_INFO("Preview started successfully");
+}
+
+void RecorderMainWidget::stopPreview() {
+    if (!m_isPreviewActive) {
+        return;
+    }
+
+    AV_LOGGER_INFO("Stopping preview");
+
+    m_recorder->stopRecording();
+    m_isPreviewActive = false;
+    
+    // 停止预览定时器
+    if (m_previewTimer->isActive()) {
+        m_previewTimer->stop();
+    }
+    
+    // 清空预览窗口
+    m_videoWidget->clearFrame();
+    
+    updateUIState();
+    m_statusLabel->setText("预览已停止");
+
+    // 重置录制器状态,以便可以重新启动
+    resetRecorderForRestart();
+
+    AV_LOGGER_INFO("Preview stopped successfully");
+}
+
+void RecorderMainWidget::openSettings() {
+    if (!m_settingsDialog) {
+        m_settingsDialog = new RecorderSettingsDialog(nullptr, this);
+    }
+    
+    // TODO: 设置当前参数
+    // m_settingsDialog->setSettings(getCurrentSettings());
+    
+    if (m_settingsDialog->exec() == QDialog::Accepted) {
+        // 应用新参数
+        auto settings = m_settingsDialog->getSettings();
+        // TODO: 将settings转换为AVRecorderParams
+        // applyRecorderParams(convertSettingsToParams(settings));
+
+        AV_LOGGER_INFO("Settings applied");
+        m_statusLabel->setText("设置已应用");
+    }
+}
+
+void RecorderMainWidget::selectOutputFile() {
+    QString currentPath = m_outputPathEdit->text();
+    QString dir = QFileInfo(currentPath).absolutePath();
+    
+    QString fileName = QFileDialog::getSaveFileName(
+        this,
+        "选择输出文件",
+        currentPath,
+        "视频文件 (*.mp4 *.avi *.mkv *.mov);;音频文件 (*.mp3 *.wav *.aac);;所有文件 (*.*)"
+    );
+    
+    if (!fileName.isEmpty()) {
+        m_outputPathEdit->setText(fileName);
+    }
+}
+
+void RecorderMainWidget::updateCaptureDevices() {
+    AV_LOGGER_INFO("Updating capture devices");
+
+    // 更新采集方法
+    m_captureMethodCombo->clear();
+    m_captureMethodCombo->addItem("屏幕录制", static_cast<int>(VideoCaptureMethod::SCREEN_CAPTURE));
+    m_captureMethodCombo->addItem("窗口录制", static_cast<int>(VideoCaptureMethod::WINDOW_CAPTURE));
+    m_captureMethodCombo->addItem("摄像头录制", static_cast<int>(VideoCaptureMethod::CAMERA_CAPTURE));
+    
+    // 更新采集源(这里简化处理,实际应该查询系统)
+    onCaptureMethodChanged();
+    
+    // 更新音频设备(这里简化处理,实际应该查询系统)
+    m_audioDeviceCombo->clear();
+    m_audioDeviceCombo->addItem("默认麦克风", 0);
+    m_audioDeviceCombo->addItem("默认扬声器", 1);
+
+    AV_LOGGER_INFO("Capture devices updated");
+}
+
+void RecorderMainWidget::onCaptureSourceChanged() {
+    // 采集源改变时的处理
+    updateUIState();
+}
+
+void RecorderMainWidget::onCaptureMethodChanged() {
+    // 根据采集方法更新采集源列表
+    m_captureSourceCombo->clear();
+    
+    int method = m_captureMethodCombo->currentData().toInt();
+    switch (static_cast<VideoCaptureMethod>(method)) {
+    case VideoCaptureMethod::SCREEN_CAPTURE:
+        // 添加屏幕列表(简化处理)
+        m_captureSourceCombo->addItem("主屏幕", 0);
+        m_captureSourceCombo->addItem("扩展屏幕", 1);
+        break;
+        
+    case VideoCaptureMethod::WINDOW_CAPTURE:
+        // 添加窗口列表(简化处理)
+        m_captureSourceCombo->addItem("当前窗口", 0);
+        break;
+        
+    case VideoCaptureMethod::CAMERA_CAPTURE:
+        // 添加摄像头列表(简化处理)
+        m_captureSourceCombo->addItem("默认摄像头", 0);
+        break;
+    }
+}
+
+void RecorderMainWidget::onAudioDeviceChanged() {
+    // 音频设备改变时的处理
+    updateUIState();
+}
+
+void RecorderMainWidget::onVolumeChanged(double volume) {
+    // 音量改变时的处理
+    AV_LOGGER_DEBUGF("Volume changed to {}", volume);
+}
+
+void RecorderMainWidget::onMuteChanged(bool muted) {
+    // 静音状态改变时的处理
+    AV_LOGGER_DEBUGF("Mute changed to {}", muted);
+}
+
+void RecorderMainWidget::updateRecordingStatus() {
+    if (!m_isRecording) {
+        m_recordTimeLabel->setText("00:00:00");
+        return;
+    }
+    
+    // 计算录制时间
+    int elapsed = m_recordStartTime.msecsTo(QTime::currentTime());
+    if (m_isPaused) {
+        elapsed = m_recordDuration;
+    } else {
+        m_recordDuration = elapsed;
+    }
+    
+    m_recordTimeLabel->setText(formatTime(elapsed));
+    
+    // 更新统计信息
+    if (m_recorder) {
+        auto combinedStats = m_recorder->getCombinedStats();
+        auto& videoStats = combinedStats.videoStats;
+        m_framesLabel->setText(QString("帧数: %1").arg(videoStats.recordedFrames));
+        m_droppedFramesLabel->setText(QString("丢帧: %1").arg(videoStats.droppedFrames));
+        
+        // 计算码率 (总字节数 / 录制时长 * 8)
+        double bitrate = videoStats.recordingTime > 0 ? (videoStats.totalBytes * 8.0 / videoStats.recordingTime) : 0;
+        m_bitrateLabel->setText(QString("码率: %1").arg(formatBitrate(static_cast<int64_t>(bitrate))));
+        
+        // 显示文件大小
+        m_fileSizeLabel->setText(QString("大小: %1").arg(formatFileSize(videoStats.totalBytes)));
+    }
+}
+
+void RecorderMainWidget::updatePreviewFrame() {
+    if (!m_isPreviewActive || !m_recorder) {
+        return;
+    }
+    
+    try {
+        // 获取当前预览帧
+        auto frame = m_recorder->getCurrentVideoFrame();
+        if (frame && frame->data[0]) {
+            AV_LOGGER_DEBUGF("更新预览帧: width={}, height={}, format={}, data_ptr={}", 
+                            frame->width, frame->height, frame->format, 
+                            static_cast<void*>(frame->data[0]));
+            bool updated = m_videoWidget->updateFrame(frame.get());
+            if (!updated) {
+                AV_LOGGER_WARNING("视频预览组件更新失败");
+            }
+        } else {
+            AV_LOGGER_DEBUG("未获取到有效的预览帧");
+        }
+    } catch (const std::exception& e) {
+        AV_LOGGER_ERRORF("Error updating preview frame: {}", e.what());
+        // 预览错误不应该影响录制,继续运行
+    }
+}
+
+void RecorderMainWidget::updateAudioLevel() {
+    if (!m_recorder) {
+        return;
+    }
+    
+    // 获取音频电平(这里需要录制器提供音频电平接口)
+    // auto level = m_recorder->getCurrentAudioLevel();
+    // m_microphoneWidget->setLevel(level.micLevel);
+    // m_speakerWidget->setLevel(level.speakerLevel);
+}
+
+void RecorderMainWidget::onRecorderStateChanged(RecorderState state) {
+    AV_LOGGER_INFOF("Recorder state changed to {}", static_cast<int>(state));
+    updateUIState();
+}
+
+void RecorderMainWidget::onRecorderError(const QString& error) {
+    AV_LOGGER_ERRORF("Recorder error: {}", error.toStdString());
+    QMessageBox::critical(this, "录制器错误", error);
+    
+    // 停止当前操作
+    if (m_isRecording) {
+        stopRecording();
+    }
+    if (m_isPreviewActive) {
+        stopPreview();
+    }
+}
+
+void RecorderMainWidget::onStatisticsUpdated() {
+    // 统计信息更新时的处理
+    updateRecordingStatus();
+}
+
+void RecorderMainWidget::initUI() {
+    // 创建主分割器
+    m_mainSplitter = new QSplitter(Qt::Horizontal, this);
+    
+    // 创建左面板滚动区域
+    auto leftScrollArea = new QScrollArea();
+    leftScrollArea->setWidgetResizable(true);
+    leftScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    leftScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+    leftScrollArea->setMinimumWidth(350);  // 增加最小宽度,给音频控件更多空间
+    leftScrollArea->setMaximumWidth(420);  // 增加最大宽度
+    
+    // 创建实际的左面板内容widget
+    m_leftPanel = new QWidget();
+    leftScrollArea->setWidget(m_leftPanel);
+    
+    // 创建右面板
+    m_rightPanel = new QWidget();
+    
+    m_mainSplitter->addWidget(leftScrollArea);
+    m_mainSplitter->addWidget(m_rightPanel);
+    m_mainSplitter->setStretchFactor(0, 0);  // 左面板固定大小
+    m_mainSplitter->setStretchFactor(1, 1);  // 右面板占用剩余空间
+    
+    // 初始化各个面板
+    initControlPanel();
+    initIndependentControlPanel();
+    initPreviewPanel();
+    initAudioPanel();
+    initSettingsPanel();
+    initStatusBar();
+    
+    // 设置左面板紧凑布局
+    auto leftLayout = new QVBoxLayout(m_leftPanel);
+    leftLayout->setContentsMargins(4, 4, 4, 4);
+    leftLayout->setSpacing(6);  // 稍微增加间距,让组件更清晰
+    
+    // 按重要性和空间需求设置各个组件
+    leftLayout->addWidget(m_controlGroup, 0);           // 录制控制 - 最重要,固定大小
+    leftLayout->addWidget(m_independentControlGroup, 0); // 独立控制面板,固定大小
+    leftLayout->addWidget(m_captureGroup, 0);           // 采集设置,固定大小
+    leftLayout->addWidget(m_outputGroup, 0);            // 输出设置,固定大小
+    leftLayout->addWidget(m_audioGroup, 1);             // 音频控制 - 给予优先扩展空间
+    leftLayout->addWidget(m_statsGroup, 0);             // 统计信息,固定大小
+    leftLayout->addStretch(0);                          // 底部填充空间
+    
+    // 设置右面板布局
+    auto rightLayout = new QVBoxLayout(m_rightPanel);
+    rightLayout->setContentsMargins(4, 4, 4, 4);
+    rightLayout->addWidget(m_previewGroup);
+    
+    // 设置主布局
+    auto mainLayout = new QVBoxLayout(this);
+    mainLayout->setContentsMargins(2, 2, 2, 0);  // 底部边距设为0,让状态栏贴底
+    mainLayout->setSpacing(0);  // 减少组件间距
+    mainLayout->addWidget(m_mainSplitter, 1);  // 主分割器占用主要空间
+    mainLayout->addWidget(m_statusBar, 0);     // 状态栏固定大小
+    
+    // 创建定时器
+    m_updateTimer = new QTimer(this);
+    m_previewTimer = new QTimer(this);
+    m_audioLevelTimer = new QTimer(this);
+}
+
+void RecorderMainWidget::initControlPanel() {
+    m_controlGroup = new QGroupBox("录制控制");
+    m_controlGroup->setMaximumHeight(140);
+    
+    // 创建按钮
+    m_recordButton = new QPushButton("开始录制");
+    m_pauseButton = new QPushButton("暂停");
+    m_stopButton = new QPushButton("停止");
+    m_previewButton = new QPushButton("预览");
+    m_settingsButton = new QPushButton("设置");
+    
+    // 设置按钮最小高度和样式
+    const int buttonHeight = 28;
+    m_recordButton->setMinimumHeight(buttonHeight);
+    m_pauseButton->setMinimumHeight(buttonHeight);
+    m_stopButton->setMinimumHeight(buttonHeight);
+    m_previewButton->setMinimumHeight(buttonHeight);
+    m_settingsButton->setMinimumHeight(buttonHeight);
+    
+    // 创建状态标签
+    m_recordTimeLabel = new QLabel("00:00:00");
+    m_recordTimeLabel->setStyleSheet("QLabel { font-weight: bold; color: #0066cc; }");
+    m_recordStatusLabel = new QLabel("就绪");
+    
+    // 紧凑布局
+    auto layout = new QGridLayout(m_controlGroup);
+    layout->setContentsMargins(6, 8, 6, 6);
+    layout->setSpacing(4);
+    layout->addWidget(m_recordButton, 0, 0);
+    layout->addWidget(m_pauseButton, 0, 1);
+    layout->addWidget(m_stopButton, 0, 2);
+    layout->addWidget(m_previewButton, 1, 0);
+    layout->addWidget(m_settingsButton, 1, 1, 1, 2);
+    
+    // 状态信息用更紧凑的布局
+    auto statusLayout = new QHBoxLayout();
+    statusLayout->setSpacing(8);
+    statusLayout->addWidget(new QLabel("时间:"));
+    statusLayout->addWidget(m_recordTimeLabel);
+    statusLayout->addWidget(new QLabel("状态:"));
+    statusLayout->addWidget(m_recordStatusLabel);
+    statusLayout->addStretch();
+    
+    layout->addLayout(statusLayout, 2, 0, 1, 3);
+}
+
+void RecorderMainWidget::initIndependentControlPanel() {
+    m_independentControlGroup = new QGroupBox("独立采集控制");
+    m_independentControlGroup->setMaximumHeight(120);
+    
+    // 创建控制按钮
+    m_audioStartButton = new QPushButton("启动音频");
+    m_audioStopButton = new QPushButton("停止音频");
+    m_videoCaptureButton = new QPushButton("启动视频");
+    m_videoStopButton = new QPushButton("停止视频");
+    
+    // 设置按钮高度
+    const int buttonHeight = 26;
+    m_audioStartButton->setMinimumHeight(buttonHeight);
+    m_audioStopButton->setMinimumHeight(buttonHeight);
+    m_videoCaptureButton->setMinimumHeight(buttonHeight);
+    m_videoStopButton->setMinimumHeight(buttonHeight);
+    
+    // 创建启用检查框
+    m_audioEnableCheck = new QCheckBox("启用音频录制");
+    m_videoEnableCheck = new QCheckBox("启用视频录制");
+    
+    // 设置默认状态
+    m_audioEnableCheck->setChecked(true);
+    m_videoEnableCheck->setChecked(true);
+    
+    // 设置按钮样式
+    m_audioStartButton->setStyleSheet("QPushButton { background-color: #34c759; color: white; }");
+    m_audioStopButton->setStyleSheet("QPushButton { background-color: #ff3b30; color: white; }");
+    m_videoCaptureButton->setStyleSheet("QPushButton { background-color: #007aff; color: white; }");
+    m_videoStopButton->setStyleSheet("QPushButton { background-color: #ff9500; color: white; }");
+    
+    // 紧凑布局
+    auto layout = new QGridLayout(m_independentControlGroup);
+    layout->setContentsMargins(6, 8, 6, 6);
+    layout->setSpacing(3);
+    
+    // 第一行:启用选项(水平布局)
+    auto enableLayout = new QHBoxLayout();
+    enableLayout->setSpacing(10);
+    enableLayout->addWidget(m_audioEnableCheck);
+    enableLayout->addWidget(m_videoEnableCheck);
+    layout->addLayout(enableLayout, 0, 0, 1, 4);
+    
+    // 第二行:音频控制
+    layout->addWidget(new QLabel("音频:"), 1, 0);
+    layout->addWidget(m_audioStartButton, 1, 1);
+    layout->addWidget(m_audioStopButton, 1, 2);
+    
+    // 第三行:视频控制
+    layout->addWidget(new QLabel("视频:"), 2, 0);
+    layout->addWidget(m_videoCaptureButton, 2, 1);
+    layout->addWidget(m_videoStopButton, 2, 2);
+}
+
+void RecorderMainWidget::initPreviewPanel() {
+    m_previewGroup = new QGroupBox("预览窗口");
+    
+    // 创建视频预览组件
+    m_videoWidget = new RecorderVideoWidget();
+    m_videoWidget->setMinimumSize(640, 480);
+    
+    // 初始化VideoWidget(默认参数:1920x1080, YUV420P)
+    if (!m_videoWidget->initialize(1920, 1080, AV_PIX_FMT_YUV420P)) {
+        AV_LOGGER_WARNING("Failed to initialize video widget with default parameters");
+        // 尝试RGB格式作为后备
+        if (!m_videoWidget->initialize(1920, 1080, AV_PIX_FMT_RGB24)) {
+            AV_LOGGER_ERROR("Failed to initialize video widget with RGB format");
+        }
+    }
+    
+    // 布局
+    auto layout = new QVBoxLayout(m_previewGroup);
+    layout->addWidget(m_videoWidget);
+}
+
+void RecorderMainWidget::initAudioPanel() {
+    m_audioGroup = new QGroupBox("音频控制");
+    m_audioGroup->setMinimumHeight(240);  // 给音频控制足够的最小高度
+    m_audioGroup->setMaximumHeight(280);  // 设置合理的最大高度
+    m_audioGroup->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+    
+    // 创建音频控制组件
+    m_microphoneWidget = new RecorderAudioWidget(this);
+    m_speakerWidget = new RecorderAudioWidget(this);
+    
+    // 设置widget标题和大小 - 给予充足空间
+    m_microphoneWidget->setObjectName("麦克风");
+    m_microphoneWidget->setMinimumHeight(100);  // 确保有足够高度显示所有控件
+    m_microphoneWidget->setMaximumHeight(120);
+    m_microphoneWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+    
+    m_speakerWidget->setObjectName("扬声器");
+    m_speakerWidget->setMinimumHeight(100);  // 确保有足够高度显示所有控件
+    m_speakerWidget->setMaximumHeight(120);
+    m_speakerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+    
+    // 调整布局
+    auto layout = new QVBoxLayout(m_audioGroup);
+    layout->setContentsMargins(6, 10, 6, 6);  // 给顶部更多空间
+    layout->setSpacing(6);  // 增加适当间距
+    
+    // 添加标签来区分麦克风和扬声器
+    auto micLabel = new QLabel("麦克风");
+    micLabel->setStyleSheet("font-weight: bold; color: #0a84ff; font-size: 12px; margin-bottom: 2px;");
+    layout->addWidget(micLabel);
+    layout->addWidget(m_microphoneWidget);
+    
+    auto speakerLabel = new QLabel("扬声器");
+    speakerLabel->setStyleSheet("font-weight: bold; color: #34c759; font-size: 12px; margin-top: 6px; margin-bottom: 2px;");
+    layout->addWidget(speakerLabel);
+    layout->addWidget(m_speakerWidget);
+}
+
+void RecorderMainWidget::initSettingsPanel() {
+    // 采集设置组 - 紧凑布局
+    m_captureGroup = new QGroupBox("采集设置");
+    m_captureGroup->setMaximumHeight(160);
+    
+    m_captureMethodCombo = new QComboBox();
+    m_captureSourceCombo = new QComboBox();
+    m_audioDeviceCombo = new QComboBox();
+    m_refreshDevicesButton = new QPushButton("刷新设备");
+    m_drawCursorCheck = new QCheckBox("绘制光标");
+    m_captureAudioCheck = new QCheckBox("录制音频");
+    
+    // 设置控件高度
+    m_captureMethodCombo->setMaximumHeight(24);
+    m_captureSourceCombo->setMaximumHeight(24);
+    m_audioDeviceCombo->setMaximumHeight(24);
+    m_refreshDevicesButton->setMaximumHeight(26);
+    
+    m_drawCursorCheck->setChecked(true);
+    m_captureAudioCheck->setChecked(true);
+    
+    auto captureLayout = new QGridLayout(m_captureGroup);
+    captureLayout->setContentsMargins(6, 8, 6, 6);
+    captureLayout->setSpacing(3);
+    captureLayout->addWidget(new QLabel("采集方法:"), 0, 0);
+    captureLayout->addWidget(m_captureMethodCombo, 0, 1);
+    captureLayout->addWidget(new QLabel("采集源:"), 1, 0);
+    captureLayout->addWidget(m_captureSourceCombo, 1, 1);
+    captureLayout->addWidget(new QLabel("音频设备:"), 2, 0);
+    captureLayout->addWidget(m_audioDeviceCombo, 2, 1);
+    captureLayout->addWidget(m_refreshDevicesButton, 3, 0, 1, 2);
+    
+    // 选项水平布局
+    auto optionsLayout = new QHBoxLayout();
+    optionsLayout->setSpacing(10);
+    optionsLayout->addWidget(m_drawCursorCheck);
+    optionsLayout->addWidget(m_captureAudioCheck);
+    captureLayout->addLayout(optionsLayout, 4, 0, 1, 2);
+    
+    // 输出设置组 - 紧凑布局
+    m_outputGroup = new QGroupBox("输出设置");
+    m_outputGroup->setMaximumHeight(80);
+    
+    m_outputPathEdit = new QLineEdit();
+    m_browseOutputButton = new QPushButton("浏览...");
+    m_outputFormatCombo = new QComboBox();
+    
+    // 设置控件高度
+    m_outputPathEdit->setMaximumHeight(24);
+    m_browseOutputButton->setMaximumHeight(26);
+    m_outputFormatCombo->setMaximumHeight(24);
+    
+    m_outputFormatCombo->addItems({"MP4", "AVI", "MKV", "MOV"});
+    
+    auto outputLayout = new QGridLayout(m_outputGroup);
+    outputLayout->setContentsMargins(6, 8, 6, 6);
+    outputLayout->setSpacing(3);
+    outputLayout->addWidget(new QLabel("输出文件:"), 0, 0);
+    outputLayout->addWidget(m_outputPathEdit, 0, 1);
+    outputLayout->addWidget(m_browseOutputButton, 0, 2);
+    outputLayout->addWidget(new QLabel("格式:"), 1, 0);
+    outputLayout->addWidget(m_outputFormatCombo, 1, 1, 1, 2);
+    
+    // 统计信息组 - 紧凑布局
+    m_statsGroup = new QGroupBox("统计信息");
+    m_statsGroup->setMaximumHeight(120);
+    
+    m_fpsLabel = new QLabel("帧率: 0 fps");
+    m_bitrateLabel = new QLabel("码率: 0 bps");
+    m_framesLabel = new QLabel("帧数: 0");
+    m_droppedFramesLabel = new QLabel("丢帧: 0");
+    m_fileSizeLabel = new QLabel("大小: 0 B");
+    
+    // 设置标签样式
+    QString labelStyle = "QLabel { font-size: 11px; margin: 1px; }";
+    m_fpsLabel->setStyleSheet(labelStyle);
+    m_bitrateLabel->setStyleSheet(labelStyle);
+    m_framesLabel->setStyleSheet(labelStyle);
+    m_droppedFramesLabel->setStyleSheet(labelStyle);
+    m_fileSizeLabel->setStyleSheet(labelStyle);
+    
+    auto statsLayout = new QVBoxLayout(m_statsGroup);
+    statsLayout->setContentsMargins(6, 8, 6, 6);
+    statsLayout->setSpacing(2);
+    statsLayout->addWidget(m_fpsLabel);
+    statsLayout->addWidget(m_bitrateLabel);
+    statsLayout->addWidget(m_framesLabel);
+    statsLayout->addWidget(m_droppedFramesLabel);
+    statsLayout->addWidget(m_fileSizeLabel);
+}
+
+void RecorderMainWidget::initStatusBar() {
+    m_statusBar = new QStatusBar();
+    m_statusBar->setMaximumHeight(26);  // 限制状态栏最大高度
+    m_statusBar->setSizeGripEnabled(false);  // 禁用大小调整手柄
+    
+    m_statusLabel = new QLabel("就绪");
+    m_statusLabel->setStyleSheet("QLabel { padding: 2px 4px; margin: 0px; font-size: 12px; }");  // 减少内边距和字体大小
+    m_statusLabel->setMaximumHeight(22);  // 限制标签高度
+    
+    m_progressBar = new QProgressBar();
+    m_progressBar->setVisible(false);
+    m_progressBar->setMaximumHeight(18);  // 限制进度条高度
+    
+    m_statusBar->addWidget(m_statusLabel);
+    m_statusBar->addPermanentWidget(m_progressBar);
+}
+
+void RecorderMainWidget::initConnections() {
+    // 控制按钮连接
+    connect(m_recordButton, &QPushButton::clicked, this, &RecorderMainWidget::startRecording);
+    connect(m_pauseButton, &QPushButton::clicked, this, [this]() {
+        if (m_isPaused) {
+            resumeRecording();
+        } else {
+            pauseRecording();
+        }
+    });
+    connect(m_stopButton, &QPushButton::clicked, this, &RecorderMainWidget::stopRecording);
+    connect(m_previewButton, &QPushButton::clicked, this, [this]() {
+        if (m_isPreviewActive) {
+            stopPreview();
+        } else {
+            startPreview();
+        }
+    });
+    connect(m_settingsButton, &QPushButton::clicked, this, &RecorderMainWidget::openSettings);
+    
+    // 设置控件连接
+    connect(m_captureMethodCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
+            this, &RecorderMainWidget::onCaptureMethodChanged);
+    connect(m_captureSourceCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
+            this, &RecorderMainWidget::onCaptureSourceChanged);
+    connect(m_audioDeviceCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
+            this, &RecorderMainWidget::onAudioDeviceChanged);
+    connect(m_refreshDevicesButton, &QPushButton::clicked, this, &RecorderMainWidget::updateCaptureDevices);
+    connect(m_browseOutputButton, &QPushButton::clicked, this, &RecorderMainWidget::selectOutputFile);
+    
+    // 音频控件连接
+    connect(m_microphoneWidget, &RecorderAudioWidget::volumeChanged, this, &RecorderMainWidget::onVolumeChanged);
+    connect(m_microphoneWidget, &RecorderAudioWidget::mutedChanged, this, &RecorderMainWidget::onMuteChanged);
+    connect(m_speakerWidget, &RecorderAudioWidget::volumeChanged, this, &RecorderMainWidget::onVolumeChanged);
+    connect(m_speakerWidget, &RecorderAudioWidget::mutedChanged, this, &RecorderMainWidget::onMuteChanged);
+    
+    // 独立控制连接
+    connect(m_audioStartButton, &QPushButton::clicked, this, &RecorderMainWidget::onAudioStartClicked);
+    connect(m_audioStopButton, &QPushButton::clicked, this, &RecorderMainWidget::onAudioStopClicked);
+    connect(m_videoCaptureButton, &QPushButton::clicked, this, &RecorderMainWidget::onVideoCaptureClicked);
+    connect(m_videoStopButton, &QPushButton::clicked, this, &RecorderMainWidget::onVideoStopClicked);
+    connect(m_audioEnableCheck, &QCheckBox::toggled, this, &RecorderMainWidget::onAudioEnableChanged);
+    connect(m_videoEnableCheck, &QCheckBox::toggled, this, &RecorderMainWidget::onVideoEnableChanged);
+    
+    // 定时器连接
+    connect(m_updateTimer, &QTimer::timeout, this, &RecorderMainWidget::updateRecordingStatus);
+    connect(m_previewTimer, &QTimer::timeout, this, &RecorderMainWidget::updatePreviewFrame);
+    connect(m_audioLevelTimer, &QTimer::timeout, this, &RecorderMainWidget::updateAudioLevel);
+}
+
+void RecorderMainWidget::updateUIState() {
+    bool canRecord = m_isInitialized && !m_isRecording;
+    bool canStop = m_isRecording;
+    bool canPause = m_isRecording && !m_isPaused;
+    bool canResume = m_isRecording && m_isPaused;
+    bool canPreview = m_isInitialized && !m_isRecording;
+    
+    m_recordButton->setEnabled(canRecord);
+    m_stopButton->setEnabled(canStop);
+    m_pauseButton->setEnabled(canPause || canResume);
+    m_pauseButton->setText(m_isPaused ? "恢复" : "暂停");
+    m_previewButton->setEnabled(canPreview);
+    m_previewButton->setText(m_isPreviewActive ? "停止预览" : "开始预览");
+    
+    // 更新录制状态标签
+    if (m_isRecording) {
+        if (m_isPaused) {
+            m_recordStatusLabel->setText("已暂停");
+        } else {
+            m_recordStatusLabel->setText("录制中");
+        }
+    } else if (m_isPreviewActive) {
+        m_recordStatusLabel->setText("预览中");
+    } else {
+        m_recordStatusLabel->setText("就绪");
+    }
+    
+    // 禁用/启用设置控件
+    bool canChangeSettings = !m_isRecording && !m_isPreviewActive;
+    m_captureMethodCombo->setEnabled(canChangeSettings);
+    m_captureSourceCombo->setEnabled(canChangeSettings);
+    m_audioDeviceCombo->setEnabled(canChangeSettings);
+    m_outputPathEdit->setEnabled(canChangeSettings);
+    m_outputFormatCombo->setEnabled(canChangeSettings);
+    
+    // 控制音频/视频启用复选框的状态
+    bool canChangeEnableState = m_isInitialized && !m_isRecording && !m_isPreviewActive;
+    if (m_audioEnableCheck) {
+        m_audioEnableCheck->setEnabled(canChangeEnableState);
+    }
+    if (m_videoEnableCheck) {
+        m_videoEnableCheck->setEnabled(canChangeEnableState);
+    }
+    
+    // 更新独立控制按钮状态
+    updateIndependentControlButtons();
+}
+
+AVRecorderParams RecorderMainWidget::getCurrentParams() {
+    auto params = utils::getDefaultAVParams();
+    
+    // 设置输出路径
+    params.outputPath = m_outputPathEdit->text().toStdString();
+    
+    // 设置格式
+    QString format = m_outputFormatCombo->currentText().toLower();
+    params.format = format.toStdString();
+    params.audioParams.format = format.toStdString();
+    params.videoParams.format = format.toStdString();
+    
+    // 设置采集方法
+    int method = m_captureMethodCombo->currentData().toInt();
+    params.videoParams.captureMethod = static_cast<VideoCaptureMethod>(method);
+    
+    // 设置采集源
+    int source = m_captureSourceCombo->currentData().toInt();
+    if (params.videoParams.captureMethod == VideoCaptureMethod::SCREEN_CAPTURE) {
+        params.videoParams.monitorIndex = source;
+    }
+    
+    // 设置其他选项
+    params.videoParams.drawCursor = m_drawCursorCheck->isChecked();
+    params.enableAudio = m_captureAudioCheck->isChecked();
+    params.enableVideo = true;
+    params.enableSync = true;
+    
+    return params;
+}
+
+void RecorderMainWidget::applyRecorderParams(const AVRecorderParams& params) {
+    // 应用参数到UI控件
+    m_outputPathEdit->setText(QString::fromStdString(params.outputPath));
+    
+    // 设置格式
+    QString format = QString::fromStdString(params.format).toUpper();
+    int formatIndex = m_outputFormatCombo->findText(format);
+    if (formatIndex >= 0) {
+        m_outputFormatCombo->setCurrentIndex(formatIndex);
+    }
+    
+    // 设置采集方法
+    int methodIndex = m_captureMethodCombo->findData(static_cast<int>(params.videoParams.captureMethod));
+    if (methodIndex >= 0) {
+        m_captureMethodCombo->setCurrentIndex(methodIndex);
+        onCaptureMethodChanged();
+    }
+    
+    // 设置其他选项
+    m_drawCursorCheck->setChecked(params.videoParams.drawCursor);
+    m_captureAudioCheck->setChecked(params.enableAudio);
+}
+
+QString RecorderMainWidget::formatTime(int64_t ms) {
+    int seconds = ms / 1000;
+    int minutes = seconds / 60;
+    int hours = minutes / 60;
+    
+    seconds %= 60;
+    minutes %= 60;
+    
+    return QString("%1:%2:%3")
+        .arg(hours, 2, 10, QChar('0'))
+        .arg(minutes, 2, 10, QChar('0'))
+        .arg(seconds, 2, 10, QChar('0'));
+}
+
+QString RecorderMainWidget::formatFileSize(int64_t bytes) {
+    const char* units[] = {"B", "KB", "MB", "GB", "TB"};
+    int unitIndex = 0;
+    double size = bytes;
+    
+    while (size >= 1024 && unitIndex < 4) {
+        size /= 1024;
+        unitIndex++;
+    }
+    
+    return QString("%1 %2").arg(size, 0, 'f', 1).arg(units[unitIndex]);
+}
+
+QString RecorderMainWidget::formatBitrate(int64_t bps) {
+    if (bps < 1000) {
+        return QString("%1 bps").arg(bps);
+    } else if (bps < 1000000) {
+        return QString("%1 Kbps").arg(bps / 1000.0, 0, 'f', 1);
+    } else {
+        return QString("%1 Mbps").arg(bps / 1000000.0, 0, 'f', 1);
+    }
+}
+
+// 独立音频/视频控制实现
+void RecorderMainWidget::onAudioStartClicked() {
+    if (!m_recorder) {
+        QMessageBox::warning(this, "警告", "录制器未初始化");
+        return;
+    }
+    
+    auto result = m_recorder->startAudioCapture();
+    if (result == av::ErrorCode::SUCCESS) {
+        m_statusLabel->setText("音频采集已启动");
+        updateIndependentControlButtons();
+        AV_LOGGER_INFO("Audio capture started independently from UI");
+    } else {
+        QMessageBox::warning(this, "错误", "启动音频采集失败");
+        AV_LOGGER_ERRORF("Failed to start audio capture: {}", static_cast<int>(result));
+    }
+}
+
+void RecorderMainWidget::onAudioStopClicked() {
+    if (!m_recorder) {
+        return;
+    }
+    
+    auto result = m_recorder->stopAudioCapture();
+    if (result == av::ErrorCode::SUCCESS) {
+        m_statusLabel->setText("音频采集已停止");
+        updateIndependentControlButtons();
+        AV_LOGGER_INFO("Audio capture stopped independently from UI");
+    } else {
+        QMessageBox::warning(this, "错误", "停止音频采集失败");
+    }
+}
+
+void RecorderMainWidget::onVideoCaptureClicked() {
+    if (!m_recorder) {
+        QMessageBox::warning(this, "警告", "录制器未初始化");
+        return;
+    }
+    
+    auto result = m_recorder->startVideoCapture();
+    if (result == av::ErrorCode::SUCCESS) {
+        m_statusLabel->setText("视频采集已启动");
+        updateIndependentControlButtons();
+        AV_LOGGER_INFO("Video capture started independently from UI");
+    } else {
+        QMessageBox::warning(this, "错误", "启动视频采集失败");
+        AV_LOGGER_ERRORF("Failed to start video capture: {}", static_cast<int>(result));
+    }
+}
+
+void RecorderMainWidget::onVideoStopClicked() {
+    if (!m_recorder) {
+        return;
+    }
+    
+    auto result = m_recorder->stopVideoCapture();
+    if (result == av::ErrorCode::SUCCESS) {
+        m_statusLabel->setText("视频采集已停止");
+        updateIndependentControlButtons();
+        AV_LOGGER_INFO("Video capture stopped independently from UI");
+    } else {
+        QMessageBox::warning(this, "错误", "停止视频采集失败");
+    }
+}
+
+void RecorderMainWidget::onAudioEnableChanged(bool enabled) {
+    if (!m_recorder) {
+        AV_LOGGER_ERROR("Recorder not initialized when trying to change audio enable state");
+        // 阻止信号递归,安全地恢复checkbox状态
+        m_audioEnableCheck->blockSignals(true);
+        m_audioEnableCheck->setChecked(!enabled);
+        m_audioEnableCheck->blockSignals(false);
+        QMessageBox::warning(this, "错误", "录制器未初始化,无法更改音频设置");
+        return;
+    }
+    
+    // 检查录制器状态,如果正在录制则不允许更改
+    if (m_isRecording) {
+        AV_LOGGER_WARNING("Cannot change audio enable state while recording");
+        // 阻止信号递归,安全地恢复checkbox状态
+        m_audioEnableCheck->blockSignals(true);
+        m_audioEnableCheck->setChecked(!enabled);
+        m_audioEnableCheck->blockSignals(false);
+        QMessageBox::warning(this, "警告", "录制过程中无法更改音频启用状态");
+        return;
+    }
+    
+    auto result = m_recorder->setAudioEnabled(enabled);
+    if (result == av::ErrorCode::SUCCESS) {
+        updateIndependentControlButtons();
+        AV_LOGGER_INFOF("Audio recording {} from UI", enabled ? "enabled" : "disabled");
+        
+        if (enabled) {
+            m_statusLabel->setText("音频录制已启用");
+        } else {
+            m_statusLabel->setText("音频录制已禁用");
+        }
+    } else {
+        // 记录详细的错误信息
+        AV_LOGGER_ERRORF("Failed to {} audio recording: error code {}", 
+                        enabled ? "enable" : "disable", static_cast<int>(result));
+        
+        // 阻止信号递归,安全地恢复checkbox状态
+        m_audioEnableCheck->blockSignals(true);
+        m_audioEnableCheck->setChecked(!enabled);
+        m_audioEnableCheck->blockSignals(false);
+        
+        // 根据错误类型显示不同的错误信息
+        QString errorMsg;
+        switch (result) {
+            case av::ErrorCode::INVALID_STATE:
+                errorMsg = "录制器状态无效,无法更改音频设置";
+                break;
+            case av::ErrorCode::NOT_INITIALIZED:
+                errorMsg = "音频模块未初始化";
+                break;
+            case av::ErrorCode::DEVICE_NOT_FOUND:
+                errorMsg = "未找到音频设备";
+                break;
+            default:
+                errorMsg = enabled ? "启用音频录制失败" : "禁用音频录制失败";
+                errorMsg += QString("(错误代码:%1)").arg(static_cast<int>(result));
+                break;
+        }
+        
+        QMessageBox::warning(this, "错误", errorMsg);
+    }
+}
+
+void RecorderMainWidget::onVideoEnableChanged(bool enabled) {
+    if (!m_recorder) {
+        AV_LOGGER_ERROR("Recorder not initialized when trying to change video enable state");
+        // 阻止信号递归,安全地恢复checkbox状态
+        m_videoEnableCheck->blockSignals(true);
+        m_videoEnableCheck->setChecked(!enabled);
+        m_videoEnableCheck->blockSignals(false);
+        QMessageBox::warning(this, "错误", "录制器未初始化,无法更改视频设置");
+        return;
+    }
+    
+    // 检查录制器状态,如果正在录制则不允许更改
+    if (m_isRecording) {
+        AV_LOGGER_WARNING("Cannot change video enable state while recording");
+        // 阻止信号递归,安全地恢复checkbox状态
+        m_videoEnableCheck->blockSignals(true);
+        m_videoEnableCheck->setChecked(!enabled);
+        m_videoEnableCheck->blockSignals(false);
+        QMessageBox::warning(this, "警告", "录制过程中无法更改视频启用状态");
+        return;
+    }
+    
+    auto result = m_recorder->setVideoEnabled(enabled);
+    if (result == av::ErrorCode::SUCCESS) {
+        updateIndependentControlButtons();
+        AV_LOGGER_INFOF("Video recording {} from UI", enabled ? "enabled" : "disabled");
+        
+        if (enabled) {
+            m_statusLabel->setText("视频录制已启用");
+        } else {
+            m_statusLabel->setText("视频录制已禁用");
+        }
+    } else {
+        // 记录详细的错误信息
+        AV_LOGGER_ERRORF("Failed to {} video recording: error code {}", 
+                        enabled ? "enable" : "disable", static_cast<int>(result));
+        
+        // 阻止信号递归,安全地恢复checkbox状态
+        m_videoEnableCheck->blockSignals(true);
+        m_videoEnableCheck->setChecked(!enabled);
+        m_videoEnableCheck->blockSignals(false);
+        
+        // 根据错误类型显示不同的错误信息
+        QString errorMsg;
+        switch (result) {
+            case av::ErrorCode::INVALID_STATE:
+                errorMsg = "录制器状态无效,无法更改视频设置";
+                break;
+            case av::ErrorCode::NOT_INITIALIZED:
+                errorMsg = "视频模块未初始化";
+                break;
+            case av::ErrorCode::DEVICE_NOT_FOUND:
+                errorMsg = "未找到视频设备";
+                break;
+            default:
+                errorMsg = enabled ? "启用视频录制失败" : "禁用视频录制失败";
+                errorMsg += QString("(错误代码:%1)").arg(static_cast<int>(result));
+                break;
+        }
+        
+        QMessageBox::warning(this, "错误", errorMsg);
+    }
+}
+
+void RecorderMainWidget::updateIndependentControlButtons() {
+    if (!m_recorder) {
+        return;
+    }
+    
+    // 更新音频按钮状态
+    bool audioRecording = m_recorder->isAudioRecording();
+    bool audioCapturing = m_recorder->isAudioCapturing();
+    
+    m_audioStartButton->setEnabled(!audioRecording && m_audioEnableCheck->isChecked());
+    m_audioStopButton->setEnabled(audioCapturing);
+    
+    if (audioRecording) {
+        m_audioStartButton->setText("音频录制中");
+        m_audioStopButton->setText("停止音频");
+    } else if (audioCapturing) {
+        m_audioStartButton->setText("启动音频");
+        m_audioStopButton->setText("停止音频");
+    } else {
+        m_audioStartButton->setText("启动音频");
+        m_audioStopButton->setText("停止音频");
+    }
+    
+    // 更新视频按钮状态
+    bool videoRecording = m_recorder->isVideoRecording();
+    bool videoCapturing = m_recorder->isVideoCapturing();
+    
+    m_videoCaptureButton->setEnabled(!videoRecording && m_videoEnableCheck->isChecked());
+    m_videoStopButton->setEnabled(videoCapturing);
+    
+    if (videoRecording) {
+        m_videoCaptureButton->setText("视频录制中");
+        m_videoStopButton->setText("停止视频");
+    } else if (videoCapturing) {
+        m_videoCaptureButton->setText("启动视频");
+        m_videoStopButton->setText("停止视频");
+    } else {
+        m_videoCaptureButton->setText("启动视频");
+        m_videoStopButton->setText("停止视频");
+    }
+}
+
+void RecorderMainWidget::resetRecorderForRestart() {
+    AV_LOGGER_INFO("Resetting recorder for restart");
+    
+    // 确保录制器处于正确的状态
+    if (m_recorder) {
+        // 强制停止录制器(如果还在运行)
+        m_recorder->close();
+        
+        // 重新创建录制器实例
+        m_recorder = utils::createAVRecorder();
+        if (!m_recorder) {
+            AV_LOGGER_ERROR("Failed to recreate recorder");
+            QMessageBox::critical(this, "错误", "重新创建录制器失败");
+            return;
+        }
+    }
+    
+    // 重置UI状态
+    m_isRecording = false;
+    m_isPaused = false;
+    m_isPreviewActive = false;
+    m_recordDuration = 0;
+    
+    // 更新UI
+    updateUIState();
+    m_statusLabel->setText("就绪");
+    
+    AV_LOGGER_INFO("Recorder reset completed");
+}
+
+// #include "recorder_main_widget.moc"

+ 349 - 0
AV/code/recorder/ui/recorder_main_widget.h

@@ -0,0 +1,349 @@
+#ifndef AV_RECORDER_MAIN_WIDGET_H
+#define AV_RECORDER_MAIN_WIDGET_H
+
+#include <QWidget>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QGridLayout>
+#include <QPushButton>
+#include <QLabel>
+#include <QComboBox>
+#include <QCheckBox>
+#include <QSlider>
+#include <QSpinBox>
+#include <QDoubleSpinBox>
+#include <QLineEdit>
+#include <QProgressBar>
+#include <QTimer>
+#include <QTime>
+#include <QGroupBox>
+#include <QSplitter>
+#include <QStatusBar>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QScreen>
+#include <QScrollArea>
+#include <QTabWidget>
+#include <QMutex>
+#include <memory>
+
+#include "../recorder.h"
+#include "recorder_video_widget.h"
+#include "recorder_audio_widget.h"
+#include "recorder_settings_dialog.h"
+
+using namespace av::recorder;
+
+/**
+ * 录制器主界面
+ * 
+ * 提供完整的音视频录制功能界面,包括:
+ * - 录制控制(开始/停止/暂停/恢复)
+ * - 实时预览窗口
+ * - 音频控制和监控
+ * - 录制设置
+ * - 状态显示
+ */
+class RecorderMainWidget : public QWidget {
+    Q_OBJECT
+
+public:
+    explicit RecorderMainWidget(QWidget* parent = nullptr);
+    ~RecorderMainWidget();
+
+    /**
+     * 初始化录制器
+     */
+    bool initialize();
+    
+    /**
+     * 清理资源
+     */
+    void cleanup();
+
+public slots:
+    /**
+     * 开始录制
+     */
+    void startRecording();
+    
+    /**
+     * 停止录制
+     */
+    void stopRecording();
+    
+    /**
+     * 暂停录制
+     */
+    void pauseRecording();
+    
+    /**
+     * 恢复录制
+     */
+    void resumeRecording();
+    
+    /**
+     * 开始预览
+     */
+    void startPreview();
+    
+    /**
+     * 停止预览
+     */
+    void stopPreview();
+    
+    /**
+     * 打开设置对话框
+     */
+    void openSettings();
+    
+    /**
+     * 选择输出文件
+     */
+    void selectOutputFile();
+    
+    /**
+     * 更新采集设备列表
+     */
+    void updateCaptureDevices();
+    
+    /**
+     * 采集源改变
+     */
+    void onCaptureSourceChanged();
+    
+    /**
+     * 采集方法改变
+     */
+    void onCaptureMethodChanged();
+    
+    /**
+     * 音频设备改变
+     */
+    void onAudioDeviceChanged();
+    
+    /**
+     * 音量改变
+     */
+    void onVolumeChanged(double volume);
+    
+    /**
+     * 静音状态改变
+     */
+    void onMuteChanged(bool muted);
+    
+    /**
+     * 更新录制状态
+     */
+    void updateRecordingStatus();
+    
+    /**
+     * 更新预览帧
+     */
+    void updatePreviewFrame();
+    
+    /**
+     * 更新音频电平
+     */
+    void updateAudioLevel();
+    
+    /**
+     * 独立音频/视频控制槽函数
+     */
+    void onAudioStartClicked();
+    void onAudioStopClicked();
+    void onVideoCaptureClicked();
+    void onVideoStopClicked();
+    void onAudioEnableChanged(bool enabled);
+    void onVideoEnableChanged(bool enabled);
+    
+    /**
+     * 更新独立控制按钮状态
+     */
+    void updateIndependentControlButtons();
+
+private slots:
+    /**
+     * 录制器状态改变
+     */
+    void onRecorderStateChanged(RecorderState state);
+    
+    /**
+     * 录制器错误
+     */
+    void onRecorderError(const QString& error);
+    
+    /**
+     * 统计信息更新
+     */
+    void onStatisticsUpdated();
+
+private:
+    /**
+     * 初始化UI
+     */
+    void initUI();
+    
+    /**
+     * 初始化控制面板
+     */
+    void initControlPanel();
+    
+    /**
+     * 初始化独立控制面板
+     */
+    void initIndependentControlPanel();
+    
+    /**
+     * 初始化预览面板
+     */
+    void initPreviewPanel();
+    
+    /**
+     * 初始化音频面板
+     */
+    void initAudioPanel();
+    
+    /**
+     * 初始化设置面板
+     */
+    void initSettingsPanel();
+    
+    /**
+     * 初始化状态栏
+     */
+    void initStatusBar();
+    
+    /**
+     * 重置录制器状态以便重新启动
+     */
+    void resetRecorderForRestart();
+    
+    /**
+     * 初始化连接
+     */
+    void initConnections();
+    
+    /**
+     * 更新UI状态
+     */
+    void updateUIState();
+    
+    /**
+     * 获取当前录制参数
+     */
+    AVRecorderParams getCurrentParams();
+    
+    /**
+     * 应用录制参数
+     */
+    void applyRecorderParams(const AVRecorderParams& params);
+    
+    /**
+     * 格式化时间
+     */
+    QString formatTime(int64_t ms);
+    
+    /**
+     * 格式化文件大小
+     */
+    QString formatFileSize(int64_t bytes);
+    
+    /**
+     * 格式化比特率
+     */
+    QString formatBitrate(int64_t bps);
+
+private:
+    // 录制器
+    std::unique_ptr<AVRecorder> m_recorder;
+    bool m_isInitialized;
+    bool m_isRecording;
+    bool m_isPaused;
+    bool m_isPreviewActive;
+    
+    // UI组件 - 主布局
+    QSplitter* m_mainSplitter;
+    QWidget* m_leftPanel;
+    QWidget* m_rightPanel;
+    
+    // UI组件 - 控制面板
+    QGroupBox* m_controlGroup;
+    QPushButton* m_recordButton;
+    QPushButton* m_pauseButton;
+    QPushButton* m_stopButton;
+    QPushButton* m_previewButton;
+    QPushButton* m_settingsButton;
+    QLabel* m_recordTimeLabel;
+    QLabel* m_recordStatusLabel;
+    
+    // 独立控制按钮
+    QGroupBox* m_independentControlGroup;
+    QPushButton* m_audioStartButton;
+    QPushButton* m_audioStopButton;
+    QPushButton* m_videoCaptureButton;
+    QPushButton* m_videoStopButton;
+    QCheckBox* m_audioEnableCheck;
+    QCheckBox* m_videoEnableCheck;
+    
+    // UI组件 - 采集设置
+    QGroupBox* m_captureGroup;
+    QComboBox* m_captureMethodCombo;
+    QComboBox* m_captureSourceCombo;
+    QComboBox* m_audioDeviceCombo;
+    QPushButton* m_refreshDevicesButton;
+    QCheckBox* m_drawCursorCheck;
+    QCheckBox* m_captureAudioCheck;
+    
+    // UI组件 - 输出设置
+    QGroupBox* m_outputGroup;
+    QLineEdit* m_outputPathEdit;
+    QPushButton* m_browseOutputButton;
+    QComboBox* m_outputFormatCombo;
+    
+    // UI组件 - 预览面板
+    QGroupBox* m_previewGroup;
+    RecorderVideoWidget* m_videoWidget;
+    
+    // UI组件 - 音频面板
+    QGroupBox* m_audioGroup;
+    RecorderAudioWidget* m_microphoneWidget;
+    RecorderAudioWidget* m_speakerWidget;
+    
+    // UI组件 - 统计信息
+    QGroupBox* m_statsGroup;
+    QLabel* m_fpsLabel;
+    QLabel* m_bitrateLabel;
+    QLabel* m_framesLabel;
+    QLabel* m_droppedFramesLabel;
+    QLabel* m_fileSizeLabel;
+    
+    // UI组件 - 状态栏
+    QStatusBar* m_statusBar;
+    QLabel* m_statusLabel;
+    QProgressBar* m_progressBar;
+    
+    // 定时器
+    QTimer* m_updateTimer;
+    QTimer* m_previewTimer;
+    QTimer* m_audioLevelTimer;
+    
+    // 录制状态
+    QTime m_recordStartTime;
+    int64_t m_recordDuration;
+    
+    // 设置对话框
+    RecorderSettingsDialog* m_settingsDialog;
+    
+    // 线程安全
+    QMutex m_mutex;
+    
+    // 常量
+    static constexpr int UPDATE_INTERVAL_MS = 100;
+    static constexpr int PREVIEW_INTERVAL_MS = 33; // ~30 FPS
+    static constexpr int AUDIO_LEVEL_INTERVAL_MS = 50;
+};
+
+#endif // AV_RECORDER_MAIN_WIDGET_H

+ 1461 - 0
AV/code/recorder/ui/recorder_settings_dialog.cpp

@@ -0,0 +1,1461 @@
+#include "recorder_settings_dialog.h"
+#include "../recorder.h"
+#include <QApplication>
+#include <QMessageBox>
+#include <QDir>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QDateTime>
+#include <QDebug>
+#include <QHeaderView>
+#include <QSplitter>
+#include <QFormLayout>
+#include <QButtonGroup>
+#include <QRadioButton>
+#include <QScrollArea>
+#include <QCloseEvent>
+
+RecorderSettingsDialog::RecorderSettingsDialog(av::recorder::RecorderModule* recorderModule, QWidget* parent)
+    : QDialog(parent)
+    , m_recorderModule(recorderModule)
+    , m_tabWidget(nullptr)
+    , m_mainLayout(nullptr)
+    , m_buttonLayout(nullptr)
+    , m_okButton(nullptr)
+    , m_cancelButton(nullptr)
+    , m_applyButton(nullptr)
+    , m_resetButton(nullptr)
+    , m_settingsChanged(false)
+    , m_updating(false) {
+    
+    setWindowTitle("录制器设置");
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+    setModal(true);
+    resize(800, 600);
+    
+    // 初始化定时器
+    m_previewUpdateTimer = new QTimer(this);
+    m_previewUpdateTimer->setSingleShot(true);
+    m_previewUpdateTimer->setInterval(500);
+    connect(m_previewUpdateTimer, &QTimer::timeout, this, &RecorderSettingsDialog::updatePreview);
+    
+    m_deviceRefreshTimer = new QTimer(this);
+    m_deviceRefreshTimer->setInterval(5000); // 每5秒刷新一次设备列表
+    connect(m_deviceRefreshTimer, &QTimer::timeout, this, &RecorderSettingsDialog::refreshDevices);
+    
+    initializeUI();
+    connectSignals();
+    
+    // 加载默认设置
+    m_currentSettings = getDefaultSettings();
+    m_originalSettings = m_currentSettings;
+    
+    loadSettings();
+    writeSettingsToUI();
+    updateUI();
+}
+
+RecorderSettingsDialog::~RecorderSettingsDialog() = default;
+
+void RecorderSettingsDialog::setSettings(const Settings& settings) {
+    m_currentSettings = settings;
+    writeSettingsToUI();
+    updateUI();
+}
+
+RecorderSettingsDialog::Settings RecorderSettingsDialog::getSettings() const {
+    return m_currentSettings;
+}
+
+void RecorderSettingsDialog::showCategory(SettingsCategory category) {
+    if (m_tabWidget) {
+        m_tabWidget->setCurrentIndex(static_cast<int>(category));
+    }
+    show();
+    raise();
+    activateWindow();
+}
+
+void RecorderSettingsDialog::resetToDefaults() {
+    int ret = QMessageBox::question(this, "重置设置", 
+                                   "确定要重置所有设置为默认值吗?",
+                                   QMessageBox::Yes | QMessageBox::No,
+                                   QMessageBox::No);
+    
+    if (ret == QMessageBox::Yes) {
+        m_currentSettings = getDefaultSettings();
+        writeSettingsToUI();
+        updateUI();
+        m_settingsChanged = true;
+    }
+}
+
+void RecorderSettingsDialog::loadSettings() {
+    QSettings settings("AV", "Recorder");
+    
+    // 音频设置
+    settings.beginGroup("Audio");
+    m_currentSettings.audio.deviceName = settings.value("deviceName", "").toString();
+    m_currentSettings.audio.sampleRate = settings.value("sampleRate", 44100).toInt();
+    m_currentSettings.audio.channels = settings.value("channels", 2).toInt();
+    m_currentSettings.audio.bitDepth = settings.value("bitDepth", 16).toInt();
+    m_currentSettings.audio.codec = settings.value("codec", "aac").toString();
+    m_currentSettings.audio.bitrate = settings.value("bitrate", 128000).toInt();
+    m_currentSettings.audio.enableNoiseSuppression = settings.value("enableNoiseSuppression", false).toBool();
+    m_currentSettings.audio.enableEchoCancellation = settings.value("enableEchoCancellation", false).toBool();
+    m_currentSettings.audio.inputGain = settings.value("inputGain", 1.0).toDouble();
+    settings.endGroup();
+    
+    // 视频设置
+    settings.beginGroup("Video");
+    m_currentSettings.video.deviceName = settings.value("deviceName", "").toString();
+    m_currentSettings.video.width = settings.value("width", 1920).toInt();
+    m_currentSettings.video.height = settings.value("height", 1080).toInt();
+    m_currentSettings.video.frameRate = settings.value("frameRate", 30.0).toDouble();
+    m_currentSettings.video.codec = settings.value("codec", "h264").toString();
+    m_currentSettings.video.bitrate = settings.value("bitrate", 5000000).toInt();
+    m_currentSettings.video.preset = settings.value("preset", "medium").toString();
+    m_currentSettings.video.profile = settings.value("profile", "high").toString();
+    m_currentSettings.video.keyFrameInterval = settings.value("keyFrameInterval", 60).toInt();
+    m_currentSettings.video.enableHardwareAcceleration = settings.value("enableHardwareAcceleration", true).toBool();
+    settings.endGroup();
+    
+    // 输出设置
+    settings.beginGroup("Output");
+    m_currentSettings.output.outputDirectory = settings.value("outputDirectory", 
+        QStandardPaths::writableLocation(QStandardPaths::MoviesLocation)).toString();
+    m_currentSettings.output.fileNameTemplate = settings.value("fileNameTemplate", "recording_%Y%m%d_%H%M%S").toString();
+    m_currentSettings.output.containerFormat = settings.value("containerFormat", "mp4").toString();
+    m_currentSettings.output.autoCreateDirectory = settings.value("autoCreateDirectory", true).toBool();
+    m_currentSettings.output.overwriteExisting = settings.value("overwriteExisting", false).toBool();
+    m_currentSettings.output.maxFileSize = settings.value("maxFileSize", 0).toInt();
+    m_currentSettings.output.maxDuration = settings.value("maxDuration", 0).toInt();
+    settings.endGroup();
+    
+    // 高级设置
+    settings.beginGroup("Advanced");
+    m_currentSettings.advanced.bufferSize = settings.value("bufferSize", 4096).toInt();
+    m_currentSettings.advanced.threadCount = settings.value("threadCount", 0).toInt();
+    m_currentSettings.advanced.enableGPUAcceleration = settings.value("enableGPUAcceleration", true).toBool();
+    m_currentSettings.advanced.gpuDevice = settings.value("gpuDevice", "").toString();
+    m_currentSettings.advanced.enableLowLatency = settings.value("enableLowLatency", false).toBool();
+    m_currentSettings.advanced.enableRealTimeEncoding = settings.value("enableRealTimeEncoding", true).toBool();
+    m_currentSettings.advanced.encodingPriority = settings.value("encodingPriority", 0).toInt();
+    settings.endGroup();
+}
+
+void RecorderSettingsDialog::saveSettings() {
+    QSettings settings("AV", "Recorder");
+    
+    // 音频设置
+    settings.beginGroup("Audio");
+    settings.setValue("deviceName", m_currentSettings.audio.deviceName);
+    settings.setValue("sampleRate", m_currentSettings.audio.sampleRate);
+    settings.setValue("channels", m_currentSettings.audio.channels);
+    settings.setValue("bitDepth", m_currentSettings.audio.bitDepth);
+    settings.setValue("codec", m_currentSettings.audio.codec);
+    settings.setValue("bitrate", m_currentSettings.audio.bitrate);
+    settings.setValue("enableNoiseSuppression", m_currentSettings.audio.enableNoiseSuppression);
+    settings.setValue("enableEchoCancellation", m_currentSettings.audio.enableEchoCancellation);
+    settings.setValue("inputGain", m_currentSettings.audio.inputGain);
+    settings.endGroup();
+    
+    // 视频设置
+    settings.beginGroup("Video");
+    settings.setValue("deviceName", m_currentSettings.video.deviceName);
+    settings.setValue("width", m_currentSettings.video.width);
+    settings.setValue("height", m_currentSettings.video.height);
+    settings.setValue("frameRate", m_currentSettings.video.frameRate);
+    settings.setValue("codec", m_currentSettings.video.codec);
+    settings.setValue("bitrate", m_currentSettings.video.bitrate);
+    settings.setValue("preset", m_currentSettings.video.preset);
+    settings.setValue("profile", m_currentSettings.video.profile);
+    settings.setValue("keyFrameInterval", m_currentSettings.video.keyFrameInterval);
+    settings.setValue("enableHardwareAcceleration", m_currentSettings.video.enableHardwareAcceleration);
+    settings.endGroup();
+    
+    // 输出设置
+    settings.beginGroup("Output");
+    settings.setValue("outputDirectory", m_currentSettings.output.outputDirectory);
+    settings.setValue("fileNameTemplate", m_currentSettings.output.fileNameTemplate);
+    settings.setValue("containerFormat", m_currentSettings.output.containerFormat);
+    settings.setValue("autoCreateDirectory", m_currentSettings.output.autoCreateDirectory);
+    settings.setValue("overwriteExisting", m_currentSettings.output.overwriteExisting);
+    settings.setValue("maxFileSize", m_currentSettings.output.maxFileSize);
+    settings.setValue("maxDuration", m_currentSettings.output.maxDuration);
+    settings.endGroup();
+    
+    // 高级设置
+    settings.beginGroup("Advanced");
+    settings.setValue("bufferSize", m_currentSettings.advanced.bufferSize);
+    settings.setValue("threadCount", m_currentSettings.advanced.threadCount);
+    settings.setValue("enableGPUAcceleration", m_currentSettings.advanced.enableGPUAcceleration);
+    settings.setValue("gpuDevice", m_currentSettings.advanced.gpuDevice);
+    settings.setValue("enableLowLatency", m_currentSettings.advanced.enableLowLatency);
+    settings.setValue("enableRealTimeEncoding", m_currentSettings.advanced.enableRealTimeEncoding);
+    settings.setValue("encodingPriority", m_currentSettings.advanced.encodingPriority);
+    settings.endGroup();
+    
+    settings.sync();
+}
+
+bool RecorderSettingsDialog::validateSettings(QString* errorMessage) const {
+    // 验证音频设置
+    if (m_currentSettings.audio.sampleRate <= 0) {
+        if (errorMessage) *errorMessage = "无效的音频采样率";
+        return false;
+    }
+    
+    if (m_currentSettings.audio.channels <= 0 || m_currentSettings.audio.channels > 8) {
+        if (errorMessage) *errorMessage = "无效的音频声道数";
+        return false;
+    }
+    
+    if (m_currentSettings.audio.bitrate <= 0) {
+        if (errorMessage) *errorMessage = "无效的音频比特率";
+        return false;
+    }
+    
+    // 验证视频设置
+    if (m_currentSettings.video.width <= 0 || m_currentSettings.video.height <= 0) {
+        if (errorMessage) *errorMessage = "无效的视频分辨率";
+        return false;
+    }
+    
+    if (m_currentSettings.video.frameRate <= 0) {
+        if (errorMessage) *errorMessage = "无效的视频帧率";
+        return false;
+    }
+    
+    if (m_currentSettings.video.bitrate <= 0) {
+        if (errorMessage) *errorMessage = "无效的视频比特率";
+        return false;
+    }
+    
+    // 验证输出设置
+    if (!validateOutputDirectory(m_currentSettings.output.outputDirectory)) {
+        if (errorMessage) *errorMessage = "输出目录无效或无法访问";
+        return false;
+    }
+    
+    if (m_currentSettings.output.fileNameTemplate.isEmpty()) {
+        if (errorMessage) *errorMessage = "文件名模板不能为空";
+        return false;
+    }
+    
+    return true;
+}
+
+void RecorderSettingsDialog::showEvent(QShowEvent* event) {
+    QDialog::showEvent(event);
+    
+    // 刷新设备列表
+    updateAudioDevices();
+    updateVideoDevices();
+    updateCodecLists();
+    
+    // 启动设备刷新定时器
+    m_deviceRefreshTimer->start();
+}
+
+void RecorderSettingsDialog::closeEvent(QCloseEvent* event) {
+    // 停止定时器
+    m_deviceRefreshTimer->stop();
+    
+    if (m_settingsChanged) {
+        int ret = QMessageBox::question(this, "保存设置", 
+                                       "设置已修改,是否保存?",
+                                       QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
+                                       QMessageBox::Save);
+        
+        if (ret == QMessageBox::Save) {
+            onApplySettings();
+        } else if (ret == QMessageBox::Cancel) {
+            event->ignore();
+            return;
+        }
+    }
+    
+    QDialog::closeEvent(event);
+}
+
+void RecorderSettingsDialog::onTabChanged(int index) {
+    Q_UNUSED(index)
+    updateUI();
+}
+
+void RecorderSettingsDialog::onAudioDeviceChanged(const QString& device) {
+    if (m_updating) return;
+    
+    m_currentSettings.audio.deviceName = device;
+    m_settingsChanged = true;
+    updateUI();
+}
+
+void RecorderSettingsDialog::onVideoDeviceChanged(const QString& device) {
+    if (m_updating) return;
+    
+    m_currentSettings.video.deviceName = device;
+    m_settingsChanged = true;
+    updateUI();
+}
+
+void RecorderSettingsDialog::onOutputDirectoryBrowse() {
+    QString dir = QFileDialog::getExistingDirectory(this, "选择输出目录", 
+                                                   m_currentSettings.output.outputDirectory);
+    if (!dir.isEmpty()) {
+        m_currentSettings.output.outputDirectory = dir;
+        if (m_outputDirectoryEdit) {
+            m_outputDirectoryEdit->setText(dir);
+        }
+        m_settingsChanged = true;
+        updateUI();
+    }
+}
+
+void RecorderSettingsDialog::onFileNameTemplateChanged() {
+    if (m_updating || !m_fileNameTemplateEdit) return;
+    
+    m_currentSettings.output.fileNameTemplate = m_fileNameTemplateEdit->text();
+    m_settingsChanged = true;
+    
+    // 延迟更新预览
+    m_previewUpdateTimer->start();
+}
+
+void RecorderSettingsDialog::onPresetSave() {
+    // TODO: 实现预设保存
+    QMessageBox::information(this, "预设管理", "预设保存功能待实现");
+}
+
+void RecorderSettingsDialog::onPresetLoad() {
+    // TODO: 实现预设加载
+    QMessageBox::information(this, "预设管理", "预设加载功能待实现");
+}
+
+void RecorderSettingsDialog::onPresetDelete() {
+    // TODO: 实现预设删除
+    QMessageBox::information(this, "预设管理", "预设删除功能待实现");
+}
+
+void RecorderSettingsDialog::onPresetExport() {
+    // TODO: 实现预设导出
+    QMessageBox::information(this, "预设管理", "预设导出功能待实现");
+}
+
+void RecorderSettingsDialog::onPresetImport() {
+    // TODO: 实现预设导入
+    QMessageBox::information(this, "预设管理", "预设导入功能待实现");
+}
+
+void RecorderSettingsDialog::onTestAudioDevice() {
+    // TODO: 实现音频设备测试
+    QMessageBox::information(this, "设备测试", "音频设备测试功能待实现");
+}
+
+void RecorderSettingsDialog::onTestVideoDevice() {
+    // TODO: 实现视频设备测试
+    QMessageBox::information(this, "设备测试", "视频设备测试功能待实现");
+}
+
+void RecorderSettingsDialog::onResetCategory() {
+    int currentTab = m_tabWidget ? m_tabWidget->currentIndex() : 0;
+    
+    int ret = QMessageBox::question(this, "重置设置", 
+                                   "确定要重置当前页面的设置为默认值吗?",
+                                   QMessageBox::Yes | QMessageBox::No,
+                                   QMessageBox::No);
+    
+    if (ret == QMessageBox::Yes) {
+        Settings defaultSettings = getDefaultSettings();
+        
+        switch (currentTab) {
+        case AudioCategory:
+            m_currentSettings.audio = defaultSettings.audio;
+            break;
+        case VideoCategory:
+            m_currentSettings.video = defaultSettings.video;
+            break;
+        case OutputCategory:
+            m_currentSettings.output = defaultSettings.output;
+            break;
+        case AdvancedCategory:
+            m_currentSettings.advanced = defaultSettings.advanced;
+            break;
+        default:
+            break;
+        }
+        
+        writeSettingsToUI();
+        updateUI();
+        m_settingsChanged = true;
+    }
+}
+
+void RecorderSettingsDialog::onApplySettings() {
+    readSettingsFromUI();
+    
+    QString errorMessage;
+    if (!validateSettings(&errorMessage)) {
+        QMessageBox::warning(this, "设置错误", errorMessage);
+        return;
+    }
+    
+    saveSettings();
+    emit settingsApplied(m_currentSettings);
+    
+    m_originalSettings = m_currentSettings;
+    m_settingsChanged = false;
+    
+    if (m_applyButton) {
+        m_applyButton->setEnabled(false);
+    }
+}
+
+void RecorderSettingsDialog::onOkClicked() {
+    onApplySettings();
+    accept();
+}
+
+void RecorderSettingsDialog::onCancelClicked() {
+    if (m_settingsChanged) {
+        int ret = QMessageBox::question(this, "取消设置", 
+                                       "设置已修改,确定要取消吗?",
+                                       QMessageBox::Yes | QMessageBox::No,
+                                       QMessageBox::No);
+        
+        if (ret == QMessageBox::No) {
+            return;
+        }
+    }
+    
+    // 恢复原始设置
+    m_currentSettings = m_originalSettings;
+    reject();
+}
+
+void RecorderSettingsDialog::updatePreview() {
+    if (m_fileNamePreviewLabel) {
+        m_fileNamePreviewLabel->setText(formatFileNamePreview());
+    }
+}
+
+void RecorderSettingsDialog::refreshDevices() {
+    updateAudioDevices();
+    updateVideoDevices();
+}
+
+void RecorderSettingsDialog::initializeUI() {
+    // 创建主布局
+    m_mainLayout = new QVBoxLayout(this);
+    m_mainLayout->setContentsMargins(8, 8, 8, 8);
+    m_mainLayout->setSpacing(8);
+    
+    // 创建选项卡
+    m_tabWidget = new QTabWidget();
+    m_tabWidget->addTab(createAudioSettingsPage(), "音频");
+    m_tabWidget->addTab(createVideoSettingsPage(), "视频");
+    m_tabWidget->addTab(createOutputSettingsPage(), "输出");
+    m_tabWidget->addTab(createAdvancedSettingsPage(), "高级");
+    m_tabWidget->addTab(createPresetSettingsPage(), "预设");
+    
+    // 创建按钮布局
+    m_buttonLayout = new QHBoxLayout();
+    
+    m_resetButton = new QPushButton("重置");
+    m_resetButton->setToolTip("重置当前页面设置为默认值");
+    
+    m_buttonLayout->addWidget(m_resetButton);
+    m_buttonLayout->addStretch();
+    
+    m_okButton = new QPushButton("确定");
+    m_okButton->setDefault(true);
+    
+    m_cancelButton = new QPushButton("取消");
+    
+    m_applyButton = new QPushButton("应用");
+    m_applyButton->setEnabled(false);
+    
+    m_buttonLayout->addWidget(m_okButton);
+    m_buttonLayout->addWidget(m_cancelButton);
+    m_buttonLayout->addWidget(m_applyButton);
+    
+    // 添加到主布局
+    m_mainLayout->addWidget(m_tabWidget);
+    m_mainLayout->addLayout(m_buttonLayout);
+    
+    // 设置样式
+    setStyleSheet(R"(
+        QDialog {
+            background-color: #2b2b2b;
+            color: #fff;
+        }
+        QTabWidget::pane {
+            border: 1px solid #555;
+            background-color: #333;
+        }
+        QTabBar::tab {
+            background-color: #444;
+            color: #fff;
+            padding: 8px 16px;
+            margin-right: 2px;
+        }
+        QTabBar::tab:selected {
+            background-color: #0a84ff;
+        }
+        QTabBar::tab:hover {
+            background-color: #555;
+        }
+        QGroupBox {
+            font-weight: bold;
+            border: 1px solid #555;
+            border-radius: 4px;
+            margin-top: 8px;
+            padding-top: 8px;
+        }
+        QGroupBox::title {
+            subcontrol-origin: margin;
+            left: 8px;
+            padding: 0 4px 0 4px;
+        }
+        QLabel {
+            color: #fff;
+        }
+        QLineEdit, QComboBox, QSpinBox, QDoubleSpinBox {
+            background-color: #444;
+            border: 1px solid #666;
+            border-radius: 3px;
+            color: #fff;
+            padding: 4px;
+        }
+        QLineEdit:focus, QComboBox:focus, QSpinBox:focus, QDoubleSpinBox:focus {
+            border-color: #0a84ff;
+        }
+        QPushButton {
+            background-color: #444;
+            border: 1px solid #666;
+            border-radius: 3px;
+            color: #fff;
+            padding: 6px 12px;
+        }
+        QPushButton:hover {
+            background-color: #555;
+        }
+        QPushButton:pressed {
+            background-color: #333;
+        }
+        QPushButton:default {
+            background-color: #0a84ff;
+        }
+        QCheckBox {
+            color: #fff;
+        }
+        QCheckBox::indicator {
+            width: 16px;
+            height: 16px;
+        }
+        QCheckBox::indicator:unchecked {
+            background-color: #444;
+            border: 1px solid #666;
+        }
+        QCheckBox::indicator:checked {
+            background-color: #0a84ff;
+            border: 1px solid #0a84ff;
+        }
+        QSlider::groove:horizontal {
+            border: 1px solid #555;
+            height: 6px;
+            background: #333;
+            border-radius: 3px;
+        }
+        QSlider::handle:horizontal {
+            background: #0a84ff;
+            border: 1px solid #0a84ff;
+            width: 14px;
+            margin: -4px 0;
+            border-radius: 7px;
+        }
+        QSlider::sub-page:horizontal {
+            background: #0a84ff;
+            border-radius: 3px;
+        }
+    )");
+}
+
+QWidget* RecorderSettingsDialog::createAudioSettingsPage() {
+    QWidget* page = new QWidget();
+    QVBoxLayout* layout = new QVBoxLayout(page);
+    layout->setContentsMargins(16, 16, 16, 16);
+    layout->setSpacing(12);
+    
+    // 音频设备组
+    QGroupBox* deviceGroup = new QGroupBox("音频设备");
+    QFormLayout* deviceLayout = new QFormLayout(deviceGroup);
+    
+    m_audioDeviceCombo = new QComboBox();
+    m_testAudioButton = new QPushButton("测试");
+    m_testAudioButton->setMaximumWidth(60);
+    
+    QHBoxLayout* deviceControlLayout = new QHBoxLayout();
+    deviceControlLayout->addWidget(m_audioDeviceCombo);
+    deviceControlLayout->addWidget(m_testAudioButton);
+    
+    deviceLayout->addRow("设备:", deviceControlLayout);
+    
+    // 音频格式组
+    QGroupBox* formatGroup = new QGroupBox("音频格式");
+    QFormLayout* formatLayout = new QFormLayout(formatGroup);
+    
+    m_audioSampleRateCombo = new QComboBox();
+    m_audioSampleRateCombo->addItems({"8000", "16000", "22050", "44100", "48000", "96000"});
+    m_audioSampleRateCombo->setCurrentText("44100");
+    
+    m_audioChannelsCombo = new QComboBox();
+    m_audioChannelsCombo->addItems({"1 (单声道)", "2 (立体声)", "6 (5.1)", "8 (7.1)"});
+    m_audioChannelsCombo->setCurrentIndex(1);
+    
+    m_audioBitDepthCombo = new QComboBox();
+    m_audioBitDepthCombo->addItems({"16", "24", "32"});
+    m_audioBitDepthCombo->setCurrentText("16");
+    
+    formatLayout->addRow("采样率:", m_audioSampleRateCombo);
+    formatLayout->addRow("声道:", m_audioChannelsCombo);
+    formatLayout->addRow("位深:", m_audioBitDepthCombo);
+    
+    // 音频编码组
+    QGroupBox* codecGroup = new QGroupBox("音频编码");
+    QFormLayout* codecLayout = new QFormLayout(codecGroup);
+    
+    m_audioCodecCombo = new QComboBox();
+    m_audioCodecCombo->addItems({"AAC", "MP3", "FLAC", "PCM"});
+    m_audioCodecCombo->setCurrentText("AAC");
+    
+    m_audioBitrateSpinBox = new QSpinBox();
+    m_audioBitrateSpinBox->setRange(64, 320);
+    m_audioBitrateSpinBox->setValue(128);
+    m_audioBitrateSpinBox->setSuffix(" kbps");
+    
+    codecLayout->addRow("编码器:", m_audioCodecCombo);
+    codecLayout->addRow("比特率:", m_audioBitrateSpinBox);
+    
+    // 音频处理组
+    QGroupBox* processingGroup = new QGroupBox("音频处理");
+    QFormLayout* processingLayout = new QFormLayout(processingGroup);
+    
+    m_audioNoiseSuppressionCheckBox = new QCheckBox("启用噪声抑制");
+    m_audioEchoCancellationCheckBox = new QCheckBox("启用回声消除");
+    
+    m_audioInputGainSpinBox = new QDoubleSpinBox();
+    m_audioInputGainSpinBox->setRange(0.1, 10.0);
+    m_audioInputGainSpinBox->setValue(1.0);
+    m_audioInputGainSpinBox->setSingleStep(0.1);
+    m_audioInputGainSpinBox->setDecimals(1);
+    
+    processingLayout->addRow(m_audioNoiseSuppressionCheckBox);
+    processingLayout->addRow(m_audioEchoCancellationCheckBox);
+    processingLayout->addRow("输入增益:", m_audioInputGainSpinBox);
+    
+    // 添加到页面布局
+    layout->addWidget(deviceGroup);
+    layout->addWidget(formatGroup);
+    layout->addWidget(codecGroup);
+    layout->addWidget(processingGroup);
+    layout->addStretch();
+    
+    return page;
+}
+
+QWidget* RecorderSettingsDialog::createVideoSettingsPage() {
+    QWidget* page = new QWidget();
+    QVBoxLayout* layout = new QVBoxLayout(page);
+    layout->setContentsMargins(16, 16, 16, 16);
+    layout->setSpacing(12);
+    
+    // 视频设备组
+    QGroupBox* deviceGroup = new QGroupBox("视频设备");
+    QFormLayout* deviceLayout = new QFormLayout(deviceGroup);
+    
+    m_videoDeviceCombo = new QComboBox();
+    m_testVideoButton = new QPushButton("测试");
+    m_testVideoButton->setMaximumWidth(60);
+    
+    QHBoxLayout* deviceControlLayout = new QHBoxLayout();
+    deviceControlLayout->addWidget(m_videoDeviceCombo);
+    deviceControlLayout->addWidget(m_testVideoButton);
+    
+    deviceLayout->addRow("设备:", deviceControlLayout);
+    
+    // 视频格式组
+    QGroupBox* formatGroup = new QGroupBox("视频格式");
+    QFormLayout* formatLayout = new QFormLayout(formatGroup);
+    
+    m_videoResolutionCombo = new QComboBox();
+    m_videoResolutionCombo->addItems({
+        "640x480", "800x600", "1024x768", "1280x720", 
+        "1920x1080", "2560x1440", "3840x2160"
+    });
+    m_videoResolutionCombo->setCurrentText("1920x1080");
+    
+    m_videoFrameRateSpinBox = new QDoubleSpinBox();
+    m_videoFrameRateSpinBox->setRange(1.0, 120.0);
+    m_videoFrameRateSpinBox->setValue(30.0);
+    m_videoFrameRateSpinBox->setSingleStep(1.0);
+    m_videoFrameRateSpinBox->setDecimals(1);
+    m_videoFrameRateSpinBox->setSuffix(" fps");
+    
+    formatLayout->addRow("分辨率:", m_videoResolutionCombo);
+    formatLayout->addRow("帧率:", m_videoFrameRateSpinBox);
+    
+    // 视频编码组
+    QGroupBox* codecGroup = new QGroupBox("视频编码");
+    QFormLayout* codecLayout = new QFormLayout(codecGroup);
+    
+    m_videoCodecCombo = new QComboBox();
+    m_videoCodecCombo->addItems({"H.264", "H.265", "VP9", "AV1"});
+    m_videoCodecCombo->setCurrentText("H.264");
+    
+    m_videoBitrateSpinBox = new QSpinBox();
+    m_videoBitrateSpinBox->setRange(500, 50000);
+    m_videoBitrateSpinBox->setValue(5000);
+    m_videoBitrateSpinBox->setSuffix(" kbps");
+    
+    m_videoPresetCombo = new QComboBox();
+    m_videoPresetCombo->addItems({"ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow"});
+    m_videoPresetCombo->setCurrentText("medium");
+    
+    m_videoProfileCombo = new QComboBox();
+    m_videoProfileCombo->addItems({"baseline", "main", "high"});
+    m_videoProfileCombo->setCurrentText("high");
+    
+    m_videoKeyFrameSpinBox = new QSpinBox();
+    m_videoKeyFrameSpinBox->setRange(1, 300);
+    m_videoKeyFrameSpinBox->setValue(60);
+    
+    codecLayout->addRow("编码器:", m_videoCodecCombo);
+    codecLayout->addRow("比特率:", m_videoBitrateSpinBox);
+    codecLayout->addRow("预设:", m_videoPresetCombo);
+    codecLayout->addRow("配置:", m_videoProfileCombo);
+    codecLayout->addRow("关键帧间隔:", m_videoKeyFrameSpinBox);
+    
+    // 硬件加速组
+    QGroupBox* accelerationGroup = new QGroupBox("硬件加速");
+    QFormLayout* accelerationLayout = new QFormLayout(accelerationGroup);
+    
+    m_videoHardwareAccelCheckBox = new QCheckBox("启用硬件加速");
+    m_videoHardwareAccelCheckBox->setChecked(true);
+    
+    accelerationLayout->addRow(m_videoHardwareAccelCheckBox);
+    
+    // 添加到页面布局
+    layout->addWidget(deviceGroup);
+    layout->addWidget(formatGroup);
+    layout->addWidget(codecGroup);
+    layout->addWidget(accelerationGroup);
+    layout->addStretch();
+    
+    return page;
+}
+
+QWidget* RecorderSettingsDialog::createOutputSettingsPage() {
+    QWidget* page = new QWidget();
+    QVBoxLayout* layout = new QVBoxLayout(page);
+    layout->setContentsMargins(16, 16, 16, 16);
+    layout->setSpacing(12);
+    
+    // 输出路径组
+    QGroupBox* pathGroup = new QGroupBox("输出路径");
+    QFormLayout* pathLayout = new QFormLayout(pathGroup);
+    
+    m_outputDirectoryEdit = new QLineEdit();
+    m_outputDirectoryBrowseButton = new QPushButton("浏览");
+    m_outputDirectoryBrowseButton->setMaximumWidth(60);
+    
+    QHBoxLayout* pathControlLayout = new QHBoxLayout();
+    pathControlLayout->addWidget(m_outputDirectoryEdit);
+    pathControlLayout->addWidget(m_outputDirectoryBrowseButton);
+    
+    pathLayout->addRow("输出目录:", pathControlLayout);
+    
+    // 文件命名组
+    QGroupBox* namingGroup = new QGroupBox("文件命名");
+    QFormLayout* namingLayout = new QFormLayout(namingGroup);
+    
+    m_fileNameTemplateEdit = new QLineEdit();
+    m_fileNameTemplateEdit->setText("recording_%Y%m%d_%H%M%S");
+    
+    m_fileNamePreviewLabel = new QLabel();
+    m_fileNamePreviewLabel->setStyleSheet("color: #888; font-style: italic;");
+    
+    namingLayout->addRow("文件名模板:", m_fileNameTemplateEdit);
+    namingLayout->addRow("预览:", m_fileNamePreviewLabel);
+    
+    // 格式设置组
+    QGroupBox* formatGroup = new QGroupBox("格式设置");
+    QFormLayout* formatLayout = new QFormLayout(formatGroup);
+    
+    m_containerFormatCombo = new QComboBox();
+    m_containerFormatCombo->addItems({"MP4", "AVI", "MKV", "MOV", "FLV"});
+    m_containerFormatCombo->setCurrentText("MP4");
+    
+    formatLayout->addRow("容器格式:", m_containerFormatCombo);
+    
+    // 文件选项组
+    QGroupBox* optionsGroup = new QGroupBox("文件选项");
+    QFormLayout* optionsLayout = new QFormLayout(optionsGroup);
+    
+    m_autoCreateDirectoryCheckBox = new QCheckBox("自动创建目录");
+    m_autoCreateDirectoryCheckBox->setChecked(true);
+    
+    m_overwriteExistingCheckBox = new QCheckBox("覆盖已存在文件");
+    
+    m_maxFileSizeSpinBox = new QSpinBox();
+    m_maxFileSizeSpinBox->setRange(0, 10000);
+    m_maxFileSizeSpinBox->setValue(0);
+    m_maxFileSizeSpinBox->setSuffix(" MB (0=无限制)");
+    
+    m_maxDurationSpinBox = new QSpinBox();
+    m_maxDurationSpinBox->setRange(0, 10000);
+    m_maxDurationSpinBox->setValue(0);
+    m_maxDurationSpinBox->setSuffix(" 分钟 (0=无限制)");
+    
+    optionsLayout->addRow(m_autoCreateDirectoryCheckBox);
+    optionsLayout->addRow(m_overwriteExistingCheckBox);
+    optionsLayout->addRow("最大文件大小:", m_maxFileSizeSpinBox);
+    optionsLayout->addRow("最大录制时长:", m_maxDurationSpinBox);
+    
+    // 添加到页面布局
+    layout->addWidget(pathGroup);
+    layout->addWidget(namingGroup);
+    layout->addWidget(formatGroup);
+    layout->addWidget(optionsGroup);
+    layout->addStretch();
+    
+    return page;
+}
+
+QWidget* RecorderSettingsDialog::createAdvancedSettingsPage() {
+    QWidget* page = new QWidget();
+    QVBoxLayout* layout = new QVBoxLayout(page);
+    layout->setContentsMargins(16, 16, 16, 16);
+    layout->setSpacing(12);
+    
+    // 性能设置组
+    QGroupBox* performanceGroup = new QGroupBox("性能设置");
+    QFormLayout* performanceLayout = new QFormLayout(performanceGroup);
+    
+    m_bufferSizeSpinBox = new QSpinBox();
+    m_bufferSizeSpinBox->setRange(1024, 65536);
+    m_bufferSizeSpinBox->setValue(4096);
+    
+    m_threadCountSpinBox = new QSpinBox();
+    m_threadCountSpinBox->setRange(0, 16);
+    m_threadCountSpinBox->setValue(0);
+    m_threadCountSpinBox->setSuffix(" (0=自动)");
+    
+    performanceLayout->addRow("缓冲区大小:", m_bufferSizeSpinBox);
+    performanceLayout->addRow("线程数:", m_threadCountSpinBox);
+    
+    // GPU加速组
+    QGroupBox* gpuGroup = new QGroupBox("GPU加速");
+    QFormLayout* gpuLayout = new QFormLayout(gpuGroup);
+    
+    m_gpuAccelerationCheckBox = new QCheckBox("启用GPU加速");
+    m_gpuAccelerationCheckBox->setChecked(true);
+    
+    m_gpuDeviceCombo = new QComboBox();
+    m_gpuDeviceCombo->addItems({"自动选择", "NVIDIA CUDA", "Intel Quick Sync", "AMD VCE"});
+    
+    gpuLayout->addRow(m_gpuAccelerationCheckBox);
+    gpuLayout->addRow("GPU设备:", m_gpuDeviceCombo);
+    
+    // 编码设置组
+    QGroupBox* encodingGroup = new QGroupBox("编码设置");
+    QFormLayout* encodingLayout = new QFormLayout(encodingGroup);
+    
+    m_lowLatencyCheckBox = new QCheckBox("启用低延迟模式");
+    m_realTimeEncodingCheckBox = new QCheckBox("启用实时编码");
+    m_realTimeEncodingCheckBox->setChecked(true);
+    
+    m_encodingPrioritySlider = new QSlider(Qt::Horizontal);
+    m_encodingPrioritySlider->setRange(-2, 2);
+    m_encodingPrioritySlider->setValue(0);
+    m_encodingPrioritySlider->setTickPosition(QSlider::TicksBelow);
+    m_encodingPrioritySlider->setTickInterval(1);
+    
+    m_encodingPriorityLabel = new QLabel("正常");
+    
+    QHBoxLayout* priorityLayout = new QHBoxLayout();
+    priorityLayout->addWidget(m_encodingPrioritySlider);
+    priorityLayout->addWidget(m_encodingPriorityLabel);
+    
+    encodingLayout->addRow(m_lowLatencyCheckBox);
+    encodingLayout->addRow(m_realTimeEncodingCheckBox);
+    encodingLayout->addRow("编码优先级:", priorityLayout);
+    
+    // 添加到页面布局
+    layout->addWidget(performanceGroup);
+    layout->addWidget(gpuGroup);
+    layout->addWidget(encodingGroup);
+    layout->addStretch();
+    
+    return page;
+}
+
+QWidget* RecorderSettingsDialog::createPresetSettingsPage() {
+    QWidget* page = new QWidget();
+    QVBoxLayout* layout = new QVBoxLayout(page);
+    layout->setContentsMargins(16, 16, 16, 16);
+    layout->setSpacing(12);
+    
+    // 预设列表组
+    QGroupBox* listGroup = new QGroupBox("预设列表");
+    QVBoxLayout* listLayout = new QVBoxLayout(listGroup);
+    
+    m_presetListWidget = new QListWidget();
+    m_presetListWidget->setMinimumHeight(200);
+    
+    listLayout->addWidget(m_presetListWidget);
+    
+    // 预设操作组
+    QGroupBox* operationsGroup = new QGroupBox("预设操作");
+    QHBoxLayout* operationsLayout = new QHBoxLayout(operationsGroup);
+    
+    m_savePresetButton = new QPushButton("保存");
+    m_loadPresetButton = new QPushButton("加载");
+    m_deletePresetButton = new QPushButton("删除");
+    m_exportPresetButton = new QPushButton("导出");
+    m_importPresetButton = new QPushButton("导入");
+    
+    operationsLayout->addWidget(m_savePresetButton);
+    operationsLayout->addWidget(m_loadPresetButton);
+    operationsLayout->addWidget(m_deletePresetButton);
+    operationsLayout->addStretch();
+    operationsLayout->addWidget(m_exportPresetButton);
+    operationsLayout->addWidget(m_importPresetButton);
+    
+    // 预设描述组
+    QGroupBox* descriptionGroup = new QGroupBox("预设描述");
+    QVBoxLayout* descriptionLayout = new QVBoxLayout(descriptionGroup);
+    
+    m_presetDescriptionEdit = new QTextEdit();
+    m_presetDescriptionEdit->setMaximumHeight(100);
+    m_presetDescriptionEdit->setPlaceholderText("输入预设描述...");
+    
+    descriptionLayout->addWidget(m_presetDescriptionEdit);
+    
+    // 添加到页面布局
+    layout->addWidget(listGroup);
+    layout->addWidget(operationsGroup);
+    layout->addWidget(descriptionGroup);
+    
+    return page;
+}
+
+void RecorderSettingsDialog::connectSignals() {
+    // 选项卡信号
+    connect(m_tabWidget, QOverload<int>::of(&QTabWidget::currentChanged),
+            this, &RecorderSettingsDialog::onTabChanged);
+    
+    // 按钮信号
+    connect(m_okButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onOkClicked);
+    connect(m_cancelButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onCancelClicked);
+    connect(m_applyButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onApplySettings);
+    connect(m_resetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onResetCategory);
+    
+    // 音频设置信号
+    if (m_audioDeviceCombo) {
+        connect(m_audioDeviceCombo, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
+                this, &RecorderSettingsDialog::onAudioDeviceChanged);
+    }
+    if (m_testAudioButton) {
+        connect(m_testAudioButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onTestAudioDevice);
+    }
+    
+    // 视频设置信号
+    if (m_videoDeviceCombo) {
+        connect(m_videoDeviceCombo, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
+                this, &RecorderSettingsDialog::onVideoDeviceChanged);
+    }
+    if (m_testVideoButton) {
+        connect(m_testVideoButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onTestVideoDevice);
+    }
+    
+    // 输出设置信号
+    if (m_outputDirectoryBrowseButton) {
+        connect(m_outputDirectoryBrowseButton, &QPushButton::clicked, 
+                this, &RecorderSettingsDialog::onOutputDirectoryBrowse);
+    }
+    if (m_fileNameTemplateEdit) {
+        connect(m_fileNameTemplateEdit, &QLineEdit::textChanged, 
+                this, &RecorderSettingsDialog::onFileNameTemplateChanged);
+    }
+    
+    // 预设管理信号
+    if (m_savePresetButton) {
+        connect(m_savePresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetSave);
+    }
+    if (m_loadPresetButton) {
+        connect(m_loadPresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetLoad);
+    }
+    if (m_deletePresetButton) {
+        connect(m_deletePresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetDelete);
+    }
+    if (m_exportPresetButton) {
+        connect(m_exportPresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetExport);
+    }
+    if (m_importPresetButton) {
+        connect(m_importPresetButton, &QPushButton::clicked, this, &RecorderSettingsDialog::onPresetImport);
+    }
+    
+    // 高级设置信号
+    if (m_encodingPrioritySlider) {
+        connect(m_encodingPrioritySlider, &QSlider::valueChanged, [this](int value) {
+            if (m_encodingPriorityLabel) {
+                QStringList labels = {"最低", "低", "正常", "高", "最高"};
+                m_encodingPriorityLabel->setText(labels[value + 2]);
+            }
+            m_settingsChanged = true;
+            if (m_applyButton) m_applyButton->setEnabled(true);
+        });
+    }
+    
+    // 通用设置改变信号
+    auto connectSettingsChanged = [this](QWidget* widget) {
+        if (auto* combo = qobject_cast<QComboBox*>(widget)) {
+            connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() {
+                if (!m_updating) {
+                    m_settingsChanged = true;
+                    if (m_applyButton) m_applyButton->setEnabled(true);
+                }
+            });
+        } else if (auto* spinBox = qobject_cast<QSpinBox*>(widget)) {
+            connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), [this]() {
+                if (!m_updating) {
+                    m_settingsChanged = true;
+                    if (m_applyButton) m_applyButton->setEnabled(true);
+                }
+            });
+        } else if (auto* doubleSpinBox = qobject_cast<QDoubleSpinBox*>(widget)) {
+            connect(doubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this]() {
+                if (!m_updating) {
+                    m_settingsChanged = true;
+                    if (m_applyButton) m_applyButton->setEnabled(true);
+                }
+            });
+        } else if (auto* checkBox = qobject_cast<QCheckBox*>(widget)) {
+            connect(checkBox, &QCheckBox::toggled, [this]() {
+                if (!m_updating) {
+                    m_settingsChanged = true;
+                    if (m_applyButton) m_applyButton->setEnabled(true);
+                }
+            });
+        } else if (auto* lineEdit = qobject_cast<QLineEdit*>(widget)) {
+            connect(lineEdit, &QLineEdit::textChanged, [this]() {
+                if (!m_updating) {
+                    m_settingsChanged = true;
+                    if (m_applyButton) m_applyButton->setEnabled(true);
+                }
+            });
+        }
+    };
+    
+    // 连接所有设置控件
+    QList<QWidget*> settingsWidgets = {
+        m_audioSampleRateCombo, m_audioChannelsCombo, m_audioBitDepthCombo,
+        m_audioCodecCombo, m_audioBitrateSpinBox, m_audioNoiseSuppressionCheckBox,
+        m_audioEchoCancellationCheckBox, m_audioInputGainSpinBox,
+        m_videoResolutionCombo, m_videoFrameRateSpinBox, m_videoCodecCombo,
+        m_videoBitrateSpinBox, m_videoPresetCombo, m_videoProfileCombo,
+        m_videoKeyFrameSpinBox, m_videoHardwareAccelCheckBox,
+        m_outputDirectoryEdit, m_containerFormatCombo, m_autoCreateDirectoryCheckBox,
+        m_overwriteExistingCheckBox, m_maxFileSizeSpinBox, m_maxDurationSpinBox,
+        m_bufferSizeSpinBox, m_threadCountSpinBox, m_gpuAccelerationCheckBox,
+        m_gpuDeviceCombo, m_lowLatencyCheckBox, m_realTimeEncodingCheckBox
+    };
+    
+    for (QWidget* widget : settingsWidgets) {
+        if (widget) {
+            connectSettingsChanged(widget);
+        }
+    }
+}
+
+void RecorderSettingsDialog::updateUI() {
+    // 更新按钮状态
+    if (m_applyButton) {
+        m_applyButton->setEnabled(m_settingsChanged);
+    }
+    
+    // 更新预览
+    updatePreview();
+}
+
+void RecorderSettingsDialog::updateAudioDevices() {
+    if (!m_audioDeviceCombo || !m_recorderModule) {
+        return;
+    }
+    
+    // TODO: 从录制器模块获取音频设备列表
+    QStringList devices = {"默认音频设备", "麦克风 (内置)", "麦克风 (USB)"};
+    
+    QString currentDevice = m_audioDeviceCombo->currentText();
+    m_audioDeviceCombo->clear();
+    m_audioDeviceCombo->addItems(devices);
+    
+    int index = m_audioDeviceCombo->findText(currentDevice);
+    if (index >= 0) {
+        m_audioDeviceCombo->setCurrentIndex(index);
+    }
+}
+
+void RecorderSettingsDialog::updateVideoDevices() {
+    if (!m_videoDeviceCombo || !m_recorderModule) {
+        return;
+    }
+    
+    // TODO: 从录制器模块获取视频设备列表
+    QStringList devices = {"默认摄像头", "USB摄像头", "屏幕录制"};
+    
+    QString currentDevice = m_videoDeviceCombo->currentText();
+    m_videoDeviceCombo->clear();
+    m_videoDeviceCombo->addItems(devices);
+    
+    int index = m_videoDeviceCombo->findText(currentDevice);
+    if (index >= 0) {
+        m_videoDeviceCombo->setCurrentIndex(index);
+    }
+}
+
+void RecorderSettingsDialog::updateCodecLists() {
+    // TODO: 从录制器模块获取支持的编码器列表
+}
+
+void RecorderSettingsDialog::updatePresetList() {
+    if (!m_presetListWidget) {
+        return;
+    }
+    
+    // TODO: 加载预设列表
+    m_presetListWidget->clear();
+    m_presetListWidget->addItems({"默认设置", "高质量", "低延迟", "直播"});
+}
+
+void RecorderSettingsDialog::readSettingsFromUI() {
+    m_updating = true;
+    
+    // 读取音频设置
+    if (m_audioDeviceCombo) {
+        m_currentSettings.audio.deviceName = m_audioDeviceCombo->currentText();
+    }
+    if (m_audioSampleRateCombo) {
+        m_currentSettings.audio.sampleRate = m_audioSampleRateCombo->currentText().toInt();
+    }
+    if (m_audioChannelsCombo) {
+        m_currentSettings.audio.channels = m_audioChannelsCombo->currentIndex() == 0 ? 1 : 
+                                          (m_audioChannelsCombo->currentIndex() == 1 ? 2 : 
+                                          (m_audioChannelsCombo->currentIndex() == 2 ? 6 : 8));
+    }
+    if (m_audioBitDepthCombo) {
+        m_currentSettings.audio.bitDepth = m_audioBitDepthCombo->currentText().toInt();
+    }
+    if (m_audioCodecCombo) {
+        m_currentSettings.audio.codec = m_audioCodecCombo->currentText().toLower();
+    }
+    if (m_audioBitrateSpinBox) {
+        m_currentSettings.audio.bitrate = m_audioBitrateSpinBox->value() * 1000;
+    }
+    if (m_audioNoiseSuppressionCheckBox) {
+        m_currentSettings.audio.enableNoiseSuppression = m_audioNoiseSuppressionCheckBox->isChecked();
+    }
+    if (m_audioEchoCancellationCheckBox) {
+        m_currentSettings.audio.enableEchoCancellation = m_audioEchoCancellationCheckBox->isChecked();
+    }
+    if (m_audioInputGainSpinBox) {
+        m_currentSettings.audio.inputGain = m_audioInputGainSpinBox->value();
+    }
+    
+    // 读取视频设置
+    if (m_videoDeviceCombo) {
+        m_currentSettings.video.deviceName = m_videoDeviceCombo->currentText();
+    }
+    if (m_videoResolutionCombo) {
+        QStringList parts = m_videoResolutionCombo->currentText().split('x');
+        if (parts.size() == 2) {
+            m_currentSettings.video.width = parts[0].toInt();
+            m_currentSettings.video.height = parts[1].toInt();
+        }
+    }
+    if (m_videoFrameRateSpinBox) {
+        m_currentSettings.video.frameRate = m_videoFrameRateSpinBox->value();
+    }
+    if (m_videoCodecCombo) {
+        QString codec = m_videoCodecCombo->currentText().toLower();
+        if (codec == "h.264") codec = "h264";
+        else if (codec == "h.265") codec = "h265";
+        m_currentSettings.video.codec = codec;
+    }
+    if (m_videoBitrateSpinBox) {
+        m_currentSettings.video.bitrate = m_videoBitrateSpinBox->value() * 1000;
+    }
+    if (m_videoPresetCombo) {
+        m_currentSettings.video.preset = m_videoPresetCombo->currentText();
+    }
+    if (m_videoProfileCombo) {
+        m_currentSettings.video.profile = m_videoProfileCombo->currentText();
+    }
+    if (m_videoKeyFrameSpinBox) {
+        m_currentSettings.video.keyFrameInterval = m_videoKeyFrameSpinBox->value();
+    }
+    if (m_videoHardwareAccelCheckBox) {
+        m_currentSettings.video.enableHardwareAcceleration = m_videoHardwareAccelCheckBox->isChecked();
+    }
+    
+    // 读取输出设置
+    if (m_outputDirectoryEdit) {
+        m_currentSettings.output.outputDirectory = m_outputDirectoryEdit->text();
+    }
+    if (m_fileNameTemplateEdit) {
+        m_currentSettings.output.fileNameTemplate = m_fileNameTemplateEdit->text();
+    }
+    if (m_containerFormatCombo) {
+        m_currentSettings.output.containerFormat = m_containerFormatCombo->currentText().toLower();
+    }
+    if (m_autoCreateDirectoryCheckBox) {
+        m_currentSettings.output.autoCreateDirectory = m_autoCreateDirectoryCheckBox->isChecked();
+    }
+    if (m_overwriteExistingCheckBox) {
+        m_currentSettings.output.overwriteExisting = m_overwriteExistingCheckBox->isChecked();
+    }
+    if (m_maxFileSizeSpinBox) {
+        m_currentSettings.output.maxFileSize = m_maxFileSizeSpinBox->value();
+    }
+    if (m_maxDurationSpinBox) {
+        m_currentSettings.output.maxDuration = m_maxDurationSpinBox->value();
+    }
+    
+    // 读取高级设置
+    if (m_bufferSizeSpinBox) {
+        m_currentSettings.advanced.bufferSize = m_bufferSizeSpinBox->value();
+    }
+    if (m_threadCountSpinBox) {
+        m_currentSettings.advanced.threadCount = m_threadCountSpinBox->value();
+    }
+    if (m_gpuAccelerationCheckBox) {
+        m_currentSettings.advanced.enableGPUAcceleration = m_gpuAccelerationCheckBox->isChecked();
+    }
+    if (m_gpuDeviceCombo) {
+        m_currentSettings.advanced.gpuDevice = m_gpuDeviceCombo->currentText();
+    }
+    if (m_lowLatencyCheckBox) {
+        m_currentSettings.advanced.enableLowLatency = m_lowLatencyCheckBox->isChecked();
+    }
+    if (m_realTimeEncodingCheckBox) {
+        m_currentSettings.advanced.enableRealTimeEncoding = m_realTimeEncodingCheckBox->isChecked();
+    }
+    if (m_encodingPrioritySlider) {
+        m_currentSettings.advanced.encodingPriority = m_encodingPrioritySlider->value();
+    }
+    
+    m_updating = false;
+}
+
+void RecorderSettingsDialog::writeSettingsToUI() {
+    m_updating = true;
+    
+    // 写入音频设置
+    if (m_audioDeviceCombo) {
+        int index = m_audioDeviceCombo->findText(m_currentSettings.audio.deviceName);
+        if (index >= 0) m_audioDeviceCombo->setCurrentIndex(index);
+    }
+    if (m_audioSampleRateCombo) {
+        m_audioSampleRateCombo->setCurrentText(QString::number(m_currentSettings.audio.sampleRate));
+    }
+    if (m_audioChannelsCombo) {
+        int index = m_currentSettings.audio.channels == 1 ? 0 : 
+                   (m_currentSettings.audio.channels == 2 ? 1 : 
+                   (m_currentSettings.audio.channels == 6 ? 2 : 3));
+        m_audioChannelsCombo->setCurrentIndex(index);
+    }
+    if (m_audioBitDepthCombo) {
+        m_audioBitDepthCombo->setCurrentText(QString::number(m_currentSettings.audio.bitDepth));
+    }
+    if (m_audioCodecCombo) {
+        QString codec = m_currentSettings.audio.codec.toUpper();
+        int index = m_audioCodecCombo->findText(codec);
+        if (index >= 0) m_audioCodecCombo->setCurrentIndex(index);
+    }
+    if (m_audioBitrateSpinBox) {
+        m_audioBitrateSpinBox->setValue(m_currentSettings.audio.bitrate / 1000);
+    }
+    if (m_audioNoiseSuppressionCheckBox) {
+        m_audioNoiseSuppressionCheckBox->setChecked(m_currentSettings.audio.enableNoiseSuppression);
+    }
+    if (m_audioEchoCancellationCheckBox) {
+        m_audioEchoCancellationCheckBox->setChecked(m_currentSettings.audio.enableEchoCancellation);
+    }
+    if (m_audioInputGainSpinBox) {
+        m_audioInputGainSpinBox->setValue(m_currentSettings.audio.inputGain);
+    }
+    
+    // 写入视频设置
+    if (m_videoDeviceCombo) {
+        int index = m_videoDeviceCombo->findText(m_currentSettings.video.deviceName);
+        if (index >= 0) m_videoDeviceCombo->setCurrentIndex(index);
+    }
+    if (m_videoResolutionCombo) {
+        QString resolution = QString("%1x%2").arg(m_currentSettings.video.width).arg(m_currentSettings.video.height);
+        int index = m_videoResolutionCombo->findText(resolution);
+        if (index >= 0) m_videoResolutionCombo->setCurrentIndex(index);
+    }
+    if (m_videoFrameRateSpinBox) {
+        m_videoFrameRateSpinBox->setValue(m_currentSettings.video.frameRate);
+    }
+    if (m_videoCodecCombo) {
+        QString codec = m_currentSettings.video.codec;
+        if (codec == "h264") codec = "H.264";
+        else if (codec == "h265") codec = "H.265";
+        else codec = codec.toUpper();
+        int index = m_videoCodecCombo->findText(codec);
+        if (index >= 0) m_videoCodecCombo->setCurrentIndex(index);
+    }
+    if (m_videoBitrateSpinBox) {
+        m_videoBitrateSpinBox->setValue(m_currentSettings.video.bitrate / 1000);
+    }
+    if (m_videoPresetCombo) {
+        int index = m_videoPresetCombo->findText(m_currentSettings.video.preset);
+        if (index >= 0) m_videoPresetCombo->setCurrentIndex(index);
+    }
+    if (m_videoProfileCombo) {
+        int index = m_videoProfileCombo->findText(m_currentSettings.video.profile);
+        if (index >= 0) m_videoProfileCombo->setCurrentIndex(index);
+    }
+    if (m_videoKeyFrameSpinBox) {
+        m_videoKeyFrameSpinBox->setValue(m_currentSettings.video.keyFrameInterval);
+    }
+    if (m_videoHardwareAccelCheckBox) {
+        m_videoHardwareAccelCheckBox->setChecked(m_currentSettings.video.enableHardwareAcceleration);
+    }
+    
+    // 写入输出设置
+    if (m_outputDirectoryEdit) {
+        m_outputDirectoryEdit->setText(m_currentSettings.output.outputDirectory);
+    }
+    if (m_fileNameTemplateEdit) {
+        m_fileNameTemplateEdit->setText(m_currentSettings.output.fileNameTemplate);
+    }
+    if (m_containerFormatCombo) {
+        QString format = m_currentSettings.output.containerFormat.toUpper();
+        int index = m_containerFormatCombo->findText(format);
+        if (index >= 0) m_containerFormatCombo->setCurrentIndex(index);
+    }
+    if (m_autoCreateDirectoryCheckBox) {
+        m_autoCreateDirectoryCheckBox->setChecked(m_currentSettings.output.autoCreateDirectory);
+    }
+    if (m_overwriteExistingCheckBox) {
+        m_overwriteExistingCheckBox->setChecked(m_currentSettings.output.overwriteExisting);
+    }
+    if (m_maxFileSizeSpinBox) {
+        m_maxFileSizeSpinBox->setValue(m_currentSettings.output.maxFileSize);
+    }
+    if (m_maxDurationSpinBox) {
+        m_maxDurationSpinBox->setValue(m_currentSettings.output.maxDuration);
+    }
+    
+    // 写入高级设置
+    if (m_bufferSizeSpinBox) {
+        m_bufferSizeSpinBox->setValue(m_currentSettings.advanced.bufferSize);
+    }
+    if (m_threadCountSpinBox) {
+        m_threadCountSpinBox->setValue(m_currentSettings.advanced.threadCount);
+    }
+    if (m_gpuAccelerationCheckBox) {
+        m_gpuAccelerationCheckBox->setChecked(m_currentSettings.advanced.enableGPUAcceleration);
+    }
+    if (m_gpuDeviceCombo) {
+        int index = m_gpuDeviceCombo->findText(m_currentSettings.advanced.gpuDevice);
+        if (index >= 0) m_gpuDeviceCombo->setCurrentIndex(index);
+    }
+    if (m_lowLatencyCheckBox) {
+        m_lowLatencyCheckBox->setChecked(m_currentSettings.advanced.enableLowLatency);
+    }
+    if (m_realTimeEncodingCheckBox) {
+        m_realTimeEncodingCheckBox->setChecked(m_currentSettings.advanced.enableRealTimeEncoding);
+    }
+    if (m_encodingPrioritySlider) {
+        m_encodingPrioritySlider->setValue(m_currentSettings.advanced.encodingPriority);
+        if (m_encodingPriorityLabel) {
+            QStringList labels = {"最低", "低", "正常", "高", "最高"};
+            m_encodingPriorityLabel->setText(labels[m_currentSettings.advanced.encodingPriority + 2]);
+        }
+    }
+    
+    m_updating = false;
+}
+
+RecorderSettingsDialog::Settings RecorderSettingsDialog::getDefaultSettings() const {
+    Settings settings;
+    
+    // 默认音频设置
+    settings.audio.deviceName = "";
+    settings.audio.sampleRate = 44100;
+    settings.audio.channels = 2;
+    settings.audio.bitDepth = 16;
+    settings.audio.codec = "aac";
+    settings.audio.bitrate = 128000;
+    settings.audio.enableNoiseSuppression = false;
+    settings.audio.enableEchoCancellation = false;
+    settings.audio.inputGain = 1.0;
+    
+    // 默认视频设置
+    settings.video.deviceName = "";
+    settings.video.width = 1920;
+    settings.video.height = 1080;
+    settings.video.frameRate = 30.0;
+    settings.video.codec = "h264";
+    settings.video.bitrate = 5000000;
+    settings.video.preset = "medium";
+    settings.video.profile = "high";
+    settings.video.keyFrameInterval = 60;
+    settings.video.enableHardwareAcceleration = true;
+    
+    // 默认输出设置
+    settings.output.outputDirectory = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
+    settings.output.fileNameTemplate = "recording_%Y%m%d_%H%M%S";
+    settings.output.containerFormat = "mp4";
+    settings.output.autoCreateDirectory = true;
+    settings.output.overwriteExisting = false;
+    settings.output.maxFileSize = 0;
+    settings.output.maxDuration = 0;
+    
+    // 默认高级设置
+    settings.advanced.bufferSize = 4096;
+    settings.advanced.threadCount = 0;
+    settings.advanced.enableGPUAcceleration = true;
+    settings.advanced.gpuDevice = "自动选择";
+    settings.advanced.enableLowLatency = false;
+    settings.advanced.enableRealTimeEncoding = true;
+    settings.advanced.encodingPriority = 0;
+    
+    return settings;
+}
+
+QString RecorderSettingsDialog::formatFileNamePreview() const {
+    QString preview = m_currentSettings.output.fileNameTemplate;
+    QDateTime now = QDateTime::currentDateTime();
+    
+    preview.replace("%Y", now.toString("yyyy"));
+    preview.replace("%m", now.toString("MM"));
+    preview.replace("%d", now.toString("dd"));
+    preview.replace("%H", now.toString("hh"));
+    preview.replace("%M", now.toString("mm"));
+    preview.replace("%S", now.toString("ss"));
+    
+    preview += "." + m_currentSettings.output.containerFormat;
+    
+    return preview;
+}
+
+bool RecorderSettingsDialog::validateOutputDirectory(const QString& path) const {
+    QDir dir(path);
+    return dir.exists() || dir.mkpath(".");
+}

+ 413 - 0
AV/code/recorder/ui/recorder_settings_dialog.h

@@ -0,0 +1,413 @@
+#ifndef AV_RECORDER_SETTINGS_DIALOG_H
+#define AV_RECORDER_SETTINGS_DIALOG_H
+
+#include <QDialog>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QGridLayout>
+#include <QTabWidget>
+#include <QGroupBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QSpinBox>
+#include <QDoubleSpinBox>
+#include <QSlider>
+#include <QCheckBox>
+#include <QPushButton>
+#include <QFileDialog>
+#include <QStandardPaths>
+#include <QSettings>
+#include <QTimer>
+#include <QProgressBar>
+#include <QTextEdit>
+#include <QSplitter>
+#include <QTreeWidget>
+#include <QListWidget>
+#include <memory>
+
+// 前向声明
+namespace av {
+namespace recorder {
+class RecorderModule;
+}
+}
+
+/**
+ * 录制器设置对话框
+ * 
+ * 提供完整的录制参数配置界面,包括:
+ * - 音频设置(设备、格式、质量)
+ * - 视频设置(设备、分辨率、帧率、编码)
+ * - 输出设置(路径、格式、文件名模板)
+ * - 高级设置(编码器参数、性能优化)
+ * - 预设管理(保存/加载配置预设)
+ */
+class RecorderSettingsDialog : public QDialog {
+    Q_OBJECT
+
+public:
+    /**
+     * 设置类别
+     */
+    enum SettingsCategory {
+        AudioCategory,
+        VideoCategory,
+        OutputCategory,
+        AdvancedCategory,
+        PresetCategory
+    };
+    
+    /**
+     * 音频设置结构
+     */
+    struct AudioSettings {
+        QString deviceName;
+        int sampleRate = 44100;
+        int channels = 2;
+        int bitDepth = 16;
+        QString codec = "aac";
+        int bitrate = 128000;
+        bool enableNoiseSuppression = false;
+        bool enableEchoCancellation = false;
+        double inputGain = 1.0;
+        
+        AudioSettings() = default;
+    };
+    
+    /**
+     * 视频设置结构
+     */
+    struct VideoSettings {
+        QString deviceName;
+        int width = 1920;
+        int height = 1080;
+        double frameRate = 30.0;
+        QString codec = "h264";
+        int bitrate = 5000000;
+        QString preset = "medium";
+        QString profile = "high";
+        int keyFrameInterval = 60;
+        bool enableHardwareAcceleration = true;
+        
+        VideoSettings() = default;
+    };
+    
+    /**
+     * 输出设置结构
+     */
+    struct OutputSettings {
+        QString outputDirectory;
+        QString fileNameTemplate = "recording_%Y%m%d_%H%M%S";
+        QString containerFormat = "mp4";
+        bool autoCreateDirectory = true;
+        bool overwriteExisting = false;
+        int maxFileSize = 0; // 0 = unlimited
+        int maxDuration = 0; // 0 = unlimited
+        
+        OutputSettings() {
+            outputDirectory = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
+        }
+    };
+    
+    /**
+     * 高级设置结构
+     */
+    struct AdvancedSettings {
+        int bufferSize = 4096;
+        int threadCount = 0; // 0 = auto
+        bool enableGPUAcceleration = true;
+        QString gpuDevice;
+        bool enableLowLatency = false;
+        bool enableRealTimeEncoding = true;
+        int encodingPriority = 0; // -2 to 2
+        
+        AdvancedSettings() = default;
+    };
+    
+    /**
+     * 完整设置结构
+     */
+    struct Settings {
+        AudioSettings audio;
+        VideoSettings video;
+        OutputSettings output;
+        AdvancedSettings advanced;
+        
+        Settings() = default;
+    };
+
+public:
+    explicit RecorderSettingsDialog(av::recorder::RecorderModule* recorderModule, QWidget* parent = nullptr);
+    ~RecorderSettingsDialog();
+
+    /**
+     * 设置当前配置
+     */
+    void setSettings(const Settings& settings);
+    
+    /**
+     * 获取当前配置
+     */
+    Settings getSettings() const;
+    
+    /**
+     * 显示指定类别的设置
+     */
+    void showCategory(SettingsCategory category);
+    
+    /**
+     * 重置为默认设置
+     */
+    void resetToDefaults();
+    
+    /**
+     * 加载设置
+     */
+    void loadSettings();
+    
+    /**
+     * 保存设置
+     */
+    void saveSettings();
+    
+    /**
+     * 验证设置有效性
+     */
+    bool validateSettings(QString* errorMessage = nullptr) const;
+
+protected:
+    void showEvent(QShowEvent* event) override;
+    void closeEvent(QCloseEvent* event) override;
+
+private slots:
+    void onTabChanged(int index);
+    void onAudioDeviceChanged(const QString& device);
+    void onVideoDeviceChanged(const QString& device);
+    void onOutputDirectoryBrowse();
+    void onFileNameTemplateChanged();
+    void onPresetSave();
+    void onPresetLoad();
+    void onPresetDelete();
+    void onPresetExport();
+    void onPresetImport();
+    void onTestAudioDevice();
+    void onTestVideoDevice();
+    void onResetCategory();
+    void onApplySettings();
+    void onOkClicked();
+    void onCancelClicked();
+    void updatePreview();
+    void refreshDevices();
+
+signals:
+    /**
+     * 设置已应用信号
+     */
+    void settingsApplied(const Settings& settings);
+    
+    /**
+     * 设置已改变信号
+     */
+    void settingsChanged();
+
+private:
+    /**
+     * 初始化UI
+     */
+    void initializeUI();
+    
+    /**
+     * 创建音频设置页面
+     */
+    QWidget* createAudioSettingsPage();
+    
+    /**
+     * 创建视频设置页面
+     */
+    QWidget* createVideoSettingsPage();
+    
+    /**
+     * 创建输出设置页面
+     */
+    QWidget* createOutputSettingsPage();
+    
+    /**
+     * 创建高级设置页面
+     */
+    QWidget* createAdvancedSettingsPage();
+    
+    /**
+     * 创建预设管理页面
+     */
+    QWidget* createPresetSettingsPage();
+    
+    /**
+     * 连接信号槽
+     */
+    void connectSignals();
+    
+    /**
+     * 更新UI状态
+     */
+    void updateUI();
+    
+    /**
+     * 更新音频设备列表
+     */
+    void updateAudioDevices();
+    
+    /**
+     * 更新视频设备列表
+     */
+    void updateVideoDevices();
+    
+    /**
+     * 更新编码器列表
+     */
+    void updateCodecLists();
+    
+    /**
+     * 更新预设列表
+     */
+    void updatePresetList();
+    
+    /**
+     * 从UI读取设置
+     */
+    void readSettingsFromUI();
+    
+    /**
+     * 将设置写入UI
+     */
+    void writeSettingsToUI();
+    
+    /**
+     * 获取默认设置
+     */
+    Settings getDefaultSettings() const;
+    
+    /**
+     * 格式化文件名预览
+     */
+    QString formatFileNamePreview() const;
+    
+    /**
+     * 验证输出目录
+     */
+    bool validateOutputDirectory(const QString& path) const;
+    
+    /**
+     * 创建设置组
+     */
+    QGroupBox* createSettingsGroup(const QString& title, QWidget* content);
+    
+    /**
+     * 创建标签和控件的水平布局
+     */
+    QHBoxLayout* createLabeledControl(const QString& label, QWidget* control, 
+                                     const QString& tooltip = QString());
+    
+    /**
+     * 保存预设到文件
+     */
+    bool savePresetToFile(const QString& name, const Settings& settings);
+    
+    /**
+     * 从文件加载预设
+     */
+    bool loadPresetFromFile(const QString& name, Settings& settings);
+    
+    /**
+     * 获取预设文件路径
+     */
+    QString getPresetFilePath(const QString& name) const;
+    
+    /**
+     * 获取预设目录
+     */
+    QString getPresetDirectory() const;
+
+private:
+    // 核心组件
+    av::recorder::RecorderModule* m_recorderModule;
+    
+    // UI组件
+    QTabWidget* m_tabWidget;
+    QVBoxLayout* m_mainLayout;
+    QHBoxLayout* m_buttonLayout;
+    
+    // 按钮
+    QPushButton* m_okButton;
+    QPushButton* m_cancelButton;
+    QPushButton* m_applyButton;
+    QPushButton* m_resetButton;
+    
+    // 音频设置控件
+    QComboBox* m_audioDeviceCombo;
+    QComboBox* m_audioSampleRateCombo;
+    QComboBox* m_audioChannelsCombo;
+    QComboBox* m_audioBitDepthCombo;
+    QComboBox* m_audioCodecCombo;
+    QSpinBox* m_audioBitrateSpinBox;
+    QCheckBox* m_audioNoiseSuppressionCheckBox;
+    QCheckBox* m_audioEchoCancellationCheckBox;
+    QDoubleSpinBox* m_audioInputGainSpinBox;
+    QPushButton* m_testAudioButton;
+    
+    // 视频设置控件
+    QComboBox* m_videoDeviceCombo;
+    QComboBox* m_videoResolutionCombo;
+    QDoubleSpinBox* m_videoFrameRateSpinBox;
+    QComboBox* m_videoCodecCombo;
+    QSpinBox* m_videoBitrateSpinBox;
+    QComboBox* m_videoPresetCombo;
+    QComboBox* m_videoProfileCombo;
+    QSpinBox* m_videoKeyFrameSpinBox;
+    QCheckBox* m_videoHardwareAccelCheckBox;
+    QPushButton* m_testVideoButton;
+    
+    // 输出设置控件
+    QLineEdit* m_outputDirectoryEdit;
+    QPushButton* m_outputDirectoryBrowseButton;
+    QLineEdit* m_fileNameTemplateEdit;
+    QLabel* m_fileNamePreviewLabel;
+    QComboBox* m_containerFormatCombo;
+    QCheckBox* m_autoCreateDirectoryCheckBox;
+    QCheckBox* m_overwriteExistingCheckBox;
+    QSpinBox* m_maxFileSizeSpinBox;
+    QSpinBox* m_maxDurationSpinBox;
+    
+    // 高级设置控件
+    QSpinBox* m_bufferSizeSpinBox;
+    QSpinBox* m_threadCountSpinBox;
+    QCheckBox* m_gpuAccelerationCheckBox;
+    QComboBox* m_gpuDeviceCombo;
+    QCheckBox* m_lowLatencyCheckBox;
+    QCheckBox* m_realTimeEncodingCheckBox;
+    QSlider* m_encodingPrioritySlider;
+    QLabel* m_encodingPriorityLabel;
+    
+    // 预设管理控件
+    QListWidget* m_presetListWidget;
+    QPushButton* m_savePresetButton;
+    QPushButton* m_loadPresetButton;
+    QPushButton* m_deletePresetButton;
+    QPushButton* m_exportPresetButton;
+    QPushButton* m_importPresetButton;
+    QTextEdit* m_presetDescriptionEdit;
+    
+    // 数据
+    Settings m_currentSettings;
+    Settings m_originalSettings;
+    
+    // 状态
+    bool m_settingsChanged;
+    bool m_updating;
+    
+    // 定时器
+    QTimer* m_previewUpdateTimer;
+    QTimer* m_deviceRefreshTimer;
+};
+
+#endif // AV_RECORDER_SETTINGS_DIALOG_H

+ 36 - 0
AV/code/recorder/ui/recorder_ui.pri

@@ -0,0 +1,36 @@
+# UI模块头文件
+HEADERS += \
+    $$PWD/recorder_main_widget.h \
+    $$PWD/recorder_video_widget.h \
+    $$PWD/recorder_audio_widget.h \
+    $$PWD/recorder_settings_dialog.h \
+    $$PWD/recorder_example_app.h
+
+# UI模块源文件
+SOURCES += \
+    # $$PWD/recorder_main.cpp \
+    $$PWD/recorder_main_widget.cpp \
+    $$PWD/recorder_video_widget.cpp \
+    $$PWD/recorder_audio_widget.cpp \
+    $$PWD/recorder_settings_dialog.cpp \
+    $$PWD/recorder_example_app.cpp
+
+# Qt模块依赖
+QT += core widgets opengl multimedia
+
+# 编译器配置
+CONFIG += c++17
+
+# 包含路径
+INCLUDEPATH += $$PWD
+INCLUDEPATH += $$PWD/..
+INCLUDEPATH += $$PWD/../..
+INCLUDEPATH += $$PWD/../../..
+
+# 依赖路径
+DEPENDPATH += $$PWD
+DEPENDPATH += $$PWD/..
+
+
+# 资源文件
+RESOURCES += $$PWD/recorder_ui.qrc

+ 5 - 0
AV/code/recorder/ui/recorder_ui.qrc

@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/">
+        <file>styles/recorder_ui.qss</file>
+    </qresource>
+</RCC>

+ 806 - 0
AV/code/recorder/ui/recorder_video_widget.cpp

@@ -0,0 +1,806 @@
+#include "recorder_video_widget.h"
+#include <QDebug>
+#include <QApplication>
+#include <QOpenGLContext>
+#include <QDateTime>
+#include <cstring>
+
+extern "C" {
+#include <libavutil/pixfmt.h>
+#include <libswscale/swscale.h>
+}
+
+// 顶点着色器源码
+static const char* vertexShaderSource = R"(
+#version 330 core
+layout (location = 0) in vec2 aPos;
+layout (location = 1) in vec2 aTexCoord;
+
+out vec2 TexCoord;
+
+uniform bool flipHorizontal;
+uniform bool flipVertical;
+
+void main() {
+    gl_Position = vec4(aPos, 0.0, 1.0);
+    
+    vec2 texCoord = aTexCoord;
+    if (flipHorizontal) {
+        texCoord.x = 1.0 - texCoord.x;
+    }
+    if (flipVertical) {
+        texCoord.y = 1.0 - texCoord.y;
+    }
+    
+    TexCoord = texCoord;
+}
+)";
+
+// YUV片段着色器源码
+static const char* yuvFragmentShaderSource = R"(
+#version 330 core
+out vec4 FragColor;
+
+in vec2 TexCoord;
+
+uniform sampler2D textureY;
+uniform sampler2D textureU;
+uniform sampler2D textureV;
+uniform bool grayscale;
+uniform float brightness;
+uniform float contrast;
+uniform float saturation;
+
+void main() {
+    float y = texture(textureY, TexCoord).r;
+    float u = texture(textureU, TexCoord).r - 0.5;
+    float v = texture(textureV, TexCoord).r - 0.5;
+    
+    // YUV to RGB conversion
+    float r = y + 1.402 * v;
+    float g = y - 0.344 * u - 0.714 * v;
+    float b = y + 1.772 * u;
+    
+    vec3 rgb = vec3(r, g, b);
+    
+    // Apply brightness
+    rgb += brightness;
+    
+    // Apply contrast
+    rgb = (rgb - 0.5) * contrast + 0.5;
+    
+    // Apply saturation
+    if (!grayscale) {
+        float gray = dot(rgb, vec3(0.299, 0.587, 0.114));
+        rgb = mix(vec3(gray), rgb, saturation);
+    } else {
+        float gray = dot(rgb, vec3(0.299, 0.587, 0.114));
+        rgb = vec3(gray);
+    }
+    
+    FragColor = vec4(clamp(rgb, 0.0, 1.0), 1.0);
+}
+)";
+
+// RGB片段着色器源码
+static const char* rgbFragmentShaderSource = R"(
+#version 330 core
+out vec4 FragColor;
+
+in vec2 TexCoord;
+
+uniform sampler2D textureRGB;
+uniform bool grayscale;
+uniform float brightness;
+uniform float contrast;
+uniform float saturation;
+
+void main() {
+    vec3 rgb = texture(textureRGB, TexCoord).rgb;
+    
+    // Apply brightness
+    rgb += brightness;
+    
+    // Apply contrast
+    rgb = (rgb - 0.5) * contrast + 0.5;
+    
+    // Apply saturation
+    if (!grayscale) {
+        float gray = dot(rgb, vec3(0.299, 0.587, 0.114));
+        rgb = mix(vec3(gray), rgb, saturation);
+    } else {
+        float gray = dot(rgb, vec3(0.299, 0.587, 0.114));
+        rgb = vec3(gray);
+    }
+    
+    FragColor = vec4(clamp(rgb, 0.0, 1.0), 1.0);
+}
+)";
+
+RecorderVideoWidget::RecorderVideoWidget(QWidget* parent)
+    : QOpenGLWidget(parent)
+    , m_textureY(0)
+    , m_textureU(0)
+    , m_textureV(0)
+    , m_textureRGB(0)
+    , m_VAO(0)
+    , m_VBO(0)
+    , m_frameWidth(0)
+    , m_frameHeight(0)
+    , m_frameFormat(AV_PIX_FMT_NONE)
+    , m_frameReady(false)
+    , m_keepAspectRatio(true)
+    , m_showFPS(true)
+    , m_noVideoText("No Video")
+    , m_backgroundColor(Qt::black)
+    , m_grayscale(false)
+    , m_flipHorizontal(false)
+    , m_flipVertical(false)
+    , m_brightness(0.0f)
+    , m_contrast(1.0f)
+    , m_saturation(1.0f)
+    , m_frameCount(0)
+    , m_currentFPS(0.0)
+    , m_lastFPSUpdate(0)
+    , m_initialized(false) {
+    
+    // 初始化帧数据
+    for (int i = 0; i < 4; ++i) {
+        m_frameData[i] = nullptr;
+        m_frameLinesize[i] = 0;
+    }
+    
+    // 创建FPS定时器
+    m_fpsTimer = new QTimer(this);
+    connect(m_fpsTimer, &QTimer::timeout, this, &RecorderVideoWidget::updateFPS);
+    m_fpsTimer->start(1000); // 每秒更新一次FPS
+    
+    // 设置OpenGL格式
+    QSurfaceFormat format;
+    format.setVersion(3, 3);
+    format.setProfile(QSurfaceFormat::CoreProfile);
+    setFormat(format);
+}
+
+RecorderVideoWidget::~RecorderVideoWidget() {
+    cleanup();
+}
+
+bool RecorderVideoWidget::initialize(int width, int height, int format) {
+    QMutexLocker locker(&m_mutex);
+    
+    if (width <= 0 || height <= 0) {
+        qWarning() << "Invalid video dimensions:" << width << "x" << height;
+        return false;
+    }
+    
+    // 分配帧缓冲区
+    if (!allocateFrameBuffer(width, height, format)) {
+        qWarning() << "Failed to allocate frame buffer";
+        return false;
+    }
+    
+    m_initialized = true;
+    
+    // 触发重绘
+    QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
+    
+    return true;
+}
+
+void RecorderVideoWidget::cleanup() {
+    QMutexLocker locker(&m_mutex);
+    
+    makeCurrent();
+    
+    // 释放OpenGL资源
+    if (m_textureY) {
+        glDeleteTextures(1, &m_textureY);
+        m_textureY = 0;
+    }
+    if (m_textureU) {
+        glDeleteTextures(1, &m_textureU);
+        m_textureU = 0;
+    }
+    if (m_textureV) {
+        glDeleteTextures(1, &m_textureV);
+        m_textureV = 0;
+    }
+    if (m_textureRGB) {
+        glDeleteTextures(1, &m_textureRGB);
+        m_textureRGB = 0;
+    }
+    if (m_VAO) {
+        glDeleteVertexArrays(1, &m_VAO);
+        m_VAO = 0;
+    }
+    if (m_VBO) {
+        glDeleteBuffers(1, &m_VBO);
+        m_VBO = 0;
+    }
+    
+    m_shaderProgram.reset();
+    
+    doneCurrent();
+    
+    // 释放帧缓冲区
+    freeFrameBuffer();
+    
+    m_frameReady = false;
+    m_initialized = false;
+}
+
+bool RecorderVideoWidget::updateFrame(AVFrame* frame) {
+    if (!frame || !m_initialized) {
+        qDebug() << "RecorderVideoWidget::updateFrame failed: frame=" << frame << ", initialized=" << m_initialized;
+        return false;
+    }
+    
+    // 验证帧数据的有效性
+    if (frame->width <= 0 || frame->height <= 0 || !frame->data[0]) {
+        qWarning() << "Invalid frame data received, skipping: width=" << frame->width 
+                   << ", height=" << frame->height << ", data[0]=" << frame->data[0];
+        return false;
+    }
+    
+    qDebug() << "RecorderVideoWidget::updateFrame: width=" << frame->width 
+             << ", height=" << frame->height << ", format=" << frame->format;
+    
+    QMutexLocker locker(&m_mutex);
+    
+    try {
+        // 检查帧格式是否匹配
+        if (frame->width != m_frameWidth || 
+            frame->height != m_frameHeight || 
+            frame->format != m_frameFormat) {
+            
+            // 重新分配缓冲区
+            if (!allocateFrameBuffer(frame->width, frame->height, frame->format)) {
+                qWarning() << "Failed to allocate frame buffer";
+                return false;
+            }
+            qDebug() << "Frame buffer reallocated:" << frame->width << "x" << frame->height;
+        }
+        
+        // 复制帧数据
+        if (!copyFromAVFrame(frame)) {
+            qWarning() << "Failed to copy frame data";
+            return false;
+        }
+        
+        m_frameReady = true;
+        m_frameCount++;
+        
+        // 限制触发重绘的频率,避免过度绘制
+        if (m_frameCount % 2 == 0) {  // 每2帧触发一次重绘
+            QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
+        }
+        
+        return true;
+    } catch (const std::exception& e) {
+        qWarning() << "Exception in updateFrame:" << e.what();
+        return false;
+    } catch (...) {
+        qWarning() << "Unknown exception in updateFrame";
+        return false;
+    }
+}
+
+bool RecorderVideoWidget::updateFrame(const VideoFrame& frame) {
+    if (!m_initialized) {
+        return false;
+    }
+    
+    QMutexLocker locker(&m_mutex);
+    
+    // 检查帧格式是否匹配
+    if (frame.width != m_frameWidth || 
+        frame.height != m_frameHeight || 
+        frame.format != m_frameFormat) {
+        
+        // 重新分配缓冲区
+        if (!allocateFrameBuffer(frame.width, frame.height, frame.format)) {
+            return false;
+        }
+    }
+    
+    // 复制帧数据
+    if (!copyFromVideoFrame(frame)) {
+        return false;
+    }
+    
+    m_frameReady = true;
+    m_frameCount++;
+    
+    // 触发重绘
+    QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
+    
+    return true;
+}
+
+void RecorderVideoWidget::clearFrame() {
+    QMutexLocker locker(&m_mutex);
+    
+    m_frameReady = false;
+    
+    // 触发重绘
+    QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
+}
+
+void RecorderVideoWidget::setGrayscale(bool enable) {
+    m_grayscale = enable;
+    update();
+}
+
+void RecorderVideoWidget::setFlipHorizontal(bool enable) {
+    m_flipHorizontal = enable;
+    update();
+}
+
+void RecorderVideoWidget::setFlipVertical(bool enable) {
+    m_flipVertical = enable;
+    update();
+}
+
+void RecorderVideoWidget::setBrightness(float brightness) {
+    m_brightness = qBound(-1.0f, brightness, 1.0f);
+    update();
+}
+
+void RecorderVideoWidget::setContrast(float contrast) {
+    m_contrast = qBound(0.0f, contrast, 2.0f);
+    update();
+}
+
+void RecorderVideoWidget::setSaturation(float saturation) {
+    m_saturation = qBound(0.0f, saturation, 2.0f);
+    update();
+}
+
+void RecorderVideoWidget::initializeGL() {
+    initializeOpenGLFunctions();
+    QOpenGLExtraFunctions::initializeOpenGLFunctions();
+    
+    // 设置背景色
+    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+    
+    // 初始化着色器
+    if (!initShaders()) {
+        qWarning() << "Failed to initialize shaders";
+        return;
+    }
+    
+    // 创建纹理
+    createTextures();
+    
+    // 创建顶点数组对象
+    glGenVertexArrays(1, &m_VAO);
+    glGenBuffers(1, &m_VBO);
+    
+    glBindVertexArray(m_VAO);
+    
+    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES), VERTICES, GL_STATIC_DRAW);
+    
+    // 位置属性
+    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
+    glEnableVertexAttribArray(0);
+    
+    // 纹理坐标属性
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
+    glEnableVertexAttribArray(1);
+    
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+void RecorderVideoWidget::paintGL() {
+    glClear(GL_COLOR_BUFFER_BIT);
+    
+    QMutexLocker locker(&m_mutex);
+    
+    if (!m_frameReady || !m_shaderProgram) {
+        // 绘制无视频提示
+        locker.unlock();
+        drawNoVideoHint();
+        return;
+    }
+    
+    // 使用着色器程序
+    m_shaderProgram->bind();
+    
+    // 设置uniform变量
+    m_shaderProgram->setUniformValue("grayscale", m_grayscale);
+    m_shaderProgram->setUniformValue("flipHorizontal", m_flipHorizontal);
+    m_shaderProgram->setUniformValue("flipVertical", m_flipVertical);
+    m_shaderProgram->setUniformValue("brightness", m_brightness);
+    m_shaderProgram->setUniformValue("contrast", m_contrast);
+    m_shaderProgram->setUniformValue("saturation", m_saturation);
+    
+    // 更新纹理数据
+    updateTextures();
+    
+    // 绑定纹理
+    if (m_frameFormat == AV_PIX_FMT_YUV420P) {
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, m_textureY);
+        m_shaderProgram->setUniformValue("textureY", 0);
+        
+        glActiveTexture(GL_TEXTURE1);
+        glBindTexture(GL_TEXTURE_2D, m_textureU);
+        m_shaderProgram->setUniformValue("textureU", 1);
+        
+        glActiveTexture(GL_TEXTURE2);
+        glBindTexture(GL_TEXTURE_2D, m_textureV);
+        m_shaderProgram->setUniformValue("textureV", 2);
+    } else {
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, m_textureRGB);
+        m_shaderProgram->setUniformValue("textureRGB", 0);
+    }
+    
+    // 绘制四边形
+    glBindVertexArray(m_VAO);
+    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+    glBindVertexArray(0);
+    
+    m_shaderProgram->release();
+    
+    locker.unlock();
+    
+    // 绘制FPS信息
+    if (m_showFPS) {
+        drawFPSInfo();
+    }
+}
+
+void RecorderVideoWidget::resizeGL(int width, int height) {
+    glViewport(0, 0, width, height);
+}
+
+void RecorderVideoWidget::mousePressEvent(QMouseEvent* event) {
+    if (event->button() == Qt::LeftButton) {
+        emit clicked(event->pos());
+    }
+    QOpenGLWidget::mousePressEvent(event);
+}
+
+void RecorderVideoWidget::mouseDoubleClickEvent(QMouseEvent* event) {
+    if (event->button() == Qt::LeftButton) {
+        emit doubleClicked(event->pos());
+    }
+    QOpenGLWidget::mouseDoubleClickEvent(event);
+}
+
+void RecorderVideoWidget::updateFPS() {
+    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
+    
+    if (m_lastFPSUpdate > 0) {
+        qint64 elapsed = currentTime - m_lastFPSUpdate;
+        if (elapsed > 0) {
+            m_currentFPS = (m_frameCount * 1000.0) / elapsed;
+        }
+    }
+    
+    m_frameCount = 0;
+    m_lastFPSUpdate = currentTime;
+    
+    if (m_showFPS) {
+        update();
+    }
+}
+
+bool RecorderVideoWidget::initShaders() {
+    m_shaderProgram = std::make_unique<QOpenGLShaderProgram>();
+    
+    // 添加顶点着色器
+    if (!m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource)) {
+        qWarning() << "Failed to compile vertex shader:" << m_shaderProgram->log();
+        return false;
+    }
+    
+    // 根据格式选择片段着色器
+    const char* fragmentSource = (m_frameFormat == AV_PIX_FMT_YUV420P) ? 
+                                  yuvFragmentShaderSource : rgbFragmentShaderSource;
+    
+    if (!m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource)) {
+        qWarning() << "Failed to compile fragment shader:" << m_shaderProgram->log();
+        return false;
+    }
+    
+    // 链接着色器程序
+    if (!m_shaderProgram->link()) {
+        qWarning() << "Failed to link shader program:" << m_shaderProgram->log();
+        return false;
+    }
+    
+    return true;
+}
+
+void RecorderVideoWidget::createTextures() {
+    // 创建Y纹理
+    glGenTextures(1, &m_textureY);
+    glBindTexture(GL_TEXTURE_2D, m_textureY);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    
+    // 创建U纹理
+    glGenTextures(1, &m_textureU);
+    glBindTexture(GL_TEXTURE_2D, m_textureU);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    
+    // 创建V纹理
+    glGenTextures(1, &m_textureV);
+    glBindTexture(GL_TEXTURE_2D, m_textureV);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    
+    // 创建RGB纹理
+    glGenTextures(1, &m_textureRGB);
+    glBindTexture(GL_TEXTURE_2D, m_textureRGB);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void RecorderVideoWidget::updateTextures() {
+    if (!m_frameReady) {
+        return;
+    }
+    
+    if (m_frameFormat == AV_PIX_FMT_YUV420P) {
+        // 更新Y纹理
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, m_textureY);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameWidth, m_frameHeight, 
+                     0, GL_RED, GL_UNSIGNED_BYTE, m_frameData[0]);
+        
+        // 更新U纹理
+        glActiveTexture(GL_TEXTURE1);
+        glBindTexture(GL_TEXTURE_2D, m_textureU);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameWidth/2, m_frameHeight/2, 
+                     0, GL_RED, GL_UNSIGNED_BYTE, m_frameData[1]);
+        
+        // 更新V纹理
+        glActiveTexture(GL_TEXTURE2);
+        glBindTexture(GL_TEXTURE_2D, m_textureV);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameWidth/2, m_frameHeight/2, 
+                     0, GL_RED, GL_UNSIGNED_BYTE, m_frameData[2]);
+    } else {
+        // 更新RGB纹理
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, m_textureRGB);
+        
+        GLenum format = GL_RGB;
+        if (m_frameFormat == AV_PIX_FMT_RGBA || m_frameFormat == AV_PIX_FMT_BGRA) {
+            format = GL_RGBA;
+        }
+        
+        glTexImage2D(GL_TEXTURE_2D, 0, format, m_frameWidth, m_frameHeight, 
+                     0, format, GL_UNSIGNED_BYTE, m_frameData[0]);
+    }
+}
+
+QRectF RecorderVideoWidget::calculateDisplayRect() const {
+    if (!m_keepAspectRatio || m_frameWidth <= 0 || m_frameHeight <= 0) {
+        return QRectF(0, 0, width(), height());
+    }
+    
+    double widgetAspect = static_cast<double>(width()) / height();
+    double frameAspect = static_cast<double>(m_frameWidth) / m_frameHeight;
+    
+    QRectF displayRect;
+    
+    if (widgetAspect > frameAspect) {
+        // 控件更宽,以高度为准
+        int displayWidth = static_cast<int>(height() * frameAspect);
+        displayRect = QRectF((width() - displayWidth) / 2, 0, displayWidth, height());
+    } else {
+        // 控件更高,以宽度为准
+        int displayHeight = static_cast<int>(width() / frameAspect);
+        displayRect = QRectF(0, (height() - displayHeight) / 2, width(), displayHeight);
+    }
+    
+    return displayRect;
+}
+
+void RecorderVideoWidget::drawNoVideoHint() {
+    QPainter painter(this);
+    painter.setRenderHint(QPainter::Antialiasing);
+    
+    // 设置背景色
+    painter.fillRect(rect(), m_backgroundColor);
+    
+    // 绘制提示文本
+    painter.setPen(Qt::white);
+    painter.setFont(QFont("Arial", 16));
+    painter.drawText(rect(), Qt::AlignCenter, m_noVideoText);
+}
+
+void RecorderVideoWidget::drawFPSInfo() {
+    QPainter painter(this);
+    painter.setRenderHint(QPainter::Antialiasing);
+    
+    // 设置字体和颜色
+    painter.setPen(Qt::yellow);
+    painter.setFont(QFont("Arial", 12, QFont::Bold));
+    
+    // 绘制FPS信息
+    QString fpsText = QString("FPS: %1").arg(m_currentFPS, 0, 'f', 1);
+    QRect textRect = painter.fontMetrics().boundingRect(fpsText);
+    
+    // 绘制背景
+    QRect bgRect = textRect.adjusted(-5, -2, 5, 2);
+    bgRect.moveTopLeft(QPoint(10, 10));
+    painter.fillRect(bgRect, QColor(0, 0, 0, 128));
+    
+    // 绘制文本
+    painter.drawText(bgRect, Qt::AlignCenter, fpsText);
+}
+
+bool RecorderVideoWidget::copyFromAVFrame(AVFrame* frame) {
+    if (!frame || !frame->data[0]) {
+        return false;
+    }
+    
+    // 复制Y平面
+    if (m_frameData[0] && frame->data[0]) {
+        for (int y = 0; y < m_frameHeight; ++y) {
+            memcpy(m_frameData[0] + y * m_frameLinesize[0],
+                   frame->data[0] + y * frame->linesize[0],
+                   m_frameWidth);
+        }
+    }
+    
+    // 复制U平面
+    if (m_frameFormat == AV_PIX_FMT_YUV420P && m_frameData[1] && frame->data[1]) {
+        for (int y = 0; y < m_frameHeight / 2; ++y) {
+            memcpy(m_frameData[1] + y * m_frameLinesize[1],
+                   frame->data[1] + y * frame->linesize[1],
+                   m_frameWidth / 2);
+        }
+    }
+    
+    // 复制V平面
+    if (m_frameFormat == AV_PIX_FMT_YUV420P && m_frameData[2] && frame->data[2]) {
+        for (int y = 0; y < m_frameHeight / 2; ++y) {
+            memcpy(m_frameData[2] + y * m_frameLinesize[2],
+                   frame->data[2] + y * frame->linesize[2],
+                   m_frameWidth / 2);
+        }
+    }
+    
+    return true;
+}
+
+bool RecorderVideoWidget::copyFromVideoFrame(const VideoFrame& frame) {
+    if (!frame.data[0]) {
+        return false;
+    }
+    
+    // 复制Y平面或RGB数据
+    if (m_frameData[0] && frame.data[0]) {
+        for (int y = 0; y < m_frameHeight; ++y) {
+            int copySize = (m_frameFormat == AV_PIX_FMT_YUV420P) ? m_frameWidth : 
+                          (m_frameWidth * ((m_frameFormat == AV_PIX_FMT_RGB24) ? 3 : 4));
+            memcpy(m_frameData[0] + y * m_frameLinesize[0],
+                   frame.data[0] + y * frame.linesize[0],
+                   copySize);
+        }
+    }
+    
+    // 复制U平面
+    if (m_frameFormat == AV_PIX_FMT_YUV420P && m_frameData[1] && frame.data[1]) {
+        for (int y = 0; y < m_frameHeight / 2; ++y) {
+            memcpy(m_frameData[1] + y * m_frameLinesize[1],
+                   frame.data[1] + y * frame.linesize[1],
+                   m_frameWidth / 2);
+        }
+    }
+    
+    // 复制V平面
+    if (m_frameFormat == AV_PIX_FMT_YUV420P && m_frameData[2] && frame.data[2]) {
+        for (int y = 0; y < m_frameHeight / 2; ++y) {
+            memcpy(m_frameData[2] + y * m_frameLinesize[2],
+                   frame.data[2] + y * frame.linesize[2],
+                   m_frameWidth / 2);
+        }
+    }
+    
+    return true;
+}
+
+bool RecorderVideoWidget::allocateFrameBuffer(int width, int height, int format) {
+    // 验证参数
+    if (width <= 0 || height <= 0 || width > 8192 || height > 8192) {
+        qWarning() << "Invalid frame dimensions:" << width << "x" << height;
+        return false;
+    }
+    
+    // 释放旧缓冲区
+    freeFrameBuffer();
+    
+    m_frameWidth = width;
+    m_frameHeight = height;
+    m_frameFormat = format;
+    
+    try {
+        if (format == AV_PIX_FMT_YUV420P) {
+            // 分配Y平面
+            m_frameLinesize[0] = width;
+            size_t ySize = static_cast<size_t>(width) * height;
+            m_frameData[0] = static_cast<uint8_t*>(av_malloc(ySize));
+            
+            // 分配U平面
+            m_frameLinesize[1] = width / 2;
+            size_t uvSize = static_cast<size_t>(width) * height / 4;
+            m_frameData[1] = static_cast<uint8_t*>(av_malloc(uvSize));
+            
+            // 分配V平面
+            m_frameLinesize[2] = width / 2;
+            m_frameData[2] = static_cast<uint8_t*>(av_malloc(uvSize));
+            
+            bool success = m_frameData[0] && m_frameData[1] && m_frameData[2];
+            if (!success) {
+                qWarning() << "Failed to allocate YUV420P frame buffer";
+                freeFrameBuffer(); // 清理部分分配的内存
+                return false;
+            }
+            
+            qDebug() << "Allocated YUV420P buffer:" << width << "x" << height 
+                     << "Y:" << ySize << "U/V:" << uvSize;
+            return true;
+        } else {
+            // RGB格式
+            int bytesPerPixel = (format == AV_PIX_FMT_RGB24) ? 3 : 4;
+            m_frameLinesize[0] = width * bytesPerPixel;
+            size_t totalSize = static_cast<size_t>(width) * height * bytesPerPixel;
+            m_frameData[0] = static_cast<uint8_t*>(av_malloc(totalSize));
+            
+            bool success = (m_frameData[0] != nullptr);
+            if (!success) {
+                qWarning() << "Failed to allocate RGB frame buffer";
+                freeFrameBuffer();
+                return false;
+            }
+            
+            qDebug() << "Allocated RGB buffer:" << width << "x" << height 
+                     << "size:" << totalSize;
+            return true;
+        }
+    } catch (const std::exception& e) {
+        qWarning() << "Exception in allocateFrameBuffer:" << e.what();
+        freeFrameBuffer();
+        return false;
+    } catch (...) {
+        qWarning() << "Unknown exception in allocateFrameBuffer";
+        freeFrameBuffer();
+        return false;
+    }
+}
+
+void RecorderVideoWidget::freeFrameBuffer() {
+    for (int i = 0; i < 4; ++i) {
+        if (m_frameData[i]) {
+            av_free(m_frameData[i]);
+            m_frameData[i] = nullptr;
+        }
+        m_frameLinesize[i] = 0;
+    }
+    
+    m_frameWidth = 0;
+    m_frameHeight = 0;
+    m_frameFormat = AV_PIX_FMT_NONE;
+}
+
+// 静态成员定义
+constexpr float RecorderVideoWidget::VERTICES[];
+constexpr unsigned int RecorderVideoWidget::INDICES[];

+ 290 - 0
AV/code/recorder/ui/recorder_video_widget.h

@@ -0,0 +1,290 @@
+#ifndef AV_RECORDER_VIDEO_WIDGET_H
+#define AV_RECORDER_VIDEO_WIDGET_H
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions>
+#include <QOpenGLExtraFunctions>
+#include <QOpenGLShaderProgram>
+#include <QOpenGLTexture>
+#include <QMutex>
+#include <QTimer>
+#include <QImage>
+#include <QPainter>
+#include <QResizeEvent>
+#include <QMouseEvent>
+#include <memory>
+
+extern "C" {
+#include <libavutil/frame.h>
+#include <libavutil/imgutils.h>
+}
+
+/**
+ * 录制器视频预览组件
+ * 
+ * 基于OpenGL的高性能视频显示组件,支持:
+ * - YUV和RGB格式显示
+ * - 硬件加速渲染
+ * - 保持宽高比
+ * - 实时帧率显示
+ * - 多种视觉效果
+ */
+class RecorderVideoWidget : public QOpenGLWidget, protected QOpenGLExtraFunctions {
+    Q_OBJECT
+
+public:
+    /**
+     * 视频帧结构
+     */
+    struct VideoFrame {
+        uint8_t* data[4] = {nullptr};
+        int linesize[4] = {0};
+        int width = 0;
+        int height = 0;
+        int format = 0; // AVPixelFormat
+        int64_t pts = 0;
+        
+        VideoFrame() = default;
+        ~VideoFrame() {
+            for (int i = 0; i < 4; ++i) {
+                if (data[i]) {
+                    av_free(data[i]);
+                    data[i] = nullptr;
+                }
+            }
+        }
+        
+        // 禁用拷贝,只允许移动
+        VideoFrame(const VideoFrame&) = delete;
+        VideoFrame& operator=(const VideoFrame&) = delete;
+        VideoFrame(VideoFrame&& other) noexcept {
+            *this = std::move(other);
+        }
+        VideoFrame& operator=(VideoFrame&& other) noexcept {
+            if (this != &other) {
+                for (int i = 0; i < 4; ++i) {
+                    data[i] = other.data[i];
+                    linesize[i] = other.linesize[i];
+                    other.data[i] = nullptr;
+                    other.linesize[i] = 0;
+                }
+                width = other.width;
+                height = other.height;
+                format = other.format;
+                pts = other.pts;
+            }
+            return *this;
+        }
+    };
+
+public:
+    explicit RecorderVideoWidget(QWidget* parent = nullptr);
+    ~RecorderVideoWidget();
+
+    /**
+     * 初始化视频显示
+     */
+    bool initialize(int width, int height, int format);
+    
+    /**
+     * 清理资源
+     */
+    void cleanup();
+    
+    /**
+     * 更新视频帧
+     */
+    bool updateFrame(AVFrame* frame);
+    
+    /**
+     * 更新视频帧(自定义格式)
+     */
+    bool updateFrame(const VideoFrame& frame);
+    
+    /**
+     * 清空当前帧
+     */
+    void clearFrame();
+    
+    /**
+     * 设置保持宽高比
+     */
+    void setKeepAspectRatio(bool keep) {
+        m_keepAspectRatio = keep;
+        update();
+    }
+    
+    /**
+     * 获取是否保持宽高比
+     */
+    bool keepAspectRatio() const { return m_keepAspectRatio; }
+    
+    /**
+     * 设置显示FPS
+     */
+    void setShowFPS(bool show) {
+        m_showFPS = show;
+        update();
+    }
+    
+    /**
+     * 获取当前FPS
+     */
+    double getCurrentFPS() const { return m_currentFPS; }
+    
+    /**
+     * 设置无视频提示文本
+     */
+    void setNoVideoText(const QString& text) {
+        m_noVideoText = text;
+        update();
+    }
+    
+    /**
+     * 设置背景颜色
+     */
+    void setBackgroundColor(const QColor& color) {
+        m_backgroundColor = color;
+        update();
+    }
+    
+    // 视觉效果
+    void setGrayscale(bool enable);
+    void setFlipHorizontal(bool enable);
+    void setFlipVertical(bool enable);
+    void setBrightness(float brightness); // -1.0 to 1.0
+    void setContrast(float contrast);     // 0.0 to 2.0
+    void setSaturation(float saturation); // 0.0 to 2.0
+
+protected:
+    void initializeGL() override;
+    void paintGL() override;
+    void resizeGL(int width, int height) override;
+    void mousePressEvent(QMouseEvent* event) override;
+    void mouseDoubleClickEvent(QMouseEvent* event) override;
+
+private slots:
+    void updateFPS();
+
+signals:
+    /**
+     * 鼠标点击信号
+     */
+    void clicked(QPoint position);
+    
+    /**
+     * 双击信号
+     */
+    void doubleClicked(QPoint position);
+
+private:
+    /**
+     * 初始化着色器
+     */
+    bool initShaders();
+    
+    /**
+     * 创建纹理
+     */
+    void createTextures();
+    
+    /**
+     * 更新纹理数据
+     */
+    void updateTextures();
+    
+    /**
+     * 计算显示矩形
+     */
+    QRectF calculateDisplayRect() const;
+    
+    /**
+     * 绘制无视频提示
+     */
+    void drawNoVideoHint();
+    
+    /**
+     * 绘制FPS信息
+     */
+    void drawFPSInfo();
+    
+    /**
+     * 从AVFrame复制数据
+     */
+    bool copyFromAVFrame(AVFrame* frame);
+    
+    /**
+     * 从VideoFrame复制数据
+     */
+    bool copyFromVideoFrame(const VideoFrame& frame);
+    
+    /**
+     * 分配帧缓冲区
+     */
+    bool allocateFrameBuffer(int width, int height, int format);
+    
+    /**
+     * 释放帧缓冲区
+     */
+    void freeFrameBuffer();
+
+private:
+    // OpenGL资源
+    std::unique_ptr<QOpenGLShaderProgram> m_shaderProgram;
+    GLuint m_textureY;
+    GLuint m_textureU;
+    GLuint m_textureV;
+    GLuint m_textureRGB;
+    GLuint m_VAO;
+    GLuint m_VBO;
+    
+    // 帧数据
+    uint8_t* m_frameData[4];
+    int m_frameLinesize[4];
+    int m_frameWidth;
+    int m_frameHeight;
+    int m_frameFormat;
+    bool m_frameReady;
+    
+    // 显示设置
+    bool m_keepAspectRatio;
+    bool m_showFPS;
+    QString m_noVideoText;
+    QColor m_backgroundColor;
+    
+    // 视觉效果
+    bool m_grayscale;
+    bool m_flipHorizontal;
+    bool m_flipVertical;
+    float m_brightness;
+    float m_contrast;
+    float m_saturation;
+    
+    // FPS计算
+    QTimer* m_fpsTimer;
+    int m_frameCount;
+    double m_currentFPS;
+    qint64 m_lastFPSUpdate;
+    
+    // 线程安全
+    mutable QMutex m_mutex;
+    
+    // 初始化状态
+    bool m_initialized;
+    
+    // 顶点数据
+    static constexpr float VERTICES[] = {
+        // 位置        // 纹理坐标
+        -1.0f, -1.0f,  0.0f, 1.0f,
+         1.0f, -1.0f,  1.0f, 1.0f,
+         1.0f,  1.0f,  1.0f, 0.0f,
+        -1.0f,  1.0f,  0.0f, 0.0f
+    };
+    
+    static constexpr unsigned int INDICES[] = {
+        0, 1, 2,
+        2, 3, 0
+    };
+};
+
+#endif // AV_RECORDER_VIDEO_WIDGET_H

+ 611 - 0
AV/code/recorder/ui/styles/recorder_ui.qss

@@ -0,0 +1,611 @@
+/* AV录制器UI样式表 */
+/* 现代化深色主题 */
+
+/* 全局样式 */
+* {
+    font-family: "Segoe UI", "Microsoft YaHei", Arial, sans-serif;
+    font-size: 9pt;
+}
+
+/* 主窗口 */
+QMainWindow {
+    background-color: #2b2b2b;
+    color: #ffffff;
+}
+
+/* 中央部件 */
+QWidget {
+    background-color: #2b2b2b;
+    color: #ffffff;
+    border: none;
+}
+
+/* 菜单栏 */
+QMenuBar {
+    background-color: #333333;
+    color: #ffffff;
+    border-bottom: 1px solid #555555;
+    padding: 2px;
+}
+
+QMenuBar::item {
+    background-color: transparent;
+    padding: 4px 8px;
+    border-radius: 3px;
+}
+
+QMenuBar::item:selected {
+    background-color: #0a84ff;
+}
+
+QMenuBar::item:pressed {
+    background-color: #0066cc;
+}
+
+/* 菜单 */
+QMenu {
+    background-color: #333333;
+    color: #ffffff;
+    border: 1px solid #555555;
+    border-radius: 4px;
+    padding: 4px;
+}
+
+QMenu::item {
+    background-color: transparent;
+    padding: 6px 20px;
+    border-radius: 3px;
+}
+
+QMenu::item:selected {
+    background-color: #0a84ff;
+}
+
+QMenu::separator {
+    height: 1px;
+    background-color: #555555;
+    margin: 4px 0px;
+}
+
+/* 工具栏 */
+QToolBar {
+    background-color: #333333;
+    border: 1px solid #555555;
+    border-radius: 4px;
+    spacing: 2px;
+    padding: 2px;
+}
+
+QToolBar::handle {
+    background-color: #555555;
+    width: 8px;
+    margin: 4px;
+    border-radius: 2px;
+}
+
+QToolBar::separator {
+    background-color: #555555;
+    width: 1px;
+    margin: 4px 2px;
+}
+
+/* 工具按钮 */
+QToolButton {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    color: #ffffff;
+    padding: 6px;
+    margin: 1px;
+}
+
+QToolButton:hover {
+    background-color: #555555;
+    border-color: #777777;
+}
+
+QToolButton:pressed {
+    background-color: #333333;
+    border-color: #555555;
+}
+
+QToolButton:checked {
+    background-color: #0a84ff;
+    border-color: #0066cc;
+}
+
+QToolButton:disabled {
+    background-color: #2b2b2b;
+    border-color: #444444;
+    color: #666666;
+}
+
+/* 按钮 */
+QPushButton {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    color: #ffffff;
+    padding: 6px 12px;
+    min-width: 60px;
+}
+
+QPushButton:hover {
+    background-color: #555555;
+    border-color: #777777;
+}
+
+QPushButton:pressed {
+    background-color: #333333;
+    border-color: #555555;
+}
+
+QPushButton:checked {
+    background-color: #0a84ff;
+    border-color: #0066cc;
+}
+
+QPushButton:disabled {
+    background-color: #2b2b2b;
+    border-color: #444444;
+    color: #666666;
+}
+
+/* 主要按钮 */
+QPushButton.primary {
+    background-color: #0a84ff;
+    border-color: #0066cc;
+}
+
+QPushButton.primary:hover {
+    background-color: #0066cc;
+    border-color: #004499;
+}
+
+QPushButton.primary:pressed {
+    background-color: #004499;
+    border-color: #003366;
+}
+
+/* 危险按钮 */
+QPushButton.danger {
+    background-color: #ff3b30;
+    border-color: #cc2e24;
+}
+
+QPushButton.danger:hover {
+    background-color: #cc2e24;
+    border-color: #99221b;
+}
+
+QPushButton.danger:pressed {
+    background-color: #99221b;
+    border-color: #661612;
+}
+
+/* 成功按钮 */
+QPushButton.success {
+    background-color: #34c759;
+    border-color: #2a9f47;
+}
+
+QPushButton.success:hover {
+    background-color: #2a9f47;
+    border-color: #1f7735;
+}
+
+QPushButton.success:pressed {
+    background-color: #1f7735;
+    border-color: #154f23;
+}
+
+/* 标签 */
+QLabel {
+    color: #ffffff;
+    background-color: transparent;
+}
+
+QLabel.title {
+    font-size: 12pt;
+    font-weight: bold;
+    color: #ffffff;
+}
+
+QLabel.subtitle {
+    font-size: 10pt;
+    color: #cccccc;
+}
+
+QLabel.caption {
+    font-size: 8pt;
+    color: #999999;
+}
+
+/* 输入框 */
+QLineEdit {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    color: #ffffff;
+    padding: 6px;
+    selection-background-color: #0a84ff;
+}
+
+QLineEdit:focus {
+    border-color: #0a84ff;
+}
+
+QLineEdit:disabled {
+    background-color: #2b2b2b;
+    border-color: #444444;
+    color: #666666;
+}
+
+/* 文本编辑器 */
+QTextEdit, QPlainTextEdit {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    color: #ffffff;
+    selection-background-color: #0a84ff;
+}
+
+QTextEdit:focus, QPlainTextEdit:focus {
+    border-color: #0a84ff;
+}
+
+/* 组合框 */
+QComboBox {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    color: #ffffff;
+    padding: 6px;
+    min-width: 100px;
+}
+
+QComboBox:hover {
+    border-color: #777777;
+}
+
+QComboBox:focus {
+    border-color: #0a84ff;
+}
+
+QComboBox::drop-down {
+    border: none;
+    width: 20px;
+}
+
+QComboBox::down-arrow {
+    image: url(:/icons/arrow_down.png);
+    width: 12px;
+    height: 12px;
+}
+
+QComboBox QAbstractItemView {
+    background-color: #333333;
+    border: 1px solid #555555;
+    border-radius: 4px;
+    color: #ffffff;
+    selection-background-color: #0a84ff;
+}
+
+/* 滑块 */
+QSlider::groove:horizontal {
+    background-color: #444444;
+    height: 6px;
+    border-radius: 3px;
+}
+
+QSlider::handle:horizontal {
+    background-color: #0a84ff;
+    border: 1px solid #0066cc;
+    width: 16px;
+    height: 16px;
+    border-radius: 8px;
+    margin: -5px 0;
+}
+
+QSlider::handle:horizontal:hover {
+    background-color: #0066cc;
+}
+
+QSlider::handle:horizontal:pressed {
+    background-color: #004499;
+}
+
+QSlider::sub-page:horizontal {
+    background-color: #0a84ff;
+    border-radius: 3px;
+}
+
+/* 进度条 */
+QProgressBar {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    text-align: center;
+    color: #ffffff;
+    height: 20px;
+}
+
+QProgressBar::chunk {
+    background-color: #0a84ff;
+    border-radius: 3px;
+}
+
+/* 复选框 */
+QCheckBox {
+    color: #ffffff;
+    spacing: 8px;
+}
+
+QCheckBox::indicator {
+    width: 16px;
+    height: 16px;
+    border: 1px solid #666666;
+    border-radius: 3px;
+    background-color: #444444;
+}
+
+QCheckBox::indicator:hover {
+    border-color: #777777;
+}
+
+QCheckBox::indicator:checked {
+    background-color: #0a84ff;
+    border-color: #0066cc;
+    image: url(:/icons/check.png);
+}
+
+/* 单选按钮 */
+QRadioButton {
+    color: #ffffff;
+    spacing: 8px;
+}
+
+QRadioButton::indicator {
+    width: 16px;
+    height: 16px;
+    border: 1px solid #666666;
+    border-radius: 8px;
+    background-color: #444444;
+}
+
+QRadioButton::indicator:hover {
+    border-color: #777777;
+}
+
+QRadioButton::indicator:checked {
+    background-color: #0a84ff;
+    border-color: #0066cc;
+}
+
+QRadioButton::indicator:checked::after {
+    content: "";
+    width: 6px;
+    height: 6px;
+    border-radius: 3px;
+    background-color: #ffffff;
+    margin: 4px;
+}
+
+/* 分组框 */
+QGroupBox {
+    color: #ffffff;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    margin-top: 10px;
+    padding-top: 10px;
+}
+
+QGroupBox::title {
+    subcontrol-origin: margin;
+    subcontrol-position: top left;
+    padding: 0 8px;
+    background-color: #2b2b2b;
+    color: #ffffff;
+    font-weight: bold;
+}
+
+/* 选项卡 */
+QTabWidget::pane {
+    border: 1px solid #666666;
+    border-radius: 4px;
+    background-color: #2b2b2b;
+}
+
+QTabBar::tab {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-bottom: none;
+    border-radius: 4px 4px 0 0;
+    color: #ffffff;
+    padding: 8px 16px;
+    margin-right: 2px;
+}
+
+QTabBar::tab:hover {
+    background-color: #555555;
+}
+
+QTabBar::tab:selected {
+    background-color: #0a84ff;
+    border-color: #0066cc;
+}
+
+/* 滚动条 */
+QScrollBar:vertical {
+    background-color: #333333;
+    width: 12px;
+    border-radius: 6px;
+}
+
+QScrollBar::handle:vertical {
+    background-color: #666666;
+    border-radius: 6px;
+    min-height: 20px;
+}
+
+QScrollBar::handle:vertical:hover {
+    background-color: #777777;
+}
+
+QScrollBar::add-line:vertical,
+QScrollBar::sub-line:vertical {
+    border: none;
+    background: none;
+}
+
+QScrollBar:horizontal {
+    background-color: #333333;
+    height: 12px;
+    border-radius: 6px;
+}
+
+QScrollBar::handle:horizontal {
+    background-color: #666666;
+    border-radius: 6px;
+    min-width: 20px;
+}
+
+QScrollBar::handle:horizontal:hover {
+    background-color: #777777;
+}
+
+QScrollBar::add-line:horizontal,
+QScrollBar::sub-line:horizontal {
+    border: none;
+    background: none;
+}
+
+/* 状态栏 */
+QStatusBar {
+    background-color: #333333;
+    color: #ffffff;
+    border-top: 1px solid #555555;
+    padding: 2px;
+}
+
+QStatusBar::item {
+    border: none;
+}
+
+/* 分割器 */
+QSplitter::handle {
+    background-color: #555555;
+}
+
+QSplitter::handle:horizontal {
+    width: 4px;
+}
+
+QSplitter::handle:vertical {
+    height: 4px;
+}
+
+QSplitter::handle:hover {
+    background-color: #777777;
+}
+
+/* 对话框 */
+QDialog {
+    background-color: #2b2b2b;
+    color: #ffffff;
+}
+
+/* 消息框 */
+QMessageBox {
+    background-color: #2b2b2b;
+    color: #ffffff;
+}
+
+QMessageBox QLabel {
+    color: #ffffff;
+}
+
+/* 文件对话框 */
+QFileDialog {
+    background-color: #2b2b2b;
+    color: #ffffff;
+}
+
+/* 工具提示 */
+QToolTip {
+    background-color: #333333;
+    color: #ffffff;
+    border: 1px solid #555555;
+    border-radius: 4px;
+    padding: 4px;
+}
+
+/* 录制器特定样式 */
+.RecorderMainWidget {
+    background-color: #2b2b2b;
+}
+
+.RecorderVideoWidget {
+    background-color: #000000;
+    border: 1px solid #666666;
+    border-radius: 4px;
+}
+
+.RecorderAudioWidget {
+    background-color: #333333;
+    border: 1px solid #666666;
+    border-radius: 4px;
+    padding: 8px;
+}
+
+.AudioLevelWidget {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 2px;
+}
+
+.RecorderSettingsDialog {
+    background-color: #2b2b2b;
+}
+
+/* 录制状态指示器 */
+.recording-indicator {
+    background-color: #ff3b30;
+    border-radius: 6px;
+    width: 12px;
+    height: 12px;
+}
+
+.paused-indicator {
+    background-color: #ff9500;
+    border-radius: 6px;
+    width: 12px;
+    height: 12px;
+}
+
+.stopped-indicator {
+    background-color: #666666;
+    border-radius: 6px;
+    width: 12px;
+    height: 12px;
+}
+
+/* 音频电平条 */
+.audio-level-bar {
+    background-color: #444444;
+    border: 1px solid #666666;
+    border-radius: 2px;
+}
+
+.audio-level-fill {
+    background-color: #34c759;
+    border-radius: 1px;
+}
+
+.audio-level-peak {
+    background-color: #ff9500;
+}
+
+.audio-level-overload {
+    background-color: #ff3b30;
+}

+ 31 - 28
AV/code/utils/utils_frame_queue.cpp

@@ -1,5 +1,6 @@
 #include "utils_frame_queue.h"
 #include "../base/logger.h"
+#include "../base/media_common.h"
 #include <algorithm>
 #include <deque>
 #include <shared_mutex>
@@ -114,9 +115,13 @@ const FrameQueueItem* FrameQueue::peek(int index) const {
     return queue_[index].get();
 }
 
-AVFrame* FrameQueue::peekFrame() const {
+const AVFramePtr& FrameQueue::peekFramePtr() const {
     const FrameQueueItem* item = peek();
-    return item ? item->frame : nullptr;
+    if (item) {
+        return item->frame;
+    }
+    static AVFramePtr nullFrame;
+    return nullFrame;
 }
 
 std::unique_ptr<FrameQueueItem> FrameQueue::dequeue() {
@@ -162,31 +167,27 @@ std::unique_ptr<FrameQueueItem> FrameQueue::dequeue(int timeoutMs) {
     return item;
 }
 
-ErrorCode FrameQueue::enqueue(AVFrame* frame, int streamIndex) {
+ErrorCode FrameQueue::enqueue(AVFramePtr frame, int streamIndex) {
     if (!frame) {
         return ErrorCode::INVALID_PARAMS;
     }
     
-    auto item = std::make_unique<FrameQueueItem>(frame, streamIndex);
+    auto item = std::make_unique<FrameQueueItem>(std::move(frame), streamIndex);
     return enqueue(std::move(item));
 }
 
-AVFrame* FrameQueue::dequeueFrame() {
+AVFramePtr FrameQueue::dequeueFrame() {
     auto item = dequeue();
-    if (item) {
-        AVFrame* frame = item->frame;
-        item->frame = nullptr; // 转移所有权
-        return frame;
+    if (item && item->frame) {
+        return std::move(item->frame);
     }
     return nullptr;
 }
 
-AVFrame* FrameQueue::dequeueFrame(int timeoutMs) {
+AVFramePtr FrameQueue::dequeueFrame(int timeoutMs) {
     auto item = dequeue(timeoutMs);
-    if (item) {
-        AVFrame* frame = item->frame;
-        item->frame = nullptr; // 转移所有权
-        return frame;
+    if (item && item->frame) {
+        return std::move(item->frame);
     }
     return nullptr;
 }
@@ -437,7 +438,7 @@ std::vector<int> MultiStreamFrameQueue::getStreamIndices() const {
     return indices;
 }
 
-ErrorCode MultiStreamFrameQueue::enqueue(AVFrame* frame, int streamIndex) {
+ErrorCode MultiStreamFrameQueue::enqueue(AVFramePtr frame, int streamIndex) {
     std::shared_lock<std::shared_mutex> lock(streamsMutex_);
     
     auto it = streamQueues_.find(streamIndex);
@@ -453,10 +454,10 @@ ErrorCode MultiStreamFrameQueue::enqueue(AVFrame* frame, int streamIndex) {
         }
     }
     
-    return it->second->enqueue(frame, streamIndex);
+    return it->second->enqueue(std::move(frame), streamIndex);
 }
 
-AVFrame* MultiStreamFrameQueue::dequeue(int streamIndex) {
+AVFramePtr MultiStreamFrameQueue::dequeue(int streamIndex) {
     std::shared_lock<std::shared_mutex> lock(streamsMutex_);
     
     auto it = streamQueues_.find(streamIndex);
@@ -467,7 +468,7 @@ AVFrame* MultiStreamFrameQueue::dequeue(int streamIndex) {
     return it->second->dequeueFrame();
 }
 
-AVFrame* MultiStreamFrameQueue::dequeue(int streamIndex, int timeoutMs) {
+AVFramePtr MultiStreamFrameQueue::dequeue(int streamIndex, int timeoutMs) {
     std::shared_lock<std::shared_mutex> lock(streamsMutex_);
     
     auto it = streamQueues_.find(streamIndex);
@@ -478,27 +479,29 @@ AVFrame* MultiStreamFrameQueue::dequeue(int streamIndex, int timeoutMs) {
     return it->second->dequeueFrame(timeoutMs);
 }
 
-ErrorCode MultiStreamFrameQueue::enqueueToAll(AVFrame* frame) {
+ErrorCode MultiStreamFrameQueue::enqueueToAll(AVFramePtr frame) {
     std::shared_lock<std::shared_mutex> lock(streamsMutex_);
     
+    if (!frame) {
+        return ErrorCode::INVALID_PARAMS;
+    }
+    
     ErrorCode result = ErrorCode::SUCCESS;
     for (const auto& pair : streamQueues_) {
         // 为每个流创建帧的副本
-        AVFrame* frameCopy = av_frame_alloc();
+        AVFramePtr frameCopy = makeAVFrame();
         if (!frameCopy) {
             result = ErrorCode::MEMORY_ALLOC_FAILED;
             continue;
         }
         
-        if (av_frame_ref(frameCopy, frame) < 0) {
-            av_frame_free(&frameCopy);
+        if (av_frame_ref(frameCopy.get(), frame.get()) < 0) {
             result = ErrorCode::COPY_FAILED;
             continue;
         }
         
-        ErrorCode enqueueResult = pair.second->enqueue(frameCopy, pair.first);
+        ErrorCode enqueueResult = pair.second->enqueue(std::move(frameCopy), pair.first);
         if (enqueueResult != ErrorCode::SUCCESS) {
-            av_frame_free(&frameCopy);
             result = enqueueResult;
         }
     }
@@ -506,13 +509,13 @@ ErrorCode MultiStreamFrameQueue::enqueueToAll(AVFrame* frame) {
     return result;
 }
 
-std::vector<AVFrame*> MultiStreamFrameQueue::dequeueFromAll() {
+std::vector<AVFramePtr> MultiStreamFrameQueue::dequeueFromAll() {
     std::shared_lock<std::shared_mutex> lock(streamsMutex_);
     
-    std::vector<AVFrame*> frames;
+    std::vector<AVFramePtr> frames;
     for (const auto& pair : streamQueues_) {
-        AVFrame* frame = pair.second->dequeueFrame();
-        frames.push_back(frame); // 可能为nullptr
+        AVFramePtr frame = pair.second->dequeueFrame();
+        frames.push_back(std::move(frame)); // 可能为nullptr
     }
     
     return frames;

+ 38 - 30
AV/code/utils/utils_frame_queue.h

@@ -23,9 +23,9 @@ namespace utils {
 
 using namespace av;
 
-// 帧队列项
+// 帧队列项 - 使用智能指针统一管理内存
 struct FrameQueueItem {
-    AVFrame* frame = nullptr;           // 帧数据
+    AVFramePtr frame;                   // 帧数据 - 使用智能指针
     int64_t pts = AV_NOPTS_VALUE;      // 显示时间戳
     int64_t dts = AV_NOPTS_VALUE;      // 解码时间戳
     double duration = 0.0;              // 帧持续时间
@@ -37,7 +37,8 @@ struct FrameQueueItem {
         enqueueTime = std::chrono::steady_clock::now();
     }
     
-    FrameQueueItem(AVFrame* f, int stream = -1) : frame(f), streamIndex(stream) {
+    // 从智能指针构造
+    FrameQueueItem(AVFramePtr f, int stream = -1) : frame(std::move(f)), streamIndex(stream) {
         if (frame) {
             pts = frame->pts;
             dts = frame->pkt_dts;
@@ -46,34 +47,39 @@ struct FrameQueueItem {
         enqueueTime = std::chrono::steady_clock::now();
     }
     
-    ~FrameQueueItem() {
-        if (frame) {
-            av_frame_free(&frame);
+    // 从原生指针构造(为了兼容性,自动转换为智能指针)
+    FrameQueueItem(AVFrame* f, int stream = -1) : streamIndex(stream) {
+        if (f) {
+            frame = AVFramePtr(f);  // 转换为智能指针
+            pts = frame->pts;
+            dts = frame->pkt_dts;
+            isKeyFrame = (frame->key_frame == 1);
         }
+        enqueueTime = std::chrono::steady_clock::now();
     }
     
+    // 智能指针自动管理内存,无需手动析构
+    ~FrameQueueItem() = default;
+    
     // 移动构造函数
     FrameQueueItem(FrameQueueItem&& other) noexcept
-        : frame(other.frame), pts(other.pts), dts(other.dts),
+        : frame(std::move(other.frame)), pts(other.pts), dts(other.dts),
           duration(other.duration), streamIndex(other.streamIndex),
           isKeyFrame(other.isKeyFrame), enqueueTime(other.enqueueTime) {
-        other.frame = nullptr;
+        // frame 已经被移动,无需置空
     }
     
     // 移动赋值操作符
     FrameQueueItem& operator=(FrameQueueItem&& other) noexcept {
         if (this != &other) {
-            if (frame) {
-                av_frame_free(&frame);
-            }
-            frame = other.frame;
+            frame = std::move(other.frame);
             pts = other.pts;
             dts = other.dts;
             duration = other.duration;
             streamIndex = other.streamIndex;
             isKeyFrame = other.isKeyFrame;
             enqueueTime = other.enqueueTime;
-            other.frame = nullptr;
+            // other.frame 已经被移动,无需手动置空
         }
         return *this;
     }
@@ -124,24 +130,26 @@ public:
     std::unique_ptr<FrameQueueItem> dequeue();
     std::unique_ptr<FrameQueueItem> dequeue(int timeoutMs);
     
-    // 便捷方法
-    ErrorCode enqueue(AVFrame* frame, int streamIndex = -1);
-    AVFrame* dequeueFrame();
-    AVFrame* dequeueFrame(int timeoutMs);
+    // 安全接口(使用智能指针)
+    ErrorCode enqueue(AVFramePtr frame, int streamIndex = -1);
     
     // 预览方法(不移除队列中的帧)
     const FrameQueueItem* peek() const;
     const FrameQueueItem* peek(int index) const;  // 预览第index个帧(0为队首)
-    AVFrame* peekFrame() const;  // 预览队首帧的AVFrame
+    const AVFramePtr& peekFramePtr() const;  // 预览队首帧
+    
+    // 帧操作接口
+    AVFramePtr dequeueFrame();
+    AVFramePtr dequeueFrame(int timeoutMs);
     
-    // 兼容性方法 (push/pop 别名)
-    ErrorCode push(AVFrame* frame, int streamIndex = -1) {
-        return enqueue(frame, streamIndex);
+    // 便捷别名
+    ErrorCode push(AVFramePtr frame, int streamIndex = -1) {
+        return enqueue(std::move(frame), streamIndex);
     }
-    AVFrame* pop() {
+    AVFramePtr pop() {
         return dequeueFrame();
     }
-    AVFrame* pop(int timeoutMs) {
+    AVFramePtr pop(int timeoutMs) {
         return dequeueFrame(timeoutMs);
     }
     
@@ -229,14 +237,14 @@ public:
     bool hasStream(int streamIndex) const;
     std::vector<int> getStreamIndices() const;
     
-    // 帧操作
-    ErrorCode enqueue(AVFrame* frame, int streamIndex);
-    AVFrame* dequeue(int streamIndex);
-    AVFrame* dequeue(int streamIndex, int timeoutMs);
+    // 安全帧操作接口
+    ErrorCode enqueue(AVFramePtr frame, int streamIndex);
+    AVFramePtr dequeue(int streamIndex);
+    AVFramePtr dequeue(int streamIndex, int timeoutMs);
     
-    // 批量操作
-    ErrorCode enqueueToAll(AVFrame* frame);
-    std::vector<AVFrame*> dequeueFromAll();
+    // 安全批量操作接口
+    ErrorCode enqueueToAll(AVFramePtr frame);
+    std::vector<AVFramePtr> dequeueFromAll();
     
     // 队列控制
     void clear();

+ 0 - 0
AV/debug_player.cpp → AV/examples/debug_player.cpp


+ 0 - 0
AV/integration_example.cpp → AV/examples/integration_example.cpp


+ 0 - 0
AV/code/examples/player_v2_example.cpp → AV/examples/player_v2_example.cpp


+ 0 - 0
AV/test_audio.cpp → AV/test/test_audio.cpp


+ 0 - 0
AV/test_audio_debug.cpp → AV/test/test_audio_debug.cpp


+ 0 - 0
AV/test_audio_encoder.cpp → AV/test/test_audio_encoder.cpp


+ 41 - 0
AV/test/test_audio_fix.cpp

@@ -0,0 +1,41 @@
+#include "code/capture/capture_audio_capturer.h"
+#include "code/base/logger.h"
+#include <iostream>
+
+using namespace av::capture;
+
+int main() {
+    // 初始化日志
+    av::Logger::instance().setLevel(av::LogLevel::DEBUG);
+    
+    std::cout << "测试音频采集器修复..." << std::endl;
+    
+    // 创建音频采集器
+    AudioCapturer capturer;
+    
+    // 设置参数
+    AudioCaptureParams params(CapturerType::AUDIO_MIC);
+    params.micIndex = 0;
+    params.sampleRate = 44100;
+    params.channels = 1;
+    params.sampleFormat = AV_SAMPLE_FMT_S16;
+    
+    // 初始化采集器
+    auto result = capturer.initialize(params);
+    
+    if (result == av::ErrorCode::SUCCESS) {
+        std::cout << "✓ 音频采集器初始化成功!" << std::endl;
+        
+        // 测试设备枚举
+        auto devices = capturer.getAvailableDevices();
+        std::cout << "找到 " << devices.size() << " 个音频设备" << std::endl;
+        
+        capturer.close();
+    } else {
+        std::cout << "✗ 音频采集器初始化失败,错误码: " << static_cast<int>(result) << std::endl;
+        return 1;
+    }
+    
+    std::cout << "测试完成!" << std::endl;
+    return 0;
+}

+ 70 - 0
AV/test/test_audio_recorder_complete.cpp

@@ -0,0 +1,70 @@
+#include "code/recorder/recorder_audio_recorder.h"
+#include "code/base/logger.h"
+#include <iostream>
+#include <thread>
+#include <chrono>
+
+using namespace av;
+using namespace av::recorder;
+
+int main() {
+    // 初始化日志
+    Logger::instance().setLevel(LogLevel::DEBUG);
+    Logger::instance().info("开始测试音频录制器完整修复");
+    
+    try {
+        // 创建音频录制器
+        auto audioRecorder = std::make_unique<AudioRecorder>();
+        
+        // 设置录制参数
+        RecorderParams params;
+        params.type = MediaType::AUDIO;
+        params.outputPath = "test_audio_complete.aac";
+        params.audioParams.sampleRate = 44100;
+        params.audioParams.channels = 2;
+        params.audioParams.sampleFormat = AV_SAMPLE_FMT_S16;
+        params.audioParams.bitrate = 128000;
+        params.audioParams.codecName = "aac";
+        params.audioParams.deviceId = "";
+        
+        std::cout << "初始化音频录制器..." << std::endl;
+        ErrorCode result = audioRecorder->initialize(params);
+        if (result != ErrorCode::SUCCESS) {
+            std::cerr << "音频录制器初始化失败: " << static_cast<int>(result) << std::endl;
+            return -1;
+        }
+        std::cout << "音频录制器初始化成功!" << std::endl;
+        
+        std::cout << "开始录制..." << std::endl;
+        result = audioRecorder->startRecording();
+        if (result != ErrorCode::SUCCESS) {
+            std::cerr << "开始录制失败: " << static_cast<int>(result) << std::endl;
+            return -1;
+        }
+        std::cout << "录制已开始!" << std::endl;
+        
+        // 录制5秒
+        std::cout << "录制中,请说话..." << std::endl;
+        std::this_thread::sleep_for(std::chrono::seconds(5));
+        
+        std::cout << "停止录制..." << std::endl;
+        result = audioRecorder->stopRecording();
+        if (result != ErrorCode::SUCCESS) {
+            std::cerr << "停止录制失败: " << static_cast<int>(result) << std::endl;
+            return -1;
+        }
+        std::cout << "录制已停止!" << std::endl;
+        
+        // 关闭录制器
+        audioRecorder->close();
+        std::cout << "音频录制器已关闭" << std::endl;
+        
+        std::cout << "测试完成! 输出文件: test_audio_complete.aac" << std::endl;
+        
+    } catch (const std::exception& e) {
+        std::cerr << "测试过程中发生异常: " << e.what() << std::endl;
+        return -1;
+    }
+    
+    return 0;
+}

+ 72 - 0
AV/test/test_audio_recorder_fix.cpp

@@ -0,0 +1,72 @@
+#include "code/recorder/recorder_audio_recorder.h"
+#include "code/base/logger.h"
+#include <iostream>
+#include <thread>
+#include <chrono>
+
+using namespace av::recorder;
+using namespace av;
+
+int main() {
+    // 初始化日志
+    Logger::instance().setLevel(LogLevel::DEBUG);
+    
+    std::cout << "测试音频录制器修复..." << std::endl;
+    
+    try {
+        // 创建音频录制器
+        AudioRecorder recorder;
+        
+        // 设置录制参数
+        AudioRecorderParams params;
+        params.capturerType = capture::CapturerType::AUDIO_MIC;
+        params.sampleRate = 44100;
+        params.channels = 2;  // 设置为2声道
+        params.sampleFormat = AV_SAMPLE_FMT_S16;
+        params.codecName = "aac";
+        params.bitrate = 128000;
+        params.outputPath = "./test_audio_fix.mp4";
+        params.format = "mp4";
+        
+        std::cout << "初始化录制器参数: " << params.sampleRate << "Hz, " 
+                  << params.channels << "ch, " << params.codecName << std::endl;
+        
+        // 初始化录制器
+        ErrorCode result = recorder.initialize(params);
+        
+        if (result == ErrorCode::SUCCESS) {
+            std::cout << "✓ 音频录制器初始化成功!" << std::endl;
+            
+            // 尝试开始录制
+            result = recorder.startRecording();
+            if (result == ErrorCode::SUCCESS) {
+                std::cout << "✓ 音频录制开始成功!" << std::endl;
+                
+                // 录制3秒
+                std::this_thread::sleep_for(std::chrono::seconds(3));
+                
+                // 停止录制
+                result = recorder.stopRecording();
+                if (result == ErrorCode::SUCCESS) {
+                    std::cout << "✓ 音频录制停止成功!" << std::endl;
+                } else {
+                    std::cout << "✗ 停止录制失败,错误码: " << static_cast<int>(result) << std::endl;
+                }
+            } else {
+                std::cout << "✗ 开始录制失败,错误码: " << static_cast<int>(result) << std::endl;
+            }
+            
+            recorder.close();
+        } else {
+            std::cout << "✗ 音频录制器初始化失败,错误码: " << static_cast<int>(result) << std::endl;
+            return 1;
+        }
+        
+    } catch (const std::exception& e) {
+        std::cout << "✗ 异常: " << e.what() << std::endl;
+        return 1;
+    }
+    
+    std::cout << "测试完成!" << std::endl;
+    return 0;
+}

+ 0 - 0
AV/test_basic.cpp → AV/test/test_basic.cpp


+ 0 - 0
AV/test_codec.cpp → AV/test/test_codec.cpp


+ 0 - 0
AV/test_decoder.cpp → AV/test/test_decoder.cpp


+ 0 - 0
AV/test_muxer.cpp → AV/test/test_muxer.cpp


+ 86 - 0
AV/test/test_muxer_fix.cpp

@@ -0,0 +1,86 @@
+#include "code/muxer/muxer_file_muxer.h"
+#include "code/base/logger.h"
+#include <iostream>
+
+using namespace av::muxer;
+using namespace av;
+
+int main() {
+    // 初始化日志
+    Logger::instance().setLevel(LogLevel::DEBUG);
+    
+    std::cout << "测试 FileMuxer 初始化修复..." << std::endl;
+    
+    try {
+        // 创建文件复用器
+        FileMuxer muxer;
+        
+        // 测试1: 使用正确的 FileMuxerParams
+        std::cout << "\n=== 测试1: 正确的 FileMuxerParams ===" << std::endl;
+        FileMuxerParams correctParams;
+        correctParams.type = MuxerType::FILE_MUXER;
+        correctParams.outputPath = "./test_output.mp4";
+        correctParams.outputFile = "./test_output.mp4";
+        correctParams.format = "mp4";
+        correctParams.overwrite = true;
+        
+        ErrorCode result = muxer.initialize(correctParams);
+        if (result == ErrorCode::SUCCESS) {
+            std::cout << "✓ 正确参数初始化成功!" << std::endl;
+        } else {
+            std::cout << "✗ 正确参数初始化失败,错误码: " << static_cast<int>(result) << std::endl;
+        }
+        
+        muxer.close();
+        
+        // 测试2: 使用错误类型的 MuxerParams(基类)
+        std::cout << "\n=== 测试2: 错误的 MuxerParams 类型 ===" << std::endl;
+        MuxerParams wrongParams;
+        wrongParams.type = MuxerType::FILE_MUXER;  // 类型正确但实际是基类
+        wrongParams.outputPath = "./test_output2.mp4";
+        
+        FileMuxer muxer2;
+        result = muxer2.initialize(wrongParams);
+        if (result != ErrorCode::SUCCESS) {
+            std::cout << "✓ 错误参数类型被正确拒绝,错误码: " << static_cast<int>(result) << std::endl;
+        } else {
+            std::cout << "✗ 错误参数类型未被拒绝!" << std::endl;
+        }
+        
+        // 测试3: 空输出路径
+        std::cout << "\n=== 测试3: 空输出路径 ===" << std::endl;
+        FileMuxerParams emptyPathParams;
+        emptyPathParams.type = MuxerType::FILE_MUXER;
+        emptyPathParams.outputPath = "";  // 空路径
+        emptyPathParams.outputFile = "";   // 空文件
+        
+        FileMuxer muxer3;
+        result = muxer3.initialize(emptyPathParams);
+        if (result != ErrorCode::SUCCESS) {
+            std::cout << "✓ 空路径参数被正确拒绝,错误码: " << static_cast<int>(result) << std::endl;
+        } else {
+            std::cout << "✗ 空路径参数未被拒绝!" << std::endl;
+        }
+        
+        // 测试4: 错误的复用器类型
+        std::cout << "\n=== 测试4: 错误的复用器类型 ===" << std::endl;
+        FileMuxerParams wrongTypeParams;
+        wrongTypeParams.type = MuxerType::STREAM_MUXER;  // 错误的类型
+        wrongTypeParams.outputPath = "./test_output4.mp4";
+        
+        FileMuxer muxer4;
+        result = muxer4.initialize(wrongTypeParams);
+        if (result != ErrorCode::SUCCESS) {
+            std::cout << "✓ 错误复用器类型被正确拒绝,错误码: " << static_cast<int>(result) << std::endl;
+        } else {
+            std::cout << "✗ 错误复用器类型未被拒绝!" << std::endl;
+        }
+        
+    } catch (const std::exception& e) {
+        std::cout << "✗ 异常: " << e.what() << std::endl;
+        return 1;
+    }
+    
+    std::cout << "\n测试完成!" << std::endl;
+    return 0;
+}

+ 0 - 0
AV/test_player.cpp → AV/test/test_player.cpp


+ 0 - 0
AV/test_player_adapter.cpp → AV/test/test_player_adapter.cpp


+ 0 - 0
AV/test_player_with_ui.cpp → AV/test/test_player_with_ui.cpp


+ 0 - 0
AV/test_playerv2.pri → AV/test/test_playerv2.pri


+ 315 - 0
AV/test/test_recorder.cpp

@@ -0,0 +1,315 @@
+/**
+ * AV录制器模块测试示例
+ * 
+ * 这个文件展示了如何使用重构后的录制器模块进行音频、视频和音视频同步录制。
+ * 基于AV模块的现有组件构建,提供了统一的录制接口。
+ */
+
+#include "code/recorder/recorder.h"
+#include "code/base/logger.h"
+#include <QCoreApplication>
+#include <QTimer>
+#include <QDebug>
+#include <memory>
+
+using namespace av::recorder;
+using namespace av::recorder::utils;
+
+class RecorderTest : public QObject {
+    Q_OBJECT
+
+public:
+    RecorderTest(QObject* parent = nullptr) : QObject(parent) {}
+    
+    void runTests() {
+        // 初始化录制器模块
+        auto result = RecorderModule::initialize();
+        if (result != av::ErrorCode::SUCCESS) {
+            qCritical() << "Failed to initialize recorder module";
+            return;
+        }
+        
+        qInfo() << "Recorder Module Version:" << QString::fromStdString(RecorderModule::getVersion());
+        qInfo() << "Supported formats:" << getSupportedFormatsString();
+        qInfo() << "Supported audio codecs:" << getSupportedAudioCodecsString();
+        qInfo() << "Supported video codecs:" << getSupportedVideoCodecsString();
+        
+        // 测试音频录制
+        testAudioRecording();
+        
+        // 延迟测试视频录制
+        QTimer::singleShot(3000, this, &RecorderTest::testVideoRecording);
+        
+        // 延迟测试音视频同步录制
+        QTimer::singleShot(6000, this, &RecorderTest::testAVRecording);
+        
+        // 延迟退出
+        QTimer::singleShot(10000, this, &RecorderTest::cleanup);
+    }
+    
+private slots:
+    void testAudioRecording() {
+        qInfo() << "\n=== Testing Audio Recording ===";
+        
+        // 创建音频录制器
+        auto audioRecorder = createAudioRecorder();
+        if (!audioRecorder) {
+            qCritical() << "Failed to create audio recorder";
+            return;
+        }
+        
+        // 设置音频参数
+        auto audioParams = getDefaultAudioParams();
+        audioParams.outputPath = "test_audio_output.mp4";
+        audioParams.sampleRate = 44100;
+        audioParams.channels = 2;
+        audioParams.bitrate = 128000;
+        audioParams.codecName = "aac";
+        
+        qInfo() << "Audio params:" << formatAudioParams(audioParams);
+        
+        // 初始化录制器
+        auto result = audioRecorder->initialize(audioParams);
+        if (result != av::ErrorCode::SUCCESS) {
+            qCritical() << "Failed to initialize audio recorder";
+            return;
+        }
+        
+        // 开始录制
+        result = audioRecorder->startRecording();
+        if (result != av::ErrorCode::SUCCESS) {
+            qCritical() << "Failed to start audio recording";
+            return;
+        }
+        
+        qInfo() << "Audio recording started, will record for 2 seconds...";
+        
+        // 2秒后停止录制
+        QTimer::singleShot(2000, [audioRecorder = std::move(audioRecorder)]() mutable {
+            auto result = audioRecorder->stopRecording();
+            if (result == av::ErrorCode::SUCCESS) {
+                qInfo() << "Audio recording stopped successfully";
+                
+                // 获取统计信息
+                auto stats = audioRecorder->getStatistics();
+                qInfo() << "Audio recording stats:" << formatRecordingStats(stats);
+            } else {
+                qCritical() << "Failed to stop audio recording";
+            }
+        });
+    }
+    
+    void testVideoRecording() {
+        qInfo() << "\n=== Testing Video Recording ===";
+        
+        // 创建视频录制器
+        auto videoRecorder = createVideoRecorder();
+        if (!videoRecorder) {
+            qCritical() << "Failed to create video recorder";
+            return;
+        }
+        
+        // 设置视频参数(使用推荐参数)
+        auto videoParams = getRecommendedVideoParams();
+        videoParams.outputPath = "test_video_output.mp4";
+        videoParams.captureMethod = VideoCaptureMethod::SCREEN_CAPTURE;
+        videoParams.monitorIndex = 0;
+        videoParams.drawCursor = true;
+        
+        qInfo() << "Video params:" << formatVideoParams(videoParams);
+        
+        // 初始化录制器
+        auto result = videoRecorder->initialize(videoParams);
+        if (result != av::ErrorCode::SUCCESS) {
+            qCritical() << "Failed to initialize video recorder";
+            return;
+        }
+        
+        // 开始录制
+        result = videoRecorder->startRecording();
+        if (result != av::ErrorCode::SUCCESS) {
+            qCritical() << "Failed to start video recording";
+            return;
+        }
+        
+        qInfo() << "Video recording started, will record for 2 seconds...";
+        
+        // 2秒后停止录制
+        QTimer::singleShot(2000, [videoRecorder = std::move(videoRecorder)]() mutable {
+            auto result = videoRecorder->stopRecording();
+            if (result == av::ErrorCode::SUCCESS) {
+                qInfo() << "Video recording stopped successfully";
+                
+                // 获取统计信息
+                auto stats = videoRecorder->getStatistics();
+                qInfo() << "Video recording stats:" << formatRecordingStats(stats);
+            } else {
+                qCritical() << "Failed to stop video recording";
+            }
+        });
+    }
+    
+    void testAVRecording() {
+        qInfo() << "\n=== Testing AV Synchronized Recording ===";
+        
+        // 创建音视频录制器
+        auto avRecorder = createAVRecorder();
+        if (!avRecorder) {
+            qCritical() << "Failed to create AV recorder";
+            return;
+        }
+        
+        // 设置音视频参数
+        auto avParams = getDefaultAVParams();
+        avParams.outputPath = "test_av_output.mp4";
+        avParams.enableAudio = true;
+        avParams.enableVideo = true;
+        avParams.enableSync = true;
+        avParams.syncThresholdMs = 40;
+        avParams.dropFrameOnSync = true;
+        
+        // 调整音频参数
+        avParams.audioParams.sampleRate = 44100;
+        avParams.audioParams.channels = 2;
+        avParams.audioParams.bitrate = 128000;
+        
+        // 调整视频参数
+        avParams.videoParams.width = 1280;
+        avParams.videoParams.height = 720;
+        avParams.videoParams.frameRate = 30;
+        avParams.videoParams.bitrate = 2000000;
+        avParams.videoParams.captureMethod = VideoCaptureMethod::SCREEN_CAPTURE;
+        
+        qInfo() << "AV params:" << formatAVParams(avParams);
+        
+        // 初始化录制器
+        auto result = avRecorder->initialize(avParams);
+        if (result != av::ErrorCode::SUCCESS) {
+            qCritical() << "Failed to initialize AV recorder";
+            return;
+        }
+        
+        // 开始录制
+        result = avRecorder->startRecording();
+        if (result != av::ErrorCode::SUCCESS) {
+            qCritical() << "Failed to start AV recording";
+            return;
+        }
+        
+        qInfo() << "AV recording started, will record for 3 seconds...";
+        
+        // 3秒后停止录制
+        QTimer::singleShot(3000, [avRecorder = std::move(avRecorder)]() mutable {
+            auto result = avRecorder->stopRecording();
+            if (result == av::ErrorCode::SUCCESS) {
+                qInfo() << "AV recording stopped successfully";
+                
+                // 获取统计信息
+                auto stats = avRecorder->getStatistics();
+                qInfo() << "AV recording stats:" << formatRecordingStats(stats);
+                
+                // 获取同步状态
+                auto syncStatus = avRecorder->getSyncStatus();
+                qInfo() << "Sync status:" << formatSyncStatus(syncStatus);
+            } else {
+                qCritical() << "Failed to stop AV recording";
+            }
+        });
+    }
+    
+    void cleanup() {
+        qInfo() << "\n=== Cleaning up ===";
+        
+        // 清理录制器模块
+        RecorderModule::cleanup();
+        
+        qInfo() << "Test completed, exiting...";
+        QCoreApplication::quit();
+    }
+    
+private:
+    QString getSupportedFormatsString() {
+        auto formats = RecorderModule::getSupportedFormats();
+        QStringList list;
+        for (const auto& format : formats) {
+            list << QString::fromStdString(format);
+        }
+        return list.join(", ");
+    }
+    
+    QString getSupportedAudioCodecsString() {
+        auto codecs = RecorderModule::getSupportedAudioCodecs();
+        QStringList list;
+        for (const auto& codec : codecs) {
+            list << QString::fromStdString(codec);
+        }
+        return list.join(", ");
+    }
+    
+    QString getSupportedVideoCodecsString() {
+        auto codecs = RecorderModule::getSupportedVideoCodecs();
+        QStringList list;
+        for (const auto& codec : codecs) {
+            list << QString::fromStdString(codec);
+        }
+        return list.join(", ");
+    }
+    
+    QString formatAudioParams(const AudioRecorderParams& params) {
+        return QString("SR:%1Hz, CH:%2, BR:%3bps, Codec:%4")
+            .arg(params.sampleRate)
+            .arg(params.channels)
+            .arg(params.bitrate)
+            .arg(QString::fromStdString(params.codecName));
+    }
+    
+    QString formatVideoParams(const VideoRecorderParams& params) {
+        return QString("Res:%1x%2, FPS:%3, BR:%4bps, Codec:%5")
+            .arg(params.width)
+            .arg(params.height)
+            .arg(params.frameRate)
+            .arg(params.bitrate)
+            .arg(QString::fromStdString(params.codecName));
+    }
+    
+    QString formatAVParams(const AVRecorderParams& params) {
+        return QString("Audio:[%1], Video:[%2], Sync:%3")
+            .arg(formatAudioParams(params.audioParams))
+            .arg(formatVideoParams(params.videoParams))
+            .arg(params.enableSync ? "ON" : "OFF");
+    }
+    
+    QString formatRecordingStats(const av::RecordingStatistics& stats) {
+        return QString("Duration:%1s, Frames:%2, Packets:%3, Errors:%4")
+            .arg(stats.durationMs / 1000.0, 0, 'f', 2)
+            .arg(stats.totalFrames)
+            .arg(stats.totalPackets)
+            .arg(stats.errorCount);
+    }
+    
+    QString formatSyncStatus(const av::SyncStatus& status) {
+        return QString("Drift:%1ms, Dropped:%2, Duplicated:%3")
+            .arg(status.avgDriftMs, 0, 'f', 2)
+            .arg(status.droppedFrames)
+            .arg(status.duplicatedFrames);
+    }
+};
+
+int main(int argc, char *argv[]) {
+    QCoreApplication app(argc, argv);
+    
+    // 设置日志级别
+    av::Logger::setLevel(av::LogLevel::INFO);
+    
+    qInfo() << "Starting AV Recorder Module Test...";
+    qInfo() << "This test will demonstrate audio, video, and synchronized AV recording.";
+    qInfo() << "Output files will be created in the current directory.";
+    
+    // 创建并运行测试
+    RecorderTest test;
+    test.runTests();
+    
+    return app.exec();
+}
+
+#include "test_recorder.moc"

+ 202 - 0
AV/test/test_seek_pause_fixed.cpp

@@ -0,0 +1,202 @@
+#include "code/player/player_core_v2.h"
+#include "code/base/logger.h"
+
+#include <iostream>
+#include <fstream>
+#include <thread>
+#include <chrono>
+
+using namespace av::player;
+using namespace av;
+class TestCallback : public PlayerEventCallback {
+public:
+    TestCallback(std::ofstream& output) : outputFile(output) {}
+    
+    void onStateChanged(PlayerState newState) override {
+        std::cout << "State changed to: " << static_cast<int>(newState) << std::endl;
+        currentState = newState;
+    }
+    
+    void onMediaInfoChanged(const MediaInfo& info) override {
+        std::cout << "Media info: " << info.filename << ", duration: " << info.duration
+                  << std::endl;
+    }
+    
+    void onPositionChanged(int64_t position) override {
+        std::cout << "Position: " << position / 1000000.0 << "s" << std::endl;
+        currentPosition = position;
+    }
+    
+    void onErrorOccurred(const std::string& error) override {
+        std::cout << "Error: " << error << std::endl;
+    }
+
+    void onEndOfFile() override { std::cout << "End of file" << std::endl; }
+
+    void onSyncError(double error, const std::string& reason) override
+    {
+        std::cout << "Sync error: " << error << ", reason: " << reason << std::endl;
+    }
+
+    void onFrameDropped(int64_t count) override
+    {
+        std::cout << "Frame dropped: " << count << std::endl;
+    }
+
+    void onVideoFrameReady(AVFrame* frame) override
+    {
+        // 简单处理视频帧
+    }
+
+    void onVideoRendererInitRequired(int width, int height) override
+    {
+        std::cout << "Video renderer init: " << width << "x" << height << std::endl;
+    }
+
+    void onVideoRendererCloseRequired() override
+    {
+        std::cout << "Video renderer close" << std::endl;
+    }
+
+    PlayerState currentState = PlayerState::Idle;
+    int64_t currentPosition = 0;
+    
+private:
+    std::ofstream& outputFile;
+};
+
+int main() {
+    // 创建输出文件
+    std::ofstream outputFile("test_seek_pause_output.txt");
+    if (!outputFile.is_open()) {
+        std::cerr << "无法创建输出文件" << std::endl;
+        return 1;
+    }
+    
+    // 初始化日志
+    Logger::instance().initialize("test.log", LogLevel::ERROR, false, true);
+    Logger::instance().info("PlayerCoreV2 Example Started");
+
+    // 创建播放器
+    PlayerCoreV2 player;
+    TestCallback callback(outputFile);
+    player.setEventCallback(&callback);
+
+    std::cout << "=== 测试修复后的暂停后seek功能 ===" << std::endl;
+
+    // 请用户提供测试文件路径
+    std::string filename = "C:/Users/zhuizhu/Videos/2.mp4";
+    // std::cout << "请输入测试视频文件路径: ";
+    // std::getline(std::cin, filename);
+
+    // if (filename.empty()) {
+    //     std::cout << "未提供文件路径,退出测试" << std::endl;
+    //     return 1;
+    // }
+
+    // 打开文件
+    std::cout << "\n1. 打开文件: " << filename << std::endl;
+    auto result = player.openFile(filename);
+    if (result != ErrorCode::SUCCESS) {
+        std::cout << "打开文件失败" << std::endl;
+        return 1;
+    }
+    
+    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+    
+    // 开始播放
+    std::cout << "\n2. 开始播放" << std::endl;
+    player.play();
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+    
+    // 暂停
+    std::cout << "\n3. 暂停播放" << std::endl;
+    player.pause();
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    
+    // 获取当前位置
+    int64_t pausePosition = player.getCurrentTime();
+    std::cout << "暂停时位置: " << pausePosition / 1000000.0 << "s" << std::endl;
+
+    // 在暂停状态下seek
+    int64_t seekTarget = pausePosition + 5000000; // 向前seek 5秒
+    std::cout << "\n4. 在暂停状态下seek到: " << seekTarget / 1000000.0 << "s" << std::endl;
+    player.seek(seekTarget);
+    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+    
+    // 检查seek后的位置
+    int64_t afterSeekPosition = player.getCurrentTime();
+    std::cout << "seek后位置: " << afterSeekPosition / 1000000.0 << "s" << std::endl;
+    std::cout << "状态: " << static_cast<int>(callback.currentState) << std::endl;
+
+    // 验证结果
+    if (callback.currentState == PlayerState::Paused) {
+        std::cout << "✓ 状态正确:保持暂停状态" << std::endl;
+    } else {
+        std::cout << "✗ 状态错误:应该保持暂停状态" << std::endl;
+    }
+    
+    if (std::abs(afterSeekPosition - seekTarget) < 1000000) { // 允许1秒误差
+        std::cout << "✓ 位置正确:seek到目标位置" << std::endl;
+    } else {
+        std::cout << "✗ 位置错误:seek位置不正确" << std::endl;
+        std::cout << "  期望: " << seekTarget / 1000000.0 << "s" << std::endl;
+        std::cout << "  实际: " << afterSeekPosition / 1000000.0 << "s" << std::endl;
+    }
+    
+    // 恢复播放测试
+    std::cout << "\n5. 恢复播放测试" << std::endl;
+    player.play();
+    std::this_thread::sleep_for(std::chrono::seconds(2));
+    
+    int64_t playPosition = player.getCurrentTime();
+    std::cout << "恢复播放后位置: " << playPosition / 1000000.0 << "s" << std::endl;
+
+    if (playPosition > afterSeekPosition) {
+        std::cout << "✓ 播放正常:时间在前进" << std::endl;
+    } else {
+        std::cout << "✗ 播放异常:时间没有前进" << std::endl;
+    }
+
+    // 测试连续seek
+    std::cout << "\n6. 测试连续seek" << std::endl;
+    player.pause();
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    
+    // 第一次seek
+    int64_t seek1 = seekTarget + 2000000; // 再向前2秒
+    std::cout << "第一次seek到: " << seek1 / 1000000.0 << "s" << std::endl;
+    player.seek(seek1);
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    
+    int64_t pos1 = player.getCurrentTime();
+    std::cout << "第一次seek后位置: " << pos1 / 1000000.0 << "s" << std::endl;
+
+    // 第二次seek
+    int64_t seek2 = seek1 - 3000000; // 向后3秒
+    std::cout << "第二次seek到: " << seek2 / 1000000.0 << "s" << std::endl;
+    player.seek(seek2);
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    
+    int64_t pos2 = player.getCurrentTime();
+    std::cout << "第二次seek后位置: " << pos2 / 1000000.0 << "s" << std::endl;
+
+    if (callback.currentState == PlayerState::Paused) {
+        std::cout << "✓ 连续seek测试:状态保持暂停" << std::endl;
+    } else {
+        std::cout << "✗ 连续seek测试:状态错误" << std::endl;
+    }
+
+    // 停止播放
+    std::cout << "\n7. 停止播放" << std::endl;
+    player.stop();
+
+    std::cout << "\n=== 测试完成 ===" << std::endl;
+
+    // 关闭输出文件
+    outputFile.close();
+    
+    std::cout << "测试完成,结果已保存到 test_seek_pause_output.txt" << std::endl;
+    
+    return 0;
+}

+ 0 - 0
AV/test_simple_player.cpp → AV/test/test_simple_player.cpp


+ 0 - 0
AV/test_utils.cpp → AV/test/test_utils.cpp


+ 0 - 0
AV/test_window_capture.cpp → AV/test/test_window_capture.cpp


+ 0 - 347
AV/utils_test_log.txt

@@ -1,347 +0,0 @@
-2025-07-27 01:27:27.259 [INFO] AV Logger initialized
-2025-07-27 01:27:27.260 [INFO] === AV工具类模块测试套件 ===
-2025-07-27 01:27:27.261 [INFO] 开始运行所有工具类测试...
-2025-07-27 01:27:27.261 [INFO] 
-=== 运行测试: 线程池基本功能 ===
-2025-07-27 01:27:27.261 [INFO] [测试] 线程池基本功能...
-2025-07-27 01:27:27.261 [INFO] Thread pool initialized with 2 min threads, 4 max threads
-2025-07-27 01:27:27.261 [INFO] Thread pool started with 2 threads
-2025-07-27 01:27:27.261 [INFO] 线程池启动成功
-2025-07-27 01:27:27.261 [DEBUG] Created new worker thread, total: %zu
-2025-07-27 01:27:27.261 [DEBUG] Created new worker thread, total: %zu
-2025-07-27 01:27:27.262 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:27.264 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:27.264 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:27.264 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:27.289 [INFO] 任务 9 完成
-2025-07-27 01:27:27.289 [INFO] 任务 6 完成
-2025-07-27 01:27:27.289 [INFO] 任务 0 完成
-2025-07-27 01:27:27.289 [INFO] 任务 2 完成
-2025-07-27 01:27:27.305 [INFO] 任务 4 完成
-2025-07-27 01:27:27.305 [INFO] 任务 7 完成
-2025-07-27 01:27:27.305 [INFO] 任务 8 完成
-2025-07-27 01:27:27.305 [INFO] 任务 5 完成
-2025-07-27 01:27:27.320 [INFO] 任务 1 完成
-2025-07-27 01:27:27.320 [INFO] 任务 3 完成
-2025-07-27 01:27:27.320 [INFO] 线程池统计: 总线程数=4, 完成任务数=10
-2025-07-27 01:27:27.320 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:27.320 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:27.320 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:27.320 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:27.321 [INFO] Thread pool stopped
-2025-07-27 01:27:27.321 [INFO] [成功] 线程池基本功能测试通过
-2025-07-27 01:27:27.321 [INFO] ✓ 线程池基本功能 测试通过
-2025-07-27 01:27:27.321 [INFO] 
-=== 运行测试: 线程池优先级功能 ===
-2025-07-27 01:27:27.321 [INFO] [测试] 线程池优先级功能...
-2025-07-27 01:27:27.321 [INFO] Thread pool initialized with 1 min threads, 1 max threads
-2025-07-27 01:27:27.321 [INFO] Thread pool started with 1 threads
-2025-07-27 01:27:27.321 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:27.321 [INFO] 关键优先级任务执行
-2025-07-27 01:27:27.321 [INFO] 高优先级任务执行
-2025-07-27 01:27:27.322 [INFO] 普通优先级任务执行
-2025-07-27 01:27:27.322 [INFO] 低优先级任务执行
-2025-07-27 01:27:27.322 [INFO] 任务执行顺序:
-2025-07-27 01:27:27.322 [INFO]   第1个执行的任务ID: 4
-2025-07-27 01:27:27.322 [INFO]   第2个执行的任务ID: 3
-2025-07-27 01:27:27.322 [INFO]   第3个执行的任务ID: 2
-2025-07-27 01:27:27.322 [INFO]   第4个执行的任务ID: 1
-2025-07-27 01:27:27.322 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:27.322 [INFO] Thread pool stopped
-2025-07-27 01:27:27.322 [INFO] [成功] 线程池优先级功能测试通过
-2025-07-27 01:27:27.322 [INFO] ✓ 线程池优先级功能 测试通过
-2025-07-27 01:27:27.323 [INFO] 
-=== 运行测试: 帧队列功能 ===
-2025-07-27 01:27:27.323 [INFO] [测试] 帧队列功能...
-2025-07-27 01:27:27.323 [DEBUG] FrameQueue created with max size: 10
-2025-07-27 01:27:27.323 [INFO] 队列大小: 5
-2025-07-27 01:27:27.323 [INFO] [成功] 帧队列功能测试通过
-2025-07-27 01:27:27.323 [DEBUG] Frame queue cleared
-2025-07-27 01:27:27.323 [DEBUG] FrameQueue destroyed
-2025-07-27 01:27:27.323 [INFO] ✓ 帧队列功能 测试通过
-2025-07-27 01:27:27.323 [INFO] 
-=== 运行测试: 数据包队列功能 ===
-2025-07-27 01:27:27.323 [INFO] [测试] 数据包队列功能...
-2025-07-27 01:27:27.324 [DEBUG] PacketQueue created with max size: 20, max bytes: 52428800
-2025-07-27 01:27:27.324 [INFO] 队列大小: 10
-2025-07-27 01:27:27.324 [INFO] [成功] 数据包队列功能测试通过
-2025-07-27 01:27:27.324 [DEBUG] Packet queue cleared
-2025-07-27 01:27:27.324 [DEBUG] PacketQueue destroyed
-2025-07-27 01:27:27.324 [INFO] ✓ 数据包队列功能 测试通过
-2025-07-27 01:27:27.324 [INFO] 
-=== 运行测试: 性能监控功能 ===
-2025-07-27 01:27:27.324 [INFO] [测试] 性能监控功能...
-2025-07-27 01:27:27.324 [DEBUG] Registered metric: system.cpu_usage (type: 1)
-2025-07-27 01:27:27.325 [DEBUG] Registered metric: system.memory_usage (type: 1)
-2025-07-27 01:27:27.325 [DEBUG] Registered metric: system.disk_usage (type: 1)
-2025-07-27 01:27:27.325 [DEBUG] Registered metric: performance.frame_rate (type: 4)
-2025-07-27 01:27:27.325 [DEBUG] Registered metric: performance.latency (type: 2)
-2025-07-27 01:27:27.325 [DEBUG] Registered metric: performance.throughput (type: 4)
-2025-07-27 01:27:27.325 [INFO] Performance monitor initialized successfully
-2025-07-27 01:27:27.325 [DEBUG] Registered metric: frames_processed (type: 0)
-2025-07-27 01:27:27.325 [DEBUG] Registered metric: bytes_processed (type: 0)
-2025-07-27 01:27:27.325 [INFO] Performance monitor started
-2025-07-27 01:27:27.325 [DEBUG] Metric updated: frames_processed = 1
-2025-07-27 01:27:27.326 [DEBUG] Metric updated: bytes_processed = 1024
-2025-07-27 01:27:27.336 [DEBUG] Metric updated: frames_processed = 2
-2025-07-27 01:27:27.336 [DEBUG] Metric updated: bytes_processed = 2048
-2025-07-27 01:27:27.352 [DEBUG] Metric updated: frames_processed = 3
-2025-07-27 01:27:27.352 [DEBUG] Metric updated: bytes_processed = 3072
-2025-07-27 01:27:27.368 [DEBUG] Metric updated: frames_processed = 4
-2025-07-27 01:27:27.368 [DEBUG] Metric updated: bytes_processed = 4096
-2025-07-27 01:27:27.384 [DEBUG] Metric updated: frames_processed = 5
-2025-07-27 01:27:27.384 [DEBUG] Metric updated: bytes_processed = 5120
-2025-07-27 01:27:27.400 [DEBUG] Metric updated: frames_processed = 6
-2025-07-27 01:27:27.400 [DEBUG] Metric updated: bytes_processed = 6144
-2025-07-27 01:27:27.415 [DEBUG] Metric updated: frames_processed = 7
-2025-07-27 01:27:27.415 [DEBUG] Metric updated: bytes_processed = 7168
-2025-07-27 01:27:27.431 [DEBUG] Metric updated: frames_processed = 8
-2025-07-27 01:27:27.431 [DEBUG] Metric updated: bytes_processed = 8192
-2025-07-27 01:27:27.447 [DEBUG] Metric updated: frames_processed = 9
-2025-07-27 01:27:27.447 [DEBUG] Metric updated: bytes_processed = 9216
-2025-07-27 01:27:27.463 [DEBUG] Metric updated: frames_processed = 10
-2025-07-27 01:27:27.463 [DEBUG] Metric updated: bytes_processed = 10240
-2025-07-27 01:27:27.479 [DEBUG] Metric updated: frames_processed = 11
-2025-07-27 01:27:27.479 [DEBUG] Metric updated: bytes_processed = 11264
-2025-07-27 01:27:27.494 [DEBUG] Metric updated: frames_processed = 12
-2025-07-27 01:27:27.494 [DEBUG] Metric updated: bytes_processed = 12288
-2025-07-27 01:27:27.509 [DEBUG] Metric updated: frames_processed = 13
-2025-07-27 01:27:27.509 [DEBUG] Metric updated: bytes_processed = 13312
-2025-07-27 01:27:27.524 [DEBUG] Metric updated: frames_processed = 14
-2025-07-27 01:27:27.524 [DEBUG] Metric updated: bytes_processed = 14336
-2025-07-27 01:27:27.539 [DEBUG] Metric updated: frames_processed = 15
-2025-07-27 01:27:27.539 [DEBUG] Metric updated: bytes_processed = 15360
-2025-07-27 01:27:27.555 [DEBUG] Metric updated: frames_processed = 16
-2025-07-27 01:27:27.555 [DEBUG] Metric updated: bytes_processed = 16384
-2025-07-27 01:27:27.571 [DEBUG] Metric updated: frames_processed = 17
-2025-07-27 01:27:27.571 [DEBUG] Metric updated: bytes_processed = 17408
-2025-07-27 01:27:27.586 [DEBUG] Metric updated: frames_processed = 18
-2025-07-27 01:27:27.586 [DEBUG] Metric updated: bytes_processed = 18432
-2025-07-27 01:27:27.601 [DEBUG] Metric updated: frames_processed = 19
-2025-07-27 01:27:27.601 [DEBUG] Metric updated: bytes_processed = 19456
-2025-07-27 01:27:27.617 [DEBUG] Metric updated: frames_processed = 20
-2025-07-27 01:27:27.617 [DEBUG] Metric updated: bytes_processed = 20480
-2025-07-27 01:27:27.633 [DEBUG] Metric updated: frames_processed = 21
-2025-07-27 01:27:27.633 [DEBUG] Metric updated: bytes_processed = 21504
-2025-07-27 01:27:27.649 [DEBUG] Metric updated: frames_processed = 22
-2025-07-27 01:27:27.649 [DEBUG] Metric updated: bytes_processed = 22528
-2025-07-27 01:27:27.665 [DEBUG] Metric updated: frames_processed = 23
-2025-07-27 01:27:27.665 [DEBUG] Metric updated: bytes_processed = 23552
-2025-07-27 01:27:27.681 [DEBUG] Metric updated: frames_processed = 24
-2025-07-27 01:27:27.681 [DEBUG] Metric updated: bytes_processed = 24576
-2025-07-27 01:27:27.697 [DEBUG] Metric updated: frames_processed = 25
-2025-07-27 01:27:27.697 [DEBUG] Metric updated: bytes_processed = 25600
-2025-07-27 01:27:27.712 [DEBUG] Metric updated: frames_processed = 26
-2025-07-27 01:27:27.712 [DEBUG] Metric updated: bytes_processed = 26624
-2025-07-27 01:27:27.727 [DEBUG] Metric updated: frames_processed = 27
-2025-07-27 01:27:27.727 [DEBUG] Metric updated: bytes_processed = 27648
-2025-07-27 01:27:27.743 [DEBUG] Metric updated: frames_processed = 28
-2025-07-27 01:27:27.743 [DEBUG] Metric updated: bytes_processed = 28672
-2025-07-27 01:27:27.759 [DEBUG] Metric updated: frames_processed = 29
-2025-07-27 01:27:27.759 [DEBUG] Metric updated: bytes_processed = 29696
-2025-07-27 01:27:27.775 [DEBUG] Metric updated: frames_processed = 30
-2025-07-27 01:27:27.775 [DEBUG] Metric updated: bytes_processed = 30720
-2025-07-27 01:27:27.791 [DEBUG] Metric updated: frames_processed = 31
-2025-07-27 01:27:27.791 [DEBUG] Metric updated: bytes_processed = 31744
-2025-07-27 01:27:27.807 [DEBUG] Metric updated: frames_processed = 32
-2025-07-27 01:27:27.807 [DEBUG] Metric updated: bytes_processed = 32768
-2025-07-27 01:27:27.823 [DEBUG] Metric updated: frames_processed = 33
-2025-07-27 01:27:27.823 [DEBUG] Metric updated: bytes_processed = 33792
-2025-07-27 01:27:27.839 [DEBUG] Metric updated: frames_processed = 34
-2025-07-27 01:27:27.839 [DEBUG] Metric updated: bytes_processed = 34816
-2025-07-27 01:27:27.855 [DEBUG] Metric updated: frames_processed = 35
-2025-07-27 01:27:27.855 [DEBUG] Metric updated: bytes_processed = 35840
-2025-07-27 01:27:27.871 [DEBUG] Metric updated: frames_processed = 36
-2025-07-27 01:27:27.871 [DEBUG] Metric updated: bytes_processed = 36864
-2025-07-27 01:27:27.887 [DEBUG] Metric updated: frames_processed = 37
-2025-07-27 01:27:27.887 [DEBUG] Metric updated: bytes_processed = 37888
-2025-07-27 01:27:27.903 [DEBUG] Metric updated: frames_processed = 38
-2025-07-27 01:27:27.903 [DEBUG] Metric updated: bytes_processed = 38912
-2025-07-27 01:27:27.918 [DEBUG] Metric updated: frames_processed = 39
-2025-07-27 01:27:27.918 [DEBUG] Metric updated: bytes_processed = 39936
-2025-07-27 01:27:27.934 [DEBUG] Metric updated: frames_processed = 40
-2025-07-27 01:27:27.934 [DEBUG] Metric updated: bytes_processed = 40960
-2025-07-27 01:27:27.950 [DEBUG] Metric updated: frames_processed = 41
-2025-07-27 01:27:27.950 [DEBUG] Metric updated: bytes_processed = 41984
-2025-07-27 01:27:27.966 [DEBUG] Metric updated: frames_processed = 42
-2025-07-27 01:27:27.966 [DEBUG] Metric updated: bytes_processed = 43008
-2025-07-27 01:27:27.982 [DEBUG] Metric updated: frames_processed = 43
-2025-07-27 01:27:27.982 [DEBUG] Metric updated: bytes_processed = 44032
-2025-07-27 01:27:27.998 [DEBUG] Metric updated: frames_processed = 44
-2025-07-27 01:27:27.998 [DEBUG] Metric updated: bytes_processed = 45056
-2025-07-27 01:27:28.014 [DEBUG] Metric updated: frames_processed = 45
-2025-07-27 01:27:28.014 [DEBUG] Metric updated: bytes_processed = 46080
-2025-07-27 01:27:28.029 [DEBUG] Metric updated: frames_processed = 46
-2025-07-27 01:27:28.030 [DEBUG] Metric updated: bytes_processed = 47104
-2025-07-27 01:27:28.044 [DEBUG] Metric updated: frames_processed = 47
-2025-07-27 01:27:28.045 [DEBUG] Metric updated: bytes_processed = 48128
-2025-07-27 01:27:28.060 [DEBUG] Metric updated: frames_processed = 48
-2025-07-27 01:27:28.060 [DEBUG] Metric updated: bytes_processed = 49152
-2025-07-27 01:27:28.076 [DEBUG] Metric updated: frames_processed = 49
-2025-07-27 01:27:28.076 [DEBUG] Metric updated: bytes_processed = 50176
-2025-07-27 01:27:28.091 [DEBUG] Metric updated: frames_processed = 50
-2025-07-27 01:27:28.091 [DEBUG] Metric updated: bytes_processed = 51200
-2025-07-27 01:27:28.106 [DEBUG] Metric updated: frames_processed = 51
-2025-07-27 01:27:28.106 [DEBUG] Metric updated: bytes_processed = 52224
-2025-07-27 01:27:28.121 [DEBUG] Metric updated: frames_processed = 52
-2025-07-27 01:27:28.121 [DEBUG] Metric updated: bytes_processed = 53248
-2025-07-27 01:27:28.137 [DEBUG] Metric updated: frames_processed = 53
-2025-07-27 01:27:28.137 [DEBUG] Metric updated: bytes_processed = 54272
-2025-07-27 01:27:28.153 [DEBUG] Metric updated: frames_processed = 54
-2025-07-27 01:27:28.153 [DEBUG] Metric updated: bytes_processed = 55296
-2025-07-27 01:27:28.168 [DEBUG] Metric updated: frames_processed = 55
-2025-07-27 01:27:28.168 [DEBUG] Metric updated: bytes_processed = 56320
-2025-07-27 01:27:28.183 [DEBUG] Metric updated: frames_processed = 56
-2025-07-27 01:27:28.183 [DEBUG] Metric updated: bytes_processed = 57344
-2025-07-27 01:27:28.199 [DEBUG] Metric updated: frames_processed = 57
-2025-07-27 01:27:28.199 [DEBUG] Metric updated: bytes_processed = 58368
-2025-07-27 01:27:28.214 [DEBUG] Metric updated: frames_processed = 58
-2025-07-27 01:27:28.215 [DEBUG] Metric updated: bytes_processed = 59392
-2025-07-27 01:27:28.230 [DEBUG] Metric updated: frames_processed = 59
-2025-07-27 01:27:28.230 [DEBUG] Metric updated: bytes_processed = 60416
-2025-07-27 01:27:28.245 [DEBUG] Metric updated: frames_processed = 60
-2025-07-27 01:27:28.245 [DEBUG] Metric updated: bytes_processed = 61440
-2025-07-27 01:27:28.260 [DEBUG] Metric updated: frames_processed = 61
-2025-07-27 01:27:28.260 [DEBUG] Metric updated: bytes_processed = 62464
-2025-07-27 01:27:28.275 [DEBUG] Metric updated: frames_processed = 62
-2025-07-27 01:27:28.275 [DEBUG] Metric updated: bytes_processed = 63488
-2025-07-27 01:27:28.291 [DEBUG] Metric updated: frames_processed = 63
-2025-07-27 01:27:28.291 [DEBUG] Metric updated: bytes_processed = 64512
-2025-07-27 01:27:28.306 [DEBUG] Metric updated: frames_processed = 64
-2025-07-27 01:27:28.307 [DEBUG] Metric updated: bytes_processed = 65536
-2025-07-27 01:27:28.322 [DEBUG] Metric updated: frames_processed = 65
-2025-07-27 01:27:28.322 [DEBUG] Metric updated: bytes_processed = 66560
-2025-07-27 01:27:28.337 [DEBUG] Metric updated: frames_processed = 66
-2025-07-27 01:27:28.337 [DEBUG] Metric updated: bytes_processed = 67584
-2025-07-27 01:27:28.353 [DEBUG] Metric updated: frames_processed = 67
-2025-07-27 01:27:28.353 [DEBUG] Metric updated: bytes_processed = 68608
-2025-07-27 01:27:28.369 [DEBUG] Metric updated: frames_processed = 68
-2025-07-27 01:27:28.369 [DEBUG] Metric updated: bytes_processed = 69632
-2025-07-27 01:27:28.385 [DEBUG] Metric updated: frames_processed = 69
-2025-07-27 01:27:28.385 [DEBUG] Metric updated: bytes_processed = 70656
-2025-07-27 01:27:28.400 [DEBUG] Metric updated: frames_processed = 70
-2025-07-27 01:27:28.400 [DEBUG] Metric updated: bytes_processed = 71680
-2025-07-27 01:27:28.415 [DEBUG] Metric updated: frames_processed = 71
-2025-07-27 01:27:28.415 [DEBUG] Metric updated: bytes_processed = 72704
-2025-07-27 01:27:28.430 [DEBUG] Metric updated: frames_processed = 72
-2025-07-27 01:27:28.430 [DEBUG] Metric updated: bytes_processed = 73728
-2025-07-27 01:27:28.445 [DEBUG] Metric updated: frames_processed = 73
-2025-07-27 01:27:28.445 [DEBUG] Metric updated: bytes_processed = 74752
-2025-07-27 01:27:28.461 [DEBUG] Metric updated: frames_processed = 74
-2025-07-27 01:27:28.461 [DEBUG] Metric updated: bytes_processed = 75776
-2025-07-27 01:27:28.477 [DEBUG] Metric updated: frames_processed = 75
-2025-07-27 01:27:28.477 [DEBUG] Metric updated: bytes_processed = 76800
-2025-07-27 01:27:28.493 [DEBUG] Metric updated: frames_processed = 76
-2025-07-27 01:27:28.493 [DEBUG] Metric updated: bytes_processed = 77824
-2025-07-27 01:27:28.509 [DEBUG] Metric updated: frames_processed = 77
-2025-07-27 01:27:28.509 [DEBUG] Metric updated: bytes_processed = 78848
-2025-07-27 01:27:28.525 [DEBUG] Metric updated: frames_processed = 78
-2025-07-27 01:27:28.525 [DEBUG] Metric updated: bytes_processed = 79872
-2025-07-27 01:27:28.541 [DEBUG] Metric updated: frames_processed = 79
-2025-07-27 01:27:28.541 [DEBUG] Metric updated: bytes_processed = 80896
-2025-07-27 01:27:28.557 [DEBUG] Metric updated: frames_processed = 80
-2025-07-27 01:27:28.557 [DEBUG] Metric updated: bytes_processed = 81920
-2025-07-27 01:27:28.573 [DEBUG] Metric updated: frames_processed = 81
-2025-07-27 01:27:28.573 [DEBUG] Metric updated: bytes_processed = 82944
-2025-07-27 01:27:28.589 [DEBUG] Metric updated: frames_processed = 82
-2025-07-27 01:27:28.589 [DEBUG] Metric updated: bytes_processed = 83968
-2025-07-27 01:27:28.605 [DEBUG] Metric updated: frames_processed = 83
-2025-07-27 01:27:28.605 [DEBUG] Metric updated: bytes_processed = 84992
-2025-07-27 01:27:28.620 [DEBUG] Metric updated: frames_processed = 84
-2025-07-27 01:27:28.620 [DEBUG] Metric updated: bytes_processed = 86016
-2025-07-27 01:27:28.635 [DEBUG] Metric updated: frames_processed = 85
-2025-07-27 01:27:28.635 [DEBUG] Metric updated: bytes_processed = 87040
-2025-07-27 01:27:28.650 [DEBUG] Metric updated: frames_processed = 86
-2025-07-27 01:27:28.650 [DEBUG] Metric updated: bytes_processed = 88064
-2025-07-27 01:27:28.665 [DEBUG] Metric updated: frames_processed = 87
-2025-07-27 01:27:28.665 [DEBUG] Metric updated: bytes_processed = 89088
-2025-07-27 01:27:28.681 [DEBUG] Metric updated: frames_processed = 88
-2025-07-27 01:27:28.681 [DEBUG] Metric updated: bytes_processed = 90112
-2025-07-27 01:27:28.697 [DEBUG] Metric updated: frames_processed = 89
-2025-07-27 01:27:28.697 [DEBUG] Metric updated: bytes_processed = 91136
-2025-07-27 01:27:28.712 [DEBUG] Metric updated: frames_processed = 90
-2025-07-27 01:27:28.712 [DEBUG] Metric updated: bytes_processed = 92160
-2025-07-27 01:27:28.727 [DEBUG] Metric updated: frames_processed = 91
-2025-07-27 01:27:28.727 [DEBUG] Metric updated: bytes_processed = 93184
-2025-07-27 01:27:28.743 [DEBUG] Metric updated: frames_processed = 92
-2025-07-27 01:27:28.743 [DEBUG] Metric updated: bytes_processed = 94208
-2025-07-27 01:27:28.759 [DEBUG] Metric updated: frames_processed = 93
-2025-07-27 01:27:28.759 [DEBUG] Metric updated: bytes_processed = 95232
-2025-07-27 01:27:28.774 [DEBUG] Metric updated: frames_processed = 94
-2025-07-27 01:27:28.774 [DEBUG] Metric updated: bytes_processed = 96256
-2025-07-27 01:27:28.789 [DEBUG] Metric updated: frames_processed = 95
-2025-07-27 01:27:28.789 [DEBUG] Metric updated: bytes_processed = 97280
-2025-07-27 01:27:28.805 [DEBUG] Metric updated: frames_processed = 96
-2025-07-27 01:27:28.805 [DEBUG] Metric updated: bytes_processed = 98304
-2025-07-27 01:27:28.821 [DEBUG] Metric updated: frames_processed = 97
-2025-07-27 01:27:28.821 [DEBUG] Metric updated: bytes_processed = 99328
-2025-07-27 01:27:28.836 [DEBUG] Metric updated: frames_processed = 98
-2025-07-27 01:27:28.836 [DEBUG] Metric updated: bytes_processed = 100352
-2025-07-27 01:27:28.851 [DEBUG] Metric updated: frames_processed = 99
-2025-07-27 01:27:28.851 [DEBUG] Metric updated: bytes_processed = 101376
-2025-07-27 01:27:28.867 [DEBUG] Metric updated: frames_processed = 100
-2025-07-27 01:27:28.867 [DEBUG] Metric updated: bytes_processed = 102400
-2025-07-27 01:27:28.882 [INFO] Performance monitor stopped
-2025-07-27 01:27:28.882 [INFO] 性能统计:
-2025-07-27 01:27:28.882 [INFO]   处理帧数: 100
-2025-07-27 01:27:28.882 [INFO]   处理字节数: 102400
-2025-07-27 01:27:28.883 [INFO] [成功] 性能监控功能测试通过
-2025-07-27 01:27:28.883 [INFO] Performance monitor closed
-2025-07-27 01:27:28.883 [INFO] ✓ 性能监控功能 测试通过
-2025-07-27 01:27:28.883 [INFO] 
-=== 运行测试: 同步器功能 ===
-2025-07-27 01:27:28.883 [INFO] [测试] 同步器功能...
-2025-07-27 01:27:28.883 [DEBUG] Synchronizer created with strategy: 0
-2025-07-27 01:27:28.883 [INFO] 视频延迟: {:.2f} ms
-2025-07-27 01:27:28.883 [INFO] 音频延迟: {:.2f} ms
-2025-07-27 01:27:28.883 [INFO] 音视频同步状态: 不同步
-2025-07-27 01:27:28.884 [INFO] 同步误差: {:.2f} ms
-2025-07-27 01:27:28.884 [INFO] [成功] 同步器功能测试通过
-2025-07-27 01:27:28.884 [INFO] Synchronizer closed
-2025-07-27 01:27:28.884 [DEBUG] Synchronizer destroyed
-2025-07-27 01:27:28.884 [INFO] ✓ 同步器功能 测试通过
-2025-07-27 01:27:28.884 [INFO] 
-=== 运行测试: 线程池工厂功能 ===
-2025-07-27 01:27:28.884 [INFO] [测试] 线程池工厂功能...
-2025-07-27 01:27:28.884 [INFO] Thread pool initialized with 2 min threads, 24 max threads
-2025-07-27 01:27:28.884 [INFO] Thread pool started with 2 threads
-2025-07-27 01:27:28.884 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:28.884 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:28.885 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:28.885 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:28.885 [INFO] Thread pool stopped
-2025-07-27 01:27:28.885 [INFO] CPU核心数: 24
-2025-07-27 01:27:28.885 [INFO] 推荐线程数: 24
-2025-07-27 01:27:28.885 [INFO] [成功] 线程池工厂功能测试通过
-2025-07-27 01:27:28.885 [INFO] ✓ 线程池工厂功能 测试通过
-2025-07-27 01:27:28.885 [INFO] 
-=== 运行测试: 线程池管理器功能 ===
-2025-07-27 01:27:28.885 [INFO] [测试] 线程池管理器功能...
-2025-07-27 01:27:28.885 [INFO] Thread pool initialized with 2 min threads, 24 max threads
-2025-07-27 01:27:28.885 [INFO] Thread pool started with 2 threads
-2025-07-27 01:27:28.886 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:28.886 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:28.886 [INFO] Thread pool initialized with 2 min threads, 4 max threads
-2025-07-27 01:27:28.886 [INFO] Thread pool started with 2 threads
-2025-07-27 01:27:28.886 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:28.886 [DEBUG] Worker thread %zu started
-2025-07-27 01:27:28.886 [INFO] Created thread pool: test_pool
-2025-07-27 01:27:28.886 [INFO] 线程池数量: 1
-2025-07-27 01:27:28.886 [INFO]   - test_pool
-2025-07-27 01:27:28.886 [INFO] Cleared 0 pending tasks
-2025-07-27 01:27:28.886 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:28.886 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:28.887 [INFO] Thread pool stopped
-2025-07-27 01:27:28.887 [INFO] Destroyed thread pool: test_pool
-2025-07-27 01:27:28.887 [INFO] [成功] 线程池管理器功能测试通过
-2025-07-27 01:27:28.887 [INFO] ✓ 线程池管理器功能 测试通过
-2025-07-27 01:27:28.887 [INFO] 
-=== 测试结果汇总 ===
-2025-07-27 01:27:28.887 [INFO] 通过测试: 8/8
-2025-07-27 01:27:28.887 [INFO] 成功率: 100%
-2025-07-27 01:27:28.887 [INFO] 所有工具类测试通过
-2025-07-27 01:27:28.887 [INFO] Cleared 0 pending tasks
-2025-07-27 01:27:28.887 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:28.888 [DEBUG] Worker thread %zu stopped
-2025-07-27 01:27:28.888 [INFO] Thread pool stopped
-2025-07-27 01:27:28.888 [INFO] All thread pools shutdown

+ 75 - 127
AV/xmake.lua

@@ -1,3 +1,10 @@
+set_project("AV_Framework")
+set_version("1.0.0")
+set_languages("c++17")
+
+-- 设置编译模式
+add_rules("mode.debug", "mode.release")
+
 -- FFmpeg库路径配置 - 支持环境变量和默认路径
 local ffmpeg_path = os.getenv("FFMPEG_PATH") or "E:/AAA/ffmpeg-7.0.2-full_build-shared"
 local ffmpeg_include = ffmpeg_path .. "/include"
@@ -9,6 +16,26 @@ if not os.isdir(ffmpeg_include) then
     print("Please set FFMPEG_PATH environment variable or update the path in xmake.lua")
 end
 
+set_runtimes("MD")
+
+-- 公共FFmpeg配置函数
+function add_ffmpeg_config()
+    if is_plat("windows") then
+        add_includedirs(ffmpeg_include)
+        add_linkdirs(ffmpeg_lib)
+        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
+        add_links("avdevice", "avfilter", "postproc")
+    else
+        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
+    end
+end
+
+-- 公共基础配置函数
+function add_common_config()
+    add_includedirs(".", {public = true})
+    set_targetdir("$(buildir)/bin")
+end
+
 -- 基础库
 target("av_base")
     set_kind("static")
@@ -16,14 +43,12 @@ target("av_base")
     add_headerfiles("code/base/*.h")
     add_includedirs(".", {public = true})
     
-    -- Windows特定设置
+    -- FFmpeg配置
+    add_ffmpeg_config()
+    
+    -- 平台特定设置
     if is_plat("windows") then
         add_syslinks("ws2_32", "winmm")
-        -- FFmpeg库链接
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
     else
         add_syslinks("pthread")
     end
@@ -36,15 +61,8 @@ target("av_codec")
     add_includedirs(".", {public = true})
     add_deps("av_base")
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    else
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 捕获库
 target("av_capture")
@@ -54,13 +72,8 @@ target("av_capture")
     add_includedirs(".", {public = true})
     add_deps("av_base")
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 混流库
 target("av_muxer")
@@ -70,13 +83,8 @@ target("av_muxer")
     add_includedirs(".", {public = true})
     add_deps("av_base")
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 工具库
 target("av_utils")
@@ -86,13 +94,8 @@ target("av_utils")
     add_includedirs(".", {public = true})
     add_deps("av_base")
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- -- 完整的AV框架库
 -- target("av_framework")
@@ -100,70 +103,50 @@ target("av_utils")
 --     add_deps("av_base", "av_codec", "av_capture", "av_muxer", "av_utils")
 --     add_includedirs(".", {public = true})
 
-set_runtimes("MD")
+
 
 target("player")
     add_rules("qt.widgetapp")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     add_files("integration_example.cpp", {rules = "qt.moc"})
     add_deps("av_base", "av_codec", "av_capture", "av_muxer", "av_utils")
-    add_includedirs(".", {public = true})
     add_files("code/player/*.cpp")
     add_headerfiles("code/player/*.h")
     add_files("code/player/*.h", {rules = "qt.moc"})
     add_frameworks("QtNetwork", "QtGui", "QtCore", "QtWidgets", "QtMultimedia", "QtOpenGL")
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 基础测试程序
 target("test_basic")
     set_kind("binary")
     add_files("test_basic.cpp")
     add_deps("av_base")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 编解码测试程序
 target("test_codec")
     set_kind("binary")
     add_files("test_codec.cpp")
     add_deps("av_codec")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 解码器测试程序
 target("test_decoder")
     set_kind("binary")
     add_files("test_decoder.cpp")
     add_deps("av_codec")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
     
 
 -- 音频编码器测试程序
@@ -171,15 +154,10 @@ target("test_audio_encoder")
     set_kind("binary")
     add_files("test_audio_encoder.cpp")
     add_deps("av_codec")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 
 -- 窗口采集测试程序
@@ -187,45 +165,30 @@ target("test_window_capture")
     set_kind("binary")
     add_files("test_window_capture.cpp")
     add_deps("av_capture")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 工具类测试程序
 target("test_utils")
     set_kind("binary")
     add_files("test_utils.cpp")
     add_deps("av_utils")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 混流器测试程序
 target("test_muxer")
     set_kind("binary")
     add_files("test_muxer.cpp")
     add_deps("av_muxer")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 音频调试测试程序
 target("test_audio_debug")
@@ -236,23 +199,18 @@ target("test_audio_debug")
     add_files("code/player/audio_output.cpp")
     add_files("code/player/thread_manager.cpp")
     add_headerfiles("code/player/*.h")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     
     add_rules("qt.widgetapp")
     add_frameworks("QtCore", "QtWidgets", "QtMultimedia")
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
 
 -- 带UI的播放器测试程序
 target("test_player_with_ui")
     add_rules("qt.widgetapp")
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     add_files("test_player_with_ui.cpp", {rules = "qt.moc"})
     add_deps("av_base", "av_codec", "av_utils")
     add_files("code/player/*.cpp")
@@ -260,13 +218,8 @@ target("test_player_with_ui")
     add_files("code/player/*.h", {rules = "qt.moc"})
     add_frameworks("QtNetwork", "QtGui", "QtCore", "QtWidgets", "QtMultimedia", "QtOpenGL")
     
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    -- FFmpeg配置
+    add_ffmpeg_config()
     
     
 -- 混流器测试程序
@@ -275,13 +228,8 @@ target("test_seek_pause_fixed")
     add_rules("qt.widgetapp")
     add_files("test_seek_pause_fixed.cpp")
     add_deps("av_base", "av_codec", "av_utils")
-    add_includedirs(".", {public = true})
-    set_targetdir("$(buildir)/bin")
+    add_common_config()
     add_frameworks("QtNetwork", "QtGui", "QtCore", "QtWidgets", "QtMultimedia", "QtOpenGL")
-    -- FFmpeg库链接
-    if is_plat("windows") then
-        add_includedirs(ffmpeg_include)
-        add_linkdirs(ffmpeg_lib)
-        add_links("avcodec", "avformat", "avutil", "swscale", "swresample")
-        add_links("avdevice", "avfilter", "postproc")
-    end
+    
+    -- FFmpeg配置
+    add_ffmpeg_config()

+ 48 - 17
AvRecorder/encoder/video_encoder.cpp

@@ -77,12 +77,20 @@ const std::vector<std::string>& Encoder<MediaType::VIDEO>::GetUsableEncoders()
 {
     if (_usableEncoders.empty()) {
         _FindUsableEncoders();
+        
+        // 如果仍然没有找到可用编码器,至少添加libx264作为后备
+        if (_usableEncoders.empty()) {
+            qDebug() << "VideoEncoder: No encoders found during testing, adding libx264 as fallback";
+            _usableEncoders.push_back("libx264");
+        }
     }
     return _usableEncoders;
 }
 
 void Encoder<MediaType::VIDEO>::_FindUsableEncoders()
 {
+    qDebug() << "VideoEncoder: Finding usable encoders...";
+    
     // 尝试打开编码器看看编码器能不能用
     Param param;
     param.bitRate = 1000;
@@ -93,26 +101,31 @@ void Encoder<MediaType::VIDEO>::_FindUsableEncoders()
     AVFormatContext* fmtCtx = nullptr;
 
     __CheckNo(avformat_alloc_output_context2(&fmtCtx, nullptr, nullptr, "test.mp4") >= 0);
+    
+    // 测试所有编码器,不做任何假设
     for (const auto& name : _encoderNames) {
-        if (strcmp(name, "libx264") == 0) { // 软件编码器必定支持
-            _usableEncoders.push_back(name);
-            continue;
-        }
         param.name = name;
+        qDebug() << "VideoEncoder: Testing encoder:" << name;
+        
         if (encoder.Open(param, fmtCtx)) {
             _usableEncoders.push_back(name);
+            qDebug() << "VideoEncoder: Encoder" << name << "is usable";
+        } else {
+            qDebug() << "VideoEncoder: Encoder" << name << "failed to open";
         }
         encoder.Close();
     }
+    
+    qDebug() << "VideoEncoder: Found" << _usableEncoders.size() << "usable encoders";
     Free(fmtCtx, [&fmtCtx] { avformat_free_context(fmtCtx); });
 }
 
 bool Encoder<MediaType::VIDEO>::_Init(const Param& encodeParam, AVFormatContext* fmtCtx)
 {
-    _isHardware = encodeParam.name != "libx264";
+    _isHardware = (encodeParam.name != "libx264" && encodeParam.name != "libx265" && encodeParam.name != "libaom-av1");
     AVHWDeviceType hwType;
-    if (encodeParam.name == "libx264") {
-        _pixFmt = AV_PIX_FMT_NV12;
+    if (encodeParam.name == "libx264" || encodeParam.name == "libx265" || encodeParam.name == "libaom-av1") {
+        _pixFmt = AV_PIX_FMT_YUV420P;
     } else if (encodeParam.name == "h264_nvenc") {
         _pixFmt = AV_PIX_FMT_CUDA;
         hwType = AV_HWDEVICE_TYPE_CUDA;
@@ -120,10 +133,13 @@ bool Encoder<MediaType::VIDEO>::_Init(const Param& encodeParam, AVFormatContext*
         _pixFmt = AV_PIX_FMT_QSV;
         hwType = AV_HWDEVICE_TYPE_QSV;
     } else if (encodeParam.name == "h264_amf") {
-        _pixFmt = AV_PIX_FMT_VULKAN;
-        hwType = AV_HWDEVICE_TYPE_VULKAN;
+        _pixFmt = AV_PIX_FMT_D3D11;
+        hwType = AV_HWDEVICE_TYPE_D3D11VA;
+    } else if (encodeParam.name == "h264_videotoolbox") {
+        _pixFmt = AV_PIX_FMT_VIDEOTOOLBOX;
+        hwType = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
     }
-    _isHardware = _pixFmt != AV_PIX_FMT_NV12;
+    _isHardware = (_pixFmt != AV_PIX_FMT_YUV420P && _pixFmt != AV_PIX_FMT_NV12);
     if (_isHardware
         && av_hwdevice_ctx_create(&_hwDeviceCtx, hwType, nullptr, nullptr, 0) < 0) { // 硬件解码
         __DebugPrint("av_hwdevice_ctx_create failed\n");
@@ -147,14 +163,29 @@ bool Encoder<MediaType::VIDEO>::_Init(const Param& encodeParam, AVFormatContext*
         _codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
     }
 
-    if (!_isHardware) { // 软件编码设置为快,避免占用过高的 CPU ,反正硬盘不值钱
-        // av_opt_set(_codecCtx->priv_data, "preset", "veryfast", 0);
-        av_opt_set(_codecCtx->priv_data, "preset", "ultrafast", 0); // 使用最快的预设
-        av_opt_set(_codecCtx->priv_data, "tune", "zerolatency", 0); // 零延迟调优
+    if (!_isHardware) { // 软件编码设置为快,避免占用过高的 CPU
+        if (encodeParam.name == "libx264") {
+            av_opt_set(_codecCtx->priv_data, "preset", "ultrafast", 0); // 使用最快的预设
+            av_opt_set(_codecCtx->priv_data, "tune", "zerolatency", 0); // 零延迟调优
+        } else if (encodeParam.name == "libx265") {
+            av_opt_set(_codecCtx->priv_data, "preset", "ultrafast", 0);
+            av_opt_set(_codecCtx->priv_data, "tune", "zerolatency", 0);
+        } else if (encodeParam.name == "libaom-av1") {
+            av_opt_set(_codecCtx->priv_data, "cpu-used", "8", 0); // 最快速度
+            av_opt_set(_codecCtx->priv_data, "rt", "1", 0); // 实时模式
+        }
     } else {
-        // 为硬件编码器添加低延迟设置
-        av_opt_set(_codecCtx->priv_data, "preset", "llhp", 0); // 低延迟高性能
-        av_opt_set(_codecCtx->priv_data, "zerolatency", "1", 0);
+        // 为不同硬件编码器设置特定参数
+        if (encodeParam.name == "h264_nvenc") {
+            av_opt_set(_codecCtx->priv_data, "preset", "p4", 0); // NVENC预设
+            av_opt_set(_codecCtx->priv_data, "rc", "vbr", 0);
+        } else if (encodeParam.name == "h264_qsv") {
+            av_opt_set(_codecCtx->priv_data, "preset", "medium", 0); // QSV有效预设
+            av_opt_set(_codecCtx->priv_data, "look_ahead", "0", 0);
+        } else if (encodeParam.name == "h264_amf") {
+            av_opt_set(_codecCtx->priv_data, "quality", "speed", 0); // AMF预设
+            av_opt_set(_codecCtx->priv_data, "rc", "vbr_peak", 0);
+        }
     }
 
     __CheckBool(!_isHardware || _SetHwFrameCtx());

+ 4 - 1
AvRecorder/encoder/video_encoder.h

@@ -32,11 +32,14 @@ private:
     bool _isHardware = false;
     std::unique_ptr<FfmpegConverter> _converter = nullptr;
     AVFrame* _bufferFrame = nullptr;
-    static constexpr const char* _encoderNames[4] = {
+    static constexpr const char* _encoderNames[7] = {
         "h264_nvenc",
         "h264_qsv",
         "h264_amf",
+        "h264_videotoolbox", // Apple硬件编码器
         "libx264",
+        "libx265",
+        "libaom-av1", // AV1软件编码器
     };
     static std::vector<std::string> _usableEncoders;
     AVBufferRef* _hwDeviceCtx = nullptr;

+ 49 - 3
AvRecorder/muxer/av_muxer.cpp

@@ -198,10 +198,56 @@ int AvMuxer::AddVideoStream(const Encoder<MediaType::VIDEO>::Param& param)
     Info info;
     info.pts = 0;
     info.fps = param.fps;
+    
+    // 获取可用编码器列表
+    const auto& usableEncoders = Encoder<MediaType::VIDEO>::GetUsableEncoders();
+    if (usableEncoders.empty()) {
+        qDebug() << "AddVideoStream failed: No usable video encoders found";
+        return -1;
+    }
+    
+    // 尝试使用指定的编码器,如果失败则自动回退
     auto encoder = new Encoder<MediaType::VIDEO>;
+    auto modifiableParam = param; // 创建可修改的副本
     
-    if (!encoder->Open(param, _fmtCtx)) {
-        qDebug() << "AddVideoStream failed: Cannot open video encoder";
+    // 首先尝试用户指定的编码器
+    bool encoderOpened = false;
+    std::string usedEncoder = modifiableParam.name;
+    
+    if (!modifiableParam.name.empty()) {
+        qDebug() << "AddVideoStream: Trying user specified encoder:" << QString::fromStdString(modifiableParam.name);
+        if (encoder->Open(modifiableParam, _fmtCtx)) {
+            encoderOpened = true;
+            qDebug() << "AddVideoStream: Successfully opened user specified encoder:" << QString::fromStdString(modifiableParam.name);
+        } else {
+            qDebug() << "AddVideoStream: User specified encoder failed:" << QString::fromStdString(modifiableParam.name);
+        }
+    }
+    
+    // 如果指定编码器失败,尝试可用编码器列表
+    if (!encoderOpened) {
+        qDebug() << "AddVideoStream: Trying fallback encoders...";
+        for (const auto& encoderName : usableEncoders) {
+            if (encoderName == modifiableParam.name) {
+                continue; // 跳过已经尝试过的编码器
+            }
+            
+            modifiableParam.name = encoderName;
+            qDebug() << "AddVideoStream: Trying fallback encoder:" << QString::fromStdString(encoderName);
+            
+            if (encoder->Open(modifiableParam, _fmtCtx)) {
+                encoderOpened = true;
+                usedEncoder = encoderName;
+                qDebug() << "AddVideoStream: Successfully opened fallback encoder:" << QString::fromStdString(encoderName);
+                break;
+            } else {
+                qDebug() << "AddVideoStream: Fallback encoder failed:" << QString::fromStdString(encoderName);
+            }
+        }
+    }
+    
+    if (!encoderOpened) {
+        qDebug() << "AddVideoStream failed: All video encoders failed to open";
         delete encoder;
         return -1;
     }
@@ -216,7 +262,7 @@ int AvMuxer::AddVideoStream(const Encoder<MediaType::VIDEO>::Param& param)
     }
     
     _infos.back().stream->time_base = {1, info.fps};
-    qDebug() << "AddVideoStream: Video stream added successfully, index:" << info.streamIndex;
+    qDebug() << "AddVideoStream: Video stream added successfully with encoder:" << QString::fromStdString(usedEncoder) << "index:" << info.streamIndex;
     return info.streamIndex;
 }
 

+ 25 - 5
AvRecorder/recorder/video_recorder.cpp

@@ -100,13 +100,21 @@ bool VideoRecorder::LoadMuxer(AvMuxer& muxer)
     // 检查是否已经加载过这个muxer
     for (const auto& info : _muxers) {
         if (info.muxer == &muxer) {
+            qDebug() << "VideoRecorder::LoadMuxer: Muxer already loaded, streamIndex:" << info.streamIndex;
             return true; // 已经加载过,直接返回成功
         }
     }
     
+    qDebug() << "VideoRecorder::LoadMuxer: Adding video stream with params - name:" << QString::fromStdString(_param.name) 
+             << "width:" << _param.width << "height:" << _param.height << "fps:" << _param.fps << "bitRate:" << _param.bitRate;
+    
     int streamIndex = muxer.AddVideoStream(_param);
-    __CheckBool(streamIndex != -1);
+    if (streamIndex == -1) {
+        qDebug() << "VideoRecorder::LoadMuxer: Failed to add video stream to muxer";
+        return false;
+    }
     
+    qDebug() << "VideoRecorder::LoadMuxer: Successfully added video stream, streamIndex:" << streamIndex;
     _muxers.emplace_back(&muxer, streamIndex);
     return true;
 }
@@ -138,7 +146,10 @@ bool VideoRecorder::StartRecord()
     
     _totalPts = 0;
     _lossPts = 0;
-    _lossHistory.clear();
+    {
+        std::lock_guard<std::mutex> lock(_lossMtx);
+        _lossHistory.clear();
+    }
     _muxTimer.Start(_param.fps, [this] {
         ++_totalPts;
         bool anySuccess = false;
@@ -156,9 +167,14 @@ bool VideoRecorder::StartRecord()
         bool loss = !anySuccess;
         if (loss)
             ++_lossPts;
-        _lossHistory.push_back(loss);
-        if (_lossHistory.size() > LOSS_WINDOW)
-            _lossHistory.pop_front();
+
+        {
+            std::lock_guard<std::mutex> lock(_lossMtx);
+            _lossHistory.push_back(loss);
+            if (_lossHistory.size() > LOSS_WINDOW)
+                _lossHistory.pop_front();
+        }
+       
     });
     _isRecord = true;
     return true;
@@ -171,9 +187,13 @@ void VideoRecorder::StopRecord()
 
 double VideoRecorder::GetLossRate()
 {
+    std::lock_guard<std::mutex> lock(_lossMtx);
     if (_lossHistory.size() < LOSS_WINDOW)
         return -1.0; // 统计中
     int lossCount = std::count(_lossHistory.begin(), _lossHistory.end(), true);
+    if (_lossHistory.empty()) {
+        return 0.0;
+    }
     return double(lossCount) / _lossHistory.size();
 }
 

+ 1 - 0
AvRecorder/recorder/video_recorder.h

@@ -46,6 +46,7 @@ private:
     Timer _captureTimer;
     Timer _muxTimer;
     std::mutex _renderMtx;
+    std::mutex _lossMtx;
     uint64_t _totalPts = 0;
     uint64_t _lossPts = 0;
     // 滑动窗口丢帧统计

+ 176 - 0
docker-compose.yml

@@ -0,0 +1,176 @@
+networks:
+  score-admin:
+    driver: bridge
+    enable_ipv6: false
+
+services:
+  mysql:
+    image: mysql:8.4.0
+    container_name: score_mysql
+    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
+    restart: always
+    ports:
+      - '1236:3306'
+    environment:
+      MYSQL_DATABASE: 'score'
+      MYSQL_ROOT_PASSWORD: 'UeoGr9qOhBWpQV'
+    volumes:
+      - /docker/score/mysql/log:/var/log
+      - /docker/score/mysql/data:/var/lib/mysql
+      - /docker/score/mysql/conf.d:/etc/mysql/conf.d
+      - /etc/localtime:/etc/localtime:ro # 时间同步
+    networks:
+      score-admin:
+        aliases:
+          - mysqlserver
+    deploy:
+      resources:
+        limits:
+          cpus: '0.5'
+          memory: 1000M
+        reservations:
+          cpus: '0.05'
+          memory: 200M
+
+  redis:
+    image: redis:7.0.8-alpine
+    container_name: score_redis
+    restart: always
+#    ports:
+#      - '6379:6379'
+    volumes:
+      - /docker/score/redis:/data
+      - /etc/localtime:/etc/localtime:ro # 时间同步
+    networks:
+      score-admin:
+        aliases:
+          - redisserver
+    deploy:
+      resources:
+        limits:
+          cpus: '0.5'
+          memory: 500M
+        reservations:
+          cpus: '0.05'
+          memory: 200M
+
+  zlmediakit:
+    image: zlmediakit/zlmediakit:master
+    container_name: zlmediakit
+    restart: always
+    ports:
+      - "1935:1935"
+      - "8080:80"
+      - "8443:443"
+      - "8554:554"
+      - "10000:10000"
+      - "10000:10000/udp"
+      - "8000:8000/udp"
+      - "9000:9000/udp"
+    volumes:
+      - /docker/zlmediakit/media/bin/log:/opt/media/bin/log
+      - /docker/zlmediakit/media/conf:/opt/media/conf
+    tty: true
+    stdin_open: true
+    networks:
+      score-admin:
+        aliases:
+          - zlmediakit
+
+  core-rpc:
+    image: core_rpc:1.0.0
+    container_name: score_core-rpc
+    restart: always
+#    ports:
+#      - '9101:9101'
+    networks:
+      score-admin:
+        aliases:
+          - core-rpc
+    volumes:
+      - /docker/score/rpc:/app/etc
+      - /etc/localtime:/etc/localtime:ro # 时间同步
+    depends_on:
+      - mysql
+      - redis
+    deploy:
+      resources:
+        limits:
+          cpus: '0.5'
+          memory: 500M
+        reservations:
+          cpus: '0.05'
+          memory: 200M
+
+  core-api:
+    image: core_api:1.0.0
+    container_name: score_core-api
+    restart: always
+    ports:
+      - '9100:9100'
+    networks:
+      score-admin:
+        aliases:
+          - core-api
+    volumes:
+      - /docker/score/api:/app/etc
+      - /docker/score/locale/core-api:/app/locale
+      - /etc/localtime:/etc/localtime:ro # 时间同步
+    depends_on:
+      - mysql
+      - redis
+      - core-rpc
+    deploy:
+      resources:
+        limits:
+          cpus: '0.5'
+          memory: 500M
+        reservations:
+          cpus: '0.05'
+          memory: 200M
+          
+  score-api:
+    image: score_api:1.0.8
+    container_name: score-api
+    restart: always
+    ports:
+      - '8100:8100'
+    networks:
+      score-admin:
+        aliases:
+          - score-api
+    volumes:
+      - /docker/score/api:/app/etc
+      - /docker/score/data/:/app/data
+      - /etc/localtime:/etc/localtime:ro # 时间同步
+    depends_on:
+      - mysql
+      - redis
+      - core-rpc
+    deploy:
+      resources:
+        limits:
+          cpus: '0.5'
+          memory: 500M
+        reservations:
+          cpus: '0.05'
+          memory: 200M
+          
+  learningsmart-api:
+    image: learningsmart_api:1.0.1
+    container_name: learningsmart_api
+    restart: always
+    ports:
+      - '8200:8200'
+    networks:
+      score-admin:
+        aliases:
+          - core-api
+    volumes:
+      - /docker/learningsmart/api:/app/etc
+      - /etc/localtime:/etc/localtime:ro # 时间同步
+    depends_on:
+      - mysql
+      - redis
+      - core-rpc
+      - zlmediakit

+ 141 - 143
main.cpp

@@ -1,143 +1,141 @@
-// // #include "AVPlayer2/mainwindowa.h"
-
-// #include <QApplication>
-// #include <QDateTime>
-// #include <QDebug>
-// #include <QFile>
-// #include <QLoggingCategory>
-// #include <QMutex>
-// #include <QTextStream>
-// #include <QVBoxLayout>
-// #include <qendian.h>
-// #include <qmath.h>
-
-// #include <AvPlayer2/PlayWidget.h>
-
-// #include "mainwindow.h"
-// #include "thememanager.h"
-// #include "themesettingswidget.h"
-
-// #include "tlogger.h"
-
-// #include "ui/av_recorder.h"
-
-// namespace avrecorder::video {
-// void InitWinRTCapture();
-// }
-
-// #undef ERROR
-// // Qt输出(用于兼容现有Qt日志系统)
-
-// namespace TC {
-// class QtOutput : public LogOutput
-// {
-// public:
-//     void write(LogLevel level, const std::string &message) override;
-// };
-
-// void QtOutput::write(LogLevel level, const std::string &message)
-// {
-//     QString qmsg = QString::fromUtf8(message.c_str());
-//     switch (level) {
-//     case LogLevel::DEBUG:
-//         qDebug() << qmsg;
-//         break;
-//     case LogLevel::INFO:
-//         qInfo() << qmsg;
-//         break;
-//     case LogLevel::WARNING:
-//         qWarning() << qmsg;
-//         break;
-//     case LogLevel::ERROR:
-//         qCritical() << qmsg;
-//         break;
-//     }
-// }
-// } // namespace TC
-
-// int main(int argc, char *argv[])
-// {
-//     // "player.controller.ReadThread=false\n"
-//     QLoggingCategory::setFilterRules(QStringLiteral("player.controller.AudioPlayThread=false\n"
-//                                                     "player.controller.AudioDecodeThread=false\n"));
-//     // QLoggingCategory::setFilterRules("*.debug=false\n"
-//     //                                  "*.info=false\n"
-//     //                                  "*.warning=false\n"
-//     //                                  "*.critical=false\n"
-//     //                                  "player.controller.*.debug=true\n"
-//     //                                  "player.controller.*.info=true\n");
-
-//     // 安装日志处理器
-//     //qInstallMessageHandler(myMessageHandler);
-
-//     // std::freopen(nullptr, "w", stdout);
-//     setvbuf(stdout, nullptr, _IONBF, 0);
-
-// #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
-//     QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
-//         Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
-// #endif
-// #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-//     QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-//     QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
-// #endif
-
-//     QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
-
-//     QApplication a(argc, argv);
-
-//     qRegisterMetaType<AVFrame *>("AVFrame*");
-
-//     ThemeManager::instance().setThemeMode(ThemeManager::Light);
-
-//     // 注册Room 相关的类型 方便 序列化
-//     void initRoomType();
-//     initRoomType();
-
-//     // 初始化wgc
-
-//     avrecorder::video::InitWinRTCapture();
-
-//     /*
-// docker run -itd  --name zlmediakit --restart=always
-// -p 1935:1935 -p 8080:80 -p 8443:443
-// -p 8554:554 -p 10000:10000
-// -p 10000:10000/udp -p 8000:8000/udp
-// -p 9000:9000/udp
-// -v /data/zlmediakit/media/bin:/opt/media/bin
-// -v /data/zlmediakit/media/conf:/opt/media/conf
-// zlmediakit/zlmediakit:master
-// */
-//     MainWindow w;
-//     w.show();
-
-//     // PlayWidget playWidget;
-//     // playWidget.resize(960, 540);
-//     // playWidget.show();
-
-//     // for (int var = 0; var < 20; ++var) {
-//     //     playWidget.startToPlay("C:/Users/zhuizhu/Videos/2.mp4");
-//     // }
-
-//     // AvRecorder avRecorder;
-//     // avRecorder.show();
-//     // ThemeSettingsWidget ThemeSettingsWidget;
-//     // ThemeSettingsWidget.show();
-
-//     // PlayerWindow w;
-//     // w.resize(960, 540);
-//     // w.show();
-
-//     // MainWindowA aa;
-//     // aa.show();
-
-//     // // 这里填你的流地址
-//     // // w.startPlay("http://vd3.bdstatic.com/mda-jennyc5ci1ugrxzi/mda-jennyc5ci1ugrxzi.mp4");
-
-//     // w.open("C:/Users/zhuizhu/Videos/1.mp4");
-//     // // w.startPlay("rtmp://192.168.3.76:1935/stream/V1/stream");
-
-//     int ret = a.exec();
-
-//     return ret;
-// }
+// #include "AVPlayer2/mainwindowa.h"
+
+#include <QApplication>
+#include <QDateTime>
+#include <QDebug>
+#include <QFile>
+#include <QLoggingCategory>
+#include <QMutex>
+#include <QTextStream>
+#include <QVBoxLayout>
+#include <qendian.h>
+#include <qmath.h>
+
+#include <AvPlayer2/PlayWidget.h>
+
+#include "mainwindow.h"
+#include "thememanager.h"
+#include "themesettingswidget.h"
+
+#include "tlogger.h"
+
+#include "ui/av_recorder.h"
+
+namespace avrecorder::video { void InitWinRTCapture(); }
+
+#undef ERROR
+// Qt输出(用于兼容现有Qt日志系统)
+
+namespace TC {
+class QtOutput : public LogOutput
+{
+public:
+    void write(LogLevel level, const std::string &message) override;
+};
+
+void QtOutput::write(LogLevel level, const std::string &message)
+{
+    QString qmsg = QString::fromUtf8(message.c_str());
+    switch (level) {
+    case LogLevel::DEBUG:
+        qDebug() << qmsg;
+        break;
+    case LogLevel::INFO:
+        qInfo() << qmsg;
+        break;
+    case LogLevel::WARNING:
+        qWarning() << qmsg;
+        break;
+    case LogLevel::ERROR:
+        qCritical() << qmsg;
+        break;
+    }
+}
+} // namespace TC
+
+int main(int argc, char *argv[])
+{
+    // "player.controller.ReadThread=false\n"
+    QLoggingCategory::setFilterRules(QStringLiteral("player.controller.AudioPlayThread=false\n"
+                                                    "player.controller.AudioDecodeThread=false\n"));
+    // QLoggingCategory::setFilterRules("*.debug=false\n"
+    //                                  "*.info=false\n"
+    //                                  "*.warning=false\n"
+    //                                  "*.critical=false\n"
+    //                                  "player.controller.*.debug=true\n"
+    //                                  "player.controller.*.info=true\n");
+
+    // 安装日志处理器
+    //qInstallMessageHandler(myMessageHandler);
+
+    // std::freopen(nullptr, "w", stdout);
+    setvbuf(stdout, nullptr, _IONBF, 0);
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+    QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
+        Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
+#endif
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+#endif
+
+    QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
+
+    QApplication a(argc, argv);
+
+    qRegisterMetaType<AVFrame *>("AVFrame*");
+
+    ThemeManager::instance().setThemeMode(ThemeManager::Light);
+
+    // 注册Room 相关的类型 方便 序列化
+    void initRoomType();
+    initRoomType();
+
+    // 初始化wgc
+
+    avrecorder::video::InitWinRTCapture();
+
+    /*
+docker run -itd  --name zlmediakit --restart=always
+-p 1935:1935 -p 8080:80 -p 8443:443
+-p 8554:554 -p 10000:10000
+-p 10000:10000/udp -p 8000:8000/udp
+-p 9000:9000/udp
+-v /data/zlmediakit/media/bin:/opt/media/bin
+-v /data/zlmediakit/media/conf:/opt/media/conf
+zlmediakit/zlmediakit:master
+*/
+    MainWindow w;
+    w.show();
+
+    // PlayWidget playWidget;
+    // playWidget.resize(960, 540);
+    // playWidget.show();
+
+    // for (int var = 0; var < 20; ++var) {
+    //     playWidget.startToPlay("C:/Users/zhuizhu/Videos/2.mp4");
+    // }
+
+    // AvRecorder avRecorder;
+    // avRecorder.show();
+    // ThemeSettingsWidget ThemeSettingsWidget;
+    // ThemeSettingsWidget.show();
+
+    // PlayerWindow w;
+    // w.resize(960, 540);
+    // w.show();
+
+    // MainWindowA aa;
+    // aa.show();
+
+    // // 这里填你的流地址
+    // // w.startPlay("http://vd3.bdstatic.com/mda-jennyc5ci1ugrxzi/mda-jennyc5ci1ugrxzi.mp4");
+
+    // w.open("C:/Users/zhuizhu/Videos/1.mp4");
+    // // w.startPlay("rtmp://192.168.3.76:1935/stream/V1/stream");
+
+    int ret = a.exec();
+
+    return ret;
+}

+ 153 - 0
test_player_stress.cpp

@@ -0,0 +1,153 @@
+#include <QApplication>
+#include <QDebug>
+#include <QTimer>
+#include <QThread>
+#include <chrono>
+#include <thread>
+
+#include "AVPlayer2/PlayWidget.h"
+#include "AVPlayer2/playercontroller.h"
+
+/**
+ * @brief 压力测试PlayerController的线程安全性
+ * 
+ * 这个测试程序验证PlayerController在暴力调用startToPlay时的稳定性
+ */
+class PlayerStressTest : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit PlayerStressTest(QObject* parent = nullptr)
+        : QObject(parent)
+        , m_playWidget(new PlayWidget)
+    {
+        m_playWidget->resize(960, 540);
+        m_playWidget->show();
+    }
+    
+    ~PlayerStressTest()
+    {
+        delete m_playWidget;
+    }
+    
+    void runStressTest()
+    {
+        qDebug() << "开始PlayerController压力测试...";
+        
+        // 测试1: 快速连续调用
+        qDebug() << "测试1: 快速连续调用startToPlay (20次)";
+        for (int i = 0; i < 20; ++i) {
+            m_playWidget->startToPlay("C:/Users/zhuizhu/Videos/2.mp4");
+            qDebug() << "调用" << (i + 1) << "/20";
+        }
+        
+        // 等待一段时间让请求处理完成
+        QTimer::singleShot(2000, [this]() {
+            // 测试2: 多线程并发调用
+            qDebug() << "测试2: 多线程并发调用startToPlay";
+            runConcurrentTest();
+        });
+        
+        // 测试3: 交替播放和停止
+        QTimer::singleShot(5000, [this]() {
+            qDebug() << "测试3: 交替播放和停止";
+            runAlternatingTest();
+        });
+        
+        // 测试4: 不同文件的快速切换
+        QTimer::singleShot(8000, [this]() {
+            qDebug() << "测试4: 不同文件的快速切换";
+            runFileSwitchTest();
+        });
+        
+        // 测试完成
+        QTimer::singleShot(12000, [this]() {
+            qDebug() << "所有压力测试完成!";
+            QApplication::quit();
+        });
+    }
+    
+private:
+    void runConcurrentTest()
+    {
+        // 创建多个线程同时调用startToPlay
+        std::vector<std::thread> threads;
+        
+        for (int i = 0; i < 5; ++i) {
+            threads.emplace_back([this, i]() {
+                for (int j = 0; j < 10; ++j) {
+                    // 使用QMetaObject::invokeMethod确保在主线程中调用
+                    QMetaObject::invokeMethod(this, [this]() {
+                        m_playWidget->startToPlay("C:/Users/zhuizhu/Videos/2.mp4");
+                    }, Qt::QueuedConnection);
+                    
+                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                }
+            });
+        }
+        
+        // 等待所有线程完成
+        for (auto& thread : threads) {
+            thread.join();
+        }
+        
+        qDebug() << "并发测试完成";
+    }
+    
+    void runAlternatingTest()
+    {
+        // 交替调用播放和停止
+        for (int i = 0; i < 10; ++i) {
+            m_playWidget->startToPlay("C:/Users/zhuizhu/Videos/2.mp4");
+            
+            QTimer::singleShot(100, [this]() {
+                // 假设PlayWidget有stopPlay方法,如果没有可以通过PlayerController调用
+                // m_playWidget->stopPlay();
+            });
+            
+            std::this_thread::sleep_for(std::chrono::milliseconds(200));
+        }
+        
+        qDebug() << "交替测试完成";
+    }
+    
+    void runFileSwitchTest()
+    {
+        // 快速切换不同文件(如果有多个测试文件的话)
+        QStringList testFiles = {
+            "C:/Users/zhuizhu/Videos/2.mp4",
+            "C:/Users/zhuizhu/Videos/2.mp4", // 重复文件测试去重功能
+            "C:/Users/zhuizhu/Videos/2.mp4"
+        };
+        
+        for (int i = 0; i < 15; ++i) {
+            QString file = testFiles[i % testFiles.size()];
+            m_playWidget->startToPlay(file);
+            qDebug() << "切换到文件:" << file;
+            std::this_thread::sleep_for(std::chrono::milliseconds(50));
+        }
+        
+        qDebug() << "文件切换测试完成";
+    }
+    
+private:
+    PlayWidget* m_playWidget;
+};
+
+int main(int argc, char *argv[])
+{
+    QApplication app(argc, argv);
+    
+    // 启用详细日志
+    QLoggingCategory::setFilterRules("player.controller.debug=true");
+    
+    PlayerStressTest test;
+    
+    // 延迟启动测试,确保UI完全初始化
+    QTimer::singleShot(1000, &test, &PlayerStressTest::runStressTest);
+    
+    return app.exec();
+}
+
+#include "test_player_stress.moc"