FFmpeg实现RTSP推流

以下是的示例代码,演示了如何从本地文件(mp4)读取媒体流,并将其推送到 RTSP 服务器:
代码未经验证,供参考

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>

#define RTPPKT_LEN 1400

// TCP Socket
int tcpSocket;

// TCP 发送函数
int tcp_write_buffer(void* opaque, uint8_t* buf, int buf_size) {
    ssize_t sentBytes = send(tcpSocket, buf, buf_size, 0);
    if (sentBytes < 0) {
        perror("TCP 发送失败");
        return -1;
    }

    return 0;
}

int main() {
    // 初始化 FFmpeg 库
    av_register_all();
    avformat_network_init();

    // 创建 TCP Socket
    tcpSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpSocket < 0) {
        perror("无法创建 TCP Socket");
        return -1;
    }

    // 连接目标服务器
    struct sockaddr_in destAddr;
    memset(&destAddr, 0, sizeof(destAddr));
    destAddr.sin_family = AF_INET;
    destAddr.sin_port = htons(1234); // 设置目标端口号
    destAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置目标 IP 地址

    int ret = connect(tcpSocket, (struct sockaddr*)&destAddr, sizeof(destAddr));
    if (ret < 0) {
        perror("无法连接到服务器");
        return -1;
    }

    // 创建 AVIO 缓存空间
    unsigned char* outBuffer = (unsigned char*)av_malloc(RTPPKT_LEN);

    // 创建 AVIO 上下文
    AVIOContext* avioOut = avio_alloc_context(outBuffer, RTPPKT_LEN, 1, nullptr, nullptr, tcp_write_buffer, nullptr);
    if (!avioOut) {
        printf("无法创建 AVIO 上下文\n");
        return -1;
    }

    // 创建输出格式上下文
    AVFormatContext* outputFormatCtx = nullptr;
    const std::string serverUrl = "rtsp://127.0.0.1/live/stream"; // 修改为您的 RTSP 服务器地址
    ret = avformat_alloc_output_context2(&outputFormatCtx, nullptr, "rtsp", serverUrl.c_str());
    if (ret < 0) {
        printf("无法创建输出格式上下文\n");
        return -1;
    }

    outputFormatCtx->pb = avioOut;

    // 打开输入文件
    AVFormatContext* inputFormatCtx = nullptr;
    const std::string inputUrl = "input.mp4"; // 修改为您的输入文件路径
    ret = avformat_open_input(&inputFormatCtx, inputUrl.c_str(), nullptr, nullptr);
    if (ret != 0) {
        printf("无法打开输入文件:%s\n", inputUrl.c_str());
        return -1;
    }

    // 获取流信息
    ret = avformat_find_stream_info(inputFormatCtx, nullptr);
    if (ret < 0) {
        printf("无法获取流信息\n");
        return -1;
    }

    // 复制输入流的参数到输出流
    for (unsigned int i = 0; i < inputFormatCtx->nb_streams; i++) {
        AVStream* inputStream = inputFormatCtx->streams[i];
        AVCodec* codec = avcodec_find_decoder(inputStream->codecpar->codec_id);
        AVStream* outputStream = avformat_new_stream(outputFormatCtx, codec);
        if (!outputStream) {
            printf("无法创建输出流\n");
            return -1;
        }

        ret = avcodec_parameters_copy(outputStream->codecpar, inputStream->codecpar);
        if (ret < 0) {
            printf("无法复制编解码器参数\n");
            return -1;
        }
    }

    // 写入输出头部
    ret = avformat_write_header(outputFormatCtx, nullptr);
    if (ret < 0) {
        printf("无法写入输出头部\n");
        return -1;
    }

    // 开始读取和发送数据包
    AVPacket packet;
    while (av_read_frame(inputFormatCtx, &packet) >= 0) {
        // 发送数据包到输出上下文
        ret = av_interleaved_write_frame(outputFormatCtx, &packet);
        if (ret < 0) {
            printf("无法发送数据包\n");
            return -1;
        }

        av_packet_unref(&packet);
    }

    // 发送 RTSP TEARDOWN 请求
    av_write_trailer(outputFormatCtx);

    // 关闭 RTSP 会话
    avio_closep(&outputFormatCtx->pb);

    // 关闭 Socket
    close(tcpSocket);

    // 释放资源
    avformat_close_input(&inputFormatCtx);
    avformat_free_context(inputFormatCtx);
    avformat_free_context(outputFormatCtx);
    avio_context_free(&avioOut);
    av_free(outBuffer);

    return 0;
}

在这个示例中,我们使用 avformat_open_input 函数打开输入文件(mp4),然后读取并发送数据包到输出上下文。通过 av_interleaved_write_frame 函数将数据包写入输出上下文。

请注意,您需要将输入文件的路径(input.mp4)和目标 RTSP 服务器地址(rtsp://127.0.0.1/live/stream)根据实际情况进行修改。

以下是上述代码的整体流程:

  1. 初始化 FFmpeg 库,包括注册所需的组件和网络模块。

  2. 创建 TCP Socket,并连接到目标服务器。

  3. 创建 AVIO 缓存空间,并使用 avio_alloc_context 函数创建 AVIO 上下文,用于将数据发送到 RTSP 服务器。

  4. 创建输出格式上下文,设置推流的目标 URL(RTSP 服务器地址)。

  5. 打开输入文件(本地 mp4 文件),创建输入格式上下文,并读取流信息。

  6. 复制输入流的参数到输出流,为每个输入流创建一个对应的输出流。

  7. 写入输出头部,使用 avformat_write_header 函数将输出格式上下文的头部写入输出上下文。

  8. 开始读取输入文件并发送数据包。使用 av_read_frame 函数从输入文件中读取数据包,然后通过 av_interleaved_write_frame 函数将数据包发送到输出上下文。

  9. 发送 RTSP TEARDOWN 请求,调用 av_write_trailer 函数向输出上下文发送 RTSP TEARDOWN 请求,结束 RTSP 会话。

  10. 关闭 RTSP 会话和 TCP Socket。

  11. 释放资源,包括关闭输入文件、释放输入和输出格式上下文、释放 AVIO 上下文以及释放相关内存缓冲区。

以上是整体流程的简要描述。实际应用中,您可能需要根据具体需求进行更多的配置和处理,如设置音频流、传输参数、验证身份等。

相关推荐
l***77523 小时前
从MySQL5.7平滑升级到MySQL8.0的最佳实践分享
ffmpeg
ZouZou老师9 小时前
FFmpeg性能优化经典案例
性能优化·ffmpeg
aqi0012 小时前
FFmpeg开发笔记(九十)采用FFmpeg套壳的音视频转码百宝箱FFBox
ffmpeg·音视频·直播·流媒体
齐齐大魔王14 小时前
FFmpeg
ffmpeg
你好音视频15 小时前
FFmpeg RTSP拉流流程深度解析
ffmpeg
IFTICing1 天前
【环境配置】ffmpeg下载、安装、配置(Windows环境)
windows·ffmpeg
haiy20111 天前
FFmpeg 编译
ffmpeg
aqi001 天前
FFmpeg开发笔记(八十九)基于FFmpeg的直播视频录制工具StreamCap
ffmpeg·音视频·直播·流媒体
八月的雨季 最後的冰吻1 天前
FFmepg--28- 滤镜处理 YUV 视频帧:实现上下镜像效果
ffmpeg·音视频
ganqiuye1 天前
向ffmpeg官方源码仓库提交patch
大数据·ffmpeg·video-codec