使用 FFmpeg 推流 RTSP 视频 - 完整教程及常见问题解决

本文将介绍如何使用 FFmpeg 推流 RTSP 视频,并提供完整的代码示例以及常见问题的解决方法,帮助您快速入门 RTSP 视频推流。

1. 初始化 FFmpeg 库

av_register_all();
avformat_network_init();

2. 打开视频文件

AVFormatContext *formatContext = avformat_alloc_context();
if (avformat_open_input(&formatContext, 'path/to/your/mp4/file.mp4', nullptr, nullptr) != 0) {
    qDebug() << 'Failed to open video file';
    return -1;
}

3. 查找视频流

if (avformat_find_stream_info(formatContext, nullptr) < 0) {
    qDebug() << 'Failed to find video stream';
    return -1;
}

int videoStreamIndex = -1;
for (int i = 0; i < formatContext->nb_streams; i++) {
    if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        videoStreamIndex = i;
        break;
    }
}

if (videoStreamIndex == -1) {
    qDebug() << 'Failed to find video stream';
    return -1;
}

4. 获取视频流的解码器上下文

AVCodecContext *codecContext = avcodec_alloc_context3(nullptr);
avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar);

5. 查找解码器

AVCodec *codec = avcodec_find_decoder(codecContext->codec_id);
if (codec == nullptr) {
    qDebug() << 'Failed to find video decoder';
    return -1;
}

6. 打开解码器

if (avcodec_open2(codecContext, codec, nullptr) < 0) {
    qDebug() << 'Failed to open video decoder';
    return -1;
}

7. 创建视频帧

AVFrame *frame = av_frame_alloc();
AVFrame *rgbFrame = av_frame_alloc();

8. 计算帧大小并分配帧缓冲区

int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1);
uint8_t *buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, buffer, AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1);

9. 创建图像转换上下文

struct SwsContext *swsContext = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt,
                                                  codecContext->width, codecContext->height, AV_PIX_FMT_RGB24,
                                                  SWS_BILINEAR, nullptr, nullptr, nullptr);

10. 创建 RTSP 流的上下文并设置输出格式

AVFormatContext *rtspFormatContext = avformat_alloc_context();
AVOutputFormat *outputFormat = av_guess_format('rtsp', nullptr, nullptr);
rtspFormatContext->oformat = outputFormat;

11. 打开 RTSP 流

if (avio_open(&rtspFormatContext->pb, 'RTSP_URL', AVIO_FLAG_WRITE) < 0) {
    qDebug() << 'Failed to open RTSP stream';
    return -1;
}

12. 添加视频流到 RTSP 流

AVStream *rtspStream = avformat_new_stream(rtspFormatContext, nullptr);
avcodec_parameters_copy(rtspStream->codecpar, codecContext->codecpar);
rtspStream->codecpar->codec_tag = 0;
rtspStream->time_base = codecContext->time_base;

13. 写入 RTSP 流的头部

avformat_write_header(rtspFormatContext, nullptr);

14. 推送视频流到 RTSP 服务器

// 定义开始时间
qint64 startTime = QDateTime::currentMSecsSinceEpoch();

AVPacket packet;
while (av_read_frame(formatContext, &packet) >= 0) {
    if (packet.stream_index == videoStreamIndex) {
        // 解码视频帧
        if (avcodec_send_packet(codecContext, &packet) >= 0) {
            while (avcodec_receive_frame(codecContext, frame) >= 0) {
                // 转换图像格式
                sws_scale(swsContext, frame->data, frame->linesize, 0, codecContext->height, rgbFrame->data, rgbFrame->linesize);

                // 设置时间戳
                qint64 currentTime = QDateTime::currentMSecsSinceEpoch() - startTime;
                rgbFrame->pts = av_rescale_q(currentTime, AV_TIME_BASE_Q, codecContext->time_base);

                // 编码并写入 RTSP 流
                av_interleaved_write_frame(rtspFormatContext, &packet);
            }
        }
    }

    av_packet_unref(&packet);
}

15. 写入 RTSP 流的尾部

av_write_trailer(rtspFormatContext);

16. 清理资源

avformat_close_input(&formatContext);
avcodec_free_context(&codecContext);
av_frame_free(&frame);
av_frame_free(&rgbFrame);
av_free(buffer);
avformat_free_context(rtspFormatContext);

常见问题解决

1. avcodec_parameters_copy(rtspStream->codecpar, codecContext->codecpar); 报错

该错误表示无法复制解码器上下文中的编解码器参数到 RTSP 流中的编解码器参数。这可能是由于编解码器参数类型不匹配导致的。

解决方法:

  • 使用 avcodec_copy_context 函数来复制解码器上下文中的参数,而不是使用 avcodec_parameters_copy 函数。
avcodec_copy_context(rtspStream->codec, codecContext);
  • 如果使用 avcodec_copy_context 函数仍然导致错误,可以尝试手动复制每个参数。
rtspStream->codecpar->codec_type = codecContext->codec_type;
rtspStream->codecpar->codec_id = codecContext->codec_id;
rtspStream->codecpar->bit_rate = codecContext->bit_rate;
// 继续复制其他参数...

请注意,根据 FFmpeg 版本的不同,代码可能需要进行相应的调整。另外,确保 RTSP_URL 变量包含正确的 RTSP 服务器 URL。

总结

本文详细介绍了使用 FFmpeg 推流 RTSP 视频的完整流程,并提供了一些常见问题的解决方法。希望本文能帮助您快速入门 RTSP 视频推流,并顺利实现您的项目需求。

FFmpeg 推流 RTSP 视频 - 完整教程及常见问题解决

原文地址: https://www.cveoy.top/t/topic/pxe8 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录