Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] avformat/whip: enable RTCP NACK for whip (PR #20460)
@ 2025-09-08  2:46 Jack Lau via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: Jack Lau via ffmpeg-devel @ 2025-09-08  2:46 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Jack Lau

PR #20460 opened by Jack Lau (JackLau)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20460
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20460.patch

Refer to RFC 4585 4.2,
Add SDP "a=rtcp-fb" so the peer can request rtx
through sending NACKs.

Add basic parsing for NACK packet.
Decrypt into a newly allocated buffer (do not
overwrite whip->buf) so multiple NACKs in a
bundled packet can be parsed in a loop while
keeping whip->buf available for sending rtx

Broken or wrong NACk are logged and skipped.

Signed-off-by: Jack Lau <jacklau1222@qq.com>


>From f008fe3da908d4a577a79908a9fc7fb052ce957b Mon Sep 17 00:00:00 2001
From: Jack Lau <jacklau1222@qq.com>
Date: Mon, 8 Sep 2025 10:19:49 +0800
Subject: [PATCH] avformat/whip: enable RTCP NACK for whip

Refer to RFC 4585 4.2,
Add SDP "a=rtcp-fb" so the peer can request rtx
through sending NACKs.

Add basic parsing for NACK packet.
Decrypt into a newly allocated buffer (do not
overwrite whip->buf) so multiple NACKs in a
bundled packet can be parsed in a loop while
keeping whip->buf available for sending rtx

Broken or wrong NACk are logged and skipped.

Signed-off-by: Jack Lau <jacklau1222@qq.com>
---
 libavformat/whip.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/libavformat/whip.c b/libavformat/whip.c
index 20db03a239..316c0fd6b9 100644
--- a/libavformat/whip.c
+++ b/libavformat/whip.c
@@ -40,6 +40,7 @@
 #include "internal.h"
 #include "mux.h"
 #include "network.h"
+#include "rtp.h"
 #include "srtp.h"
 #include "tls.h"
 
@@ -669,6 +670,7 @@ static int generate_sdp_offer(AVFormatContext *s)
             "a=rtcp-rsize\r\n"
             "a=rtpmap:%u %s/90000\r\n"
             "a=fmtp:%u level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=%02x%02x%02x\r\n"
+            "a=rtcp-fb%u nack\r\n"
             "a=ssrc:%u cname:FFmpeg\r\n"
             "a=ssrc:%u msid:FFmpeg video\r\n",
             whip->video_payload_type,
@@ -681,6 +683,7 @@ static int generate_sdp_offer(AVFormatContext *s)
             profile_idc,
             profile_iop,
             level,
+            whip->video_payload_type,
             whip->video_ssrc,
             whip->video_ssrc);
     }
@@ -1779,6 +1782,43 @@ end:
     return ret;
 }
 
+static void handle_nack_rtx(AVFormatContext *s, int size)
+{
+    int ret;
+    WHIPContext *whip = s->priv_data;
+    uint8_t *buf = NULL;
+    int rtcp_len, srtcp_len, header_len = 12/*RFC 4585 6.1*/;
+
+    /**
+     * Refer to RFC 3550 6.4.1
+     * The length of this RTCP packet in 32 bit words minus one,
+     * including the header and any padding.
+     */
+    rtcp_len = (AV_RB16(&whip->buf[2]) + 1) * 4;
+    if (rtcp_len <= header_len) {
+        av_log(whip, AV_LOG_WARNING, "NACK packet is broken, size: %d\n", rtcp_len);
+        goto error;
+    }
+    /* SRTCP index(4 bytes) + HMAC(SRTP_ARS128_CM_SHA1_80) 10bytes */
+    srtcp_len = rtcp_len + 4 + 10;
+    if (srtcp_len != size) {
+        av_log(whip, AV_LOG_WARNING, "NACK packet size not match, srtcp_len:%d, size:%d\n", srtcp_len, size);
+        goto error;
+    }
+    buf = av_memdup(whip->buf, srtcp_len);
+    if (!buf)
+        goto error;
+    if ((ret = ff_srtp_decrypt(&whip->srtp_recv, buf, &srtcp_len)) < 0) {
+        av_log(whip, AV_LOG_WARNING, "NACK packet decrypt failed: %d\n", ret);
+        goto error;
+    }
+    goto end;
+error:
+    av_log(whip, AV_LOG_WARNING, "Failed to handle NACK and RTX, Skip...\n");
+end:
+    av_freep(&buf);
+}
+
 static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     int ret;
@@ -1809,6 +1849,19 @@ static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
             goto end;
         }
     }
+    if (media_is_rtcp(whip->buf, ret)) {
+        uint8_t pt = whip->buf[1];
+        uint8_t fmt = (whip->buf[0] & 0x1f);
+        /**
+         * Handle RTCP NACK packet
+         * Refer to RFC 4585 6.2.1
+         * The Generic NACK message is identified by PT=RTPFB and FMT=1
+         */
+        if (pt != RTCP_RTPFB)
+            goto write_packet;
+        if (fmt == 1)
+            handle_nack_rtx(s, ret);
+    }
 write_packet:
     if (whip->h264_annexb_insert_sps_pps && st->codecpar->codec_id == AV_CODEC_ID_H264) {
         if ((ret = h264_annexb_insert_sps_pps(s, pkt)) < 0) {
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-09-08  2:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-08  2:46 [FFmpeg-devel] [PATCH] avformat/whip: enable RTCP NACK for whip (PR #20460) Jack Lau via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git