|
|
@@ -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;
|