選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

10ヶ月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. // RFC-4566 SDP
  2. // 6. SDP Attributes (p30)
  3. // a=fmtp:<format> <format specific parameters>
  4. #include "sdp-a-fmtp.h"
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. #if defined(OS_WINDOWS)
  9. #define strncasecmp _strnicmp
  10. #endif
  11. // RFC6184 RTP Payload Format for H.264 Video
  12. // m=video 49170 RTP/AVP 98
  13. // a=rtpmap:98 H264/90000
  14. // a=fmtp:98 profile-level-id=42A01E;
  15. // packetization-mode=1;
  16. // sprop-parameter-sets=<parameter sets data>
  17. int sdp_a_fmtp_h264(const char* fmtp, int *format, struct sdp_a_fmtp_h264_t *h264)
  18. {
  19. size_t nc, vc;
  20. const char *p1, *p2;
  21. const char *p = fmtp;
  22. // payload type
  23. *format = atoi(p);
  24. p1 = strchr(p, ' ');
  25. if(!p1 || ' ' != *p1)
  26. return -1;
  27. h264->flags = 0;
  28. assert(' ' == *p1);
  29. p = p1 + 1;
  30. while(*p)
  31. {
  32. p1 = strchr(p, '=');
  33. if(!p1 || '=' != *p1)
  34. return -1;
  35. p2 = strchr(p1+1, ';');
  36. if(!p2)
  37. p2 = p1 + strlen(p1);
  38. while(' ' == *p) p++; // skip space
  39. nc = (size_t)(p1 - p); // ptrdiff_t to size_t
  40. vc = (size_t)(p2 - p1 - 1); // ptrdiff_t to size_t
  41. switch(*p)
  42. {
  43. case 'p':
  44. // profile-level-id
  45. // packetization-mode
  46. if(0 == strncasecmp("profile-level-id", p, nc))
  47. {
  48. if(6 != vc) return -1;
  49. h264->flags |= SDP_A_FMTP_H264_PROFILE_LEVEL_ID;
  50. memcpy(h264->profile_level_id, p1+1, 6);
  51. h264->profile_level_id[6] = '\0';
  52. }
  53. else if(0 == strncasecmp("packetization-mode", p, nc))
  54. {
  55. h264->flags |= SDP_A_FMTP_H264_PACKETIZATION_MODE;
  56. h264->packetization_mode = atoi(p1+1);
  57. }
  58. break;
  59. case 'm':
  60. // max-recv-level
  61. // max-mbps
  62. // max-smbps
  63. // max-fs
  64. // max-cbp
  65. // max-dbp
  66. // max-br
  67. // max-rcmd-nalu-size
  68. if(0 == strncasecmp("max-recv-level", p, nc))
  69. {
  70. h264->flags |= SDP_A_FMTP_H264_MAX_RECV_LEVEL;
  71. h264->max_recv_level = atoi(p1+1);
  72. }
  73. else if(0 == strncasecmp("max-mbps", p, nc))
  74. {
  75. h264->flags |= SDP_A_FMTP_H264_MAX_MBPS;
  76. h264->max_mbps = atoi(p1+1);
  77. }
  78. else if(0 == strncasecmp("max-smbps", p, nc))
  79. {
  80. h264->flags |= SDP_A_FMTP_H264_MAX_SMBPS;
  81. h264->max_smbps = atoi(p1+1);
  82. }
  83. else if(0 == strncasecmp("max-fs", p, nc))
  84. {
  85. h264->flags |= SDP_A_FMTP_H264_MAX_FS;
  86. h264->max_fs = atoi(p1+1);
  87. }
  88. else if(0 == strncasecmp("max-cbp", p, nc))
  89. {
  90. h264->flags |= SDP_A_FMTP_H264_MAX_CPB;
  91. h264->max_cpb = atoi(p1+1);
  92. }
  93. else if(0 == strncasecmp("max-dbp", p, nc))
  94. {
  95. h264->flags |= SDP_A_FMTP_H264_MAX_DPB;
  96. h264->max_dpb = atoi(p1+1);
  97. }
  98. else if(0 == strncasecmp("max-br", p, nc))
  99. {
  100. h264->flags |= SDP_A_FMTP_H264_MAX_BR;
  101. h264->max_br = atoi(p1+1);
  102. }
  103. else if(0 == strncasecmp("max-rcmd-nalu-size", p, nc))
  104. {
  105. h264->flags |= SDP_A_FMTP_H264_MAX_RCMD_NALU_SIZE;
  106. h264->max_rcmd_nalu_size = (unsigned int)atoi(p1+1);
  107. }
  108. break;
  109. case 's':
  110. // sprop-parameter-sets
  111. // sprop-level-parameter-sets
  112. // sprop-deint-buf-req
  113. // sprop-interleaving-depth
  114. // sprop-max-don-diff
  115. // sprop-init-buf-time
  116. // sar-understood
  117. // sar-supported
  118. if(0 == strncasecmp("sprop-parameter-sets", p, nc))
  119. {
  120. if(vc >= sizeof(h264->sprop_parameter_sets)) return -1;
  121. h264->flags |= SDP_A_FMTP_H264_SPROP_PARAMETER_SETS;
  122. memcpy(h264->sprop_parameter_sets, p1+1, vc);
  123. h264->sprop_parameter_sets[vc] = '\0';
  124. }
  125. else if(0 == strncasecmp("sprop-level-parameter-sets", p, nc))
  126. {
  127. if(vc >= sizeof(h264->sprop_level_parameter_sets)) return -1;
  128. h264->flags |= SDP_A_FMTP_H264_SPROP_LEVEL_PARAMETER_SETS;
  129. memcpy(h264->sprop_level_parameter_sets, p1+1, vc);
  130. h264->sprop_level_parameter_sets[vc] = '\0';
  131. }
  132. else if(0 == strncasecmp("sprop-deint-buf-req", p, nc))
  133. {
  134. h264->flags |= SDP_A_FMTP_H264_SPROP_DEINT_BUF_REQ;
  135. h264->sprop_deint_buf_req = (unsigned int)atoi(p1+1);
  136. }
  137. else if(0 == strncasecmp("sprop-interleaving-depth", p, nc))
  138. {
  139. h264->flags |= SDP_A_FMTP_H264_SPROP_INTERLEAVING_DEPTH;
  140. h264->sprop_interleaving_depth = atoi(p1+1);
  141. }
  142. else if(0 == strncasecmp("sprop-max-don-diff", p, nc))
  143. {
  144. h264->flags |= SDP_A_FMTP_H264_SPROP_MAX_DON_DIFF;
  145. h264->sprop_max_don_diff = (unsigned int)atoi(p1+1);
  146. }
  147. else if(0 == strncasecmp("sprop-init-buf-time", p, nc))
  148. {
  149. if(vc >= sizeof(h264->sprop_init_buf_time)) return -1;
  150. h264->flags |= SDP_A_FMTP_H264_SPROP_INIT_BUF_TIME;
  151. memcpy(h264->sprop_init_buf_time, p1+1, vc);
  152. h264->sprop_init_buf_time[vc] = '\0';
  153. }
  154. else if(0 == strncasecmp("sar-understood", p, nc))
  155. {
  156. h264->flags |= SDP_A_FMTP_H264_SAR_UNDERSTOOD;
  157. h264->sar_understood = atoi(p1+1);
  158. }
  159. else if(0 == strncasecmp("sar-supported", p, nc))
  160. {
  161. h264->flags |= SDP_A_FMTP_H264_SAR_SUPPORTED;
  162. h264->sar_supported = atoi(p1+1);
  163. }
  164. break;
  165. case 'r':
  166. // redundant-pic-cap
  167. if(0 == strncasecmp("redundant-pic-cap", p, nc))
  168. {
  169. h264->flags |= SDP_A_FMTP_H264_REDUNDANT_PIC_CAP;
  170. h264->redundant_pic_cap = atoi(p1+1);
  171. }
  172. break;
  173. case 'd':
  174. // deint-buf-cap
  175. if(0 == strncasecmp("deint-buf-cap", p, nc))
  176. {
  177. h264->flags |= SDP_A_FMTP_H264_DEINT_BUF_CAP;
  178. h264->deint_buf_cap = (unsigned int)atoi(p1+1);
  179. }
  180. break;
  181. case 'i':
  182. // in-band-parameter-sets
  183. if(0 == strncasecmp("in-band-parameter-sets", p, nc))
  184. {
  185. h264->flags |= SDP_A_FMTP_H264_IN_BAND_PARAMETER_SETS;
  186. h264->in_band_parameter_sets = atoi(p1+1);
  187. }
  188. break;
  189. case 'u':
  190. // use-level-src-parameter-sets
  191. if(0 == strncasecmp("use-level-src-parameter-sets", p, nc))
  192. {
  193. h264->flags |= SDP_A_FMTP_H264_USE_LEVEL_SRC_PARAMETER_SETS;
  194. h264->use_level_src_parameter_sets = atoi(p1+1);
  195. }
  196. break;
  197. case 'l':
  198. // level-asymmetry-allowed
  199. if(0 == strncasecmp("level-asymmetry-allowed", p, nc))
  200. {
  201. h264->flags |= SDP_A_FMTP_H264_LEVEL_ASYMMETRY_ALLOWED;
  202. h264->level_asymmetry_allowed = atoi(p1+1);
  203. }
  204. break;
  205. }
  206. p = *p2 ? p2 + 1 : p2;
  207. }
  208. return 0;
  209. }
  210. // RFC7798 RTP Payload Format for High Efficiency Video Coding (HEVC)
  211. // m=video 49170 RTP/AVP 98
  212. // a=rtpmap:98 H265/90000
  213. // a=fmtp:98 profile-id=1; sprop-vps=<video parameter sets data>
  214. int sdp_a_fmtp_h265(const char* fmtp, int *format, struct sdp_a_fmtp_h265_t *h265)
  215. {
  216. size_t nc;
  217. const char *p1, *p2;
  218. const char *p = fmtp;
  219. // payload type
  220. *format = atoi(p);
  221. p1 = strchr(p, ' ');
  222. if (!p1 || ' ' != *p1)
  223. return -1;
  224. h265->flags = 0;
  225. assert(' ' == *p1);
  226. p = p1 + 1;
  227. while (*p)
  228. {
  229. p1 = strchr(p, '=');
  230. if (!p1 || '=' != *p1)
  231. return -1;
  232. p2 = strchr(p1 + 1, ';');
  233. if (!p2)
  234. p2 = p1 + strlen(p1);
  235. while (' ' == *p) p++; // skip space
  236. nc = (size_t)(p1 - p); // ptrdiff_t to size_t
  237. //vc = (size_t)(p2 - p1 - 1); // ptrdiff_t to size_t
  238. switch (*p)
  239. {
  240. case 'i':
  241. // interop-constraints
  242. break;
  243. case 'l':
  244. // level-id
  245. break;
  246. case 'p':
  247. // profile-space
  248. // profile-id
  249. // profile-compatibility-indicator
  250. break;
  251. case 's':
  252. // sprop-vps
  253. // sprop-sps
  254. // sprop-pps
  255. // sprop-sei
  256. if (0 == strncasecmp("sprop-vps", p, nc))
  257. {
  258. }
  259. else if (0 == strncasecmp("sprop-sps", p, nc))
  260. {
  261. }
  262. else if (0 == strncasecmp("sprop-pps", p, nc))
  263. {
  264. }
  265. else if (0 == strncasecmp("sprop-sei", p, nc))
  266. {
  267. }
  268. break;
  269. case 't':
  270. // tier-flag
  271. break;
  272. }
  273. p = *p2 ? p2 + 1 : p2;
  274. }
  275. return 0;
  276. }
  277. // RFC3640 RTP Payload Format for Transport of MPEG-4 Elementary Streams
  278. // m=audio 49230 RTP/AVP 96
  279. // a=rtpmap:96 mpeg4-generic/16000/1
  280. // a=fmtp:96 streamtype=5; profile-level-id=14; mode=CELP-cbr; config=440E00; constantSize=27; constantDuration=240
  281. //
  282. // m=video 49230 RTP/AVP 96
  283. // a=rtpmap:96 mpeg4-generic/1000
  284. // a=fmtp:96 streamType=3; profile-level-id=1807; mode=generic;
  285. // objectType=2; config=0842237F24001FB400094002C0; sizeLength=10;
  286. // CTSDeltaLength=16; randomAccessIndication=1; streamStateIndication=4
  287. int sdp_a_fmtp_mpeg4(const char* fmtp, int *format, struct sdp_a_fmtp_mpeg4_t *mpeg4)
  288. {
  289. size_t nc, vc;
  290. const char *p1, *p2;
  291. const char *p = fmtp;
  292. // payload type
  293. *format = atoi(p);
  294. p1 = strchr(p, ' ');
  295. if(!p1 || ' ' != *p1)
  296. return -1;
  297. mpeg4->flags = 0;
  298. assert(' ' == *p1);
  299. p = p1 + 1;
  300. while(*p)
  301. {
  302. p1 = strchr(p, '=');
  303. if(!p1 || '=' != *p1)
  304. return -1;
  305. p2 = strchr(p1+1, ';');
  306. if(!p2)
  307. p2 = p1 + strlen(p1);
  308. while(' ' == *p) p++; // skip space
  309. nc = (size_t)(p1 - p); // ptrdiff_t to size_t
  310. vc = (size_t)(p2 - p1 - 1); // ptrdiff_t to size_t
  311. switch(*p)
  312. {
  313. case 's':
  314. // streamType
  315. // sizeLength
  316. // streamStateIndication
  317. if(0 == strncasecmp("streamType", p, nc))
  318. {
  319. mpeg4->streamType = atoi(p1+1);
  320. }
  321. else if(0 == strncasecmp("sizeLength", p, nc))
  322. {
  323. mpeg4->flags |= SDP_A_FMTP_MPEG4_SIZELENGTH;
  324. mpeg4->sizeLength = atoi(p1+1);
  325. }
  326. else if(0 == strncasecmp("streamStateIndication", p, nc))
  327. {
  328. mpeg4->flags |= SDP_A_FMTP_MPEG4_STREAMSTATEINDICATION;
  329. mpeg4->streamStateIndication = atoi(p1+1);
  330. }
  331. break;
  332. case 'p':
  333. // profile-level-id
  334. if(0 == strncasecmp("profile-level-id", p, nc))
  335. {
  336. if(vc >= sizeof(mpeg4->profile_level_id)) return -1;
  337. memcpy(mpeg4->profile_level_id, p1+1, vc);
  338. mpeg4->profile_level_id[vc] = '\0';
  339. }
  340. break;
  341. case 'c':
  342. // config
  343. // constantSize
  344. // constantDuration
  345. if(0 == strncasecmp("config", p, nc))
  346. {
  347. if(vc >= sizeof(mpeg4->config)) return -1;
  348. memcpy(mpeg4->config, p1+1, vc);
  349. mpeg4->config[vc] = '\0';
  350. }
  351. else if(0 == strncasecmp("constantSize", p, nc))
  352. {
  353. mpeg4->flags |= SDP_A_FMTP_MPEG4_CONSTANTSIZE;
  354. mpeg4->constantSize = atoi(p1+1);
  355. }
  356. else if(0 == strncasecmp("constantDuration", p, nc))
  357. {
  358. mpeg4->flags |= SDP_A_FMTP_MPEG4_CONSTANTDURATION;
  359. mpeg4->constantDuration = atoi(p1+1);
  360. }
  361. break;
  362. case 'm':
  363. // mode
  364. // maxDisplacement
  365. if(0 == strncasecmp("mode", p, nc))
  366. {
  367. if(0 == strncasecmp("generic", p1+1, vc))
  368. mpeg4->mode = 1;
  369. else if(0 == strncasecmp("CELP-cbr", p1+1, vc))
  370. mpeg4->mode = 2;
  371. else if(0 == strncasecmp("CELP-vbr", p1+1, vc))
  372. mpeg4->mode = 3;
  373. else if(0 == strncasecmp("AAC-lbr", p1+1, vc))
  374. mpeg4->mode = 4;
  375. else if(0 == strncasecmp("AAC-hbr", p1+1, vc))
  376. mpeg4->mode = 5;
  377. else
  378. mpeg4->mode = 0; // unknown
  379. }
  380. else if(0 == strncasecmp("maxDisplacement", p, nc))
  381. {
  382. mpeg4->flags |= SDP_A_FMTP_MPEG4_MAXDISPLACEMENT;
  383. mpeg4->maxDisplacement = atoi(p1+1);
  384. }
  385. break;
  386. case 'o':
  387. // objectType
  388. if(0 == strncasecmp("objectType", p, nc))
  389. {
  390. mpeg4->flags |= SDP_A_FMTP_MPEG4_OBJECTTYPE;
  391. mpeg4->objectType = atoi(p1+1);
  392. }
  393. break;
  394. case 'd':
  395. // deinterleaveBufferSize
  396. if(0 == strncasecmp("deinterleaveBufferSize", p, nc))
  397. {
  398. mpeg4->flags |= SDP_A_FMTP_MPEG4_DEINTERLEAVEBUFFERSIZE;
  399. mpeg4->deinterleaveBufferSize = atoi(p1+1);
  400. }
  401. break;
  402. case 'i':
  403. // indexLength
  404. // indexDeltaLength
  405. if(0 == strncasecmp("indexLength", p, nc))
  406. {
  407. mpeg4->flags |= SDP_A_FMTP_MPEG4_INDEXLENGTH;
  408. mpeg4->indexLength = atoi(p1+1);
  409. }
  410. else if(0 == strncasecmp("indexDeltaLength", p, nc))
  411. {
  412. mpeg4->flags |= SDP_A_FMTP_MPEG4_INDEXDELTALENGTH;
  413. mpeg4->indexDeltaLength = atoi(p1+1);
  414. }
  415. break;
  416. case 'C':
  417. // CTSDeltaLength
  418. if(0 == strncasecmp("CTSDeltaLength", p, nc))
  419. {
  420. mpeg4->flags |= SDP_A_FMTP_MPEG4_CTSDELTALENGTH;
  421. mpeg4->CTSDeltaLength = atoi(p1+1);
  422. }
  423. break;
  424. case 'D':
  425. // DTSDeltaLength
  426. if(0 == strncasecmp("DTSDeltaLength", p, nc))
  427. {
  428. mpeg4->flags |= SDP_A_FMTP_MPEG4_DTSDELTALENGTH;
  429. mpeg4->DTSDeltaLength = atoi(p1+1);
  430. }
  431. break;
  432. case 'r':
  433. // randomAccessIndication
  434. if(0 == strncasecmp("randomAccessIndication", p, nc))
  435. {
  436. mpeg4->flags |= SDP_A_FMTP_MPEG4_RANDOMACCESSINDICATION;
  437. mpeg4->randomAccessIndication = atoi(p1+1);
  438. }
  439. break;
  440. case 'a':
  441. // auxiliaryDataSizeLength
  442. if(0 == strncasecmp("auxiliaryDataSizeLength", p, nc))
  443. {
  444. mpeg4->flags |= SDP_A_FMTP_MPEG4_AUXILIARYDATASIZELENGTH;
  445. mpeg4->auxiliaryDataSizeLength = atoi(p1+1);
  446. }
  447. break;
  448. }
  449. p = *p2 ? p2 + 1 : p2;
  450. }
  451. return 0;
  452. }
  453. // RFC4588 RTP Retransmission Payload Format
  454. // a=fmtp:<number> apt=<apt-value>;rtx-time=<rtx-time-val>
  455. int sdp_a_fmtp_rtx(const char* fmtp, int* format, struct sdp_a_fmtp_rtx_t* rtx)
  456. {
  457. size_t nc, vc;
  458. const char* p1, * p2;
  459. const char* p = fmtp;
  460. // payload type
  461. *format = atoi(p);
  462. p1 = strchr(p, ' ');
  463. if (!p1 || ' ' != *p1)
  464. return -1;
  465. assert(' ' == *p1);
  466. p = p1 + 1;
  467. while (*p)
  468. {
  469. p1 = strchr(p, '=');
  470. if (!p1 || '=' != *p1)
  471. return -1;
  472. p2 = strchr(p1 + 1, ';');
  473. if (!p2)
  474. p2 = p1 + strlen(p1);
  475. while (' ' == *p) p++; // skip space
  476. nc = (size_t)(p1 - p); // ptrdiff_t to size_t
  477. vc = (size_t)(p2 - p1 - 1); // ptrdiff_t to size_t
  478. switch (*p)
  479. {
  480. case 'a':
  481. if (0 == strncasecmp("apt", p, nc))
  482. {
  483. rtx->apt = atoi(p1 + 1);
  484. }
  485. break;
  486. case 'r':
  487. if (0 == strncasecmp("rtx-time", p, nc))
  488. {
  489. rtx->rtx_time = atoi(p1 + 1);
  490. }
  491. break;
  492. }
  493. p = *p2 ? p2 + 1 : p2;
  494. }
  495. return 0;
  496. }
  497. #if defined(DEBUG) || defined(_DEBUG)
  498. static void sdp_a_fmtp_h264_test(void)
  499. {
  500. int format = 0;
  501. struct sdp_a_fmtp_h264_t h264;
  502. const char* fmtp1 = "98 profile-level-id=42A01E;packetization-mode=1; sprop-parameter-sets=abcd";
  503. assert(0 == sdp_a_fmtp_h264(fmtp1, &format, &h264));
  504. assert(98 == format);
  505. assert(h264.flags == (SDP_A_FMTP_H264_PROFILE_LEVEL_ID|SDP_A_FMTP_H264_PACKETIZATION_MODE|SDP_A_FMTP_H264_SPROP_PARAMETER_SETS));
  506. assert(0 == strcmp("42A01E", h264.profile_level_id));
  507. assert(1 == h264.packetization_mode);
  508. assert(0 == strcmp("abcd", h264.sprop_parameter_sets));
  509. }
  510. static void sdp_a_fmtp_mpeg4_test(void)
  511. {
  512. int format = 0;
  513. struct sdp_a_fmtp_mpeg4_t mpeg4;
  514. const char* fmtp = "96 streamType=3;profile-level-id=1807; mode=generic;objectType=2; config=0842237F24001FB400094002C0;sizeLength=10;CTSDeltaLength=16;randomAccessIndication=1;streamStateIndication=4";
  515. assert(0 == sdp_a_fmtp_mpeg4(fmtp, &format, &mpeg4));
  516. assert(96 == format);
  517. assert(mpeg4.flags == (SDP_A_FMTP_MPEG4_OBJECTTYPE|SDP_A_FMTP_MPEG4_SIZELENGTH|SDP_A_FMTP_MPEG4_CTSDELTALENGTH|SDP_A_FMTP_MPEG4_RANDOMACCESSINDICATION|SDP_A_FMTP_MPEG4_STREAMSTATEINDICATION));
  518. assert(3 == mpeg4.streamType);
  519. assert(0 == strcmp("1807", mpeg4.profile_level_id));
  520. assert(1 == mpeg4.mode);
  521. assert(2 == mpeg4.objectType);
  522. assert(0 == strcmp(mpeg4.config, "0842237F24001FB400094002C0"));
  523. assert(10 == mpeg4.sizeLength);
  524. assert(16 == mpeg4.CTSDeltaLength);
  525. assert(1 == mpeg4.randomAccessIndication);
  526. assert(4 == mpeg4.streamStateIndication);
  527. }
  528. static void sdp_a_fmtp_mpeg4_aac_test(void)
  529. {
  530. int format = 0;
  531. struct sdp_a_fmtp_mpeg4_t mpeg4;
  532. const char* fmtp = "97 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=131056E59D4800";
  533. assert(0 == sdp_a_fmtp_mpeg4(fmtp, &format, &mpeg4));
  534. assert(97 == format);
  535. assert(mpeg4.flags == (SDP_A_FMTP_MPEG4_SIZELENGTH | SDP_A_FMTP_MPEG4_INDEXLENGTH | SDP_A_FMTP_MPEG4_INDEXDELTALENGTH));
  536. assert(5 == mpeg4.streamType);
  537. assert(0 == strcmp("1", mpeg4.profile_level_id));
  538. assert(5 == mpeg4.mode);
  539. assert(0 == strcmp(mpeg4.config, "131056E59D4800"));
  540. assert(13 == mpeg4.sizeLength);
  541. assert(3 == mpeg4.indexLength);
  542. assert(3 == mpeg4.indexDeltaLength);
  543. }
  544. static void sdp_a_fmtp_rtx_test(void)
  545. {
  546. int format = 0;
  547. struct sdp_a_fmtp_rtx_t rtx;
  548. const char* fmtp = "111 apt=97;rtx-time=3000";
  549. assert(0 == sdp_a_fmtp_rtx(fmtp, &format, &rtx));
  550. assert(111 == format && 97 == rtx.apt && 3000 == rtx.rtx_time);
  551. }
  552. void sdp_a_fmtp_test(void)
  553. {
  554. sdp_a_fmtp_h264_test();
  555. sdp_a_fmtp_mpeg4_test();
  556. sdp_a_fmtp_mpeg4_aac_test();
  557. sdp_a_fmtp_rtx_test();
  558. }
  559. #endif