fix: 推流优化,光电吊舱暂未设置

pull/14/head
cbwu 6 months ago
parent 6861abaf29
commit d0db97d0e6

@ -143,11 +143,13 @@ void Cffmpeg_decode::run() {
IsstopPlay = true; IsstopPlay = true;
return; return;
} }
if (bRecordTime) { // if (bRecordTime) {
// startTime = av_gettime();
// qDebug() << "*******StartTime:" << QString::number(startTime);
// bRecordTime = false;
// }
firstDts = AV_NOPTS_VALUE; // 初始化第一帧的DTS
startTime = av_gettime(); startTime = av_gettime();
qDebug() << "*******StartTime:" << QString::number(startTime);
bRecordTime = false;
}
// 读取数据包 // 读取数据包
while (av_read_frame(inputFormatCtx, inputPacket) >= 0) { while (av_read_frame(inputFormatCtx, inputPacket) >= 0) {
if (IsstopPlay) { if (IsstopPlay) {
@ -155,14 +157,20 @@ void Cffmpeg_decode::run() {
break; break;
} }
// 第一次获取时间设置起始DTS
if (firstDts == AV_NOPTS_VALUE) {
firstDts = inputPacket->dts;
startTime = av_gettime(); // 记录第一个包到来的系统时间
}
if (inputPacket->stream_index == videoStreamIndex) { if (inputPacket->stream_index == videoStreamIndex) {
// 推流 // 推流
if (bPushStreamFlag) { if (bPushStreamFlag) {
// av_packet_clone(inputPacket); // av_packet_clone(inputPacket);
AVPacket *outputPacket = av_packet_clone(inputPacket); AVPacket *outputPacket = av_packet_clone(inputPacket);
emit sendStreamData_Signal(outputPacket, frm_cnt); emit sendStreamData_Signal(outputPacket, frm_cnt, startTime, firstDts);
} }
// qDebug() << "******拉流" << QString::number(frm_cnt++);
// 保存裸流 // 保存裸流
if (m_formatContextSave) { if (m_formatContextSave) {
// 由于保存的m_formatContextSave只创建了一个视频流而读取到的图像的流索引不一定为0可能会出现错误【Invalid // 由于保存的m_formatContextSave只创建了一个视频流而读取到的图像的流索引不一定为0可能会出现错误【Invalid
@ -200,8 +208,8 @@ void Cffmpeg_decode::run() {
} }
} }
av_packet_unref(inputPacket); av_packet_unref(inputPacket);
frm_cnt++;
} }
frm_cnt++;
if (IsstopPlay) { if (IsstopPlay) {
if (m_formatContextSave) { if (m_formatContextSave) {
saveDone(); saveDone();
@ -241,6 +249,10 @@ void Cffmpeg_decode::stop() {
avcodec_close(decoderCtx); avcodec_close(decoderCtx);
if (!inputFormatCtx) if (!inputFormatCtx)
avformat_close_input(&inputFormatCtx); avformat_close_input(&inputFormatCtx);
// 停止推流
bPushStreamFlag = false;
emit sendStopPushStream_Signal();
} }
void Cffmpeg_decode::setSaveFileDirPath(QString fileDirPath) { void Cffmpeg_decode::setSaveFileDirPath(QString fileDirPath) {

@ -35,7 +35,9 @@ signals:
void sendQImage(QImage); void sendQImage(QImage);
void sendConnectFail(int); void sendConnectFail(int);
void sendInitPushStream_Signal(AVFormatContext *inputFormatCtx); void sendInitPushStream_Signal(AVFormatContext *inputFormatCtx);
void sendStreamData_Signal(AVPacket *pkt, int frm_cnt); void sendStreamData_Signal(AVPacket *pkt, int frm_cnt, int64_t startTime,
int64_t firstDts);
void sendStopPushStream_Signal();
public: public:
bool IsstopPlay = false; bool IsstopPlay = false;
@ -67,7 +69,8 @@ private:
QString _url; QString _url;
QString saveFileDirPath; QString saveFileDirPath;
bool bRecordTime = true; bool bRecordTime = true;
long long startTime; int64_t startTime;
int64_t firstDts;
/******** 保存裸流使用 ******************/ /******** 保存裸流使用 ******************/
AVFormatContext *m_formatContextSave = nullptr; // 封装上下文 AVFormatContext *m_formatContextSave = nullptr; // 封装上下文
QString m_strCodecName; // 编解码器名称 QString m_strCodecName; // 编解码器名称

@ -40,7 +40,7 @@ int FFmpegPushStream::openNetworkStream(AVFormatContext *inputFormatCtx) {
return -1; return -1;
} }
// outputStream->codecpar = inputStream->codecpar; // outputStream->codecpar = inputStream->codecpar;
// outputStream->codecpar->codec_tag = 0; outputStream->codecpar->codec_tag = 0;
// outputStream->time_base.num = 1; // outputStream->time_base.num = 1;
break; break;
} }
@ -62,16 +62,26 @@ int FFmpegPushStream::openNetworkStream(AVFormatContext *inputFormatCtx) {
} }
mInitStatus = true; mInitStatus = true;
this->inputFormatCtx = inputFormatCtx; this->inputFormatCtx = inputFormatCtx;
startTime = av_gettime_relative();
return 1; return 1;
} }
int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt) { /**
* @brief
* @param pkt:
* @param frm_cnt:
* @param startTime:
* @param firstDts: dts
* @return
*/
int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt, int64_t startTime,
int64_t firstDts) {
if (!mInitStatus) if (!mInitStatus)
return -1; return -1;
if (pkt->dts <= 0) if (pkt->dts <= 0)
return -1; return -1;
// qDebug() << "******推流" << QString::number(frm_cnt++);
int inputStreamIndex = pkt->stream_index; int inputStreamIndex = pkt->stream_index;
int outputStreamIndex = 0; int outputStreamIndex = 0;
// 没有pts的视频数据如未解码的H.264裸流需要重新计算其pts。 // 没有pts的视频数据如未解码的H.264裸流需要重新计算其pts。
@ -88,6 +98,22 @@ int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt) {
pkt->duration = pkt->duration =
(double)calc_duration / (double)(av_q2d(time_base) * AV_TIME_BASE); (double)calc_duration / (double)(av_q2d(time_base) * AV_TIME_BASE);
} }
// 视频帧推送速度
firstDts = av_rescale_q(firstDts,
inputFormatCtx->streams[inputStreamIndex]->time_base,
AVRational{1, AV_TIME_BASE});
auto pts_time = av_rescale_q(
pkt->dts, inputFormatCtx->streams[inputStreamIndex]->time_base,
AVRational{1, AV_TIME_BASE});
int64_t streamTime = pts_time - firstDts; // 计算帧的相对时间
auto now_time = av_gettime() - startTime; // 获取差值
int64_t delay = streamTime - now_time;
if (delay > 0) {
// qDebug() << "****************sleep time:" << QString::number(delay);
av_usleep(delay);
}
// 计算延时后,重新指定时间戳 // 计算延时后,重新指定时间戳
AVRational istream_base = AVRational istream_base =
inputFormatCtx->streams[inputStreamIndex]->time_base; inputFormatCtx->streams[inputStreamIndex]->time_base;
@ -108,15 +134,6 @@ int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt) {
return 1; return 1;
} }
// 视频帧推送速度
auto pts_time = av_rescale_q(pkt->dts, ostream_base, AVRational{1, 1000});
auto now_time = av_gettime() / 1000;
if (pts_time > now_time) {
qDebug() << "****************sleep time:"
<< QString::number(pts_time - now_time);
av_usleep(static_cast<std::uint32_t>(pts_time - now_time));
}
// 向推流服务器推送流数据 // 向推流服务器推送流数据
pkt->stream_index = 0; pkt->stream_index = 0;
int ret = av_interleaved_write_frame(outputFormatCtx, pkt); int ret = av_interleaved_write_frame(outputFormatCtx, pkt);
@ -126,3 +143,20 @@ int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt) {
// 数据包写入成功现在可以释放pkt // 数据包写入成功现在可以释放pkt
av_packet_unref(pkt); av_packet_unref(pkt);
} }
/**
* @brief
*/
void FFmpegPushStream::stopPush() {
av_write_trailer(outputFormatCtx);
if (inputFormatCtx != nullptr) {
avformat_close_input(&inputFormatCtx);
}
// 关闭输出
if (outputFormatCtx && !(outputFormatCtx->flags & AVFMT_NOFILE)) {
avio_close(outputFormatCtx->pb);
}
if (outputFormatCtx) {
avformat_free_context(outputFormatCtx);
}
}

@ -19,13 +19,14 @@ signals:
private: private:
AVFormatContext *inputFormatCtx = nullptr; // AVFormatContext *inputFormatCtx = nullptr; //
AVFormatContext *outputFormatCtx = NULL; // AVFormatContext *outputFormatCtx = NULL; //
AVCodecContext *encoderCtx = nullptr; //
const AVCodec *encoder = nullptr; // 编码器
int videoIndex = -1; int videoIndex = -1;
QString pushStreamIP; // 推流地址 QString pushStreamIP; // 推流地址
bool mInitStatus = false; bool mInitStatus = false;
int64_t startTime;
public slots: public slots:
int pushStream(AVPacket *pkt, int frm_cnt); int pushStream(AVPacket *pkt, int frm_cnt, int64_t startTime,
int64_t firstDts);
void stopPush();
int openNetworkStream(AVFormatContext *inputFormatCtx); int openNetworkStream(AVFormatContext *inputFormatCtx);
}; };

@ -32,7 +32,7 @@ void ffmpegvideoDlg::play(QString url) {
ffmpeg->setSaveFileDirPath(videoSaveDirPath); ffmpeg->setSaveFileDirPath(videoSaveDirPath);
ffmpeg->IsstopPlay = false; ffmpeg->IsstopPlay = false;
if (!pushStreamIP.isEmpty()) // 推流 if (!pushStreamIP.isEmpty()) // 推流
startPushStream(m_PlayStatus); startPushStream();
ffmpeg->moveToThread(&workerThread); ffmpeg->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, ffmpeg, connect(&workerThread, &QThread::finished, ffmpeg,
@ -57,8 +57,6 @@ void ffmpegvideoDlg::stop() {
ffmpeg->stop(); ffmpeg->stop();
m_PlayStatus = false; m_PlayStatus = false;
ffmpeg->IsstopPlay = true; // 线程结束标志 ffmpeg->IsstopPlay = true; // 线程结束标志
if (!pushStreamIP.isEmpty()) // 停止推流
startPushStream(m_PlayStatus);
workerThread.quit(); // 线程退出时自动delete线程里的类 workerThread.quit(); // 线程退出时自动delete线程里的类
workerThread.wait(); workerThread.wait();
img.fill(Qt::black); img.fill(Qt::black);
@ -113,8 +111,7 @@ bool ffmpegvideoDlg::Isplay(bool IsstopPlay) {
return ffmpeg->IsstopPlay = IsstopPlay; return ffmpeg->IsstopPlay = IsstopPlay;
} }
void ffmpegvideoDlg::startPushStream(bool bPush) { void ffmpegvideoDlg::startPushStream() {
if (bPush) {
if (ffmpegPushStream == nullptr) { if (ffmpegPushStream == nullptr) {
ffmpegPushStream = new FFmpegPushStream; ffmpegPushStream = new FFmpegPushStream;
ffmpegPushStream->setRemoteIP(pushStreamIP); // 设置推流地址 ffmpegPushStream->setRemoteIP(pushStreamIP); // 设置推流地址
@ -125,15 +122,13 @@ void ffmpegvideoDlg::startPushStream(bool bPush) {
pushStreamThread->start(); pushStreamThread->start();
ffmpegPushStream->moveToThread(pushStreamThread); ffmpegPushStream->moveToThread(pushStreamThread);
} }
connect(ffmpeg, &Cffmpeg_decode::sendInitPushStream_Signal, connect(ffmpeg, &Cffmpeg_decode::sendInitPushStream_Signal, ffmpegPushStream,
ffmpegPushStream, &FFmpegPushStream::openNetworkStream); &FFmpegPushStream::openNetworkStream);
connect(ffmpeg, &Cffmpeg_decode::sendStreamData_Signal, ffmpegPushStream, connect(ffmpeg, &Cffmpeg_decode::sendStreamData_Signal, ffmpegPushStream,
&FFmpegPushStream::pushStream); &FFmpegPushStream::pushStream);
connect(ffmpeg, &Cffmpeg_decode::sendStopPushStream_Signal, ffmpegPushStream,
&FFmpegPushStream::stopPush);
ffmpeg->bPushStreamFlag = true; ffmpeg->bPushStreamFlag = true;
} else {
if (ffmpeg)
ffmpeg->bPushStreamFlag = false;
}
} }
void ffmpegvideoDlg::setPushStreamIP(QString pushStreamURL) { void ffmpegvideoDlg::setPushStreamIP(QString pushStreamURL) {

@ -28,7 +28,7 @@ public:
void play(QString); void play(QString);
void stop(); void stop();
bool Isplay(bool IsstopPlay); bool Isplay(bool IsstopPlay);
void startPushStream(bool bPush); void startPushStream();
void setPushStreamIP(QString pushStreamURL); void setPushStreamIP(QString pushStreamURL);
private: private:

Loading…
Cancel
Save