This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit d7820156f92a490ecff45b9e92bfe6ca2c621585 Author: Jack Lau <[email protected]> AuthorDate: Tue Jan 20 20:30:18 2026 +0800 Commit: Jack Lau <[email protected]> CommitDate: Fri Feb 27 12:42:05 2026 +0000 avformat/whip: add RTX support See https://datatracker.ietf.org/doc/html/rfc4588 Parse sequence number from NACKs, then create RTX packet and send it. Signed-off-by: Jack Lau <[email protected]> avformat/whip: set NACK logs as DEBUG Signed-off-by: Jack Lau <[email protected]> --- libavformat/whip.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/libavformat/whip.c b/libavformat/whip.c index bc3f5a9c6d..e728464660 100644 --- a/libavformat/whip.c +++ b/libavformat/whip.c @@ -264,6 +264,8 @@ typedef struct WHIPContext { uint16_t audio_first_seq; uint16_t video_first_seq; + + uint16_t video_rtx_seq; /* The PT(Payload Type) of stream, generated by the muxer. */ uint8_t audio_payload_type; uint8_t video_payload_type; @@ -1880,9 +1882,70 @@ end: return ret; } +/** + * See https://datatracker.ietf.org/doc/html/rfc4588#section-4 + * Create RTX packet and send it out. + */ +static void handle_rtx_packet(AVFormatContext *s, uint16_t seq) +{ + int ret = -1; + WHIPContext *whip = s->priv_data; + uint8_t *ori_buf, rtx_buf[MAX_UDP_BUFFER_SIZE] = { 0 }; + int ori_size, rtx_size, cipher_size; + uint16_t ori_seq; + const RtpHistoryItem *it = rtp_history_find(whip, seq); + uint16_t latest_seq = whip->hist[(whip->hist_head - 1 + whip->hist_sz) % whip->hist_sz].seq; + + if (!it) { + av_log(whip, AV_LOG_DEBUG, + "RTP history packet seq=%"PRIu16" not found, latest seq=%"PRIu16"\n", + seq, latest_seq); + return; + } + av_log(whip, AV_LOG_DEBUG, + "Found RTP history packet for RTX, seq=%"PRIu16", latest seq=%"PRIu16"\n", + seq, latest_seq); + + ori_buf = it->buf; + ori_size = it->size; + + /* RTX packet format: header + original seq (2 bytes) + payload */ + if (ori_size + 2 > sizeof(rtx_buf)) { + av_log(whip, AV_LOG_WARNING, "RTX packet is too large, size=%d\n", ori_size); + goto end; + } + + memcpy(rtx_buf, ori_buf, ori_size); + ori_seq = AV_RB16(rtx_buf + 2); + + /* rewrite RTX packet header */ + rtx_buf[1] = (rtx_buf[1] & 0x80) | whip->video_rtx_payload_type; /* keep M bit */ + AV_WB16(rtx_buf + 2, whip->video_rtx_seq++); + AV_WB32(rtx_buf + 8, whip->video_rtx_ssrc); + + /* shift payload 2 bytes to write the original seq number */ + memmove(rtx_buf + 12 + 2, rtx_buf + 12, ori_size - 12); + AV_WB16(rtx_buf + 12, ori_seq); + + rtx_size = ori_size + 2; + cipher_size = ff_srtp_encrypt(&whip->srtp_video_rtx_send, + rtx_buf, rtx_size, + whip->buf, sizeof(whip->buf)); + if (cipher_size <= 0) { + av_log(whip, AV_LOG_WARNING, + "Failed to encrypt RTX packet, size=%d, cipher_size=%d\n", + rtx_size, cipher_size); + goto end; + } + ret = ffurl_write(whip->udp, whip->buf, cipher_size); +end: + if (ret < 0) + av_log(whip, AV_LOG_WARNING, "Failed to send RTX packet, skip this one\n"); +} + static void handle_nack_rtx(AVFormatContext *s, int size) { - int ret; + int ret, i = 0; WHIPContext *whip = s->priv_data; uint8_t *buf = NULL; int rtcp_len, srtcp_len, header_len = 12/*RFC 4585 6.1*/; @@ -1910,6 +1973,27 @@ static void handle_nack_rtx(AVFormatContext *s, int size) av_log(whip, AV_LOG_WARNING, "NACK packet decrypt failed: %d\n", ret); goto error; } + while (header_len + i + 4 <= rtcp_len) { + /** + * See https://datatracker.ietf.org/doc/html/rfc4585#section-6.1 + * Handle multi NACKs in bundled packet. + */ + uint16_t pid = AV_RB16(&buf[12 + i]); + uint16_t blp = AV_RB16(&buf[14 + i]); + + handle_rtx_packet(s, pid); + /* retransmit pid + any bit set in blp */ + for (int bit = 0; bit < 16; bit++) { + uint16_t seq = pid + bit + 1; + if (!blp) + break; + if (!(blp & (1 << bit))) + continue; + + handle_rtx_packet(s, seq); + } + i += 4; + } goto end; error: av_log(whip, AV_LOG_WARNING, "Failed to handle NACK and RTX, Skip...\n"); _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
