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