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 和释放资源。

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

相关推荐
心动啊1219 小时前
FFMPeg在Python中的使用
ffmpeg
aqi0010 小时前
FFmpeg开发笔记(一百)国产的Android开源视频压缩工具VideoSlimmer
android·ffmpeg·音视频·直播·流媒体
猿小路15 小时前
视频流熟知
ffmpeg·h.264
chen_22716 小时前
动态桌面方案
c++·qt·ffmpeg·kanzi
GeniuswongAir1 天前
苹果电脑上启动一个 RTSP 推流,用来做测试
ffmpeg
Benny的老巢1 天前
n8n工作流通过Execute Command用FFmpeg处理音频,报错 stderr maxBuffer length exceeded的解决方案
ffmpeg·音频合成·n8n·n8n工作流·execute command
七夜zippoe3 天前
Spring Data JPA原理与实战 Repository接口的魔法揭秘
java·ffmpeg·事务·jpa·repository
Benny的老巢3 天前
n8n工作流中FFmpeg 视频截取失败排查:文件路径和参数顺序错误解决方案
chrome·ffmpeg·音视频
RockWang.4 天前
【配置】FFmpeg配置环境ubuntu踩坑记录。
ffmpeg
王者鳜錸4 天前
Java使用FFmpeg获取音频文件时长:完整实现与原理详解
java·开发语言·ffmpeg·音频时长