• FFMpeg笔记(八) 读取RTP数据时的PTS计算[转载]


    结构体struct RTPDemuxContext中有若干时间戳相关的成员,含义如下

    timestamp:上一个接收到的RTP时间戳
    base_timestamp:第一个接收到的RTP时间戳
    cur_timestamp:未知
    unwrapped_timestamp:假如rtp时间没有32位溢出的话,当前的rtp时间应该是多少
    range_start_offset:RTSP Range头部指定的开始时间

    last_rtcp_ntp_time:上一次收到RTCP SR报告中的ntp时间
    last_rtcp_timestamp:上一次收到RTCP SR报告中的rtp时间
    first_rtcp_ntp_time:第一次收到的RTCP SR报告中的ntp时间
    rtcp_ts_offset:第一次接收到RTCP SR报告中的RTP时间与第一个收到的RTP时间差

    每一帧的时间戳是这样计算的,在libavformat/rtpdec.c finalize_packet()

    如果rtp只有一个音频流或者一个视频流,或者没有RTCP的SR报告,则

        pkt->pts     = s->unwrapped_timestamp + s->range_start_offset -
                       s->base_timestamp;

    表达式右边的顺序换一下,含义就清晰了 s->unwrapped_timestamp - s->base_timestamp 代表当前自运行以来的相对时间,然后再加上s->range_start_offset,变成一个绝对时间。

    如果有音视频两个流,且收到了RTCP的SR报告,计算是这样的

                if (s->first_rtcp_ntp_time == AV_NOPTS_VALUE) {
                    s->first_rtcp_ntp_time = s->last_rtcp_ntp_time;
                    if (!s->base_timestamp)
                        s->base_timestamp = s->last_rtcp_timestamp;
                    s->rtcp_ts_offset = (int32_t)(s->last_rtcp_timestamp - s->base_timestamp);
                }
    
            /* compute pts from timestamp with received ntp_time */
            delta_timestamp = timestamp - s->last_rtcp_timestamp;
            /* convert to the PTS timebase */
            addend = av_rescale(s->last_rtcp_ntp_time - s->first_rtcp_ntp_time,
                                s->st->time_base.den,
                                (uint64_t) s->st->time_base.num << 32);
            pkt->pts = s->range_start_offset + s->rtcp_ts_offset + addend +
                       delta_timestamp;

    有点不好懂的是addend这个变量。根据rfc 3550,RTCP SR报告中的ntp时间定义为
    http://www.ietf.org/rfc/rfc3550.txt

    Wallclock time (absolute date and time) is represented using the timestamp format of the Network Time Protocol (NTP), which is in seconds relative to 0h UTC on 1 January 1900 [4]. The full resolution NTP timestamp is a 64-bit unsigned fixed-point number with the integer part in the first 32 bits and the fractional part in the last 32 bits.

    由于读进来的rtcp_ntp_time是32位的定点小数,因此在做时间戳单位转换的时候做了一个32位的左移。因此addend代表最后一个收到的ntp时间距离第一个收到的ntp时间相隔多久。

    回到pkt->pts的计算,s->rtcp_ts_offset这部分代表第一次收到的RTCP SR包距离流开始时的时间差,addend代表最后一次收到RTCP SR包距离第一次收到的RTCP SR包的时间差,delta_timestamp代表当前距离最后一次收到RTCP SR包的时间差,这三部分一求和就代表当前距离流开始时的时间差。

    ffmpeg这种计算方式用于音视频流同步是有问题的,它会默认音视频流时间戳都从0开始。假如两者的开始时间不一致,会导致音视频不同步。而且显然,它这种计算方式浪费了RTCP SR报告中的ntp与rtp时间对应关系

    ---------------------------------------------------------------------------------------------------------------------------------------------------
    简单总结下:
    1. 没有RTCP的SR包时,计算的pts实际上是相对的,音视频的pts计算完事后,都是从0开始,逐步相对递增;
    2. 有SR包时,计算一个RTP包的pts实际上是三段相加,第一段是首个RTCP SR包的timestamp减去首个RTP包的timestamp,第二段是最后一个SR包的NTP timestamp减去首个SR包的NTP timestamp,第三段是要计算的这个RTP包的timestamp减去最后一个SR包中的timestamp.

    作者:叶迎宪
    链接:https://www.jianshu.com/p/67d3e6a1d72e
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    LeetCode——字符串解码
    LeetCode——迷宫 i-ii
    JavaScript实现按照指定长度为数字前面补零输出的方法
    React 修改input按钮上文字
    HTML input可以输入相同的文件
    LeetCode——重新安排行程
    LeetCode——矩阵中的最长递增路径
    c++ vector push_back对象的时候存起来的是拷贝
    char* = "name" g++报告warn的原因
    虚函数表指针、父类成员变量、子类成员变量在内存中的位置关系
  • 原文地址:https://www.cnblogs.com/jiayayao/p/12634327.html
Copyright © 2020-2023  润新知