You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
8.5KB

  1. #include "rtp-ext.h"
  2. #include "rtp-header.h"
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <errno.h>
  7. static const struct rtp_ext_uri_t sc_rtpexts[] = {
  8. {RTP_HDREXT_PADDING, ""},
  9. // https://datatracker.ietf.org/doc/html/rfc6464
  10. {RTP_HDREXT_SSRC_AUDIO_LEVEL_ID, "urn:ietf:params:rtp-hdrext:ssrc-audio-level"},
  11. // https://datatracker.ietf.org/doc/html/rfc6465
  12. {RTP_HDREXT_CSRC_AUDIO_LEVEL_ID, "urn:ietf:params:rtp-hdrext:csrc-audio-level"},
  13. // https://datatracker.ietf.org/doc/html/draft-ietf-avtext-framemarking-13
  14. //{RTP_HDREXT_FRAME_MARKING_ID, "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07"},
  15. {RTP_HDREXT_FRAME_MARKING_ID, "urn:ietf:params:rtp-hdrext:framemarking"},
  16. // https://datatracker.ietf.org/doc/html/rfc8843#section-16.2
  17. {RTP_HDREXT_SDES_MID_ID, "urn:ietf:params:rtp-hdrext:sdes:mid"},
  18. // https://datatracker.ietf.org/doc/html/rfc8852#section-4
  19. {RTP_HDREXT_SDES_RTP_STREAM_ID, "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id"},
  20. {RTP_HDREXT_SDES_REPAIRED_RTP_STREAM_ID, "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"},
  21. // https://datatracker.ietf.org/doc/html/rfc5450
  22. {RTP_HDREXT_TOFFSET_ID, "urn:ietf:params:rtp-hdrext:toffset"},
  23. // https://www.arib.or.jp/english/html/overview/doc/STD-T63V12_00/5_Appendix/Rel13/26/26114-d30.pdf
  24. {RTP_HDREXT_VIDEO_ORIENTATION_ID, "urn:3gpp:video-orientation"},
  25. // // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/abs-send-time
  26. {RTP_HDREXT_ABSOLUTE_SEND_TIME_ID, "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"},
  27. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/abs-capture-time/
  28. {RTP_HDREXT_ABSOLUTE_CAPTURE_TIME_ID, "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time"},
  29. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/transport-wide-cc-02/
  30. {RTP_HDREXT_TRANSPORT_WIDE_CC_ID_01, "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"},
  31. {RTP_HDREXT_TRANSPORT_WIDE_CC_ID, "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02"},
  32. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-timing
  33. {RTP_HDREXT_VIDEO_TIMING_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-timing"},
  34. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/playout-delay
  35. {RTP_HDREXT_PLAYOUT_DELAY_ID, "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"},
  36. {RTP_HDREXT_ONE_BYTE_RESERVED, ""},
  37. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/color-space
  38. {RTP_HDREXT_COLOR_SPACE_ID, "http://www.webrtc.org/experiments/rtp-hdrext/color-space"},
  39. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-content-type
  40. {RTP_HDREXT_VIDEO_CONTENT_TYPE_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type"},
  41. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/inband-cn/
  42. {RTP_HDREXT_INBAND_CN_ID, "http://www.webrtc.org/experiments/rtp-hdrext/inband-cn"},
  43. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-frame-tracking-id/
  44. {RTP_HDREXT_VIDEO_FRAME_TRACKING_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-frame-tracking-id"},
  45. // https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/rtp-hdrext/video-layers-allocation00/
  46. {RTP_HDREXT_VIDEO_LAYERS_ALLOCATION_ID, "http://www.webrtc.org/experiments/rtp-hdrext/video-layers-allocation00"},
  47. //{RTP_HDREXT_GENERIC_FRAME_DESCRIPTOR_00, "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00"},
  48. //{RTP_HDREXT_GENERIC_FRAME_DESCRIPTOR_02, "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-02"},
  49. //{RTP_HDREXT_ENCRYPT, "urn:ietf:params:rtp-hdrext:encrypt"},
  50. {0, NULL},
  51. };
  52. const struct rtp_ext_uri_t* rtp_ext_list()
  53. {
  54. return sc_rtpexts;
  55. }
  56. const struct rtp_ext_uri_t* rtp_ext_find_uri(const char* uri)
  57. {
  58. int i;
  59. for (i = 0; i < sizeof(sc_rtpexts) / sizeof(sc_rtpexts[0]); i++)
  60. {
  61. if (0 == strcmp(sc_rtpexts[i].uri, uri))
  62. return &sc_rtpexts[i];
  63. }
  64. return NULL;
  65. }
  66. static int rtp_ext_read_one_byte(const uint8_t* data, int bytes, struct rtp_ext_data_t exts[256])
  67. {
  68. int off;
  69. uint8_t id;
  70. uint8_t len;
  71. for (off = 0; off < bytes; off += len + 1)
  72. {
  73. id = data[off] >> 4;
  74. len = (data[off] & 0x0f) + 1;
  75. if (bytes > 0xFFFF || off + len > bytes || (RTP_HDREXT_PADDING == id && 1 != len))
  76. return -1; // invalid
  77. if (RTP_HDREXT_PADDING == data[off])
  78. continue;
  79. else if (id == RTP_HDREXT_ONE_BYTE_RESERVED)
  80. break; // one-byte header extension reserver id
  81. exts[id].id = id;
  82. exts[id].len = len;
  83. exts[id].off = off + 1; // data only
  84. }
  85. return 0;
  86. }
  87. 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)
  88. {
  89. int i, off;
  90. for (i = off = 0; i < count && off < bytes; off += exts[i++].len)
  91. {
  92. if (RTP_HDREXT_PADDING == exts[i].id)
  93. {
  94. assert(exts[i].len == 0);
  95. continue;
  96. }
  97. // 15: one-byte header extension reserver id
  98. if (exts[i].id >= RTP_HDREXT_ONE_BYTE_RESERVED
  99. || exts[i].len < 1 || exts[i].len > 16 || (int)exts[i].len + off >= bytes)
  100. {
  101. assert(0);
  102. return -EINVAL;
  103. }
  104. data[off] = ((uint8_t)exts[i].id << 4) | ((uint8_t)exts[i].len - 1);
  105. memcpy(data + off + 1, extension + exts[i].off, exts[i].len);
  106. }
  107. if (i < count || ( (off % 4 != 0) && (off + 3)/4*4 >= bytes) )
  108. return -E2BIG;
  109. while(off % 4 != 0)
  110. data[off++] = RTP_HDREXT_PADDING;
  111. return off;
  112. }
  113. static int rtp_ext_read_two_byte(const uint8_t* data, int bytes, struct rtp_ext_data_t exts[256])
  114. {
  115. int off;
  116. uint8_t id;
  117. uint8_t len;
  118. for (off = 0; off < bytes; off += len)
  119. {
  120. id = data[off++];
  121. if (RTP_HDREXT_PADDING == id)
  122. {
  123. len = 0;
  124. continue;
  125. }
  126. if (off >= bytes)
  127. return -EINVAL;
  128. len = data[off++];
  129. if (off + len > bytes)
  130. return -EINVAL;; // invalid
  131. exts[id].id = id;
  132. exts[id].len = len;
  133. exts[id].off = off; // data only
  134. }
  135. return 0;
  136. }
  137. 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)
  138. {
  139. int i, off;
  140. for (i = off = 0; i < count && off < bytes; off += exts[i++].len)
  141. {
  142. if (RTP_HDREXT_PADDING == exts[i].id)
  143. {
  144. assert(exts[i].len == 0);
  145. continue;
  146. }
  147. if ((int)exts[i].len + off + 2 >= bytes)
  148. {
  149. assert(0);
  150. return -EINVAL;
  151. }
  152. data[off++] = (uint8_t)exts[i].id;
  153. data[off++] = (uint8_t)exts[i].len;
  154. memcpy(data + off, extension + exts[i].off, exts[i].len);
  155. }
  156. if (i < count || ((off % 4 != 0) && (off + 3) / 4 * 4 >= bytes))
  157. return -E2BIG;
  158. while (off % 4 != 0)
  159. data[off++] = RTP_HDREXT_PADDING;
  160. return off;
  161. }
  162. int rtp_ext_read(uint16_t profile, const uint8_t* data, int bytes, struct rtp_ext_data_t exts[256])
  163. {
  164. // caller to do
  165. // memset(exts, 0, sizeof(exts));
  166. if(RTP_HDREXT_PROFILE_ONE_BYTE == profile)
  167. return rtp_ext_read_one_byte(data, bytes, exts);
  168. else if (RTP_HDREXT_PROFILE_TWO_BYTE == (profile & RTP_HDREXT_PROFILE_TWO_BYTE_FILTER))
  169. return rtp_ext_read_two_byte(data, bytes, exts);
  170. return 0; // ignore
  171. }
  172. 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)
  173. {
  174. int i;
  175. if (0 == profile)
  176. {
  177. profile = RTP_HDREXT_PROFILE_ONE_BYTE;
  178. for (i = 0; i < count; i++)
  179. {
  180. // 15: one-byte header extension reserver id
  181. if (exts[i].len >= 16 || RTP_HDREXT_ONE_BYTE_RESERVED == exts[i].id)
  182. profile = RTP_HDREXT_PROFILE_TWO_BYTE;
  183. }
  184. }
  185. if (RTP_HDREXT_PROFILE_ONE_BYTE == profile)
  186. return rtp_ext_write_one_byte(extension, exts, count, data, bytes);
  187. else if (RTP_HDREXT_PROFILE_TWO_BYTE == (profile & RTP_HDREXT_PROFILE_TWO_BYTE_FILTER))
  188. return rtp_ext_write_two_byte(extension, exts, count, data, bytes);
  189. return -1; // ignore
  190. }
  191. #if defined(DEBUG) || defined(_DEBUG)
  192. static void rtp_ext_read_onebyte_test(void)
  193. {
  194. const uint8_t data[] = { 0x22, 0xca, 0x4e, 0x36, 0x31, 0x00, 0x01, 0x40, 0x30, 0x10, 0xb2, 0x00 };
  195. struct rtp_ext_data_t exts[256];
  196. int i;
  197. memset(exts, 0, sizeof(exts));
  198. assert(0 == rtp_ext_read(RTP_HDREXT_PROFILE_ONE_BYTE, data, sizeof(data), exts));
  199. assert(exts[2].len == 3 && exts[3].len == 2 && exts[4].len == 1 && exts[1].len == 1);
  200. for (i = 0; i < sizeof(exts) / sizeof(exts[0]); i++)
  201. {
  202. if (i == 1 || i == 2 || i == 3 || i == 4)
  203. continue;
  204. assert(exts[i].id == 0 && exts[i].len == 0);
  205. }
  206. }
  207. static void rtp_ext_read_twobyte_test(void)
  208. {
  209. }
  210. void rtp_ext_read_test(void)
  211. {
  212. rtp_ext_read_onebyte_test();
  213. rtp_ext_read_twobyte_test();
  214. }
  215. #endif