|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- #include "rtp-ext.h"
- #include "rtp-header.h"
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <errno.h>
-
- static const struct rtp_ext_uri_t sc_rtpexts[] = {
- {RTP_HDREXT_PADDING, ""},
-
- // https://datatracker.ietf.org/doc/html/rfc6464
- {RTP_HDREXT_SSRC_AUDIO_LEVEL_ID, "urn:ietf:params:rtp-hdrext:ssrc-audio-level"},
- // https://datatracker.ietf.org/doc/html/rfc6465
- {RTP_HDREXT_CSRC_AUDIO_LEVEL_ID, "urn:ietf:params:rtp-hdrext:csrc-audio-level"},
-
- // https://datatracker.ietf.org/doc/html/draft-ietf-avtext-framemarking-13
- //{RTP_HDREXT_FRAME_MARKING_ID, "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07"},
- {RTP_HDREXT_FRAME_MARKING_ID, "urn:ietf:params:rtp-hdrext:framemarking"},
-
- // https://datatracker.ietf.org/doc/html/rfc8843#section-16.2
- {RTP_HDREXT_SDES_MID_ID, "urn:ietf:params:rtp-hdrext:sdes:mid"},
-
- // https://datatracker.ietf.org/doc/html/rfc8852#section-4
- {RTP_HDREXT_SDES_RTP_STREAM_ID, "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id"},
- {RTP_HDREXT_SDES_REPAIRED_RTP_STREAM_ID, "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"},
-
- // https://datatracker.ietf.org/doc/html/rfc5450
- {RTP_HDREXT_TOFFSET_ID, "urn:ietf:params:rtp-hdrext:toffset"},
-
- // https://www.arib.or.jp/english/html/overview/doc/STD-T63V12_00/5_Appendix/Rel13/26/26114-d30.pdf
- {RTP_HDREXT_VIDEO_ORIENTATION_ID, "urn:3gpp:video-orientation"},
-
- // // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/abs-send-time
- {RTP_HDREXT_ABSOLUTE_SEND_TIME_ID, "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/abs-capture-time/
- {RTP_HDREXT_ABSOLUTE_CAPTURE_TIME_ID, "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/transport-wide-cc-02/
- {RTP_HDREXT_TRANSPORT_WIDE_CC_ID_01, "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"},
- {RTP_HDREXT_TRANSPORT_WIDE_CC_ID, "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-timing
- {RTP_HDREXT_VIDEO_TIMING_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-timing"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/playout-delay
- {RTP_HDREXT_PLAYOUT_DELAY_ID, "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"},
-
- {RTP_HDREXT_ONE_BYTE_RESERVED, ""},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/color-space
- {RTP_HDREXT_COLOR_SPACE_ID, "http://www.webrtc.org/experiments/rtp-hdrext/color-space"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-content-type
- {RTP_HDREXT_VIDEO_CONTENT_TYPE_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/inband-cn/
- {RTP_HDREXT_INBAND_CN_ID, "http://www.webrtc.org/experiments/rtp-hdrext/inband-cn"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-frame-tracking-id/
- {RTP_HDREXT_VIDEO_FRAME_TRACKING_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-frame-tracking-id"},
-
- // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-layers-allocation00/
- {RTP_HDREXT_VIDEO_LAYERS_ALLOCATION_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-layers-allocation00"},
-
- //{RTP_HDREXT_GENERIC_FRAME_DESCRIPTOR_00, "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00"},
- //{RTP_HDREXT_GENERIC_FRAME_DESCRIPTOR_02, "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-02"},
-
- //{RTP_HDREXT_ENCRYPT, "urn:ietf:params:rtp-hdrext:encrypt"},
-
- {0, NULL},
- };
-
- const struct rtp_ext_uri_t* rtp_ext_list()
- {
- return sc_rtpexts;
- }
-
- const struct rtp_ext_uri_t* rtp_ext_find_uri(const char* uri)
- {
- int i;
- for (i = 0; i < sizeof(sc_rtpexts) / sizeof(sc_rtpexts[0]); i++)
- {
- if (0 == strcmp(sc_rtpexts[i].uri, uri))
- return &sc_rtpexts[i];
- }
- return NULL;
- }
-
- static int rtp_ext_read_one_byte(const uint8_t* data, int bytes, struct rtp_ext_data_t exts[256])
- {
- int off;
- uint8_t id;
- uint8_t len;
-
- for (off = 0; off < bytes; off += len + 1)
- {
- id = data[off] >> 4;
- len = (data[off] & 0x0f) + 1;
-
- if (bytes > 0xFFFF || off + len > bytes || (RTP_HDREXT_PADDING == id && 1 != len))
- return -1; // invalid
-
- if (RTP_HDREXT_PADDING == data[off])
- continue;
- else if (id == RTP_HDREXT_ONE_BYTE_RESERVED)
- break; // one-byte header extension reserver id
-
- exts[id].id = id;
- exts[id].len = len;
- exts[id].off = off + 1; // data only
- }
-
- return 0;
- }
-
- static int rtp_ext_write_one_byte(const uint8_t* extension, const struct rtp_ext_data_t* exts, int count, uint8_t* data, int bytes)
- {
- int i, off;
- for (i = off = 0; i < count && off < bytes; off += exts[i++].len)
- {
- if (RTP_HDREXT_PADDING == exts[i].id)
- {
- assert(exts[i].len == 0);
- continue;
- }
-
- // 15: one-byte header extension reserver id
- if (exts[i].id >= RTP_HDREXT_ONE_BYTE_RESERVED
- || exts[i].len < 1 || exts[i].len > 16 || (int)exts[i].len + off >= bytes)
- {
- assert(0);
- return -EINVAL;
- }
-
- data[off] = ((uint8_t)exts[i].id << 4) | ((uint8_t)exts[i].len - 1);
- memcpy(data + off + 1, extension + exts[i].off, exts[i].len);
- }
-
- if (i < count || ( (off % 4 != 0) && (off + 3)/4*4 >= bytes) )
- return -E2BIG;
-
- while(off % 4 != 0)
- data[off++] = RTP_HDREXT_PADDING;
- return off;
- }
-
- static int rtp_ext_read_two_byte(const uint8_t* data, int bytes, struct rtp_ext_data_t exts[256])
- {
- int off;
- uint8_t id;
- uint8_t len;
-
- for (off = 0; off < bytes; off += len)
- {
- id = data[off++];
- if (RTP_HDREXT_PADDING == id)
- {
- len = 0;
- continue;
- }
-
- if (off >= bytes)
- return -EINVAL;
-
- len = data[off++];
- if (off + len > bytes)
- return -EINVAL;; // invalid
-
- exts[id].id = id;
- exts[id].len = len;
- exts[id].off = off; // data only
- }
-
- return 0;
- }
-
- static int rtp_ext_write_two_byte(const uint8_t* extension, const struct rtp_ext_data_t* exts, int count, uint8_t* data, int bytes)
- {
- int i, off;
- for (i = off = 0; i < count && off < bytes; off += exts[i++].len)
- {
- if (RTP_HDREXT_PADDING == exts[i].id)
- {
- assert(exts[i].len == 0);
- continue;
- }
-
- if ((int)exts[i].len + off + 2 >= bytes)
- {
- assert(0);
- return -EINVAL;
- }
-
- data[off++] = (uint8_t)exts[i].id;
- data[off++] = (uint8_t)exts[i].len;
- memcpy(data + off, extension + exts[i].off, exts[i].len);
- }
-
- if (i < count || ((off % 4 != 0) && (off + 3) / 4 * 4 >= bytes))
- return -E2BIG;
-
- while (off % 4 != 0)
- data[off++] = RTP_HDREXT_PADDING;
- return off;
- }
-
- int rtp_ext_read(uint16_t profile, const uint8_t* data, int bytes, struct rtp_ext_data_t exts[256])
- {
- // caller to do
- // memset(exts, 0, sizeof(exts));
-
- if(RTP_HDREXT_PROFILE_ONE_BYTE == profile)
- return rtp_ext_read_one_byte(data, bytes, exts);
- else if (RTP_HDREXT_PROFILE_TWO_BYTE == (profile & RTP_HDREXT_PROFILE_TWO_BYTE_FILTER))
- return rtp_ext_read_two_byte(data, bytes, exts);
-
- return 0; // ignore
- }
-
- int rtp_ext_write(uint16_t profile, const uint8_t* extension, const struct rtp_ext_data_t* exts, int count, uint8_t* data, int bytes)
- {
- int i;
- if (0 == profile)
- {
- profile = RTP_HDREXT_PROFILE_ONE_BYTE;
- for (i = 0; i < count; i++)
- {
- // 15: one-byte header extension reserver id
- if (exts[i].len >= 16 || RTP_HDREXT_ONE_BYTE_RESERVED == exts[i].id)
- profile = RTP_HDREXT_PROFILE_TWO_BYTE;
- }
- }
-
- if (RTP_HDREXT_PROFILE_ONE_BYTE == profile)
- return rtp_ext_write_one_byte(extension, exts, count, data, bytes);
- else if (RTP_HDREXT_PROFILE_TWO_BYTE == (profile & RTP_HDREXT_PROFILE_TWO_BYTE_FILTER))
- return rtp_ext_write_two_byte(extension, exts, count, data, bytes);
-
- return -1; // ignore
- }
-
- #if defined(DEBUG) || defined(_DEBUG)
- static void rtp_ext_read_onebyte_test(void)
- {
- const uint8_t data[] = { 0x22, 0xca, 0x4e, 0x36, 0x31, 0x00, 0x01, 0x40, 0x30, 0x10, 0xb2, 0x00 };
- struct rtp_ext_data_t exts[256];
- int i;
- memset(exts, 0, sizeof(exts));
- assert(0 == rtp_ext_read(RTP_HDREXT_PROFILE_ONE_BYTE, data, sizeof(data), exts));
- assert(exts[2].len == 3 && exts[3].len == 2 && exts[4].len == 1 && exts[1].len == 1);
- for (i = 0; i < sizeof(exts) / sizeof(exts[0]); i++)
- {
- if (i == 1 || i == 2 || i == 3 || i == 4)
- continue;
- assert(exts[i].id == 0 && exts[i].len == 0);
- }
- }
-
- static void rtp_ext_read_twobyte_test(void)
- {
-
- }
-
- void rtp_ext_read_test(void)
- {
- rtp_ext_read_onebyte_test();
- rtp_ext_read_twobyte_test();
- }
- #endif
|