<!DOCTYPE html><html><head><title></title><style type="text/css">p.MsoNormal,p.MsoNoSpacing{margin:0}</style></head><body><div>You can't directly access the timestamps in the sender reports, but there's a couple fields that might be helpful.<br></div><div><br></div><div>The start_time_realtime field on the AVFormatContext will be set to a UNIX timestamp (microseconds) if the SR has been received, otherwise it will be set to AV_NOPTS_VALUE. <br></div><div><br></div><div>You can also use the av_packet_get_side_data function with AV_PKT_DATA_PRFT. This will give you UNIX timestamps on each individual packet if the SR has been sent. If the SR hasn't been sent, the sidedata will be missing. <br></div><div><br></div><div>If you need to synchronize multiple streams, you can use both of these. start_time_realtime, however, will be subject to clock drift. AV_PKT_DATA_PRFT is more accurate, since it's computed for each packet.<br></div><div><br></div><div>On Tue, Feb 11, 2025, at 8:31 PM, 扶桑 wrote:<br></div><blockquote type="cite" id="qt" style=""><div dir="ltr"><p>Dear FFmpeg Development Team,<br></p><p>Hello!<br></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.<br></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.<br></p><p>According to the specifications in <b>RFC 2326</b> and <b>RFC 3550</b>, the <b>RTCP SR (Sender Report)</b> contains a mapping between <b>NTP timestamps</b> and <b>RTP timestamps</b>, 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.<br></p><h3>My questions:<br></h3><ol><li><p><b>How can I retrieve the <code>ntp_time</code> and <code>rtp_time</code> from the RTCP SR report in FFmpeg?</b><br></p><ul><li>How can I access these timestamps from the RTCP SR report in FFmpeg's <code>AVFormatContext</code>?<br></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?<br></li></ul></li><li><p><b>How can I compute the offset between the RTP timestamp and the NTP timestamp?</b><br></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?<br></li></ul></li><li><p><b>How does FFmpeg handle timestamps when there are no RTCP SR reports?</b><br></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?<br></li></ul></li></ol><h3>Current Implementation:<br></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.<br></p><h3>Request:<br></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.<br></p><p>Thank you very much for your time and attention. I look forward to your response.<br></p><p><br></p><div>Best regards,<br></div><div>Fusang<br></div><p><br></p><div><hr><br></div><div style="color:rgb(59, 59, 59);font-family:"Droid Sans Mono", "monospace", monospace;font-size:14px;line-height:19px;text-wrap:nowrap;"><div><span style="color:rgb(0, 0, 255);">extern</span> <span style="color:rgb(163, 21, 21);">"C"</span><br></div><div>{<br></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><br></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><br></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><br></div><div>}<br></div><div><br></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);"><iostream></span><br></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><br></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><br></div><div><br></div><div><span style="color:rgb(0, 0, 255);">class</span> <span style="color:rgb(38, 127, 153);">Packet</span> {<br></div><div><span style="color:rgb(0, 0, 255);">public:</span><br></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>;<br></div><div><span style="color:rgb(121, 94, 38);">Packet</span>() {<br></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>();<br></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>) {<br></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>;<br></div><div>}<br></div><div>}<br></div><div><br></div><div><span style="color:rgb(121, 94, 38);">~Packet</span>() {<br></div><div><span style="color:rgb(175, 0, 219);">if</span> (<span style="color:rgb(0, 16, 128);">m_packet</span>) {<br></div><div><span style="color:rgb(121, 94, 38);">av_packet_unref</span>(<span style="color:rgb(0, 16, 128);">m_packet</span>);<br></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>);<br></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>;<br></div><div>}<br></div><div>}<br></div><div><br></div><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>;<br></div><div>};<br></div><div><br></div><div><span style="color:rgb(0, 0, 255);">class</span> <span style="color:rgb(38, 127, 153);">BInterface</span> {<br></div><div><span style="color:rgb(0, 0, 255);">public:</span><br></div><div><span style="color:rgb(0, 0, 255);">void</span> <span style="color:rgb(121, 94, 38);">read_avpacket_fun</span>();<br></div><div><br></div><div><span style="color:rgb(0, 0, 255);">private:</span><br></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>;<br></div><div>};<br></div><div><br></div><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>() {<br></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><br></div><div><br></div><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>;<br></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>) {<br></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>;<br></div><div><span style="color:rgb(175, 0, 219);">return</span>;<br></div><div>}<br></div><div><br></div><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>) {<br></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>;<br></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>);<br></div><div><span style="color:rgb(175, 0, 219);">return</span>;<br></div><div>}<br></div><div><br></div><div><span style="color:rgb(0, 128, 0);">// 查找视频流</span><br></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>;<br></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>) {<br></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>) {<br></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>;<br></div><div><span style="color:rgb(175, 0, 219);">break</span>;<br></div><div>}<br></div><div>}<br></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>) {<br></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>;<br></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>);<br></div><div><span style="color:rgb(175, 0, 219);">return</span>;<br></div><div>}<br></div><div><br></div><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>];<br></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><br></div><div><br></div><div><span style="color:rgb(175, 0, 219);">while</span> (<span style="color:rgb(0, 0, 255);">true</span>) {<br></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>>();<br></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>);<br></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>) {<br></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>;<br></div><div><span style="color:rgb(175, 0, 219);">break</span>;<br></div><div>}<br></div><div><br></div><div><span style="color:rgb(0, 128, 0);">// 判断是否是视频流</span><br></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>) {<br></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><br></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>) {<br></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>;<br></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>;<br></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>;<br></div><div>} <span style="color:rgb(175, 0, 219);">else</span> {<br></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>;<br></div><div>}<br></div><div><br></div><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>);<br></div><div>}<br></div><div>}<br></div><div><br></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>);<br></div><div>}<br></div><div><br></div><div><span style="color:rgb(0, 0, 255);">int</span> <span style="color:rgb(121, 94, 38);">main</span>() {<br></div><div><span style="color:rgb(0, 128, 0);">// 初始化FFmpeg库</span><br></div><div><span style="color:rgb(121, 94, 38);">avformat_network_init</span>();<br></div><div><br></div><div><span style="color:rgb(38, 127, 153);">BInterface</span> <span style="color:rgb(0, 16, 128);">bInterface</span>;<br></div><div><span style="color:rgb(0, 16, 128);">bInterface</span>.<span style="color:rgb(121, 94, 38);">read_avpacket_fun</span>();<br></div><div><br></div><div><span style="color:rgb(175, 0, 219);">return</span> <span style="color:rgb(9, 134, 88);">0</span>;<br></div><div>}<br></div></div></div><div>_______________________________________________<br></div><div>Libav-user mailing list<br></div><div><a href="mailto:Libav-user@ffmpeg.org">Libav-user@ffmpeg.org</a><br></div><div><a href="https://ffmpeg.org/mailman/listinfo/libav-user">https://ffmpeg.org/mailman/listinfo/libav-user</a><br></div><div><br></div><div>To unsubscribe, visit link above, or email<br></div><div><a href="mailto:libav-user-request@ffmpeg.org">libav-user-request@ffmpeg.org</a> with subject "unsubscribe".<br></div><div><br></div></blockquote><div><br></div></body></html>