|
- #include "rtp-internal.h"
- #include "rtp-util.h"
- #include <errno.h>
-
- static int rtcp_psfb_pli_pack(uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_sli_pack(const rtcp_sli_t* sli, int count, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_rpsi_pack(uint8_t pt, const uint8_t* payload, uint32_t bits, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_fir_pack(const rtcp_fir_t* fir, int count, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_tstr_pack(const rtcp_fir_t* fir, int count, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_tstn_pack(const rtcp_fir_t* fir, int count, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_vbcm_pack(const rtcp_vbcm_t* vbcm, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_pslei_pack(const uint32_t* ssrc, int count, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_lrr_pack(const rtcp_lrr_t* lrr, int count, uint8_t* ptr, uint32_t bytes);
- static int rtcp_psfb_remb_pack(const rtcp_remb_t* remb, int count, uint8_t* ptr, uint32_t bytes);
-
- static int rtcp_psfb_pli_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_sli_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_rpsi_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_fir_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_tstr_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_tstn_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_vbcm_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_pslei_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_lrr_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_roi_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
- static int rtcp_psfb_afb_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes);
-
-
- // https://datatracker.ietf.org/doc/html/rfc4585#section-6.3.1
- static int rtcp_psfb_pli_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- // 1. There MUST be exactly one PLI contained in the FCI field.
- // 2. PLI does not require parameters. Therefore, the length field MUST be 2, and there MUST NOT be any Feedback Control Information.
- assert(0 == bytes);
-
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header, (void)ptr;
- return 0;
- }
-
- static int rtcp_psfb_pli_pack(uint8_t* ptr, uint32_t bytes)
- {
- (void)ptr, (void)bytes;
- return 0;
- }
-
- // https://datatracker.ietf.org/doc/html/rfc4585#section-6.3.2
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | First | Number | PictureID |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_sli_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- size_t i;
- rtcp_sli_t* sli, sli0[32];
-
- if (bytes / 4 > sizeof(sli0) / sizeof(sli0[0]))
- {
- sli = calloc(bytes / 4, sizeof(*sli));
- if (!sli) return -ENOMEM;
- }
- else
- {
- sli = sli0;
- memset(sli, 0, sizeof(sli[0]) * (bytes / 4));
- }
-
- for (i = 0; i < bytes / 4; i++)
- {
- sli[i].first = (ptr[0] << 5) | (ptr[1] >> 3);
- sli[i].number = ((ptr[1] & 0x07) << 10) | (ptr[2] << 2) | (ptr[3] >> 6);
- sli[i].picture_id = ptr[3] & 0x3F;
-
- ptr += 4;
- }
-
- msg->u.psfb.u.sli.sli = sli;
- msg->u.psfb.u.sli.count = (int)i;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header;
- if (sli && sli != sli0)
- free(sli);
- return 0;
- }
-
- static int rtcp_psfb_sli_pack(const rtcp_sli_t* sli, int count, uint8_t* ptr, uint32_t bytes)
- {
- int i;
- for (i = 0; i < count && bytes >= 4; i++)
- {
- nbo_w32(ptr, ((sli->first & 0x1FFFF) << 19) | ((sli->number & 0x1FFFF) << 6) | (sli->picture_id & 0x3F));
-
- bytes -= 4;
- ptr += 4;
- }
- return i * 4;
- }
-
- // https://datatracker.ietf.org/doc/html/rfc4585#section-6.3.3
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | PB |0| Payload Type| Native RPSI bit string |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | defined per codec ... | Padding (0) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_rpsi_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- uint8_t pb;
- uint8_t pt;
-
- if (bytes < 4)
- return -1;
-
- pb = ptr[0];
- pt = ptr[1] & 0x7F;
-
- msg->u.psfb.u.rpsi.pt = pt;
- msg->u.psfb.u.rpsi.len = (uint32_t)bytes * 8 - pb;
- msg->u.psfb.u.rpsi.payload = (uint8_t*)ptr + 2;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header;
- return 0;
- }
-
- static int rtcp_psfb_rpsi_pack(uint8_t pt, const uint8_t* payload, uint32_t bits, uint8_t* ptr, uint32_t bytes)
- {
- uint32_t len;
- len = (bits + 7) / 8;
- if (bytes < (2 + len + 3) / 4 * 4)
- return -1;
-
- ptr[0] = (uint8_t)((2 + len + 3) / 4 * 4 * 8 - (2 * 8 + bits));
- ptr[1] = pt;
- memcpy(ptr + 2, payload, len);
- return (2 + len + 3) / 4 * 4;
- }
-
- // https://www.rfc-editor.org/rfc/rfc5104.html#section-4.3.1
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Seq nr. | Reserved |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_fir_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- size_t i;
- rtcp_fir_t *fir, fir0[32];
-
- if (bytes / 8 > sizeof(fir0) / sizeof(fir0[0]))
- {
- fir = calloc(bytes / 8, sizeof(*fir));
- if (!fir) return -ENOMEM;
- }
- else
- {
- fir = fir0;
- memset(fir, 0, sizeof(fir[0]) * (bytes / 8));
- }
-
- for (i = 0; i < bytes / 8; i++)
- {
- fir[i].ssrc = nbo_r32(ptr);
- fir[i].sn = ptr[4];
- ptr += 8;
- }
-
- msg->u.psfb.u.fir.fir = fir;
- msg->u.psfb.u.fir.count = (int)i;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header;
- if (fir && fir != fir0)
- free(fir);
- return 0;
- }
-
- static int rtcp_psfb_fir_pack(const rtcp_fir_t* fir, int count, uint8_t* ptr, uint32_t bytes)
- {
- int i;
- for (i = 0; i < count && bytes >= 8; i++)
- {
- nbo_w32(ptr, fir[i].ssrc);
- nbo_w32(ptr + 4, fir[i].sn << 24);
-
- bytes -= 8;
- ptr += 8;
- }
- return i * 8;
- }
-
- // https://www.rfc-editor.org/rfc/rfc5104.html#section-4.3.2
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Seq nr. | Reserved | Index |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_tstr_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- size_t i;
- rtcp_fir_t* fir, fir0[32];
-
- if (bytes / 8 > sizeof(fir0) / sizeof(fir0[0]))
- {
- fir = calloc(bytes / 8, sizeof(*fir));
- if (!fir) return -ENOMEM;
- }
- else
- {
- fir = fir0;
- memset(fir, 0, sizeof(fir[0]) * (bytes / 8));
- }
-
- for (i = 0; i < bytes / 8; i++)
- {
- fir[i].ssrc = nbo_r32(ptr);
- fir[i].sn = ptr[4];
- fir[i].index = ptr[7] & 0x1F;
-
- ptr += 8;
- }
-
- msg->u.psfb.u.fir.fir = fir;
- msg->u.psfb.u.fir.count = (int)i;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header;
- if (fir && fir != fir0)
- free(fir);
- return 0;
- }
-
- static int rtcp_psfb_tstr_pack(const rtcp_fir_t* fir, int count, uint8_t* ptr, uint32_t bytes)
- {
- int i;
- for (i = 0; i < count && bytes >= 8; i++)
- {
- nbo_w32(ptr, fir[i].ssrc);
- nbo_w32(ptr + 4, (fir[i].sn << 24) | fir[i].index);
-
- bytes -= 8;
- ptr += 8;
- }
- return i * 8;
- }
-
- // https://www.rfc-editor.org/rfc/rfc5104.html#section-4.3.3
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Seq nr. | Reserved | Index |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_tstn_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- size_t i;
- rtcp_fir_t* fir, fir0[32];
-
- if (bytes / 8 > sizeof(fir0) / sizeof(fir0[0]))
- {
- fir = calloc(bytes / 8, sizeof(*fir));
- if (!fir) return -ENOMEM;
- }
- else
- {
- fir = fir0;
- memset(fir, 0, sizeof(fir[0]) * (bytes / 8));
- }
-
- for (i = 0; i < bytes / 8; i++)
- {
- fir[i].ssrc = nbo_r32(ptr);
- fir[i].sn = ptr[4];
- fir[i].index = ptr[7] & 0x1F;
-
- ptr += 8;
- }
-
- msg->u.psfb.u.fir.fir = fir;
- msg->u.psfb.u.fir.count = (int)i;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header;
- if (fir && fir != fir0)
- free(fir);
- return 0;
- }
-
- static int rtcp_psfb_tstn_pack(const rtcp_fir_t* fir, int count, uint8_t* ptr, uint32_t bytes)
- {
- return rtcp_psfb_tstr_pack(fir, count, ptr, bytes);
- }
-
- // https://www.rfc-editor.org/rfc/rfc5104.html#section-4.3.4
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Seq nr. |0| Payload Type| Length |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | VBCM Octet String.... | Padding |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_vbcm_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- rtcp_vbcm_t vbcm;
-
- while(bytes > 8)
- {
- vbcm.ssrc = nbo_r32(ptr);
- vbcm.sn = ptr[4];
- vbcm.pt = ptr[5] & 0x7F;
- vbcm.len = nbo_r16(ptr + 6);
- if (vbcm.len + 8 > bytes)
- return -1;
-
- vbcm.payload = (uint8_t*)ptr + 8;
- bytes -= 8 + (vbcm.len + 3) / 4 * 4;
- ptr += 8 + (vbcm.len + 3) / 4 * 4;
-
- memcpy(&msg->u.psfb.u.vbcm, &vbcm, sizeof(vbcm));
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- }
-
- (void)ctx, (void)header;
- return 0;
- }
-
- static int rtcp_psfb_vbcm_pack(const rtcp_vbcm_t* vbcm, uint8_t* ptr, uint32_t bytes)
- {
- if (bytes < 8 + (uint32_t)(vbcm->len + 3) / 4 * 4)
- return -1;
-
- nbo_w32(ptr, vbcm->ssrc);
- ptr[4] = (uint8_t)vbcm->sn;
- ptr[5] = (uint8_t)vbcm->pt;
- nbo_w16(ptr + 6, (uint16_t)vbcm->len);
- memcpy(ptr + 8, vbcm->payload, vbcm->len);
- return 8 + (vbcm->len + 3) / 4 * 4;
- }
-
- // https://www.rfc-editor.org/rfc/rfc6642.html#section-5.2
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_pslei_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- size_t i;
- uint32_t* v, v0[32];
-
- if (bytes / 4 > sizeof(v0) / sizeof(v0[0]))
- {
- v = calloc(bytes / 4, sizeof(*v));
- if (!v) return -ENOMEM;
- }
- else
- {
- v = v0;
- memset(v, 0, sizeof(v[0]) * (bytes / 4));
- }
-
- for (i = 0; i < bytes / 4; i++)
- {
- v[i] = nbo_r32(ptr);
- ptr += 4;
- }
-
- msg->u.psfb.u.pslei.ssrc = v;
- msg->u.psfb.u.pslei.count = (int)i;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header;
- if (v && v != v0)
- free(v);
- return 0;
- }
-
- static int rtcp_psfb_pslei_pack(const uint32_t* ssrc, int count, uint8_t* ptr, uint32_t bytes)
- {
- int i;
- for (i = 0; i < count && bytes >= 4; i++)
- {
- nbo_w32(ptr, ssrc[i]);
-
- bytes -= 4;
- ptr += 4;
- }
- return i * 4;
- }
-
- // https://datatracker.ietf.org/doc/html/draft-ietf-avtext-lrr-07#section-3.1
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Seq nr. |C| Payload Type| Reserved |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | RES | TTID| TLID | RES | CTID| CLID |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_lrr_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- size_t i;
- rtcp_lrr_t* lrr, lrr0[32];
-
- if (bytes / 12 > sizeof(lrr0) / sizeof(lrr0[0]))
- {
- lrr = calloc(bytes / 12, sizeof(*lrr));
- if (!lrr) return -ENOMEM;
- }
- else
- {
- lrr = lrr0;
- memset(lrr, 0, sizeof(lrr[0]) * (bytes / 12));
- }
-
- for (i = 0; i < bytes / 12; i++)
- {
- lrr[i].ssrc = nbo_r32(ptr);
- lrr[i].sn = ptr[4];
- lrr[i].c = (ptr[5] >> 7) & 0x01;
- lrr[i].payload = ptr[5] & 0x7F;
- lrr[i].ttid = ptr[8] & 0x07;
- lrr[i].tlid = ptr[9];
- lrr[i].ctid = ptr[10] & 0x07;
- lrr[i].clid = ptr[11];
- ptr += 12;
- }
-
- msg->u.psfb.u.lrr.lrr = lrr;
- msg->u.psfb.u.lrr.count = (int)i;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- (void)ctx, (void)header;
- if (lrr && lrr != lrr0)
- free(lrr);
- return 0;
- }
-
- static int rtcp_psfb_lrr_pack(const rtcp_lrr_t* lrr, int count, uint8_t* ptr, uint32_t bytes)
- {
- int i;
- for (i = 0; i < count && bytes >= 12; i++)
- {
- nbo_w32(ptr, lrr[i].ssrc);
- nbo_w32(ptr, (lrr[i].sn << 24) | ((lrr[i].c & 0x01) << 23) | ((lrr[i].payload & 0x7F) << 16));
- nbo_w32(ptr, ((lrr[i].ttid & 0x07) << 24) | ((lrr[i].tlid & 0xFF) << 16) | ((lrr[i].ctid & 0x07) << 8) | ((lrr[i].clid & 0xFF) << 0));
-
- bytes -= 12;
- ptr += 12;
- }
- return i * 12;
- }
-
- // https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1404
- // 7.3.7 Video Region-of-Interest (ROI) Signaling
- /*
- Arbitrary ROI
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Position_X (h)| Position_X (l)| Position_Y (h)| Position_Y(l)|
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size_X (h) | Size_X (l) | Size_Y (h) | Size_Y(l) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Pre-defined ROI
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | all ones | ROI_ID |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | ID | len=7 | Position_X (h)| Position_X (l)| Position_Y (h)|
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Position_Y (l)| Size_X (h) | Size_X (l) | Size_Y (h) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size_Y (l) | zero padding |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | ID | len=0 | ROI_ID | zero padding |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtcp_psfb_roi_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- (void)ctx, (void)header, (void)msg, (void)ptr, (void)bytes;
- return 0;
- }
-
- // https://datatracker.ietf.org/doc/html/rfc4585#section-6.4
- // https://datatracker.ietf.org/doc/html/draft-alvestrand-rmcat-remb-03#section-2.2
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |V=2|P| FMT=15 | PT=206 | length |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC of packet sender |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC of media source |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Unique identifier 'R' 'E' 'M' 'B' |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Num SSRC | BR Exp | BR Mantissa |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC feedback |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | ... |
- */
- static int rtcp_psfb_afb_unpack(struct rtp_context* ctx, const rtcp_header_t* header, struct rtcp_msg_t* msg, const uint8_t* ptr, size_t bytes)
- {
- uint32_t i, n, exp, mantissa;
- rtcp_remb_t* remb, remb0[4];
- const uint8_t id[] = { 'R', 'E', 'M', 'B' };
-
- if (bytes >= 8 && 0 == memcmp(ptr, id, 4))
- {
- n = ptr[4];
- exp = (ptr[5] >> 2) & 0x3F;
- mantissa = ((ptr[5] & 0x3) << 16) | nbo_r16(ptr+6);
-
- ptr += 8;
- bytes -= 8;
- if (n * 4 > bytes)
- return -1;
-
- if (n > sizeof(remb0) / sizeof(remb0[0]))
- {
- remb = calloc(n, sizeof(*remb));
- if (!remb) return -ENOMEM;
- }
- else
- {
- remb = remb0;
- memset(remb, 0, sizeof(remb[0]) * n);
- }
-
- for (i = 0; i < n; i++)
- {
- remb[i].exp = exp;
- remb[i].mantissa = mantissa;
- remb[i].ssrc = nbo_r32(ptr);
- ptr += 4;
- }
-
- msg->u.psfb.u.afb.remb = remb;
- msg->u.psfb.u.afb.count = i;
- ctx->handler.on_rtcp(ctx->cbparam, msg);
- if (remb && remb != remb0)
- free(remb);
- return 0;
- }
-
- (void)ctx, (void)header;
- return 0;
- }
-
- static int rtcp_psfb_remb_pack(const rtcp_remb_t* remb, int count, uint8_t* ptr, uint32_t bytes)
- {
- int i;
- const uint8_t id[] = { 'R', 'E', 'M', 'B' };
-
- if (count < 1 || count > 255 || (int)bytes < 4 + 4 + count * 4)
- return -E2BIG;
-
- memcpy(ptr, id, sizeof(id));
- nbo_w32(ptr + 4, (count << 24) | (remb[0].exp << 18) | remb[0].mantissa);
-
- ptr += 8;
- for (i = 0; i < count; i++)
- {
- nbo_w32(ptr, remb[i].ssrc);
- ptr += 4;
- }
- return 4 + 4 + count * 4;
- }
-
- // https://datatracker.ietf.org/doc/html/rfc4585#section-6.3
- /*
- * Common Packet Format for Feedback Messages
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |V=2|P| FMT | PT | length |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC of packet sender |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | SSRC of media source |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- : Feedback Control Information (FCI) :
- : :
- */
- void rtcp_psfb_unpack(struct rtp_context* ctx, const rtcp_header_t* header, const uint8_t* ptr, size_t bytes)
- {
- int r;
- struct rtcp_msg_t msg;
- struct rtp_member* sender;
-
- if (bytes < 8 /*sizeof(rtcp_fci_t)*/)
- {
- assert(0);
- return;
- }
-
- msg.type = RTCP_PSFB | (header->rc << 8);
- msg.ssrc = nbo_r32(ptr);
- msg.u.psfb.media = nbo_r32(ptr + 4);
-
- sender = rtp_sender_fetch(ctx, msg.ssrc);
- if (!sender) return; // error
- assert(sender != ctx->self);
-
- r = 0;
- switch (header->rc)
- {
- case RTCP_PSFB_PLI:
- r = rtcp_psfb_pli_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_SLI:
- r = rtcp_psfb_sli_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_RPSI:
- r = rtcp_psfb_rpsi_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_FIR:
- r = rtcp_psfb_fir_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_TSTR:
- r = rtcp_psfb_tstr_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_TSTN:
- r = rtcp_psfb_tstn_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_VBCM:
- r = rtcp_psfb_vbcm_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_PSLEI:
- r = rtcp_psfb_pslei_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_ROI:
- r = rtcp_psfb_roi_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_LRR:
- r = rtcp_psfb_lrr_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- case RTCP_PSFB_AFB:
- r = rtcp_psfb_afb_unpack(ctx, header, &msg, ptr + 8, bytes - 8);
- break;
-
- default:
- assert(0);
- r = 0; // ignore
- break;
- }
-
- return;
- }
-
- int rtcp_psfb_pack(struct rtp_context* ctx, uint8_t* data, int bytes, enum rtcp_psfb_type_t id, const rtcp_psfb_t* psfb)
- {
- int r;
- rtcp_header_t header;
-
- (void)ctx;
- if (bytes < 4 + 4 + 4)
- return 4 + 4 + 4;
-
- switch (id)
- {
- case RTCP_PSFB_PLI:
- r = rtcp_psfb_pli_pack(data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_SLI:
- r = rtcp_psfb_sli_pack(psfb->u.sli.sli, psfb->u.sli.count, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_RPSI:
- r = rtcp_psfb_rpsi_pack(psfb->u.rpsi.pt, psfb->u.rpsi.payload, psfb->u.rpsi.len, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_FIR:
- r = rtcp_psfb_fir_pack(psfb->u.fir.fir, psfb->u.fir.count, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_TSTR:
- r = rtcp_psfb_tstr_pack(psfb->u.fir.fir, psfb->u.fir.count, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_TSTN:
- r = rtcp_psfb_tstn_pack(psfb->u.fir.fir, psfb->u.fir.count, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_VBCM:
- r = rtcp_psfb_vbcm_pack(&psfb->u.vbcm, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_PSLEI:
- r = rtcp_psfb_pslei_pack(psfb->u.pslei.ssrc, psfb->u.pslei.count, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_LRR:
- r = rtcp_psfb_lrr_pack(psfb->u.lrr.lrr, psfb->u.lrr.count, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_REMB:
- r = rtcp_psfb_remb_pack(psfb->u.afb.remb, psfb->u.afb.count, data + 12, bytes - 12);
- break;
-
- case RTCP_PSFB_ROI:
- default:
- assert(0);
- return -1;
- }
-
- header.v = 2;
- header.p = 0;
- header.pt = RTCP_PSFB;
- header.rc = id;
- header.length = (r + 8 + 3) / 4;
- nbo_write_rtcp_header(data, &header);
-
- nbo_w32(data + 4, ctx->self->ssrc);
- //nbo_w32(data + 4, psfb->sender);
- nbo_w32(data + 8, psfb->media);
-
- //assert(8 == (header.length + 1) * 4);
- return header.length * 4 + 4;
- }
-
- #if defined(_DEBUG) || defined(DEBUG)
- static void rtcp_on_psfb_test(void* param, const struct rtcp_msg_t* msg)
- {
- int r;
- static uint8_t buffer[1400];
- switch (msg->type & 0xFF)
- {
- case RTCP_PSFB:
- switch ((msg->type >> 8) & 0xFF)
- {
- case RTCP_PSFB_PLI:
- r = rtcp_psfb_pli_pack(buffer, sizeof(buffer));
- assert(0 == r);
- break;
-
- case RTCP_PSFB_FIR:
- assert(1 == msg->u.psfb.u.fir.count);
- assert(0x23456789 == msg->u.psfb.u.fir.fir[0].ssrc && 13 == msg->u.psfb.u.fir.fir[0].sn);
- r = rtcp_psfb_fir_pack(msg->u.psfb.u.fir.fir, msg->u.psfb.u.fir.count, buffer, sizeof(buffer));
- assert(r == 8 && 0 == memcmp(buffer, param, r));
- break;
-
- case RTCP_PSFB_REMB:
- assert(3 == msg->u.psfb.u.afb.count);
- assert(0x23456789 == msg->u.psfb.u.afb.remb[0].ssrc && 1 == msg->u.psfb.u.afb.remb[0].exp && 0x3fb93 == msg->u.psfb.u.afb.remb[0].mantissa);
- assert(0x2345678a == msg->u.psfb.u.afb.remb[1].ssrc && 1 == msg->u.psfb.u.afb.remb[1].exp && 0x3fb93 == msg->u.psfb.u.afb.remb[1].mantissa);
- assert(0x2345678b == msg->u.psfb.u.afb.remb[2].ssrc && 1 == msg->u.psfb.u.afb.remb[2].exp && 0x3fb93 == msg->u.psfb.u.afb.remb[2].mantissa);
- r = rtcp_psfb_remb_pack(msg->u.psfb.u.afb.remb, msg->u.psfb.u.afb.count, buffer, sizeof(buffer));
- assert(r == 20 && 0 == memcmp(buffer, param, r));
- break;
-
- default:
- break;
- }
- break;
-
- default:
- assert(0);
- }
- }
-
- static void rtcp_rtpfb_pli_test(void)
- {
- struct rtcp_msg_t msg;
- struct rtp_context rtp;
- rtp.handler.on_rtcp = rtcp_on_psfb_test;
- rtp.cbparam = NULL;
-
- msg.type = (RTCP_PSFB_PLI << 8) | RTCP_PSFB;
- assert(0 == rtcp_psfb_pli_unpack(&rtp, NULL, &msg, NULL, 0));
- }
-
- static void rtcp_rtpfb_fir_test(void)
- {
- const uint8_t data[] = { 0x23, 0x45, 0x67, 0x89, 0x0d, 0x00, 0x00, 0x00 };
-
- struct rtcp_msg_t msg;
- struct rtp_context rtp;
- rtp.handler.on_rtcp = rtcp_on_psfb_test;
- rtp.cbparam = (void*)data;
-
- msg.type = (RTCP_PSFB_FIR << 8) | RTCP_PSFB;
- assert(0 == rtcp_psfb_fir_unpack(&rtp, NULL, &msg, data, sizeof(data)));
- }
-
- static void rtcp_rtpfb_remb_test(void)
- {
- const uint8_t data[] = { 'R', 'E', 'M', 'B', 0x03, 0x07, 0xfb, 0x93, 0x23, 0x45, 0x67, 0x89, 0x23, 0x45, 0x67, 0x8a, 0x23, 0x45, 0x67, 0x8b };
-
- struct rtcp_msg_t msg;
- struct rtp_context rtp;
- rtp.handler.on_rtcp = rtcp_on_psfb_test;
- rtp.cbparam = (void*)data;
-
- msg.type = (RTCP_PSFB_REMB << 8) | RTCP_PSFB;
- assert(0 == rtcp_psfb_afb_unpack(&rtp, NULL, &msg, data, sizeof(data)));
- }
-
- void rtcp_psfb_test(void)
- {
- rtcp_rtpfb_pli_test();
- rtcp_rtpfb_fir_test();
- rtcp_rtpfb_remb_test();
- }
- #endif
|