Bladeren bron

添加 方便降低延迟

zhuizhu 6 maanden geleden
bovenliggende
commit
8ad2ba6e1c
2 gewijzigde bestanden met toevoegingen van 44 en 8 verwijderingen
  1. 40 6
      libs/AVPlayer/av_decoder.cpp
  2. 4 2
      libs/AVPlayer/av_player.cpp

+ 40 - 6
libs/AVPlayer/av_decoder.cpp

@@ -7,8 +7,8 @@ using AVTool::Decoder;
 
 Decoder::Decoder()
     : m_fmtCtx(nullptr)
-    , m_maxFrameQueueSize(16)
-    , m_maxPacketQueueSize(30)
+    , m_maxFrameQueueSize(6)
+    , m_maxPacketQueueSize(12)
     , m_audioIndex(-1)
     , m_videoIndex(-1)
     , m_exit(0)
@@ -35,8 +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);
 
-    ret = avformat_open_input(&fmtCtx, url.toUtf8().constData(), nullptr, nullptr);
+    ret = avformat_open_input(&fmtCtx, url.toUtf8().constData(), nullptr, &formatOpts);
     if (ret < 0) {
         av_strerror(ret, m_errBuf, sizeof(m_errBuf));
         qDebug() << "avformat_open_input error:" << m_errBuf;
@@ -46,6 +50,12 @@ AVTool::MediaInfo* Decoder::detectMediaInfo(const QString& url)
         return Q_NULLPTR;
     }
 
+    // 低延迟:关闭内部缓冲
+    if (fmtCtx) {
+        fmtCtx->flags |= AVFMT_FLAG_NOBUFFER;
+        fmtCtx->max_delay = 0;
+    }
+
     ret = avformat_find_stream_info(fmtCtx, nullptr);
     if (ret < 0) {
         av_strerror(ret, m_errBuf, sizeof(m_errBuf));
@@ -234,8 +244,12 @@ 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);
 
-    ret = avformat_open_input(&m_fmtCtx, url.toUtf8().constData(), nullptr, nullptr);
+    ret = avformat_open_input(&m_fmtCtx, url.toUtf8().constData(), nullptr, &formatOpts);
     if (ret < 0) {
         av_strerror(ret, m_errBuf, sizeof(m_errBuf));
         qDebug() << "avformat_open_input error:" << m_errBuf;
@@ -245,6 +259,12 @@ int Decoder::decode(const QString& url)
         return 0;
     }
 
+    // 低延迟:关闭内部缓冲
+    if (m_fmtCtx) {
+        m_fmtCtx->flags |= AVFMT_FLAG_NOBUFFER;
+        m_fmtCtx->max_delay = 0;
+    }
+
     ret = avformat_find_stream_info(m_fmtCtx, nullptr);
     if (ret < 0) {
         av_strerror(ret, m_errBuf, sizeof(m_errBuf));
@@ -298,6 +318,12 @@ 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_type = FF_THREAD_SLICE;
+        m_audioPktDecoder.codecCtx->thread_count = 1;
+
         ret = avcodec_open2(m_audioPktDecoder.codecCtx, audioCodec, nullptr);
         if (ret < 0) {
             av_strerror(ret, m_errBuf, sizeof(m_errBuf));
@@ -330,6 +356,12 @@ 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_type = FF_THREAD_SLICE;
+        m_videoPktDecoder.codecCtx->thread_count = 1;
+
         ret = avcodec_open2(m_videoPktDecoder.codecCtx, videoCodec, nullptr);
         if (ret < 0) {
             av_strerror(ret, m_errBuf, sizeof(m_errBuf));
@@ -341,6 +373,7 @@ int Decoder::decode(const QString& url)
         m_vidFrameRate = av_guess_frame_rate(m_fmtCtx, m_fmtCtx->streams[m_videoIndex], nullptr);
     }
 
+    // 启动解复用/解码线程
     setInitVal();
 
     ThreadPool::addTask(std::bind(&Decoder::demux, this, std::placeholders::_1),
@@ -468,7 +501,8 @@ void Decoder::demux(std::shared_ptr<void> par)
 
         ret = av_read_frame(m_fmtCtx, pkt);
         if (ret != 0) {
-            av_packet_free(&pkt);
+            // 仅清理内部引用,避免与循环末尾的 av_packet_free 重复释放
+            av_packet_unref(pkt);
             av_strerror(ret, m_errBuf, sizeof(m_errBuf));
             qDebug() << "av_read_frame error:" << m_errBuf;
             break;
@@ -539,7 +573,7 @@ void Decoder::audioDecode(std::shared_ptr<void> par)
                             m_audSeek = 0;
                         }
                     }
-                    //添加到待播放频帧队列
+                    //添加到待播放频帧队列
                     pushAFrame(frame);
                 } else {
                     break;

+ 4 - 2
libs/AVPlayer/av_player.cpp

@@ -251,7 +251,8 @@ int AVPlayer::initSDL()
     wanted_spec.silence = 0;
     wanted_spec.callback = fillAStreamCallback;
     wanted_spec.userdata = this;
-    wanted_spec.samples = m_audioCodecPar->frame_size;
+    // 缩小音频回调缓冲区,降低端到端延迟(需为2的幂)
+    wanted_spec.samples = 512;
 
     if (SDL_OpenAudio(&wanted_spec, nullptr) < 0) {
         qDebug() << "SDL_OpenAudio failed";
@@ -285,7 +286,8 @@ int AVPlayer::initVideo()
     m_imageHeight = m_videoCodecPar->height;
 
     m_dstPixFmt = AV_PIX_FMT_YUV422P;
-    m_swsFlags = SWS_BICUBIC;
+    // 改用快速缩放算法以降低转换时延
+    m_swsFlags = SWS_FAST_BILINEAR;
 
     //分配存储转换后帧数据的buffer内存
     int bufSize = av_image_get_buffer_size(m_dstPixFmt, m_imageWidth, m_imageHeight, 1);