res_format_attr_h264.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2012, Digium, Inc.
  5. *
  6. * Joshua Colp <jcolp@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. *
  18. */
  19. /*! \file
  20. *
  21. * \brief H.264 Format Attribute Module
  22. *
  23. * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim
  24. *
  25. * This is a format attribute module for the H.264 codec.
  26. * \ingroup applications
  27. */
  28. /*** MODULEINFO
  29. <support_level>core</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  33. #include "asterisk/module.h"
  34. #include "asterisk/format.h"
  35. /*! \brief Value that indicates an attribute is actually unset */
  36. #define H264_ATTR_KEY_UNSET UINT8_MAX
  37. /*! \brief Maximum size for SPS / PPS values in sprop-parameter-sets attribute
  38. * if you change this value then you must change H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT
  39. * as well. */
  40. #define H264_MAX_SPS_PPS_SIZE 16
  41. /*! \brief This is used when executing sscanf on buffers of H264_MAX_SPS_PPS_SIZE
  42. * length. It must ALWAYS be a string literal representation of one less than
  43. * H264_MAX_SPS_PPS_SIZE */
  44. #define H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "15"
  45. enum h264_attr_keys {
  46. H264_ATTR_KEY_PROFILE_IDC,
  47. H264_ATTR_KEY_PROFILE_IOP,
  48. H264_ATTR_KEY_LEVEL,
  49. H264_ATTR_KEY_MAX_MBPS,
  50. H264_ATTR_KEY_MAX_FS,
  51. H264_ATTR_KEY_MAX_CPB,
  52. H264_ATTR_KEY_MAX_DPB,
  53. H264_ATTR_KEY_MAX_BR,
  54. H264_ATTR_KEY_MAX_SMBPS,
  55. H264_ATTR_KEY_MAX_FPS,
  56. H264_ATTR_KEY_REDUNDANT_PIC_CAP,
  57. H264_ATTR_KEY_PARAMETER_ADD,
  58. H264_ATTR_KEY_PACKETIZATION_MODE,
  59. H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH,
  60. H264_ATTR_KEY_SPROP_DEINT_BUF_REQ,
  61. H264_ATTR_KEY_DEINT_BUF_CAP,
  62. H264_ATTR_KEY_SPROP_INIT_BUF_TIME,
  63. H264_ATTR_KEY_SPROP_MAX_DON_DIFF,
  64. H264_ATTR_KEY_MAX_RCMD_NALU_SIZE,
  65. H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED,
  66. H264_ATTR_KEY_SPS_LEN,
  67. H264_ATTR_KEY_PPS_LEN,
  68. H264_ATTR_KEY_SPS,
  69. H264_ATTR_KEY_PPS = H264_ATTR_KEY_SPS + H264_MAX_SPS_PPS_SIZE,
  70. H264_ATTR_KEY_END = H264_ATTR_KEY_PPS + H264_MAX_SPS_PPS_SIZE,
  71. };
  72. static enum ast_format_cmp_res h264_format_attr_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2)
  73. {
  74. if (!fattr1->format_attr[H264_ATTR_KEY_PROFILE_IDC] || !fattr2->format_attr[H264_ATTR_KEY_PROFILE_IDC] ||
  75. (fattr1->format_attr[H264_ATTR_KEY_PROFILE_IDC] == fattr2->format_attr[H264_ATTR_KEY_PROFILE_IDC])) {
  76. return AST_FORMAT_CMP_EQUAL;
  77. }
  78. return AST_FORMAT_CMP_NOT_EQUAL;
  79. }
  80. static int h264_format_attr_get_joint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
  81. {
  82. int i;
  83. for (i = H264_ATTR_KEY_PROFILE_IDC; i < H264_ATTR_KEY_END; i++) {
  84. result->format_attr[i] = fattr1->format_attr[i] ? fattr1->format_attr[i] : fattr2->format_attr[i];
  85. }
  86. return 0;
  87. }
  88. static int h264_format_attr_sdp_parse(struct ast_format_attr *format_attr, const char *attributes)
  89. {
  90. char *attribs = ast_strdupa(attributes), *attrib;
  91. format_attr->format_attr[H264_ATTR_KEY_REDUNDANT_PIC_CAP] = H264_ATTR_KEY_UNSET;
  92. format_attr->format_attr[H264_ATTR_KEY_PARAMETER_ADD] = H264_ATTR_KEY_UNSET;
  93. format_attr->format_attr[H264_ATTR_KEY_PACKETIZATION_MODE] = H264_ATTR_KEY_UNSET;
  94. format_attr->format_attr[H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED] = H264_ATTR_KEY_UNSET;
  95. while ((attrib = strsep(&attribs, ";"))) {
  96. unsigned int val;
  97. unsigned long int val2;
  98. char sps[H264_MAX_SPS_PPS_SIZE], pps[H264_MAX_SPS_PPS_SIZE];
  99. if (sscanf(attrib, "profile-level-id=%lx", &val2) == 1) {
  100. format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC] = ((val2 >> 16) & 0xFF);
  101. format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP] = ((val2 >> 8) & 0xFF);
  102. format_attr->format_attr[H264_ATTR_KEY_LEVEL] = (val2 & 0xFF);
  103. } else if (sscanf(attrib, "sprop-parameter-sets=%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "[^','],%" H264_MAX_SPS_PPS_SIZE_SCAN_LIMIT "s", sps, pps) == 2) {
  104. /* XXX sprop-parameter-sets can actually be of unlimited length. This may need to be addressed later. */
  105. unsigned char spsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }, ppsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, };
  106. int i;
  107. ast_base64decode(spsdecoded, sps, sizeof(spsdecoded));
  108. ast_base64decode(ppsdecoded, pps, sizeof(ppsdecoded));
  109. format_attr->format_attr[H264_ATTR_KEY_SPS_LEN] = 0;
  110. format_attr->format_attr[H264_ATTR_KEY_PPS_LEN] = 0;
  111. for (i = 0; i < H264_MAX_SPS_PPS_SIZE; i++) {
  112. if (spsdecoded[i]) {
  113. format_attr->format_attr[H264_ATTR_KEY_SPS + i] = spsdecoded[i];
  114. format_attr->format_attr[H264_ATTR_KEY_SPS_LEN]++;
  115. }
  116. if (ppsdecoded[i]) {
  117. format_attr->format_attr[H264_ATTR_KEY_PPS + i] = ppsdecoded[i];
  118. format_attr->format_attr[H264_ATTR_KEY_PPS_LEN]++;
  119. }
  120. }
  121. } else if (sscanf(attrib, "max-mbps=%30u", &val) == 1) {
  122. format_attr->format_attr[H264_ATTR_KEY_MAX_MBPS] = val;
  123. } else if (sscanf(attrib, "max-fs=%30u", &val) == 1) {
  124. format_attr->format_attr[H264_ATTR_KEY_MAX_FS] = val;
  125. } else if (sscanf(attrib, "max-cpb=%30u", &val) == 1) {
  126. format_attr->format_attr[H264_ATTR_KEY_MAX_CPB] = val;
  127. } else if (sscanf(attrib, "max-dpb=%30u", &val) == 1) {
  128. format_attr->format_attr[H264_ATTR_KEY_MAX_DPB] = val;
  129. } else if (sscanf(attrib, "max-br=%30u", &val) == 1) {
  130. format_attr->format_attr[H264_ATTR_KEY_MAX_BR] = val;
  131. } else if (sscanf(attrib, "max-smbps=%30u", &val) == 1) {
  132. format_attr->format_attr[H264_ATTR_KEY_MAX_SMBPS] = val;
  133. } else if (sscanf(attrib, "max-fps=%30u", &val) == 1) {
  134. format_attr->format_attr[H264_ATTR_KEY_MAX_FPS] = val;
  135. } else if (sscanf(attrib, "redundant-pic-cap=%30u", &val) == 1) {
  136. format_attr->format_attr[H264_ATTR_KEY_REDUNDANT_PIC_CAP] = val;
  137. } else if (sscanf(attrib, "parameter-add=%30u", &val) == 1) {
  138. format_attr->format_attr[H264_ATTR_KEY_PARAMETER_ADD] = val;
  139. } else if (sscanf(attrib, "packetization-mode=%30u", &val) == 1) {
  140. format_attr->format_attr[H264_ATTR_KEY_PACKETIZATION_MODE] = val;
  141. } else if (sscanf(attrib, "sprop-interleaving-depth=%30u", &val) == 1) {
  142. format_attr->format_attr[H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH] = val;
  143. } else if (sscanf(attrib, "sprop-deint-buf-req=%30u", &val) == 1) {
  144. format_attr->format_attr[H264_ATTR_KEY_SPROP_DEINT_BUF_REQ] = val;
  145. } else if (sscanf(attrib, "deint-buf-cap=%30u", &val) == 1) {
  146. format_attr->format_attr[H264_ATTR_KEY_DEINT_BUF_CAP] = val;
  147. } else if (sscanf(attrib, "sprop-init-buf-time=%30u", &val) == 1) {
  148. format_attr->format_attr[H264_ATTR_KEY_SPROP_INIT_BUF_TIME] = val;
  149. } else if (sscanf(attrib, "sprop-max-don-diff=%30u", &val) == 1) {
  150. format_attr->format_attr[H264_ATTR_KEY_SPROP_MAX_DON_DIFF] = val;
  151. } else if (sscanf(attrib, "max-rcmd-nalu-size=%30u", &val) == 1) {
  152. format_attr->format_attr[H264_ATTR_KEY_MAX_RCMD_NALU_SIZE] = val;
  153. } else if (sscanf(attrib, "level-asymmetry-allowed=%30u", &val) == 1) {
  154. format_attr->format_attr[H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED] = val;
  155. }
  156. }
  157. return 0;
  158. }
  159. /*! \brief Helper function which converts a key enum into a string value for SDP */
  160. static const char *h264_attr_key_to_str(enum h264_attr_keys key)
  161. {
  162. switch (key) {
  163. case H264_ATTR_KEY_MAX_MBPS:
  164. return "max-mbps";
  165. case H264_ATTR_KEY_MAX_FS:
  166. return "max-fs";
  167. case H264_ATTR_KEY_MAX_CPB:
  168. return "max-cpb";
  169. case H264_ATTR_KEY_MAX_DPB:
  170. return "max-dpb";
  171. case H264_ATTR_KEY_MAX_BR:
  172. return "max-br";
  173. case H264_ATTR_KEY_MAX_SMBPS:
  174. return "max-smbps";
  175. case H264_ATTR_KEY_MAX_FPS:
  176. return "max-fps";
  177. case H264_ATTR_KEY_REDUNDANT_PIC_CAP:
  178. return "redundant-pic-cap";
  179. case H264_ATTR_KEY_PARAMETER_ADD:
  180. return "parameter-add";
  181. case H264_ATTR_KEY_PACKETIZATION_MODE:
  182. return "packetization-mode";
  183. case H264_ATTR_KEY_SPROP_INTERLEAVING_DEPTH:
  184. return "sprop-interleaving-depth";
  185. case H264_ATTR_KEY_SPROP_DEINT_BUF_REQ:
  186. return "sprop-deint-buf-req";
  187. case H264_ATTR_KEY_DEINT_BUF_CAP:
  188. return "deint-buf-cap";
  189. case H264_ATTR_KEY_SPROP_INIT_BUF_TIME:
  190. return "sprop-init-buf-time";
  191. case H264_ATTR_KEY_SPROP_MAX_DON_DIFF:
  192. return "sprop-max-don-diff";
  193. case H264_ATTR_KEY_MAX_RCMD_NALU_SIZE:
  194. return "max-rcmd-nalu-size";
  195. case H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED:
  196. return "level-asymmetry-allowed";
  197. default:
  198. return NULL;
  199. }
  200. return NULL;
  201. }
  202. /*! \brief Helper function which determines if the value of an attribute can be placed into the SDP */
  203. static int h264_attr_key_addable(const struct ast_format_attr *format_attr, enum h264_attr_keys key)
  204. {
  205. switch (key) {
  206. case H264_ATTR_KEY_REDUNDANT_PIC_CAP:
  207. case H264_ATTR_KEY_PARAMETER_ADD:
  208. case H264_ATTR_KEY_PACKETIZATION_MODE:
  209. case H264_ATTR_KEY_LEVEL_ASYMMETRY_ALLOWED:
  210. return (format_attr->format_attr[key] != H264_ATTR_KEY_UNSET) ? 1 : 0;
  211. default:
  212. return format_attr->format_attr[key] ? 1 : 0;
  213. }
  214. return 1;
  215. }
  216. static void h264_format_attr_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str)
  217. {
  218. int i, added = 0;
  219. for (i = H264_ATTR_KEY_PROFILE_IDC; i < H264_ATTR_KEY_END; i++) {
  220. const char *name;
  221. if (i == H264_ATTR_KEY_SPS && format_attr->format_attr[H264_ATTR_KEY_SPS] && format_attr->format_attr[H264_ATTR_KEY_PPS]) {
  222. unsigned char spsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, }, ppsdecoded[H264_MAX_SPS_PPS_SIZE] = { 0, };
  223. int pos;
  224. char sps[H264_MAX_SPS_PPS_SIZE], pps[H264_MAX_SPS_PPS_SIZE];
  225. for (pos = 0; pos < H264_MAX_SPS_PPS_SIZE; pos++) {
  226. spsdecoded[pos] = format_attr->format_attr[H264_ATTR_KEY_SPS + pos];
  227. ppsdecoded[pos] = format_attr->format_attr[H264_ATTR_KEY_PPS + pos];
  228. }
  229. ast_base64encode(sps, spsdecoded, format_attr->format_attr[H264_ATTR_KEY_SPS_LEN], H264_MAX_SPS_PPS_SIZE);
  230. ast_base64encode(pps, ppsdecoded, format_attr->format_attr[H264_ATTR_KEY_PPS_LEN], H264_MAX_SPS_PPS_SIZE);
  231. if (!added) {
  232. ast_str_append(str, 0, "a=fmtp:%u sprop-parameter-sets=%s,%s", payload, sps, pps);
  233. added = 1;
  234. } else {
  235. ast_str_append(str, 0, ";sprop-parameter-sets=%s,%s", sps, pps);
  236. }
  237. } else if (i == H264_ATTR_KEY_PROFILE_IDC && format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC] &&
  238. format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP] && format_attr->format_attr[H264_ATTR_KEY_LEVEL]) {
  239. if (!added) {
  240. ast_str_append(str, 0, "a=fmtp:%u profile-level-id=%02X%02X%02X", payload, format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC],
  241. format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP], format_attr->format_attr[H264_ATTR_KEY_LEVEL]);
  242. added = 1;
  243. } else {
  244. ast_str_append(str, 0, ";profile-level-id=%02X%02X%02X", format_attr->format_attr[H264_ATTR_KEY_PROFILE_IDC],
  245. format_attr->format_attr[H264_ATTR_KEY_PROFILE_IOP], format_attr->format_attr[H264_ATTR_KEY_LEVEL]);
  246. }
  247. } else if ((name = h264_attr_key_to_str(i)) && h264_attr_key_addable(format_attr, i)) {
  248. if (!added) {
  249. ast_str_append(str, 0, "a=fmtp:%u %s=%u", payload, name, format_attr->format_attr[i]);
  250. added = 1;
  251. } else {
  252. ast_str_append(str, 0, ";%s=%u", name, format_attr->format_attr[i]);
  253. }
  254. }
  255. }
  256. if (added) {
  257. ast_str_append(str, 0, "\r\n");
  258. }
  259. return;
  260. }
  261. static struct ast_format_attr_interface h264_format_attr_interface = {
  262. .id = AST_FORMAT_H264,
  263. .format_attr_cmp = h264_format_attr_cmp,
  264. .format_attr_get_joint = h264_format_attr_get_joint,
  265. .format_attr_sdp_parse = h264_format_attr_sdp_parse,
  266. .format_attr_sdp_generate = h264_format_attr_sdp_generate,
  267. };
  268. static int unload_module(void)
  269. {
  270. ast_format_attr_unreg_interface(&h264_format_attr_interface);
  271. return 0;
  272. }
  273. static int load_module(void)
  274. {
  275. if (ast_format_attr_reg_interface(&h264_format_attr_interface)) {
  276. return AST_MODULE_LOAD_DECLINE;
  277. }
  278. return AST_MODULE_LOAD_SUCCESS;
  279. }
  280. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "H.264 Format Attribute Module",
  281. .load = load_module,
  282. .unload = unload_module,
  283. .load_pri = AST_MODPRI_DEFAULT,
  284. );