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

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

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

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

@ -40,7 +40,7 @@ int FFmpegPushStream::openNetworkStream(AVFormatContext *inputFormatCtx) {
return -1;
}
// outputStream->codecpar = inputStream->codecpar;
// outputStream->codecpar->codec_tag = 0;
outputStream->codecpar->codec_tag = 0;
// outputStream->time_base.num = 1;
break;
}
@ -62,16 +62,26 @@ int FFmpegPushStream::openNetworkStream(AVFormatContext *inputFormatCtx) {
}
mInitStatus = true;
this->inputFormatCtx = inputFormatCtx;
startTime = av_gettime_relative();
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)
return -1;
if (pkt->dts <= 0)
return -1;
// qDebug() << "******推流" << QString::number(frm_cnt++);
int inputStreamIndex = pkt->stream_index;
int outputStreamIndex = 0;
// 没有pts的视频数据如未解码的H.264裸流需要重新计算其pts。
@ -88,6 +98,22 @@ int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt) {
pkt->duration =
(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 =
inputFormatCtx->streams[inputStreamIndex]->time_base;
@ -108,15 +134,6 @@ int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt) {
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;
int ret = av_interleaved_write_frame(outputFormatCtx, pkt);
@ -126,3 +143,20 @@ int FFmpegPushStream::pushStream(AVPacket *pkt, int frm_cnt) {
// 数据包写入成功现在可以释放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:
AVFormatContext *inputFormatCtx = nullptr; //
AVFormatContext *outputFormatCtx = NULL; //
AVCodecContext *encoderCtx = nullptr; //
const AVCodec *encoder = nullptr; // 编码器
int videoIndex = -1;
QString pushStreamIP; // 推流地址
bool mInitStatus = false;
int64_t startTime;
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);
};

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

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

Loading…
Cancel
Save