<div dir="ltr"><p>Dear FFmpeg Development Team,</p><p>Hello!</p><p>I am currently working on using FFmpeg to parse RTSP streams, and I have encountered some issues that I would like to seek your advice on.</p><p>I would like to extract the timestamp (PTS) of each frame. Currently, I have successfully obtained the RTP packet timestamp (<code>rtptime</code>), but the RTP timestamp itself is a relative time (i.e., it is the time since the stream started), and it is not mapped to an absolute time (NTP time). Therefore, I need to convert the RTP timestamp into an absolute NTP timestamp for further processing.</p><p>According to the specifications in <strong>RFC 2326</strong> and <strong>RFC 3550</strong>, the <strong>RTCP SR (Sender Report)</strong> contains a mapping between <strong>NTP timestamps</strong> and <strong>RTP timestamps</strong>, which can be used to calculate the offset from the RTP timestamp to the NTP timestamp. Specifically, the RTCP SR report contains <code>ntp_time</code> and <code>rtp_time</code>, and I hope to calculate the offset using these values to convert the RTP timestamp into an absolute NTP timestamp.</p><h3>My questions:</h3><ol><li><p><strong>How can I retrieve the <code>ntp_time</code> and <code>rtp_time</code> from the RTCP SR report in FFmpeg?</strong></p><ul><li>How can I access these timestamps from the RTCP SR report in FFmpeg's <code>AVFormatContext</code>?</li><li>I understand that <code>AVRTPDynamicProtocolContext</code> seems to handle RTP and RTCP data, but this structure is not exposed in FFmpeg's public API. Is there another way to access this data?</li></ul></li><li><p><strong>How can I compute the offset between the RTP timestamp and the NTP timestamp?</strong></p><ul><li>I understand that the offset can be calculated from the RTCP SR report's <code>ntp_time</code> and <code>rtp_time</code>. Is there a way to achieve this calculation using FFmpeg's existing API?</li></ul></li><li><p><strong>How does FFmpeg handle timestamps when there are no RTCP SR reports?</strong></p><ul><li>If the RTSP stream does not contain RTCP SR reports, how does FFmpeg handle the RTP timestamps? Since the timestamps are relative, how can they be converted into absolute time?</li></ul></li></ol><h3>Current Implementation:</h3><p>I am currently using <code>av_read_frame()</code> in FFmpeg to read each RTP packet and calculate the PTS of each frame (using the stream's time base <code>time_base</code>). However, since the RTP timestamps in the RTSP stream are relative, I need to convert them into absolute time. Therefore, I hope to use the NTP timestamp and RTP timestamp from the RTCP SR report to calculate the offset.</p><h3>Request:</h3><p>I would appreciate your help in explaining how to retrieve the timestamps (<code>ntp_time</code> and <code>rtp_time</code>) from the RTCP SR report and how to perform the RTP timestamp to NTP timestamp conversion using FFmpeg.</p><p>Thank you very much for your time and attention. I look forward to your response.</p><p>Best regards,<br>Fusang</p><hr><div style="color:rgb(59,59,59);font-family:"Droid Sans Mono","monospace",monospace;font-size:14px;line-height:19px;white-space:pre"><div><span style="color:rgb(0,0,255)">extern</span> <span style="color:rgb(163,21,21)">"C"</span></div><div>{</div><div><span style="color:rgb(175,0,219)">#include</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(163,21,21)"><libavformat/avformat.h></span></div><div><span style="color:rgb(175,0,219)">#include</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(163,21,21)"><libavcodec/avcodec.h></span></div><div><span style="color:rgb(175,0,219)">#include</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(163,21,21)"><libavutil/time.h></span></div><div>}</div><br><div><span style="color:rgb(175,0,219)">#include</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(163,21,21)"><iostream></span></div><div><span style="color:rgb(175,0,219)">#include</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(163,21,21)"><memory></span></div><div><span style="color:rgb(175,0,219)">#include</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(163,21,21)"><queue></span></div><br><div><span style="color:rgb(0,0,255)">class</span> <span style="color:rgb(38,127,153)">Packet</span> {</div><div><span style="color:rgb(0,0,255)">public:</span></div><div>    <span style="color:rgb(0,0,255)">typedef</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(38,127,153)">shared_ptr</span><span style="color:rgb(0,0,0)"><</span><span style="color:rgb(38,127,153)">Packet</span><span style="color:rgb(0,0,0)">></span> <span style="color:rgb(38,127,153)">Ptr</span>;</div><div>    <span style="color:rgb(121,94,38)">Packet</span>() {</div><div>        <span style="color:rgb(0,16,128)">m_packet</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(121,94,38)">av_packet_alloc</span>();</div><div>        <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(0,0,0)">!</span><span style="color:rgb(0,16,128)">m_packet</span>) {</div><div>            <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cerr</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"av_packet_alloc fail"</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>        }</div><div>    }</div><br><div>    <span style="color:rgb(121,94,38)">~Packet</span>() {</div><div>        <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(0,16,128)">m_packet</span>) {</div><div>            <span style="color:rgb(121,94,38)">av_packet_unref</span>(<span style="color:rgb(0,16,128)">m_packet</span>);</div><div>            <span style="color:rgb(121,94,38)">av_packet_free</span>(<span style="color:rgb(0,0,0)">&</span><span style="color:rgb(0,16,128)">m_packet</span>);</div><div>            <span style="color:rgb(0,16,128)">m_packet</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,0,255)">nullptr</span>;</div><div>        }</div><div>    }</div><br><div>    <span style="color:rgb(38,127,153)">AVPacket</span><span style="color:rgb(0,0,0)">*</span> <span style="color:rgb(0,16,128)">m_packet</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,0,255)">nullptr</span>;</div><div>};</div><br><div><span style="color:rgb(0,0,255)">class</span> <span style="color:rgb(38,127,153)">BInterface</span> {</div><div><span style="color:rgb(0,0,255)">public:</span></div><div>    <span style="color:rgb(0,0,255)">void</span> <span style="color:rgb(121,94,38)">read_avpacket_fun</span>();</div><br><div><span style="color:rgb(0,0,255)">private:</span></div><div>    <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(38,127,153)">queue</span><span style="color:rgb(0,0,0)"><</span><span style="color:rgb(38,127,153)">Packet</span>::<span style="color:rgb(38,127,153)">Ptr</span><span style="color:rgb(0,0,0)">></span> <span style="color:rgb(0,16,128)">m_avpacket_list</span>;</div><div>};</div><br><div><span style="color:rgb(0,0,255)">void</span> <span style="color:rgb(38,127,153)">BInterface</span>::<span style="color:rgb(121,94,38)">read_avpacket_fun</span>() {</div><div>    <span style="color:rgb(0,0,255)">const</span> <span style="color:rgb(0,0,255)">char</span> <span style="color:rgb(0,0,0)">*</span><span style="color:rgb(0,16,128)">rtsp_url</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(163,21,21)">"rtsp://<a href="http://admin:123456@192.168.30.64:554/Streaming/Channels/101">admin:123456@192.168.30.64:554/Streaming/Channels/101</a>"</span>;<span style="color:rgb(0,128,0)">  // RTSP stream URL</span></div><br><div>    <span style="color:rgb(38,127,153)">AVFormatContext</span> <span style="color:rgb(0,0,0)">*</span><span style="color:rgb(0,16,128)">format_ctx</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,0,255)">nullptr</span>;</div><div>    <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(121,94,38)">avformat_open_input</span>(<span style="color:rgb(0,0,0)">&</span><span style="color:rgb(0,16,128)">format_ctx</span>, <span style="color:rgb(0,16,128)">rtsp_url</span>, <span style="color:rgb(0,0,255)">nullptr</span>, <span style="color:rgb(0,0,255)">nullptr</span>) <span style="color:rgb(0,0,0)"><</span> <span style="color:rgb(9,134,88)">0</span>) {</div><div>        <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cerr</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"Failed to open RTSP stream."</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>        <span style="color:rgb(175,0,219)">return</span>;</div><div>    }</div><br><div>    <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(121,94,38)">avformat_find_stream_info</span>(<span style="color:rgb(0,16,128)">format_ctx</span>, <span style="color:rgb(0,0,255)">nullptr</span>) <span style="color:rgb(0,0,0)"><</span> <span style="color:rgb(9,134,88)">0</span>) {</div><div>        <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cerr</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"Failed to find stream info."</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>        <span style="color:rgb(121,94,38)">avformat_close_input</span>(<span style="color:rgb(0,0,0)">&</span><span style="color:rgb(0,16,128)">format_ctx</span>);</div><div>        <span style="color:rgb(175,0,219)">return</span>;</div><div>    }</div><br><div><span style="color:rgb(0,128,0)">    // 查找视频流</span></div><div>    <span style="color:rgb(0,0,255)">int</span> <span style="color:rgb(0,16,128)">video_stream_index</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,0,0)">-</span><span style="color:rgb(9,134,88)">1</span>;</div><div>    <span style="color:rgb(175,0,219)">for</span> (<span style="color:rgb(0,0,255)">unsigned</span> <span style="color:rgb(0,0,255)">int</span> <span style="color:rgb(0,16,128)">i</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(9,134,88)">0</span>; <span style="color:rgb(0,16,128)">i</span> <span style="color:rgb(0,0,0)"><</span> <span style="color:rgb(0,16,128)">format_ctx</span>-><span style="color:rgb(0,16,128)">nb_streams</span>; <span style="color:rgb(0,0,0)">++</span><span style="color:rgb(0,16,128)">i</span>) {</div><div>        <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(0,16,128)">format_ctx</span>-><span style="color:rgb(0,16,128)">streams</span>[<span style="color:rgb(0,16,128)">i</span>]-><span style="color:rgb(0,16,128)">codecpar</span>-><span style="color:rgb(0,16,128)">codec_type</span> <span style="color:rgb(0,0,0)">==</span> <span style="color:rgb(0,112,193)">AVMEDIA_TYPE_VIDEO</span>) {</div><div>            <span style="color:rgb(0,16,128)">video_stream_index</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,16,128)">i</span>;</div><div>            <span style="color:rgb(175,0,219)">break</span>;</div><div>        }</div><div>    }</div><div>    <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(0,16,128)">video_stream_index</span> <span style="color:rgb(0,0,0)">==</span> <span style="color:rgb(0,0,0)">-</span><span style="color:rgb(9,134,88)">1</span>) {</div><div>        <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cerr</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"No video stream found."</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>        <span style="color:rgb(121,94,38)">avformat_close_input</span>(<span style="color:rgb(0,0,0)">&</span><span style="color:rgb(0,16,128)">format_ctx</span>);</div><div>        <span style="color:rgb(175,0,219)">return</span>;</div><div>    }</div><br><div>    <span style="color:rgb(38,127,153)">AVStream</span> <span style="color:rgb(0,0,0)">*</span><span style="color:rgb(0,16,128)">video_stream</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,16,128)">format_ctx</span>-><span style="color:rgb(0,16,128)">streams</span>[<span style="color:rgb(0,16,128)">video_stream_index</span>];</div><div>    <span style="color:rgb(38,127,153)">AVRational</span> <span style="color:rgb(0,16,128)">time_base</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,16,128)">video_stream</span>-><span style="color:rgb(0,16,128)">time_base</span>;<span style="color:rgb(0,128,0)"> // 视频流的时间基</span></div><br><div>    <span style="color:rgb(175,0,219)">while</span> (<span style="color:rgb(0,0,255)">true</span>) {</div><div>        <span style="color:rgb(38,127,153)">Packet</span>::<span style="color:rgb(38,127,153)">Ptr</span> <span style="color:rgb(0,16,128)">packet</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">make_shared</span><<span style="color:rgb(38,127,153)">Packet</span>>();</div><div>        <span style="color:rgb(0,0,255)">int</span> <span style="color:rgb(0,16,128)">ret</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(121,94,38)">av_read_frame</span>(<span style="color:rgb(0,16,128)">format_ctx</span>, <span style="color:rgb(0,16,128)">packet</span><span style="color:rgb(121,94,38)">-></span><span style="color:rgb(0,16,128)">m_packet</span>);</div><div>        <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(0,16,128)">ret</span> <span style="color:rgb(0,0,0)"><</span> <span style="color:rgb(9,134,88)">0</span>) {</div><div>            <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cerr</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"av_read_frame failed, ret("</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(0,16,128)">ret</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">")"</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>            <span style="color:rgb(175,0,219)">break</span>;</div><div>        }</div><br><div><span style="color:rgb(0,128,0)">        // 判断是否是视频流</span></div><div>        <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(0,16,128)">packet</span><span style="color:rgb(121,94,38)">-></span><span style="color:rgb(0,16,128)">m_packet</span>-><span style="color:rgb(0,16,128)">stream_index</span> <span style="color:rgb(0,0,0)">==</span> <span style="color:rgb(0,16,128)">video_stream_index</span>) {</div><div>            <span style="color:rgb(38,127,153)">int64_t</span> <span style="color:rgb(0,16,128)">pts</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(0,16,128)">packet</span><span style="color:rgb(121,94,38)">-></span><span style="color:rgb(0,16,128)">m_packet</span>-><span style="color:rgb(0,16,128)">pts</span>;<span style="color:rgb(0,128,0)">  // 获取PTS时间戳</span></div><div>            <span style="color:rgb(175,0,219)">if</span> (<span style="color:rgb(0,16,128)">pts</span> <span style="color:rgb(0,0,0)">!=</span> <span style="color:rgb(0,0,255)">AV_NOPTS_VALUE</span>) {</div><div>                <span style="color:rgb(0,0,255)">double</span> <span style="color:rgb(0,16,128)">pts_seconds</span> <span style="color:rgb(0,0,0)">=</span> <span style="color:rgb(121,94,38)">av_q2d</span>(<span style="color:rgb(0,16,128)">time_base</span>) <span style="color:rgb(0,0,0)">*</span> <span style="color:rgb(0,16,128)">pts</span>;</div><div>                <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cout</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"PTS:"</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(0,16,128)">pts</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>                <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cout</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"PTS (seconds): "</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(0,16,128)">pts_seconds</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>            } <span style="color:rgb(175,0,219)">else</span> {</div><div>                <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(0,16,128)">cerr</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(163,21,21)">"Invalid PTS value!"</span> <span style="color:rgb(121,94,38)"><<</span> <span style="color:rgb(38,127,153)">std</span>::<span style="color:rgb(121,94,38)">endl</span>;</div><div>            }</div><br><div>            <span style="color:rgb(0,16,128)">m_avpacket_list</span>.<span style="color:rgb(121,94,38)">push</span>(<span style="color:rgb(0,16,128)">packet</span>);</div><div>        }</div><div>    }</div><br><div>    <span style="color:rgb(121,94,38)">avformat_close_input</span>(<span style="color:rgb(0,0,0)">&</span><span style="color:rgb(0,16,128)">format_ctx</span>);</div><div>}</div><br><div><span style="color:rgb(0,0,255)">int</span> <span style="color:rgb(121,94,38)">main</span>() {</div><div><span style="color:rgb(0,128,0)">    // 初始化FFmpeg库</span></div><div>    <span style="color:rgb(121,94,38)">avformat_network_init</span>();</div><br><div>    <span style="color:rgb(38,127,153)">BInterface</span> <span style="color:rgb(0,16,128)">bInterface</span>;</div><div>    <span style="color:rgb(0,16,128)">bInterface</span>.<span style="color:rgb(121,94,38)">read_avpacket_fun</span>();</div><br><div>    <span style="color:rgb(175,0,219)">return</span> <span style="color:rgb(9,134,88)">0</span>;</div><div>}</div><br></div></div>