Bläddra i källkod

配置单独出来

zhuizhu 6 månader sedan
förälder
incheckning
ac611efb8a
3 ändrade filer med 103 tillägg och 42 borttagningar
  1. 38 22
      libs/AVPlayer/av_decoder.cpp
  2. 29 20
      libs/AVPlayer/av_player.cpp
  3. 36 0
      libs/AVPlayer/low_latency_config.h

+ 38 - 22
libs/AVPlayer/av_decoder.cpp

@@ -2,13 +2,14 @@
 #include <QDebug>
 #include <QThread>
 #include "threadpool.h"
+#include "low_latency_config.h"
 
 using AVTool::Decoder;
 
 Decoder::Decoder()
     : m_fmtCtx(nullptr)
-    , m_maxFrameQueueSize(6)
-    , m_maxPacketQueueSize(12)
+    , m_maxFrameQueueSize(LowLatencyConfig::BALANCED_FRAME_QUEUE_SIZE)      // 使用配置文件中的帧队列大小
+    , m_maxPacketQueueSize(LowLatencyConfig::BALANCED_PACKET_QUEUE_SIZE)     // 使用配置文件中的包队列大小
     , m_audioIndex(-1)
     , m_videoIndex(-1)
     , m_exit(0)
@@ -34,11 +35,12 @@ AVTool::MediaInfo* Decoder::detectMediaInfo(const QString& url)
 
     //用于获取流时长
     AVDictionary* formatOpts = nullptr;
-    av_dict_set(&formatOpts, "probesize", "32", 0);
-    av_dict_set(&formatOpts, "analyzeduration", "0", 0);
-    av_dict_set(&formatOpts, "rtsp_transport", "tcp", 0);
-    av_dict_set(&formatOpts, "fflags", "nobuffer", 0);
-    av_dict_set(&formatOpts, "max_delay", "0", 0);
+    av_dict_set(&formatOpts, "probesize", LowLatencyConfig::PROBE_SIZE, 0);       // 使用配置文件中的探测大小
+    av_dict_set(&formatOpts, "analyzeduration", LowLatencyConfig::ANALYZE_DURATION, 0);  // 使用配置文件中的分析时长
+    av_dict_set(&formatOpts, "rtsp_transport", LowLatencyConfig::RTSP_TRANSPORT, 0);
+    av_dict_set(&formatOpts, "fflags", LowLatencyConfig::FFLAGS, 0);       // 使用配置文件中的标志
+    av_dict_set(&formatOpts, "max_delay", LowLatencyConfig::MAX_DELAY, 0);      // 使用配置文件中的最大延迟
+    av_dict_set(&formatOpts, "buffer_size", LowLatencyConfig::BUFFER_SIZE, 0);     // 使用配置文件中的缓冲区大小
 
     ret = avformat_open_input(&fmtCtx, url.toUtf8().constData(), nullptr, &formatOpts);
     if (ret < 0) {
@@ -50,10 +52,12 @@ AVTool::MediaInfo* Decoder::detectMediaInfo(const QString& url)
         return Q_NULLPTR;
     }
 
-    // 低延迟:关闭内部缓冲
+    // 低延迟:关闭内部缓冲,但保持稳定性
     if (fmtCtx) {
         fmtCtx->flags |= AVFMT_FLAG_NOBUFFER;
-        fmtCtx->max_delay = 0;
+        fmtCtx->max_delay = 500000;  // 500ms,类似VLC
+        fmtCtx->probesize = 32768;   // 32KB
+        fmtCtx->max_analyze_duration = 1000000;  // 1秒
     }
 
     ret = avformat_find_stream_info(fmtCtx, nullptr);
@@ -243,11 +247,11 @@ int Decoder::decode(const QString& url)
 
     //用于获取流时长
     AVDictionary* formatOpts = nullptr;
-    av_dict_set(&formatOpts, "probesize", "32", 0);
-    av_dict_set(&formatOpts, "analyzeduration", "0", 0);
-    av_dict_set(&formatOpts, "rtsp_transport", "tcp", 0);
-    av_dict_set(&formatOpts, "fflags", "nobuffer", 0);
-    av_dict_set(&formatOpts, "max_delay", "0", 0);
+    av_dict_set(&formatOpts, "probesize", LowLatencyConfig::PROBE_SIZE, 0);
+    av_dict_set(&formatOpts, "analyzeduration", LowLatencyConfig::ANALYZE_DURATION, 0);
+    av_dict_set(&formatOpts, "rtsp_transport", LowLatencyConfig::RTSP_TRANSPORT, 0);
+    av_dict_set(&formatOpts, "fflags", LowLatencyConfig::FFLAGS, 0);
+    av_dict_set(&formatOpts, "max_delay", LowLatencyConfig::MAX_DELAY, 0);
 
     ret = avformat_open_input(&m_fmtCtx, url.toUtf8().constData(), nullptr, &formatOpts);
     if (ret < 0) {
@@ -318,13 +322,19 @@ int Decoder::decode(const QString& url)
         }
         m_audioPktDecoder.codecCtx->codec_id = audioCodec->id;
 
-        // 低延迟解码设置(音频)
+        // 平衡的解码设置(音频)
         m_audioPktDecoder.codecCtx->flags |= AV_CODEC_FLAG_LOW_DELAY;
         m_audioPktDecoder.codecCtx->flags2 |= AV_CODEC_FLAG2_FAST;
+        m_audioPktDecoder.codecCtx->thread_count = LowLatencyConfig::DECODER_THREAD_COUNT;  // 使用配置文件中的线程数
         m_audioPktDecoder.codecCtx->thread_type = FF_THREAD_SLICE;
-        m_audioPktDecoder.codecCtx->thread_count = 1;
-
-        ret = avcodec_open2(m_audioPktDecoder.codecCtx, audioCodec, nullptr);
+        
+        // H.264平衡优化
+        AVDictionary* codecOpts = nullptr;
+        av_dict_set(&codecOpts, "preset", LowLatencyConfig::CODEC_PRESET, 0);           // 使用配置文件中的预设
+        av_dict_set(&codecOpts, "tune", LowLatencyConfig::CODEC_TUNE, 0);
+        
+        ret = avcodec_open2(m_audioPktDecoder.codecCtx, audioCodec, &codecOpts);
+        av_dict_free(&codecOpts);
         if (ret < 0) {
             av_strerror(ret, m_errBuf, sizeof(m_errBuf));
             qDebug() << "error info_avcodec_open2:" << m_errBuf;
@@ -356,13 +366,19 @@ int Decoder::decode(const QString& url)
         }
         m_videoPktDecoder.codecCtx->codec_id = videoCodec->id;
 
-        // 低延迟解码设置(视频)
+        // 平衡的解码设置(视频)
         m_videoPktDecoder.codecCtx->flags |= AV_CODEC_FLAG_LOW_DELAY;
         m_videoPktDecoder.codecCtx->flags2 |= AV_CODEC_FLAG2_FAST;
+        m_videoPktDecoder.codecCtx->thread_count = LowLatencyConfig::DECODER_THREAD_COUNT;  // 使用配置文件中的线程数
         m_videoPktDecoder.codecCtx->thread_type = FF_THREAD_SLICE;
-        m_videoPktDecoder.codecCtx->thread_count = 1;
-
-        ret = avcodec_open2(m_videoPktDecoder.codecCtx, videoCodec, nullptr);
+        
+        // H.264平衡优化
+        AVDictionary* videoCodecOpts = nullptr;
+        av_dict_set(&videoCodecOpts, "preset", LowLatencyConfig::CODEC_PRESET, 0);           // 使用配置文件中的预设
+        av_dict_set(&videoCodecOpts, "tune", LowLatencyConfig::CODEC_TUNE, 0);
+        
+        ret = avcodec_open2(m_videoPktDecoder.codecCtx, videoCodec, &videoCodecOpts);
+        av_dict_free(&videoCodecOpts);
         if (ret < 0) {
             av_strerror(ret, m_errBuf, sizeof(m_errBuf));
             qDebug() << "error info_avcodec_open2:" << m_errBuf;

+ 29 - 20
libs/AVPlayer/av_player.cpp

@@ -4,19 +4,16 @@
 #include <QThread>
 #include "threadpool.h"
 #include "vframe.h"
+#include "low_latency_config.h"
+
+// 同步阈值定义已移至配置文件(low_latency_config.h)
 
-//同步阈值下限
-#define AV_SYNC_THRESHOLD_MIN 0.04
-//同步阈值上限
-#define AV_SYNC_THRESHOLD_MAX 0.1
 //单帧视频时长阈值上限,用于适配低帧时同步,
 //帧率过低视频帧超前不适合翻倍延迟,应特殊
 //处理,这里设置上限一秒10帧
-#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
+
 //同步操作摆烂阈值上限,此时同步已无意义
-#define AV_NOSYNC_THRESHOLD 10.0
 
-#define AV_SYNC_REJUDGESHOLD 0.01
 
 AVPlayer::AVPlayer()
     : m_decoder(new Decoder)
@@ -243,6 +240,7 @@ int AVPlayer::initSDL()
     m_audioIndex = m_decoder->audioIndex();
     m_fmtCtx = m_decoder->formatContext();
 
+    // 音频设备配置(平衡模式 - 类似VLC)
     SDL_AudioSpec wanted_spec;
     // wanted_spec.channels = m_audioCodecPar->channels;
     wanted_spec.channels = ffmpeg_get_codec_channels(m_fmtCtx->streams[m_audioIndex]);
@@ -251,8 +249,8 @@ int AVPlayer::initSDL()
     wanted_spec.silence = 0;
     wanted_spec.callback = fillAStreamCallback;
     wanted_spec.userdata = this;
-    // 缩小音频回调缓冲区,降低端到端延迟(需为2的幂)
-    wanted_spec.samples = 512;
+    // 平衡音频回调缓冲区,兼顾延迟与稳定性(需为2的幂)
+    wanted_spec.samples = LowLatencyConfig::BALANCED_AUDIO_SAMPLES;  // 使用配置文件中的音频样本数
 
     if (SDL_OpenAudio(&wanted_spec, nullptr) < 0) {
         qDebug() << "SDL_OpenAudio failed";
@@ -512,23 +510,34 @@ void AVPlayer::videoCallback(std::shared_ptr<void> par)
             //显示时长未到
             if (time < m_frameTimer + delay) {
                 QThread::msleep(
-                    (uint32_t) (FFMIN(AV_SYNC_REJUDGESHOLD, m_frameTimer + delay - time) * 1000));
+                    (uint32_t) (FFMIN(LowLatencyConfig::BALANCED_SYNC_REJUDGE_THRESHOLD, m_frameTimer + delay - time) * 1000));
                 continue;
             }
 
             m_frameTimer += delay;
-            if (time - m_frameTimer > AV_SYNC_THRESHOLD_MAX)
+            if (time - m_frameTimer > LowLatencyConfig::BALANCED_SYNC_THRESHOLD_MAX)
                 m_frameTimer = time;
 
             //队列中未显示帧一帧以上执行逻辑丢帧判断,倍速播放和逐帧播放
             //都不跑进此逻辑,倍速易造成丢帧过多导致界面不流畅
-            if (m_playSpeed == 1.0 && m_decoder->getRemainingVFrame() > 1) {
+            // 平衡:温和的丢帧策略,保证稳定性
+            if (m_playSpeed == 1.0 && m_decoder->getRemainingVFrame() > 1) {  // 恢复为>1,更稳定
                 MyFrame* nextFrame = m_decoder->peekNextVFrame();
-                duration = nextFrame->pts - frame->pts;
-                //若主时钟超前到大于当前帧理论显示应持续的时间了,则当前帧立即丢弃
-                if (time > m_frameTimer + duration) {
+                if (nextFrame) {
+                    duration = nextFrame->pts - frame->pts;
+                    //若主时钟超前到大于当前帧理论显示应持续的时间了,则当前帧立即丢弃
+                    // 平衡:使用原始duration阈值,避免过度丢帧
+                    if (time > m_frameTimer + duration) {
+                        m_decoder->setNextVFrame();
+                        qDebug() << "abandon vframe (balanced mode)" << Qt::endl;
+                        continue;
+                    }
+                }
+                
+                // 温和:基于延迟的丢帧阈值使用配置文件参数
+                if (delay > LowLatencyConfig::FRAME_DROP_THRESHOLD) {  // 使用配置文件中的丢帧阈值
                     m_decoder->setNextVFrame();
-                    qDebug() << "abandon vframe" << Qt::endl;
+                    qDebug() << "drop frame due to high delay:" << delay << Qt::endl;
                     continue;
                 }
             }
@@ -566,16 +575,16 @@ double AVPlayer::computeTargetDelay(double delay)
     double diff = m_videoClock.getClock() - m_audioClock.getClock();
 
     //计算同步阈值
-    double sync = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
+    double sync = FFMAX(LowLatencyConfig::BALANCED_SYNC_THRESHOLD_MIN, FFMIN(LowLatencyConfig::BALANCED_SYNC_THRESHOLD_MAX, delay));
 
     //不同步时间超过阈值直接放弃同步
-    if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
+    if (!isnan(diff) && fabs(diff) < LowLatencyConfig::BALANCED_NOSYNC_THRESHOLD) {
         if (diff
             <= -sync) { //视频已落后音频大于一帧的显示时长,delay值应为0,立马将当前帧显示追赶音频
             delay = FFMAX(0, diff + delay);
         } else if (diff >= sync
                    && delay
-                          > AV_SYNC_FRAMEDUP_THRESHOLD) { //视频超前音频大于一个视频帧的时间,延时一个视频帧时间+已超时时间,下次判定将至少被延时到下个将要显示的视频帧pts
+                          > LowLatencyConfig::BALANCED_SYNC_FRAMEDUP_THRESHOLD) { //视频超前音频大于一个视频帧的时间,延时一个视频帧时间+已超时时间,下次判定将至少被延时到下个将要显示的视频帧pts
             delay = diff + delay;
         } else if (diff >= sync) { //高帧率视频直接延时两个视频帧时间;;;;
             delay = 2 * delay;
@@ -588,7 +597,7 @@ double AVPlayer::vpDuration(MyFrame* lastFrame, MyFrame* curFrame)
 {
     if (curFrame->serial == lastFrame->serial) {
         double duration = curFrame->pts - lastFrame->pts;
-        if (isnan(duration) || duration > AV_NOSYNC_THRESHOLD)
+        if (isnan(duration) || duration > LowLatencyConfig::BALANCED_NOSYNC_THRESHOLD)
             return lastFrame->duration;
         else
             return duration;

+ 36 - 0
libs/AVPlayer/low_latency_config.h

@@ -0,0 +1,36 @@
+#ifndef LOW_LATENCY_CONFIG_H
+#define LOW_LATENCY_CONFIG_H
+
+// 低延迟模式配置参数(平衡模式 - 类似VLC)
+namespace LowLatencyConfig {
+    // 缓冲区大小优化(平衡模式)
+    constexpr int BALANCED_FRAME_QUEUE_SIZE = 3;     // 3帧 ≈ 100ms@30fps
+    constexpr int BALANCED_PACKET_QUEUE_SIZE = 6;    // 6包 ≈ 200ms
+    
+    // 音频缓冲区优化(稳定模式)
+    constexpr int BALANCED_AUDIO_SAMPLES = 512;      // 512样本 ≈ 11.6ms@44.1kHz
+    
+    // 同步阈值优化(温和模式)
+    constexpr double BALANCED_SYNC_THRESHOLD_MIN = 0.02;  // 20ms
+    constexpr double BALANCED_SYNC_THRESHOLD_MAX = 0.06;  // 60ms
+    constexpr double BALANCED_NOSYNC_THRESHOLD = 3.0;     // 3秒放弃同步
+    constexpr double BALANCED_SYNC_FRAMEDUP_THRESHOLD = 0.1;  // 100ms单帧视频时长阈值上限
+    constexpr double BALANCED_SYNC_REJUDGE_THRESHOLD = 0.01;  // 10ms同步重判阈值
+    
+    // 网络优化参数(更新为平衡配置)
+    constexpr const char* RTSP_TRANSPORT = "tcp";
+    constexpr const char* PROBE_SIZE = "32768";        // 32KB探测大小
+    constexpr const char* ANALYZE_DURATION = "1000000"; // 1秒分析时长
+    constexpr const char* MAX_DELAY = "500000";        // 500ms最大延迟
+    constexpr const char* FFLAGS = "nobuffer";         // 无缓冲模式
+    constexpr const char* BUFFER_SIZE = "65536";       // 64KB接收缓冲区
+    
+    // 解码器优化(平衡配置)
+    constexpr int DECODER_THREAD_COUNT = 2;           // 2线程平衡性能与延迟
+    constexpr const char* CODEC_PRESET = "fast";      // fast预设
+    constexpr const char* CODEC_TUNE = "zerolatency"; // 零延迟调优
+    constexpr bool ENABLE_FRAME_DROP = true;          // 启用丢帧
+    constexpr double FRAME_DROP_THRESHOLD = 0.05;     // 50ms丢帧阈值
+}
+
+#endif // LOW_LATENCY_CONFIG_H