feat: 拉流新增重连机制

video_old
cbwu 5 months ago
parent ca5d5bc82b
commit 28ba3d2281

@ -14,7 +14,7 @@ QMAKE_PROJECT_DEPTH = 0
# QMAKE_LFLAGS += /MANIFESTUAC:\"level=\'requireAdministrator\' uiAccess=\'false\'\" # QMAKE_LFLAGS += /MANIFESTUAC:\"level=\'requireAdministrator\' uiAccess=\'false\'\"
#程序版本 #程序版本
VERSION = 1.0.0.1011 VERSION = 1.0.0.1014
#程序版本 #程序版本
QMAKE_TARGET_COMPANY = "HTSDFP" QMAKE_TARGET_COMPANY = "HTSDFP"

@ -1,10 +1,7 @@
#include "cffmpeg_decode.h" #include "cffmpeg_decode.h"
// Cffmpeg_decode::Cffmpeg_decode() { // Cffmpeg_decode::Cffmpeg_decode() {
Cffmpeg_decode::Cffmpeg_decode(QObject *parent) : QObject(parent) { Cffmpeg_decode::Cffmpeg_decode(QObject *parent) : QObject(parent) {
inputFormatCtx = avformat_alloc_context(); initFFmpegContainer();
inputPacket = av_packet_alloc();
yuvFrame = av_frame_alloc();
rgbFrame = av_frame_alloc();
avformat_network_init(); avformat_network_init();
m_rtsp_transport = "tcp"; m_rtsp_transport = "tcp";
} }
@ -59,6 +56,13 @@ void Cffmpeg_decode::setPushStream(bool bPushStream) {
mutex.unlock(); mutex.unlock();
} }
void Cffmpeg_decode::initFFmpegContainer() {
inputFormatCtx = avformat_alloc_context();
inputPacket = av_packet_alloc();
yuvFrame = av_frame_alloc();
rgbFrame = av_frame_alloc();
}
bool Cffmpeg_decode::open_input_file() { bool Cffmpeg_decode::open_input_file() {
if (_url.isEmpty()) if (_url.isEmpty())
return 0; return 0;
@ -79,7 +83,7 @@ bool Cffmpeg_decode::open_input_file() {
av_dict_set(&avdic, "buffer_size", "2048000", 0); av_dict_set(&avdic, "buffer_size", "2048000", 0);
// 设置超时断开连接时间,单位微秒//listen_timeout // 设置超时断开连接时间,单位微秒//listen_timeout
// av_dict_set(&avdic, "listen_timeout", "200000", 0); // av_dict_set(&avdic, "listen_timeout", "200000", 0);
av_dict_set(&avdic, "stimeout", "3000000", 0); // 设置超时3 av_dict_set(&avdic, "stimeout", "5000000", 0); // 设置超时5
av_dict_set(&avdic, "max_delay", "300000", 0); // 设置最大时延300ms av_dict_set(&avdic, "max_delay", "300000", 0); // 设置最大时延300ms
av_dict_set(&avdic, "tune", "zerolatency", 0); // 实时编码 av_dict_set(&avdic, "tune", "zerolatency", 0); // 实时编码
av_dict_set(&avdic, "preset", "faster", 0); // ultrafast av_dict_set(&avdic, "preset", "faster", 0); // ultrafast
@ -87,6 +91,9 @@ bool Cffmpeg_decode::open_input_file() {
// 设置最大重试时间为1s,解决avformat_open_input打开空流时间过长问题 // 设置最大重试时间为1s,解决avformat_open_input打开空流时间过长问题
av_dict_set(&avdic, "max_interleave_delta", "1000000", 0); av_dict_set(&avdic, "max_interleave_delta", "1000000", 0);
// av_dict_set(&avdic, "reconnect", "1", 0); // 开启自动重连
// av_dict_set(&avdic, "reconnect_streamed", "1", 0); // 对于流媒体自动重连
// av_dict_set(&avdic, "reconnect_delay_max", "5", 0); // 最大重连延时 5 秒
// av_dict_set(&avdic, "rtsp_flags", "prefer_tcp", 0); // 保持TCP连接 // av_dict_set(&avdic, "rtsp_flags", "prefer_tcp", 0); // 保持TCP连接
// av_dict_set(&avdic, "timeout", "500000", 0); // 超时时间设置为500ms // av_dict_set(&avdic, "timeout", "500000", 0); // 超时时间设置为500ms
// av_dict_set(&avdic, "probesize", "50000000", 0); // 增加探针大小1MB // av_dict_set(&avdic, "probesize", "50000000", 0); // 增加探针大小1MB
@ -183,7 +190,8 @@ bool Cffmpeg_decode::open_input_file() {
// 线程里持续执行 // 线程里持续执行
void Cffmpeg_decode::run() { void Cffmpeg_decode::run() {
if (!open_input_file()) { m_startPullFlag = open_input_file();
if (!m_startPullFlag) {
qDebug() << "Please open video file first."; qDebug() << "Please open video file first.";
emit sendConnectFail(1); emit sendConnectFail(1);
IsstopPlay = true; IsstopPlay = true;
@ -199,15 +207,40 @@ void Cffmpeg_decode::run() {
firstDts = AV_NOPTS_VALUE; // 初始化第一帧的DTS firstDts = AV_NOPTS_VALUE; // 初始化第一帧的DTS
startTime = av_gettime(); startTime = av_gettime();
int ret1;
// 读取数据包 // 读取数据包
while (av_read_frame(inputFormatCtx, inputPacket) >= 0) { while (m_startPullFlag) {
// ret = av_read_frame(inputFormatCtx, inputPacket); ret1 = av_read_frame(inputFormatCtx, inputPacket);
// if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { if (ret1 == AVERROR(EAGAIN)) { // 暂时没有数据流
// qDebug() << "ret:" << QString::number(ret); qDebug() << "No Stream Data";
// av_packet_unref(inputPacket); av_usleep(100000); // 等待 100 毫秒
// frm_cnt++; continue;
// continue; } else if (ret1 == AVERROR_EOF) { // 流文件结束
// } qDebug() << "Stream End";
break;
} else if (ret1 < 0) { // 发生错误
qDebug() << "Stream Error";
bool ss = reconnect();
if (ss) {
qDebug() << "reconnect sucess";
// 初始化 previous_pts_time 为无效值(拉流使用)
previous_pts_time = -1.0; // 表示没有上一帧的时间戳
first_frame_pts_time = 0.0; // 第一帧的 PTS 时间
first_frame_system_time = 0.0; // 第一帧解码时的系统时间
// 推流使用
firstDts = AV_NOPTS_VALUE; // 初始化第一帧的DTS
startTime = av_gettime();
frm_cnt = 0;
continue;
} else {
qDebug() << "reconnect failed";
break;
}
// break;
// continue;
}
if (IsstopPlay) { if (IsstopPlay) {
qDebug() << "video play stop"; qDebug() << "video play stop";
@ -291,7 +324,7 @@ void Cffmpeg_decode::run() {
// qDebug() << "pull stream sleep time:" // qDebug() << "pull stream sleep time:"
// << QString::number(wait_time / 1000.0); // << QString::number(wait_time / 1000.0);
if (wait_time > 0) { if (wait_time > 0) {
av_usleep(wait_time); // 延时以同步 PTS // av_usleep(wait_time); // 延时以同步 PTS
} }
// 更新 previous_pts_time 为当前帧的 PTS // 更新 previous_pts_time 为当前帧的 PTS
previous_pts_time = pts_time; previous_pts_time = pts_time;
@ -342,6 +375,11 @@ void Cffmpeg_decode::stop() {
avformat_close_input(&inputFormatCtx); avformat_close_input(&inputFormatCtx);
} }
void Cffmpeg_decode::stopPull() {
m_startPullFlag = false;
m_reconnectFlag = false;
}
/** /**
* @brief * @brief
* @param fileDirPath: * @param fileDirPath:
@ -432,6 +470,26 @@ void Cffmpeg_decode::saveDone() {
m_saveVideoFlag = false; m_saveVideoFlag = false;
} }
bool Cffmpeg_decode::reconnect() {
m_reconnectFlag = true;
stop();
for (int i = 0; i < MAXRECONNECT; ++i) {
initFFmpegContainer();
m_startPullFlag = open_input_file();
if (!m_startPullFlag) {
stop();
} else {
IsstopPlay = false;
bOpenPushStreamFlag = false;
return true;
}
if (!m_reconnectFlag)
break;
qDebug() << "reconnect" << QString::number(i + 1);
}
return false;
}
void Cffmpeg_decode::setFlowType(QString param) { void Cffmpeg_decode::setFlowType(QString param) {
m_rtsp_transport = param; m_rtsp_transport = param;
m_bSetRtspTransport = true; m_bSetRtspTransport = true;

@ -23,6 +23,7 @@ public:
bool open_input_file(); bool open_input_file();
void stop(); void stop();
void stopPull();
/** /**
* @brief * @brief
* @param fileDirPath * @param fileDirPath
@ -87,7 +88,7 @@ private:
double previous_pts_time; // 表示没有上一帧的时间戳 double previous_pts_time; // 表示没有上一帧的时间戳
double first_frame_pts_time; // 第一帧的 PTS 时间 double first_frame_pts_time; // 第一帧的 PTS 时间
double first_frame_system_time; // 第一帧解码时的系统时间 double first_frame_system_time; // 第一帧解码时的系统时间
/******** 保存裸流使用 ******************/ /****************** 保存裸流使用 ******************/
AVFormatContext *m_formatContextSave = nullptr; // 封装上下文 AVFormatContext *m_formatContextSave = nullptr; // 封装上下文
QString m_strCodecName; // 编解码器名称 QString m_strCodecName; // 编解码器名称
AVStream *m_videoStreamOut = nullptr; // 输出视频流 AVStream *m_videoStreamOut = nullptr; // 输出视频流
@ -97,7 +98,11 @@ private:
bool m_bSetRtspTransport = false; bool m_bSetRtspTransport = false;
private: private:
int MAXRECONNECT = 12;
bool m_saveVideoFlag = false; bool m_saveVideoFlag = false;
bool m_startPullFlag = false;
bool m_reconnectFlag = false;
void initFFmpegContainer();
/** /**
* @brief * @brief
* @return * @return
@ -107,6 +112,12 @@ private:
* @brief * @brief
*/ */
void saveDone(); void saveDone();
/**
* @brief
* @return
*/
bool reconnect();
}; };
#endif // CFFMPEG_DECODE_H #endif // CFFMPEG_DECODE_H

@ -65,6 +65,7 @@ void ffmpegvideoDlg::play(QString url) {
*/ */
void ffmpegvideoDlg::stop() { void ffmpegvideoDlg::stop() {
if (m_PlayStatus) { if (m_PlayStatus) {
ffmpeg->stopPull();
ffmpeg->stop(); ffmpeg->stop();
m_PlayStatus = false; m_PlayStatus = false;
ffmpeg->IsstopPlay = true; // 线程结束标志 ffmpeg->IsstopPlay = true; // 线程结束标志

@ -2,7 +2,7 @@
global::global() {} global::global() {}
QString g_SoftwareVersion = "版本号V1.0.0.1011"; QString g_SoftwareVersion = "版本号V1.0.0.1014";
QColor g_themeColor(51, 51, 51); QColor g_themeColor(51, 51, 51);
QString g_PushBtnStyle = /**正常情况下样式**/ QString g_PushBtnStyle = /**正常情况下样式**/

Loading…
Cancel
Save