ffmpeg下载rtsp为mp4时,av_interleaved_write_frame这个函数崩溃原因。

    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格式,否者会出现崩溃问题。

FFmpeg库中处理RTSP流并进行解封装和输出操作通常涉及到以下几个步骤。首先,你需要创建`AVFormatContext`结构体的实例,这个结构是FFmpeg的核心,用于描述媒体文件或网络流。以下是一个简单的示例源代码片段,展示了如何使用`avformat_open_input`和`avformat_alloc_output_context2`打开RTSP流并配置输出: ```cpp #include <libavformat/avformat.h> int main() { // 创建输入上下文 const char* rtsp_url = "rtsp://your_rtspserver_address/stream_name"; AVFormatContext *fmt_ctx = NULL; if (avformat_open_input(&amp;fmt_ctx, rtsp_url, NULL, NULL) != 0) { fprintf(stderr, "Error opening input context: %s\n", av_err2str(av_errno)); return -1; } // 解析输入信息 if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { fprintf(stderr, "Error finding stream info: %s\n", av_err2str(av_errno)); avformat_close_input(&amp;fmt_ctx); return -1; } // 创建输出上下文 const char* output_filename = "output.mp4"; AVOutputFormat *out_fmt = NULL; if (!(out_fmt = av_guess_format("mp4", NULL, NULL))) { fprintf(stderr, "Failed to guess output format: %s\n", av_strerror(avformat_get_error())); } AVOutputStream *out_file = avformat_alloc_output_context2(NULL, out_fmt, NULL, output_filename); // 设置输出流的属性 if (!out_file) { fprintf(stderr, "Failed to allocate output context: %s\n", av_err2str(av_errno)); avformat_close_input(&amp;fmt_ctx); return -1; } for (int i = 0; i < fmt_ctx->nb_streams; i++) { AVStream *in_stream = fmt_ctx->streams[i]; AVStream *out_stream = avcodec_copy_stream(out_file, in_stream); if (!out_stream) { fprintf(stderr, "Failed to copy stream %d: %s\n", i, av_err2str(av_errno)); continue; } av_register_side_data[out_stream->codec->codec_type][AV_PKT_FLAG_KEY] = avcodec_default_side_data[out_stream->codec->codec_type]; } // 打开输出文件 int ret = avio_open(&amp;out_file->pb, output_filename, AVIO_FLAG_WRITE); if (ret < 0) { fprintf(stderr, "Failed to open output file: %s\n", av_err2str(av_errno)); avformat_close_input(&amp;fmt_ctx); avformat_free_output_context(out_file); return -1; } // 开始实际的编码和流写入过程 if (avformat_write_header(out_file, &amp;fmt_ctx->metadata) < 0) { fprintf(stderr, "Error writing header: %s\n", av_err2str(av_errno)); avio_close(out_file->pb); avformat_close_input(&amp;fmt_ctx); avformat_free_output_context(out_file); return -1; } // 现在可以开始实际的数据写入循环,例如: while (true) { int64_t size = av_read_frame(fmt_ctx, NULL); // 根据需要替换为合适的帧读取函数 if (size == AVERROR_EOF || size < 0) { break; } av_interleaved_write_frame(out_file, fmt_ctx->data[0]); } // 结束关闭文件并释放资源 av_write_trailer(out_file); avio_close(out_file->pb); avformat_close_input(&amp;fmt_ctx); avformat_free_output_context(out_file); return 0; } ``` 请注意,这只是一个基本的示例,实际应用中你可能需要添加错误处理和其他细节,比如处理不同的帧读取函数、数据分片等。同,这个例子假设你已经包含了必要的FFmpeg库头文件并且链接了FFmpeg库。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值