AVFormatContext *outputFormatCtx = nullptr;
// 创建输出上下文
avformat_alloc_output_context2(&outputFormatCtx, nullptr, "mp4", m_outputFile.toStdString().c_str());
//记录字幕流
int subtitleStreamIndex = -1;
int video_stream_index = -1;
int audio_stream_index = -1;
// 初始化输出流索引
int out_video_idx = -1;
int out_audio_idx = -1;
if(m_inFormatContext != nullptr)
{
//复制输入流信息
for (int i = 0; i < m_inFormatContext->nb_streams; i++)
{
AVStream* inStream = m_inFormatContext->streams[i];
AVCodecParameters* codecPar = inStream->codecpar;
// 跳过不需要的流类型
if (codecPar->codec_type == AVMEDIA_TYPE_SUBTITLE)
{
subtitleStreamIndex = i;
continue;
}
else if(codecPar->codec_type == AVMEDIA_TYPE_VIDEO)
{
video_stream_index = i;
}
else if(codecPar->codec_type == AVMEDIA_TYPE_AUDIO)
{
audio_stream_index = i;
}
// 创建输出流
AVStream* outStream = avformat_new_stream(outputFormatCtx, nullptr);
if (!outStream) {
qWarning() << "Failed to create output stream for stream" << i;
continue;
}
// 复制编解码参数
int ret = avcodec_parameters_copy(outStream->codecpar, codecPar);
if (ret < 0)
{
qWarning() << "Failed to copy codec parameters for stream" << i;
avformat_free_context(outputFormatCtx);
}
outStream->time_base = inStream->time_base;
}
}
//打开输出文件
avio_open(&outputFormatCtx->pb, m_outputFile.toStdString().c_str(), AVIO_FLAG_WRITE);
//写输出文件头
avformat_write_header(outputFormatCtx, nullptr);
//确保第一帧是i帧
bool firstKeyFrameWritten = false;
//记录开始时间锉
int64_t start_pts_v = AV_NOPTS_VALUE;
int64_t start_pts_a = AV_NOPTS_VALUE;
int64_t start_dts_v = AV_NOPTS_VALUE;
int64_t start_dts_a = AV_NOPTS_VALUE;
while(m_downVideoCtl == 1)
{
//qDebug() << "while....";
if(m_frameQueue.isEmpty())
{
qDebug() << "not found pack....";
QThread::sleep(1);
}
AVPacket* packet = m_frameQueue.dequeue();
if (packet->stream_index == subtitleStreamIndex || packet->stream_index == audio_stream_index)
{
av_packet_free(&packet);
continue;
}
// 强制第一帧必须是视频关键帧
if (!firstKeyFrameWritten)
{
// 情况1: 当前包是视频关键帧 -> 允许处理
if (packet->stream_index == video_stream_index &&
(packet->flags & AV_PKT_FLAG_KEY))
{
firstKeyFrameWritten = true;
}
// 情况2: 其他情况 -> 丢弃包
else {
av_packet_free(&packet);
continue; // 跳过所有非视频关键帧
}
}
// 时间戳初始化(仅处理有效包后执行)
if (packet->stream_index == video_stream_index) {
if (start_pts_v == AV_NOPTS_VALUE && packet->pts != AV_NOPTS_VALUE && packet->dts != AV_NOPTS_VALUE) {
start_pts_v = packet->pts;
start_dts_v = packet->dts;
qDebug() << "Video start PTS initialized:" << start_pts_v;
qDebug() << "Video start DTS initialized:" << start_dts_v;
// 获取视频流的 AVStream
AVStream *video_stream = outputFormatCtx->streams[video_stream_index];
AVRational time_base = video_stream->time_base;
// 打印时间基(分子/分母)
qDebug() << "Video time base:" << time_base.num << "/" << time_base.den;
}
}
else if (packet->stream_index == audio_stream_index) {
if (start_pts_a == AV_NOPTS_VALUE && packet->pts != AV_NOPTS_VALUE && packet->dts != AV_NOPTS_VALUE)
{
start_pts_a = packet->pts;
start_dts_a = packet->dts;
qDebug() << "Audio start PTS initialized:" << start_pts_a;
}
}
qDebug() << "pack frame....";
// 时间戳调整(带有效性检查)
if (packet->pts != AV_NOPTS_VALUE) {
if (packet->stream_index == video_stream_index && start_pts_v != AV_NOPTS_VALUE)
{
packet->pts -= start_pts_v;
packet->dts -= start_dts_v;
// packet->dts -= start_pts_v;
}
else if (packet->stream_index == audio_stream_index && start_pts_a != AV_NOPTS_VALUE)
{
packet->pts -= start_pts_a;
packet->dts -= start_dts_a;
// packet->dts -= start_pts_a;
}
}
qDebug() << QString("pts:%1, dts:%2").arg(packet->pts).arg(packet->dts);
av_interleaved_write_frame(outputFormatCtx, packet);
qDebug() << "av_interleaved_write_frame end....";
av_packet_free(&packet);
}
// 清理资源
av_write_trailer(outputFormatCtx);
avformat_free_context(outputFormatCtx);
av_interleaved_write_frame,这个函数使用时出现崩溃问题,后续查询发现在保存为mp4时,音频格式必须是aac格式,否者会出现崩溃问题。