FFmpeg rtp & rtp_mpegts的区别

这篇具有很好参考价值的文章主要介绍了FFmpeg rtp & rtp_mpegts的区别。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

rtp

RTP是一种用于实时传输音视频数据的协议,常用于视频会议、流媒体等场景。

在FFmpeg中,rtpenc是一个用于将音视频数据封装成RTP(Real-time Transport Protocol)数据包并发送到网络上的编码器。

rtpenc可以将音视频数据封装成RTP数据包,并通过UDP协议发送到指定的IP地址和端口号。它支持多种音视频编码格式,如H.264、AAC等,并可以设置RTP头部信息、负载类型、时间戳等参数。

ff_rtp_muxer

了解rtpenc,就来看rtp_muxer,rtp_muxer也是由AVOutputFormat定义,位于libavformat/rtpenc.c,在rtp muxer的定义中,默认的codec格式是AV_CODEC_ID_MPEG4AV_CODEC_ID_PCM_MULAWrtp_write_packet可以看到这个rtp packet的封包发送过程。

const AVOutputFormat ff_rtp_muxer = {
    .name              = "rtp",
    .long_name         = NULL_IF_CONFIG_SMALL("RTP output"),
    .priv_data_size    = sizeof(RTPMuxContext),
    .audio_codec       = AV_CODEC_ID_PCM_MULAW,
    .video_codec       = AV_CODEC_ID_MPEG4,
    .write_header      = rtp_write_header,
    .write_packet      = rtp_write_packet,
    .write_trailer     = rtp_write_trailer,
    .priv_class        = &rtp_muxer_class,
    .flags             = AVFMT_TS_NONSTRICT,
};

这里再说一下AVOutputFormat

虽然AVOutputFormat在libavdevice和libavformat中都存在,但是它们的作用不同。在libavdevice中,AVOutputFormat用于描述音视频设备的输出格式,而在libavformat中,AVOutputFormat用于描述音视频文件的输出格式。

因此,AVOutputFormat在libavdevice和libavformat中的区别在于它们所描述的对象不同。

rtp_write_packet

rtp_write_packet中根据codec_id,调用对应的ff_rtp_send_xxx函数,比如H264对应的是ff_rtp_send_h264_hevc:

static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) {
    RTPMuxContext *s = s1->priv_data;
    AVStream *st = s1->streams[0];
    int rtcp_bytes;
    int size= pkt->size;

    
    switch(st->codecpar->codec_id) {
    case AV_CODEC_ID_AAC:
        if (s->flags & FF_RTP_FLAG_MP4A_LATM)
            ff_rtp_send_latm(s1, pkt->data, size);
        else
            ff_rtp_send_aac(s1, pkt->data, size);
        break;
     case AV_CODEC_ID_H264:
        ff_rtp_send_h264_hevc(s1, pkt->data, size);
        break;   
}

ff_rtp_send_h264_hevc

该函数的主要作用是将H.264/HEVC视频流分割成NAL单元,并将其打包成RTP数据包进行传输。

该函数首先将传入的视频流数据buf1拷贝到RTPMuxContext结构体中,并设置当前时间戳为s->cur_timestamp。然后,该函数通过调用ff_avc_find_startcodeff_avc_mp4_find_startcode函数找到NAL单元的起始位置,并将NAL单元的数据通过nal_send函数打包成RTP数据包进行传输。最后,该函数通过调用flush_buffered函数将缓存中的数据进行传输。

需要注意的是,该函数中的s->nal_length_size表示NAL单元长度的字节数,不为0,buffer就是avcc类型,如果为0,就是annex

格式,根据起始码0x0000010x00000001来找到buffer的结束位置。

void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size)
{
    const uint8_t *r, *end = buf1 + size;
    RTPMuxContext *s = s1->priv_data;

    s->timestamp = s->cur_timestamp;
    s->buf_ptr   = s->buf;
    if (s->nal_length_size)
        r = ff_avc_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end;
    else
        r = ff_avc_find_startcode(buf1, end);
    while (r < end) {
        const uint8_t *r1;

        if (s->nal_length_size) {
            r1 = ff_avc_mp4_find_startcode(r, end, s->nal_length_size);
            if (!r1)
                r1 = end;
            r += s->nal_length_size;
        } else {
            while (!*(r++));
            r1 = ff_avc_find_startcode(r, end);
        }
        nal_send(s1, r, r1 - r, r1 == end);
        r = r1;
    }
    flush_buffered(s1, 1);
}

然后nal_send将NAL单元发送到RTP流中。NAL单元是视频编码中的基本单元,它包含了视频编码中的一个帧或片段。

nal_send首先检查NAL单元的大小是否小于等于最大负载大小,如果是,则将NAL单元添加到缓冲区中。如果缓冲区中已经有了一些NAL单元,则将它们作为STAP-A/AP包发送。如果NAL单元的大小大于最大负载大小,则将其分割成多个分片,并将它们作为FU-A包发送。

nal_send还根据编解码器类型设置了一些标志位,以便在发送NAL单元时进行适当的处理。例如,对于H.264编解码器,如果使用了FF_RTP_FLAG_H264_MODE0标志,则将NAL单元分割成多个分片。

ff_rtp_send_data

ff_rtp_send_data是rtp用于将数据通过RTP协议发送出去的函数。具体来说,它会构建RTP头部,将数据写入输出流,并更新一些统计信息。

void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
{
    RTPMuxContext *s = s1->priv_data;

    av_log(s1, AV_LOG_TRACE, "rtp_send_data size=%d\n", len);

    /* build the RTP header */
    avio_w8(s1->pb, RTP_VERSION << 6);
    avio_w8(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7));
    avio_wb16(s1->pb, s->seq);
    avio_wb32(s1->pb, s->timestamp);
    avio_wb32(s1->pb, s->ssrc);

    avio_write(s1->pb, buf1, len);
    avio_flush(s1->pb);

    s->seq = (s->seq + 1) & 0xffff;
    s->octet_count += len;
    s->packet_count++;
}

函数的参数包括一个AVFormatContext结构体指针s1,一个指向数据缓冲区的指针buf1,数据长度len,以及一个标志位m。其中,s1包含了输出流的相关信息,buf1是要发送的数据,len是数据长度,m表示是否是最后一个数据包。

函数首先从s1中获取RTPMuxContext结构体指针s,该结构体包含了一些RTP相关的信息。然后,函数会使用avio_w8、avio_wb16、avio_wb32等函数将RTP头写入输出流中。其中,RTP头部的格式如下:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|  CC   |M|     PT      |       sequence number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           timestamp                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           synchronization source (SSRC) identifier            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            contributing source (CSRC) identifiers             |
|                             ....                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中,V表示协议版本号,P表示是否有填充,X表示是否有扩展头部,CC表示CSRC计数器,M表示是否是最后一个数据包,PT表示负载类型,sequence number表示序列号,timestamp表示时间戳,SSRC表示同步源标识符,CSRC表示贡献源标识符。

接下来,函数会使用avio_write函数将数据写入输出流中,并使用avio_flush函数将输出流中的数据刷新。最后,函数会更新s中的一些统计信息,包括序列号、字节计数和数据包计数。

rtp_mpegts

rtp_mpegts是ffmpeg中支持的唯一一个rtp muxer,通过rtp_mpegts发送音视频数据,可以解决rtp只支持一路流的问题,默认支持的audio codec是PCM_MULAW,video codec是MPEG4,通过acodec和vcodec参数可以指定codec。

比如可以这样发送:

ffmpeg -re -stream_loop -1 -i h264.mp4 -i aac.mp4 -f rtp_mpegts rtp://10.0.1.1:5008

指定codec:

ffmpeg -re -stream_loop -1 -i h264.mp4 -i aac.mp4 -acodec aac -vcodec h264 -f rtp_mpegts rtp://10.0.1.1:5008

h264.mp4 - 只包含h264编码的视频文件

aac.mp4 - 只包含aac编码的音频文件

如果使用rtp发送,则会输出ERROR:“Only one stream supported in the RTP muxer”。

ffmpeg -re -stream_loop -1 -i h264.mp4 -i aac.mp4 -f rtp rtp://10.0.1.1:5008

ff_rtp_mpegts_muxer

const AVOutputFormat ff_rtp_mpegts_muxer = {
    .name              = "rtp_mpegts",
    .long_name         = NULL_IF_CONFIG_SMALL("RTP/mpegts output format"),
    .priv_data_size    = sizeof(MuxChain),
    .audio_codec       = AV_CODEC_ID_AAC,
    .video_codec       = AV_CODEC_ID_MPEG4,
    .write_header      = rtp_mpegts_write_header,
    .write_packet      = rtp_mpegts_write_packet,
    .write_trailer     = rtp_mpegts_write_close,
    .priv_class        = &rtp_mpegts_class,
};

write_header函数中,指定codec id为AV_CODEC_ID_MPEG2TS,这个会在rtp enc中处理,调用rtp_send_mpegts_raw,发送mpegts数据。

    st->time_base.num   = 1;
    st->time_base.den   = 90000;
    st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS;
    rtp_ctx->pb = s->pb;

所以,rtp muxer直接对音视频数据封包成rtp payload进行发送,而rtp_mpegts则对音视频数据先进行mpegts封装,然后再封装为rtp payload发送。文章来源地址https://www.toymoban.com/news/detail-688639.html

到了这里,关于FFmpeg rtp & rtp_mpegts的区别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ffmpeg基础】ffmpeg视频编码

    通过-s来指定输入yuv的分辨率(需要先指定分辨率); 通过-pix_fmt来指定输入yuv的像素格式; 通过-i来指定输入yuv的路径和名称; 通过-r 来指定要编码的帧率; 通过-vcodec来指定视频编码的编码器为libx264 通过-an参数来去掉输入input.mp4中的音频,并通过-vcodec libx264将输入的视频进

    2024年02月14日
    浏览(35)
  • 【ffmpeg基础】ffmpeg的下载安装

    1、ffmpeg github下载路径:https://github.com/FFmpeg/FFmpeg.git 在ffmpeg的github上可以下载任意版本的源码,比如最新的matser上的源码,以及各个分支上(如ffmpeg的5.1版本)的源码,如下图。 2、ffmpeg官方网站:https://www.ffmpeg.org/ ;在官方网站内也可以下载ffmpeg的源码以及ffmpeg编译好的库文件

    2024年02月04日
    浏览(43)
  • Linux系统安装ffmpeg & 升级ffmpeg

    一、介绍 多媒体视频处理工具FFmpeg有非常强大的功能,包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。由于最近要处理音视频格式转换问题,因此需要安装、升级ffmpeg,下面来记录一下踩坑过程。 二、安装 ffmpeg 1、下载并解压ffmpeg 2、指定安装路径(/usr

    2024年01月20日
    浏览(34)
  • FFMPEG源码之ffmpeg.c解析

    下面是对每个步骤的功能的详细解释: 初始化动态加载。 调用init_dynload函数,用于初始化动态加载库的相关资源,以便在需要时加载需要的库。 注册退出回调函数。 调用register_exit函数,将ffmpeg_cleanup函数注册为在程序退出时被调用的回调函数。 设置stderr的缓冲模式。 调用

    2024年02月15日
    浏览(44)
  • NDK交叉编译FFmpeg安卓编译ffmpeg

    编译工具下载 参考这个:https://blog.csdn.net/gaoliang0/article/details/81913291 或者官网 NDK编译工具下载: https://developer.android.google.cn/ndk/downloads?hl=zh-cn 官网老版本: https://github.com/android/ndk/wiki/Unsupported-Downloads 或者从我的百度网盘: 链接:https://pan.baidu.com/s/1FEtM6mVNgER_DvC2myHB5Q?pwd=28l9 提

    2024年02月08日
    浏览(37)
  • 【QT+ffmpeg】QT+ffmpeg 环境搭建

    1.qt下载地址 download.qt.io/archive/ 2. win10sdk 下载 https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ 安装 debug工具路径 qtcreater会自动识别 调试器选择

    2024年02月12日
    浏览(37)
  • FFmpeg常见命令行(五):FFmpeg滤镜使用

    在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》,结合我自己的工作学习经历,我准备写一个音视频系列blog。本文是音视频系列blog的其中一个, 对应的要学习的内容是:如何使用FF

    2024年02月13日
    浏览(37)
  • FFmpeg学习:FFmpeg4数据结构分析

    FFMPEG中结构体很多。最关键的结构体可以分成以下几类: 1、解协议(http,rtsp,rtmp,mms) AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协

    2024年02月05日
    浏览(76)
  • FFmpeg常见命令行(一):FFmpeg工具使用基础

    在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的其中一个, 对应的要学习的内容是:FFmpeg常见命令行(一):FFmpeg工具使用基础 音视频任务列表: 点击

    2024年02月14日
    浏览(38)
  • 4、ffmpeg系列学习——FFmpeg的图像处理

    调整图像大小 上述命令将输入图像 input.jpg 调整为分辨率为 640x360 的输出图像 output.jpg。 图像裁剪 上述命令将输入图像 input.jpg 裁剪为宽度 640,高度 360,x 轴偏移量为 80,y 轴偏移量为 60 的输出图像 output.jpg。 图像旋转 上述命令将输入图像 input.jpg 逆时针旋转 90 度,输出图

    2024年02月04日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包