Selaa lähdekoodia

延迟500-700ms

zhuizhu 6 kuukautta sitten
vanhempi
säilyke
bbb240eb56

+ 2 - 0
libs/Recorder/Recorder.pri

@@ -30,6 +30,7 @@ HEADERS += \
     $$PWD/muxer_define.h \
     $$PWD/muxer_ffmpeg.h \
     $$PWD/muxer_file.h \
+    $$PWD/performance_monitor.h \
     $$PWD/record_audio.h \
     $$PWD/record_audio_define.h \
     $$PWD/record_audio_dshow.h \
@@ -75,6 +76,7 @@ SOURCES += \
     $$PWD/log_helper.cpp \
     $$PWD/muxer_ffmpeg.cpp \
     $$PWD/muxer_file.cpp \
+    $$PWD/performance_monitor.cpp \
     $$PWD/record_audio.cpp \
     $$PWD/record_audio_dshow.cpp \
     $$PWD/record_audio_factory.cpp \

+ 25 - 17
libs/Recorder/encoder_video_x264.cpp

@@ -35,16 +35,16 @@ int encoder_video_x264::init(
 
     AVDictionary *options = 0;
 
-    // 使用ultrafast预设以获得最低延迟
+    // 回到超低延迟配置,但优化画质参数
     av_dict_set(&options, "preset", "ultrafast", 0);
     av_dict_set(&options, "tune", "zerolatency", 0);
     
-    // 设置x264参数以匹配低延迟配置
-    av_dict_set(&options, "x264-params", "keyint=30:min-keyint=30:no-scenecut=1", 0);
+    // 针对画质问题的特殊优化:提高码率而不是降低速度
+    av_dict_set(&options, "x264-params", "keyint=15:min-keyint=15:no-scenecut=1:rc-lookahead=0:aq-mode=2:aq-strength=0.8", 0);
     av_dict_set(&options, "profile", "high", 0);
     av_dict_set(&options, "level", "4.1", 0);
-    // 与命令行一致,明确设置CRF为18
-    av_dict_set(&options, "crf", "18", 0);
+    // 使用更高的码率而不是更低的CRF来改善画质
+    av_dict_set(&options, "crf", "20", 0);
 
     do {
         _encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
@@ -67,21 +67,24 @@ int encoder_video_x264::init(
         _encoder_ctx->time_base.num = 1;
         _encoder_ctx->time_base.den = frame_rate;
         _encoder_ctx->framerate = {frame_rate, 1};
-        _encoder_ctx->bit_rate = bit_rate;
+        _encoder_ctx->bit_rate = bit_rate * 2;  // 提高码率来改善画质,而不是降低编码速度
 
-        // 设置GOP大小为30帧,与用户ffmpeg命令一致
-        _encoder_ctx->gop_size = 30;
+        // 回到低延迟GOP设置
+        _encoder_ctx->gop_size = 15;
 
-        // 使用CRF 18以获得高质量和低延迟的平衡
-        // 注意:FFmpeg的libx264编码器通过crf参数控制质量
-        // 这里我们设置合理的qmin和qmax值
-        _encoder_ctx->qmin = 10;
-        _encoder_ctx->qmax = 25;
+        // 使用更宽松的量化参数,通过码率控制画质
+        _encoder_ctx->qmin = 12;
+        _encoder_ctx->qmax = 28;
         
-        // 设置CRF值(通过全局质量参数)
-        _encoder_ctx->global_quality = 18 * FF_QP2LAMBDA;
+        // 设置CRF值 - 稍微放宽以保证速度
+        _encoder_ctx->global_quality = 20 * FF_QP2LAMBDA;
 
         _encoder_ctx->max_b_frames = 0; //NO B Frame
+        
+        // 恢复最低延迟设置
+        _encoder_ctx->delay = 0;
+        _encoder_ctx->thread_count = 1;  // 单线程确保最低延迟
+        
         _encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 
         ret = avcodec_open2(_encoder_ctx, _encoder, &options);
@@ -209,11 +212,16 @@ void encoder_video_x264::encode_loop()
 
     while (_running) {
         std::unique_lock<std::mutex> lock(_mutex);
-        // 改为基于条件的等待,避免固定50ms超时带来的延迟抖动
-        _cond_var.wait(lock, [this] { return _cond_notify || !_running; });
+        // 恢复最激进的低延迟处理
+        if (!_cond_notify && _ring_buffer->get_pending_frames() == 0) {
+            // 使用最短等待时间
+            _cond_var.wait_for(lock, std::chrono::milliseconds(1), [this] { return _cond_notify || !_running; });
+        }
+        
         if (!_running)
             break;
 
+        // 立即处理所有可用帧,不限制批处理大小
         while (_ring_buffer->get(_buff, _buff_size, yuv_frame)) {
             // Normalize incoming frame timestamps to encoder time_base (1/fps)
             // Source pts is in AV_TIME_BASE (microseconds) from capturer

+ 40 - 0
libs/Recorder/export.cpp

@@ -16,6 +16,7 @@
 #include "error_define.h"
 #include "log_helper.h"
 #include "utils_string.h"
+#include "performance_monitor.h"
 
 #ifdef _WIN32
 #include "system_version.h"
@@ -60,6 +61,10 @@ public:
     // Expose underlying encoders for diagnostics
     encoder_video* get_video_encoder();
     encoder_aac*   get_audio_encoder();
+    
+    // 性能监控接口
+    std::string getPerformanceReport() const;
+    void resetPerformanceStats();
 
 private:
     void on_preview_yuv(const uint8_t *data, int size, int width, int height, int type);
@@ -74,6 +79,7 @@ private:
     record_desktop *_recorder_desktop;
 
     muxer_file *_muxer;
+    PerformanceMonitor *_perf_monitor;  // 性能监控器
 
     std::atomic_bool _inited;
     std::mutex _mutex;
@@ -93,6 +99,7 @@ recorder::recorder()
 
     _inited = false;
     _muxer = nullptr;
+    _perf_monitor = new PerformanceMonitor();  // 初始化性能监控器
 }
 
 recorder::~recorder()
@@ -108,6 +115,9 @@ recorder::~recorder()
 
     if (_recorder_speaker)
         delete _recorder_speaker;
+        
+    if (_perf_monitor)
+        delete _perf_monitor;  // 清理性能监控器
 }
 
 recorder *recorder::instance()
@@ -392,6 +402,23 @@ void recorder::get_valid_out_resolution(int src_width,
             scale_cy,
             scaled_vals[i]);
 }
+
+// 性能监控接口实现
+std::string recorder::getPerformanceReport() const
+{
+    if (_perf_monitor) {
+        return _perf_monitor->getPerformanceReport();
+    }
+    return "性能监控器未初始化";
+}
+
+void recorder::resetPerformanceStats()
+{
+    if (_perf_monitor) {
+        _perf_monitor->reset();
+    }
+}
+
 } // namespace am
 
 AMRECORDER_API const char *recorder_err2str(int error)
@@ -609,4 +636,17 @@ AMRECORDER_API void recorder_reset_audio_rb_dropped()
     auto enc = am::recorder::instance()->get_audio_encoder();
     if (!enc) return;
     enc->rb_reset_dropped();
+} // namespace am 结束
+
+// 导出性能监控API
+AMRECORDER_API const char* recorder_get_performance_report()
+{
+    static std::string report;
+    report = am::recorder::instance()->getPerformanceReport();
+    return report.c_str();
+}
+
+AMRECORDER_API void recorder_reset_performance_stats()
+{
+    am::recorder::instance()->resetPerformanceStats();
 }

+ 11 - 0
libs/Recorder/export.h

@@ -302,4 +302,15 @@ AMRECORDER_API int      recorder_get_audio_rb_max();
 AMRECORDER_API void     recorder_set_audio_rb_max(int max_frames);
 AMRECORDER_API void     recorder_reset_audio_rb_dropped();
 
+/**
+* Get performance monitoring report
+* @return Performance report string
+*/
+AMRECORDER_API const char* recorder_get_performance_report();
+
+/**
+* Reset performance statistics
+*/
+AMRECORDER_API void recorder_reset_performance_stats();
+
 #endif

+ 29 - 8
libs/Recorder/record_desktop_gdi.cpp

@@ -248,10 +248,19 @@ void record_desktop_gdi::do_sleep(int64_t dur, int64_t pre, int64_t now)
     int64_t delay = now - pre;
     dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
 
-    //al_debug("%lld", delay);
-
-    if (dur)
-        av_usleep(dur);
+    // 优化:使用更精确的睡眠机制,减少延迟抖动
+    if (dur > 0) {
+        // 对于小于2ms的延迟,使用忙等待以获得更精确的时序
+        if (dur < 2000) {  // 2ms
+            int64_t start = av_gettime_relative();
+            while (av_gettime_relative() - start < dur) {
+                // 忙等待,但让出CPU时间片
+                std::this_thread::yield();
+            }
+        } else {
+            av_usleep(dur);
+        }
+    }
 }
 
 void record_desktop_gdi::record_func()
@@ -260,9 +269,15 @@ void record_desktop_gdi::record_func()
 
     int64_t pre_pts = 0;
     int64_t dur = AV_TIME_BASE / _fps;
+    
+    // 优化:预分配光标信息结构,减少每帧的内存分配开销
+    memset(&_ci, 0, sizeof(CURSORINFO));
+    _ci.cbSize = sizeof(CURSORINFO);
 
     int ret = AE_NO;
     while (_running) {
+        int64_t frame_start = av_gettime_relative();
+        
         ret = do_record();
         if (ret != AE_NO) {
             if (_on_error)
@@ -271,8 +286,7 @@ void record_desktop_gdi::record_func()
         }
 
         // 使用相对时间戳,与muxer的_base_time保持一致
-        int64_t dur = av_rescale_q(1, av_inv_q(_time_base), _time_base);
-        frame->pts = av_gettime_relative();
+        frame->pts = frame_start;  // 使用帧开始时间作为时间戳
         frame->pkt_dts = frame->pts;
 
         frame->width = _width;
@@ -292,9 +306,16 @@ void record_desktop_gdi::record_func()
         if (_on_data)
             _on_data(frame);
 
-        do_sleep(dur, pre_pts, frame->pts);
+        // 优化:更精确的帧率控制
+        int64_t frame_end = av_gettime_relative();
+        int64_t processing_time = frame_end - frame_start;
+        int64_t sleep_time = dur - processing_time;
+        
+        if (sleep_time > 0) {
+            do_sleep(sleep_time, pre_pts, frame_end);
+        }
 
-        pre_pts = frame->pts;
+        pre_pts = frame_end;
     }
 
     av_frame_free(&frame);

+ 4 - 4
libs/Recorder/ring_buffer.h

@@ -23,7 +23,7 @@ template<typename T>
 class ring_buffer
 {
 public:
-    ring_buffer(unsigned int size = 1920 * 1080 * 4 * 2, size_t max_frames = 3)  // 从10帧减少到2帧,减少积压
+    ring_buffer(unsigned int size = 1920 * 1080 * 4 * 2, size_t max_frames = 1)  // 回到1帧最小延迟
     {
         _size = size;
         _head = _tail = 0;
@@ -42,9 +42,9 @@ public:
     {
         std::lock_guard<std::mutex> locker(_lock);
 
-        // 实时推流优化:当缓冲区积压超过阈值时,丢弃最旧的帧
-        while (_frames.size() >= _max_frames) {
-            // 丢弃最旧的帧
+        // 优化丢帧策略:只在缓冲区真正满时才丢帧,避免过度丢帧导致画质问题
+        if (_frames.size() >= _max_frames) {
+            // 只丢弃一帧,保持画面连续性
             if (!_frames.empty()) {
                 ring_frame<T> old_frame = _frames.front();
                 _frames.pop();