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