mirror of
https://mirror.skon.top/https://github.com/FFmpeg/FFmpeg
synced 2026-04-20 21:00:41 +08:00
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 <jacklau1222gm@gmail.com> avformat/whip: set NACK logs as DEBUG Signed-off-by: Jack Lau <jacklau1222gm@gmail.com>
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user