ffmpeg RTP PS推流

要实现 CRtpSendPs 类,使其能够将 H264 数据通过 RTP PS 流推送到指定的 URL,并支持 TCP 和 UDP 传输方式,您需要使用 FFmpeg 库。以下是该类的实现示例,包括必要的初始化、推流和退出函数。

步骤

  1. 初始化 FFmpeg 库:需要初始化 FFmpeg 网络、格式和编码器相关的库。
  2. 配置 RTP 传输:使用 RTP 封装 PS (Program Stream) 格式。
  3. 推送数据:接收 H264 数据并将其封装为 RTP 包,发送到指定的目标 URL(支持 UDP 和 TCP)。
  4. 退出处理:释放相关资源。

完整代码实现

复制代码
复制代码
#include <iostream>
#include <string>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavdevice/avdevice.h>
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>

class CRtpSendPs
{
public:
    CRtpSendPs();
    ~CRtpSendPs();

    int Init(const char *url, bool bUdpOrTcp);  // 初始化,设置目标 URL 和传输协议
    int PushStream(const void *pH264Data, uint32_t u32Len);  // 推送视频数据
    int Exit();  // 清理资源

private:
    AVFormatContext *outputFmtCtx;
    AVStream *outputStream;
    AVCodecContext *codecCtx;
    AVPacket pkt;
    bool isUdp;
    std::string outputUrl;
    bool isInitialized;
};

CRtpSendPs::CRtpSendPs() : outputFmtCtx(nullptr), outputStream(nullptr), codecCtx(nullptr), isInitialized(false)
{
    av_register_all();
    avformat_network_init();
    avcodec_register_all();
    avdevice_register_all();
    isUdp = true;
    isInitialized = false;
}

CRtpSendPs::~CRtpSendPs()
{
    Exit();
}

int CRtpSendPs::Init(const char *url, bool bUdpOrTcp)
{
    if (isInitialized) {
        std::cerr << "Already initialized!" << std::endl;
        return -1;
    }

    isUdp = bUdpOrTcp;
    outputUrl = url;

    // Create output context
    AVOutputFormat *fmt = av_guess_format(NULL, outputUrl.c_str(), NULL);
    if (!fmt) {
        std::cerr << "Could not guess output format!" << std::endl;
        return -1;
    }

    int ret = avformat_alloc_output_context2(&outputFmtCtx, fmt, NULL, outputUrl.c_str());
    if (ret < 0) {
        std::cerr << "Failed to create output context!" << std::endl;
        return ret;
    }

    // Create a new stream for the output
    outputStream = avformat_new_stream(outputFmtCtx, NULL);
    if (!outputStream) {
        std::cerr << "Failed to create new stream!" << std::endl;
        return AVERROR(ENOMEM);
    }

    // Setup codec parameters (for H264)
    AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (!encoder) {
        std::cerr << "H264 encoder not found!" << std::endl;
        return AVERROR_ENCODER_NOT_FOUND;
    }

    codecCtx = avcodec_alloc_context3(encoder);
    if (!codecCtx) {
        std::cerr << "Failed to allocate codec context!" << std::endl;
        return AVERROR(ENOMEM);
    }

    codecCtx->codec_id = AV_CODEC_ID_H264;
    codecCtx->bit_rate = 1000000;
    codecCtx->width = 1920;
    codecCtx->height = 1080;
    codecCtx->time_base = {1, 30};  // 30 fps
    codecCtx->gop_size = 12;
    codecCtx->max_b_frames = 3;
    codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;

    ret = avcodec_open2(codecCtx, encoder, NULL);
    if (ret < 0) {
        std::cerr << "Failed to open codec!" << std::endl;
        return ret;
    }

    // Copy codec parameters to the stream
    ret = avcodec_parameters_from_context(outputStream->codecpar, codecCtx);
    if (ret < 0) {
        std::cerr << "Failed to copy codec parameters!" << std::endl;
        return ret;
    }

    // Open the output file or network stream
    if (!(outputFmtCtx->oformat->flags & AVFMT_NOFILE)) {
        ret = avio_open(&outputFmtCtx->pb, outputUrl.c_str(), AVIO_FLAG_WRITE);
        if (ret < 0) {
            std::cerr << "Failed to open output URL!" << std::endl;
            return ret;
        }
    }

    // Write the header of the file (or stream)
    ret = avformat_write_header(outputFmtCtx, NULL);
    if (ret < 0) {
        std::cerr << "Failed to write header!" << std::endl;
        return ret;
    }

    isInitialized = true;
    return 0;
}

int CRtpSendPs::PushStream(const void *pH264Data, uint32_t u32Len)
{
    if (!isInitialized) {
        std::cerr << "Not initialized!" << std::endl;
        return -1;
    }

    // Create a packet and fill it with H264 data
    av_init_packet(&pkt);
    pkt.data = (uint8_t *)pH264Data;
    pkt.size = u32Len;
    pkt.stream_index = outputStream->index;
    pkt.flags |= AV_PKT_FLAG_KEY;  // Assuming it's a keyframe, adjust if needed

    // Write the packet to the RTP stream
    int ret = av_write_frame(outputFmtCtx, &pkt);
    if (ret < 0) {
        std::cerr << "Error writing frame!" << std::endl;
        return ret;
    }

    return 0;
}

int CRtpSendPs::Exit()
{
    if (!isInitialized) {
        return 0;  // Already exited
    }

    av_write_trailer(outputFmtCtx);

    // Close the output stream and free resources
    if (outputFmtCtx && !(outputFmtCtx->oformat->flags & AVFMT_NOFILE)) {
        avio_closep(&outputFmtCtx->pb);
    }

    avcodec_free_context(&codecCtx);
    avformat_free_context(outputFmtCtx);

    isInitialized = false;
    return 0;
}

代码说明

  1. CRtpSendPs 类的构造函数和析构函数

    • Init():初始化 FFmpeg 输出格式和编码器配置,设置输出 URL 并建立连接。
    • PushStream():接受一帧 H264 数据并将其封装为 RTP 包,然后通过网络发送。
    • Exit():释放资源并关闭输出流。
  2. FFmpeg 配置

    • 使用 avformat_alloc_output_context2() 创建输出流上下文。
    • 使用 avcodec_find_encoder() 查找 H264 编码器,初始化编码器上下文。
    • 使用 av_write_frame() 将数据包发送到指定的输出 URL(支持 RTP 协议)。
  3. RTP 传输:通过 RTP 推送数据流,支持 UDP 和 TCP(通过 URL 中的协议部分决定)。

编译命令

在编译前,确保已经安装了 FFmpeg 库。如果没有安装,您可以使用以下命令:

复制代码
sudo apt-get install libavformat-dev libavcodec-dev libavutil-dev libavdevice-dev libswscale-dev

然后使用以下命令来编译代码:

复制代码
复制代码
g++ -o rtp_send_ps rtp_send_ps.cpp -lavformat -lavcodec -lavutil -lavdevice -lswscale -lavfilter -lm -lz

运行示例

复制代码
复制代码
./rtp_send_ps rtp://192.168.0.49:5000

此命令将会把 H264 数据通过 RTP 协议推送到目标 IP 地址 192.168.0.49,端口 5000

注意事项

  • 您需要确保目标服务器或设备能够接收 RTP 流。
  • 在真实应用中,PushStream() 中的 H264 数据可以从文件或网络中获取,并通过该函数传输。
相关推荐
daidaidaiyu1 天前
FFmpeg 关键的结构体
c++·ffmpeg
扶尔魔ocy2 天前
【QT window】ffmpeg实现录音功能之无损格式--PCM
ffmpeg·pcm
止礼2 天前
FFmpeg8.0.1 源代码的深入分析
ffmpeg
小曾同学.com2 天前
音视频中的“透传”与“DTS音频”
ffmpeg·音视频·透传·dts
vivo互联网技术2 天前
数字人动画云端渲染方案
前端·ffmpeg·puppeteer·web3d
止礼2 天前
FFmpeg8.0.1 编解码流程
ffmpeg
qs70162 天前
c直接调用FFmpeg命令无法执行问题
c语言·开发语言·ffmpeg
止礼2 天前
FFmpeg8.0.1 Mac环境 CMake本地调试配置
macos·ffmpeg
简鹿视频3 天前
视频转mp4格式具体作步骤
ffmpeg·php·音视频·实时音视频