#include "pushstream.h" PushStream::PushStream(QObject *parent) : QObject{parent} {} void PushStream::setRemoteIP(QString url) { m_pushStreamIP = url; } bool PushStream::init(AVFormatContext *inputFormatCtx, AVPacketQueueManager *queueManager) { // m_pusherQueue = queue; m_queueManager = queueManager; m_inputFormatCtx = inputFormatCtx; m_start = openNetworkStream(inputFormatCtx); return m_start; } void PushStream::close() { // QMutexLocker locker(&m_mutex); m_start = false; m_end = true; // qDebug() << "*******m_end0:" << m_end; } bool PushStream::openNetworkStream(AVFormatContext *inputFormatCtx) { if (m_pushStreamIP.isEmpty()) return false; if (!inputFormatCtx) return false; // 初始化网络输出流 // QString m_pushStreamIP = "rtsp://182.92.130.23/app/stream999"; int ret = avformat_alloc_output_context2( &m_outputFormatCtx, NULL, "flv", m_pushStreamIP.toUtf8().constData()); if (ret < 0) { showError(ret); free(); qDebug() << "Could not create output context."; return false; } // 复制流信息 for (unsigned int i = 0; i < inputFormatCtx->nb_streams; ++i) { // AVStream *stream = inputFormatCtx->streams[i]; if (inputFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { m_istream = inputFormatCtx->streams[i]; m_ostream = avformat_new_stream(m_outputFormatCtx, nullptr); if (!m_ostream) { qDebug() << "Failed allocating output stream.\n"; free(); return false; } // 复制编解码器参数 ret = avcodec_parameters_copy(m_ostream->codecpar, m_istream->codecpar); if (ret < 0) { showError(ret); free(); qWarning() << "avcodec_parameters_from_context Failed"; return false; } // outputStream->codecpar = inputStream->codecpar; m_ostream->codecpar->codec_tag = 0; break; } } m_inputTimeBase = m_istream->time_base; m_inputFrameRate = m_istream->r_frame_rate; m_outputTimeBase = m_ostream->time_base; // 打开输出文件 if (!(m_outputFormatCtx->flags & AVFMT_NOFILE)) { if (ret = avio_open(&m_outputFormatCtx->pb, m_pushStreamIP.toUtf8().constData(), AVIO_FLAG_WRITE) < 0) { showError(ret); free(); qDebug() << "Could not open output file.\n"; return false; } } // 写入头文件 ret = avformat_write_header(m_outputFormatCtx, NULL); if (ret < 0) { showError(ret); free(); qDebug() << "Error occurred when write_header into output file.\n"; return false; } // sendSPS_PPS(inputFormatCtx, outputFormatCtx); // m_InitStatus = true; // startTime = av_gettime_relative(); m_bwriteHeader = true; m_firstPts = AV_NOPTS_VALUE; return true; } int PushStream::reconnect(int ret) { if (ret == -10053 || ret == -10054) { m_end = false; // qDebug() << "m_end:" << m_end; for (int nRetryCount = 0; nRetryCount < MAXCONNECT; ++nRetryCount) { // 关闭输出 if (m_outputFormatCtx && !(m_outputFormatCtx->flags & AVFMT_NOFILE)) { avio_close(m_outputFormatCtx->pb); } ret = avio_open(&m_outputFormatCtx->pb, m_pushStreamIP.toUtf8().constData(), AVIO_FLAG_WRITE); if (ret < 0) { showError(ret); qDebug() << "Failed to reconnect" << QString::number(nRetryCount + 1); QString str = QString("网络中断,尝试重连第%1次!").arg(nRetryCount + 1); emit sendErrorMessageSignal(str, 3); if (m_end) break; // av_usleep(5 * 1000000); continue; } // Try to reconnect ret = avformat_write_header(m_outputFormatCtx, nullptr); if (ret < 0) { showError(ret); // free(); qDebug() << "Failed to reconnect" << QString::number(nRetryCount + 1); QString str = QString("网络中断,尝试重连第%1次!").arg(nRetryCount + 1); emit sendErrorMessageSignal(str, 3); if (m_end) break; // nRetryCount++; // av_usleep(5 * 1000000); } else { m_start = true; m_firstPts = AV_NOPTS_VALUE; m_frm_cnt = 0; m_bwriteHeader = true; emit sendErrorMessageSignal("重连成功!", 1); m_queueManager->clearPushQueue(); qDebug() << "重连成功!"; return ret; } if (m_end) break; } m_start = false; m_bwriteHeader = false; emit sendErrorMessageSignal("重连失败,推流停止!", 2); return -1; } } void PushStream::pushStream(int64_t startTime) { qDebug() << "PushStreamThreadID:" << QThread::currentThreadId(); // m_startTime = startTime; while (m_start) { AVPacket *inputPacket = m_queueManager->dequeuePushPacket(); if (inputPacket) { if (inputPacket->data == nullptr || inputPacket->size <= 0 || inputPacket->pts <= 0) { // av_packet_unref(inputPacket); continue; } int outputStreamIndex = 0; // int inputStreamIndex = inputPacket->stream_index; // AVStream *istream = m_inputFormatCtx->streams[inputStreamIndex]; // AVStream *ostream = // m_outputFormatCtx->streams[outputStreamIndex]; 时间基 // AVRational istream_base = m_istream->time_base; // AVRational ostream_base = ostream->time_base; // 没有pts的视频数据,如未解码的H.264裸流,需要重新计算其pts。 if (inputPacket->pts == AV_NOPTS_VALUE) { // Duration between 2 frames (us) int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(m_inputFrameRate); // Reset Parameters inputPacket->pts = (double)(m_frm_cnt * calc_duration) / (double)(av_q2d(m_inputTimeBase) * AV_TIME_BASE); inputPacket->dts = inputPacket->pts; inputPacket->duration = (double)calc_duration / (double)(av_q2d(m_inputTimeBase) * AV_TIME_BASE); } // 视频帧推送速度 if (m_firstPts == AV_NOPTS_VALUE) { m_startTime = av_gettime(); m_firstPts = av_rescale_q(inputPacket->dts, m_inputTimeBase, AVRational{1, AV_TIME_BASE}); } auto pts_time = av_rescale_q(inputPacket->pts, m_inputTimeBase, AVRational{1, AV_TIME_BASE}); int64_t pts_time_corrected = pts_time - m_firstPts; auto now_time = av_gettime() - m_startTime; int64_t delay = pts_time_corrected - now_time; // qDebug() << "****************PushStream sleep time:" // << QString::number(delay / 1000); // delay = delay < MAXDELAY ? delay : MAXDELAY; if (delay > 0) { // qDebug() << "****************PushStream sleep time:" // << QString::number(delay / 1000); av_usleep(delay); // sleepMsec(40); } else { if (delay < -50000) { // 滞后50ms以上,丢弃非重要帧 if (!(inputPacket->flags & AV_PKT_FLAG_KEY)) { av_packet_unref(inputPacket); continue; } // 调整基准时间,减少滞后 m_startTime += 50000; } } // 计算延时后,重新指定时间戳 av_packet_rescale_ts(inputPacket, m_inputTimeBase, m_outputTimeBase); inputPacket->pos = -1; inputPacket->stream_index = 0; if (inputPacket->pts < inputPacket->dts) { // qDebug() << "pts < dts"; if (!(inputPacket->flags & AV_PKT_FLAG_KEY)) { av_packet_unref(inputPacket); continue; } } // 向推流服务器推送流数据 m_frm_cnt++; int ret = av_interleaved_write_frame(m_outputFormatCtx, inputPacket); if (ret < 0) { av_packet_unref(inputPacket); showError(ret); // if (ret == -10053) { // qDebug() << "网络不稳定"; // } if (reconnect(ret) < 0) { break; }; continue; } // 数据包写入成功,现在可以释放pkt av_packet_unref(inputPacket); av_packet_free(&inputPacket); } else { QThread::usleep(1000); } } if (m_bwriteHeader) av_write_trailer(m_outputFormatCtx); free(); qDebug() << "Push Stream End!"; emit sendErrorMessageSignal("推流结束!", NotificationType::NOTIFICATION_SUCCESS); } void PushStream::free() { m_start = false; // 关闭输出 if (m_outputFormatCtx && !(m_outputFormatCtx->flags & AVFMT_NOFILE)) { avio_close(m_outputFormatCtx->pb); } if (m_outputFormatCtx) { avformat_free_context(m_outputFormatCtx); m_outputFormatCtx = nullptr; } }