FFmpeg实现rtp推流

以下是一个简单的示例代码,演示了如何使用 UDP 或 TCP 进行音视频传输:
代码未经验证,供参考

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>

#define RTPPKT_LEN 1400
#define IPOUT_PAYNUM 1

// UDP Socket
int udpSocket;

// TCP Socket
int tcpSocket;

// UDP 发送函数
int udp_write_buffer(void* opaque, uint8_t* buf, int buf_size) {
    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地址

    ssize_t sentBytes = sendto(udpSocket, buf, buf_size, 0, (struct sockaddr*)&destAddr, sizeof(destAddr));
    if (sentBytes < 0) {
        perror("UDP 发送失败");
        return -1;
    }

    return 0;
}

// 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() {
    av_register_all();
    avformat_network_init();

    // 创建输入格式上下文
    AVFormatContext* inputFormatCtx = avformat_alloc_context();

    // 打开输入文件或网络流
    const char* inputUrl = "input.mp4";
    int ret = avformat_open_input(&inputFormatCtx, inputUrl, nullptr, nullptr);
    if (ret != 0) {
        printf("无法打开输入文件:%s\n", inputUrl);
        return -1;
    }

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

    // 寻找视频流索引
    int videoStreamIndex = -1;
    for (unsigned int i = 0; i < inputFormatCtx->nb_streams; i++) {
        if (inputFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }

    // 创建输出格式上下文
    AVFormatContext* outputFormatCtx = nullptr;
    ret = avformat_alloc_output_context2(&outputFormatCtx, nullptr, "rtp", "rtp://127.0.0.1:1234"); // 设置输出 URL
    if (ret < 0) {
        printf("无法创建输出格式上下文\n");
        return -1;
    }

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

    // 创建 UDP Socket
    udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (udpSocket < 0) {
        perror("无法创建 UDP Socket");
        return -1;
    }

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

    // 创建 AVIO 上下文
    AVIOContext* avioOut;
    if (strcmp("UDP", "RTP/AVP") == 0) {
        avioOut = avio_alloc_context(outBuffer, RTPPKT_LEN * IPOUT_PAYNUM, 1, nullptr, nullptr, udp_write_buffer, nullptr);
    } else if (strcmp("TCP", "RTP/AVP") == 0) {
        avioOut = avio_alloc_context(outBuffer, RTPPKT_LEN * IPOUT_PAYNUM, 1, nullptr, nullptr, tcp_write_buffer, nullptr);
    }

    if (!avioOut) {
        printf("无法创建 AVIO 上下文\n");
        return -1;
    }

    avioOut->max_packet_size = RTPPKT_LEN;

    outputFormatCtx->pb = avioOut;
    outputFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;

    // 复制视频流参数到输出格式上下文
    AVStream* outputStream = avformat_new_stream(outputFormatCtx, nullptr);
    ret = avcodec_parameters_copy(outputStream->codecpar, inputFormatCtx->streams[videoStreamIndex]->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) {
        if (packet.stream_index == videoStreamIndex) {
            // 发送数据包到输出上下文
            ret = av_interleaved_write_frame(outputFormatCtx, &packet);
            if (ret < 0) {
                printf("无法发送数据包\n");
                return -1;
            }
        }

        av_packet_unref(&packet);
    }

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

    // 关闭 Socket
    close(udpSocket);
    close(tcpSocket);

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

    return 0;
}

这个示例代码基于 FFmpeg 库,演示了如何使用 UDP 或 TCP 进行音视频传输。具体的步骤包括:

  1. 注册 FFmpeg 库并初始化网络模块。
  2. 创建输入格式上下文,并打开输入文件或网络流。
  3. 获取流信息,并找到视频流索引。
  4. 创建输出格式上下文,并设置输出协议为 RTP。
  5. 创建 UDP 或 TCP Socket。
  6. 创建 AVIO 缓存空间和 AVIO 上下文,并将其赋值给输出格式上下文。
  7. 复制视频流参数到输出格式上下文。
  8. 写入输出头部。
  9. 通过循环读取输入文件的数据包,并发送到输出格式上下文。
  10. 写入输出尾部。
  11. 关闭 Socket 和释放资源。

您可以根据实际需求修改相关参数,如输入文件、目标地址、端口号等,以适配您的具体场景。

相关推荐
默凉2 天前
ffmpeg 安装
ffmpeg
微瑟秋风3 天前
Python应用——ffmpeg处理音视频的常见场景
python·ffmpeg
WSSWWWSSW3 天前
警告:OPENCV_FFMPEG_READ_ATTEMPTS (current value is 4096)
人工智能·opencv·ffmpeg
A尘埃4 天前
FFmpeg音视频处理解决方案
ffmpeg·音视频
Industio_触觉智能4 天前
瑞芯微RK3576平台FFmpeg硬件编解码移植及性能测试实战攻略
ffmpeg·开发板·嵌入式开发·瑞芯微·视频解码·rk3576·rk3576j
Font Tian4 天前
FFmpeg 不同编码的压缩命令详解
ffmpeg·音视频·视频编解码·视频·视频压缩
Natsume17104 天前
音视频开发入门:FFmpeg vs GStreamer,新手该如何选择?
c语言·c++·ffmpeg·音视频·webrtc·实时音视频·视频编解码
CHN悠远4 天前
FFMPEG 10BIT下 Intel b570 qsv 硬解AV1,H265视频编码测试
ffmpeg·av1·h265
忆萧5 天前
Encoder编码器
ffmpeg
忆萧5 天前
FFMPEG学习任务
学习·ffmpeg