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.

482 lines
15KB

  1. /*
  2. * Pro-MPEG Code of Practice #3 Release 2 FEC
  3. * Copyright (c) 2016 Mobibase, France (http://www.mobibase.com)
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. /**
  22. * @file
  23. * Pro-MPEG Code of Practice #3 Release 2 FEC protocol
  24. * @author Vlad Tarca <vlad.tarca@gmail.com>
  25. */
  26. /*
  27. * Reminder:
  28. [RFC 2733] FEC Packet Structure
  29. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  30. | RTP Header |
  31. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  32. | FEC Header |
  33. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  34. | FEC Payload |
  35. | |
  36. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  37. [RFC 3550] RTP header
  38. 0 1 2 3
  39. 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
  40. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  41. |V=2|P|X| CC |M| PT | sequence number |
  42. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  43. | timestamp |
  44. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  45. | synchronization source (SSRC) identifier |
  46. +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  47. | contributing source (CSRC) identifiers |
  48. | .... |
  49. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  50. [RFC 3550] RTP header extension (after CSRC)
  51. 0 1 2 3
  52. 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
  53. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  54. | defined by profile | length |
  55. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  56. | header extension |
  57. | .... |
  58. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  59. [Pro-MPEG COP3] FEC Header
  60. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  61. | SNBase low bits | length recovery |
  62. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  63. |E| PT recovery | mask |
  64. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  65. | TS recovery |
  66. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  67. |X|D|type |index| offset | NA |SNBase ext bits|
  68. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  69. */
  70. #include "libavutil/avstring.h"
  71. #include "libavutil/intreadwrite.h"
  72. #include "libavutil/opt.h"
  73. #include "libavutil/parseutils.h"
  74. #include "libavutil/random_seed.h"
  75. #include "avformat.h"
  76. #include "config.h"
  77. #include "url.h"
  78. #define PROMPEG_RTP_PT 0x60
  79. #define PROMPEG_FEC_COL 0x0
  80. #define PROMPEG_FEC_ROW 0x1
  81. typedef struct PrompegFec {
  82. uint16_t sn;
  83. uint32_t ts;
  84. uint8_t *bitstring;
  85. } PrompegFec;
  86. typedef struct PrompegContext {
  87. const AVClass *class;
  88. URLContext *fec_col_hd, *fec_row_hd;
  89. PrompegFec **fec_arr, **fec_col_tmp, **fec_col, *fec_row;
  90. int ttl;
  91. uint8_t l, d;
  92. uint8_t *rtp_buf;
  93. uint16_t rtp_col_sn, rtp_row_sn;
  94. uint16_t length_recovery;
  95. int packet_size;
  96. int packet_idx, packet_idx_max;
  97. int fec_arr_len;
  98. int bitstring_size;
  99. int rtp_buf_size;
  100. int init;
  101. int first;
  102. } PrompegContext;
  103. #define OFFSET(x) offsetof(PrompegContext, x)
  104. #define E AV_OPT_FLAG_ENCODING_PARAM
  105. static const AVOption options[] = {
  106. { "ttl", "Time to live (in milliseconds, multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = E },
  107. { "l", "FEC L", OFFSET(l), AV_OPT_TYPE_INT, { .i64 = 5 }, 4, 20, .flags = E },
  108. { "d", "FEC D", OFFSET(d), AV_OPT_TYPE_INT, { .i64 = 5 }, 4, 20, .flags = E },
  109. { NULL }
  110. };
  111. static const AVClass prompeg_class = {
  112. .class_name = "prompeg",
  113. .item_name = av_default_item_name,
  114. .option = options,
  115. .version = LIBAVUTIL_VERSION_INT,
  116. };
  117. static void xor_fast(const uint8_t *in1, const uint8_t *in2, uint8_t *out, int size) {
  118. int i, n, s;
  119. #if HAVE_FAST_64BIT
  120. uint64_t v1, v2;
  121. n = size / sizeof (uint64_t);
  122. s = n * sizeof (uint64_t);
  123. for (i = 0; i < n; i++) {
  124. v1 = AV_RN64A(in1);
  125. v2 = AV_RN64A(in2);
  126. AV_WN64A(out, v1 ^ v2);
  127. in1 += 8;
  128. in2 += 8;
  129. out += 8;
  130. }
  131. #else
  132. uint32_t v1, v2;
  133. n = size / sizeof (uint32_t);
  134. s = n * sizeof (uint32_t);
  135. for (i = 0; i < n; i++) {
  136. v1 = AV_RN32A(in1);
  137. v2 = AV_RN32A(in2);
  138. AV_WN32A(out, v1 ^ v2);
  139. in1 += 4;
  140. in2 += 4;
  141. out += 4;
  142. }
  143. #endif
  144. n = size - s;
  145. for (i = 0; i < n; i++) {
  146. out[i] = in1[i] ^ in2[i];
  147. }
  148. }
  149. static int prompeg_create_bitstring(URLContext *h, const uint8_t *buf, int size,
  150. uint8_t **bitstring) {
  151. PrompegContext *s = h->priv_data;
  152. uint8_t *b;
  153. if (size < 12 || (buf[0] & 0xc0) != 0x80 || (buf[1] & 0x7f) != 0x21) {
  154. av_log(h, AV_LOG_ERROR, "Unsupported stream format (expected MPEG-TS over RTP)\n");
  155. return AVERROR(EINVAL);
  156. }
  157. if (size != s->packet_size) {
  158. av_log(h, AV_LOG_ERROR, "The RTP packet size must be constant (set pkt_size)\n");
  159. return AVERROR(EINVAL);
  160. }
  161. *bitstring = av_malloc(s->bitstring_size);
  162. if (!*bitstring) {
  163. av_log(h, AV_LOG_ERROR, "Failed to allocate the bitstring buffer\n");
  164. return AVERROR(ENOMEM);
  165. }
  166. b = *bitstring;
  167. // P, X, CC
  168. b[0] = buf[0] & 0x3f;
  169. // M, PT
  170. b[1] = buf[1];
  171. // Timestamp
  172. b[2] = buf[4];
  173. b[3] = buf[5];
  174. b[4] = buf[6];
  175. b[5] = buf[7];
  176. /*
  177. * length_recovery: the unsigned network-ordered sum of lengths of CSRC,
  178. * padding, extension and media payload
  179. */
  180. AV_WB16(b + 6, s->length_recovery);
  181. // Payload
  182. memcpy(b + 8, buf + 12, s->length_recovery);
  183. return 0;
  184. }
  185. static int prompeg_write_fec(URLContext *h, PrompegFec *fec, uint8_t type) {
  186. PrompegContext *s = h->priv_data;
  187. URLContext *hd;
  188. uint8_t *buf = s->rtp_buf; // zero-filled
  189. uint8_t *b = fec->bitstring;
  190. uint16_t sn;
  191. int ret;
  192. sn = type == PROMPEG_FEC_COL ? ++s->rtp_col_sn : ++s->rtp_row_sn;
  193. // V, P, X, CC
  194. buf[0] = 0x80 | (b[0] & 0x3f);
  195. // M, PT
  196. buf[1] = (b[1] & 0x80) | PROMPEG_RTP_PT;
  197. // SN
  198. AV_WB16(buf + 2, sn);
  199. // TS
  200. AV_WB32(buf + 4, fec->ts);
  201. // CSRC=0
  202. //AV_WB32(buf + 8, 0);
  203. // SNBase low bits
  204. AV_WB16(buf + 12, fec->sn);
  205. // Length recovery
  206. buf[14] = b[6];
  207. buf[15] = b[7];
  208. // E=1, PT recovery
  209. buf[16] = 0x80 | b[1];
  210. // Mask=0
  211. //buf[17] = 0x0;
  212. //buf[18] = 0x0;
  213. //buf[19] = 0x0;
  214. // TS recovery
  215. buf[20] = b[2];
  216. buf[21] = b[3];
  217. buf[22] = b[4];
  218. buf[23] = b[5];
  219. // X=0, D, type=0, index=0
  220. buf[24] = type == PROMPEG_FEC_COL ? 0x0 : 0x40;
  221. // offset
  222. buf[25] = type == PROMPEG_FEC_COL ? s->l : 0x1;
  223. // NA
  224. buf[26] = type == PROMPEG_FEC_COL ? s->d : s->l;
  225. // SNBase ext bits=0
  226. //buf[27] = 0x0;
  227. // Payload
  228. memcpy(buf + 28, b + 8, s->length_recovery);
  229. hd = type == PROMPEG_FEC_COL ? s->fec_col_hd : s->fec_row_hd;
  230. ret = ffurl_write(hd, buf, s->rtp_buf_size);
  231. return ret;
  232. }
  233. static int prompeg_open(URLContext *h, const char *uri, int flags) {
  234. PrompegContext *s = h->priv_data;
  235. AVDictionary *udp_opts = NULL;
  236. int rtp_port;
  237. char hostname[256];
  238. char buf[1024];
  239. s->fec_col_hd = NULL;
  240. s->fec_row_hd = NULL;
  241. if (s->l * s->d > 100) {
  242. av_log(h, AV_LOG_ERROR, "L * D must be <= 100\n");
  243. return AVERROR(EINVAL);
  244. }
  245. av_url_split(NULL, 0, NULL, 0, hostname, sizeof (hostname), &rtp_port,
  246. NULL, 0, uri);
  247. if (rtp_port < 1 || rtp_port > UINT16_MAX - 4) {
  248. av_log(h, AV_LOG_ERROR, "Invalid RTP base port %d\n", rtp_port);
  249. return AVERROR(EINVAL);
  250. }
  251. if (s->ttl > 0) {
  252. snprintf(buf, sizeof (buf), "%d", s->ttl);
  253. av_dict_set(&udp_opts, "ttl", buf, 0);
  254. }
  255. ff_url_join(buf, sizeof (buf), "udp", NULL, hostname, rtp_port + 2, NULL);
  256. if (ffurl_open_whitelist(&s->fec_col_hd, buf, flags, &h->interrupt_callback,
  257. &udp_opts, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
  258. goto fail;
  259. ff_url_join(buf, sizeof (buf), "udp", NULL, hostname, rtp_port + 4, NULL);
  260. if (ffurl_open_whitelist(&s->fec_row_hd, buf, flags, &h->interrupt_callback,
  261. &udp_opts, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
  262. goto fail;
  263. h->max_packet_size = s->fec_col_hd->max_packet_size;
  264. s->init = 1;
  265. av_dict_free(&udp_opts);
  266. av_log(h, AV_LOG_INFO, "ProMPEG CoP#3-R2 FEC L=%d D=%d\n", s->l, s->d);
  267. return 0;
  268. fail:
  269. ffurl_closep(&s->fec_col_hd);
  270. ffurl_closep(&s->fec_row_hd);
  271. av_dict_free(&udp_opts);
  272. return AVERROR(EIO);
  273. }
  274. static int prompeg_init(URLContext *h, const uint8_t *buf, int size) {
  275. PrompegContext *s = h->priv_data;
  276. uint32_t seed;
  277. int i;
  278. s->fec_arr = NULL;
  279. s->rtp_buf = NULL;
  280. if (size < 12 || size > UINT16_MAX + 12) {
  281. av_log(h, AV_LOG_ERROR, "Invalid RTP packet size\n");
  282. return AVERROR_INVALIDDATA;
  283. }
  284. s->packet_idx = 0;
  285. s->packet_idx_max = s->l * s->d;
  286. s->packet_size = size;
  287. s->length_recovery = size - 12;
  288. s->rtp_buf_size = 28 + s->length_recovery; // 12 + 16: RTP + FEC headers
  289. s->bitstring_size = 8 + s->length_recovery; // 8: P, X, CC, M, PT, SN, TS
  290. s->fec_arr_len = 1 + 2 * s->l; // row + column tmp + column out
  291. if (h->flags & AVFMT_FLAG_BITEXACT) {
  292. s->rtp_col_sn = 0;
  293. s->rtp_row_sn = 0;
  294. } else {
  295. seed = av_get_random_seed();
  296. s->rtp_col_sn = seed & 0x0fff;
  297. s->rtp_row_sn = (seed >> 16) & 0x0fff;
  298. }
  299. s->fec_arr = av_malloc_array(s->fec_arr_len, sizeof (PrompegFec*));
  300. if (!s->fec_arr) {
  301. goto fail;
  302. }
  303. for (i = 0; i < s->fec_arr_len; i++) {
  304. s->fec_arr[i] = av_malloc(sizeof (PrompegFec));
  305. if (!s->fec_arr[i]) {
  306. goto fail;
  307. }
  308. s->fec_arr[i]->bitstring = av_malloc_array(s->bitstring_size, sizeof (uint8_t));
  309. if (!s->fec_arr[i]->bitstring) {
  310. av_freep(&s->fec_arr[i]);
  311. goto fail;
  312. }
  313. }
  314. s->fec_row = *s->fec_arr;
  315. s->fec_col = s->fec_arr + 1;
  316. s->fec_col_tmp = s->fec_arr + 1 + s->l;
  317. s->rtp_buf = av_malloc_array(s->rtp_buf_size, sizeof (uint8_t));
  318. if (!s->rtp_buf) {
  319. goto fail;
  320. }
  321. memset(s->rtp_buf, 0, s->rtp_buf_size);
  322. s->init = 0;
  323. s->first = 1;
  324. return 0;
  325. fail:
  326. av_log(h, AV_LOG_ERROR, "Failed to allocate the FEC buffer\n");
  327. return AVERROR(ENOMEM);
  328. }
  329. static int prompeg_write(URLContext *h, const uint8_t *buf, int size) {
  330. PrompegContext *s = h->priv_data;
  331. PrompegFec *fec_tmp;
  332. uint8_t *bitstring = NULL;
  333. int col_idx, col_out_idx, row_idx;
  334. int ret, written = 0;
  335. if (s->init && ((ret = prompeg_init(h, buf, size)) < 0))
  336. goto end;
  337. if ((ret = prompeg_create_bitstring(h, buf, size, &bitstring)) < 0)
  338. goto end;
  339. col_idx = s->packet_idx % s->l;
  340. row_idx = s->packet_idx / s->l % s->d;
  341. // FEC' (row) send block-aligned, xor
  342. if (col_idx == 0) {
  343. if (!s->first || s->packet_idx > 0) {
  344. if ((ret = prompeg_write_fec(h, s->fec_row, PROMPEG_FEC_ROW)) < 0)
  345. goto end;
  346. written += ret;
  347. }
  348. memcpy(s->fec_row->bitstring, bitstring, s->bitstring_size);
  349. s->fec_row->sn = AV_RB16(buf + 2);
  350. s->fec_row->ts = AV_RB32(buf + 4);
  351. } else {
  352. xor_fast(s->fec_row->bitstring, bitstring, s->fec_row->bitstring,
  353. s->bitstring_size);
  354. }
  355. // FEC (column) xor
  356. if (row_idx == 0) {
  357. if (!s->first) {
  358. // swap fec_col and fec_col_tmp
  359. fec_tmp = s->fec_col[col_idx];
  360. s->fec_col[col_idx] = s->fec_col_tmp[col_idx];
  361. s->fec_col_tmp[col_idx] = fec_tmp;
  362. }
  363. memcpy(s->fec_col_tmp[col_idx]->bitstring, bitstring, s->bitstring_size);
  364. s->fec_col_tmp[col_idx]->sn = AV_RB16(buf + 2);
  365. s->fec_col_tmp[col_idx]->ts = AV_RB32(buf + 4);
  366. } else {
  367. xor_fast(s->fec_col_tmp[col_idx]->bitstring, bitstring,
  368. s->fec_col_tmp[col_idx]->bitstring, s->bitstring_size);
  369. }
  370. // FEC (column) send block-aligned
  371. if (!s->first && s->packet_idx % s->d == 0) {
  372. col_out_idx = s->packet_idx / s->d;
  373. if ((ret = prompeg_write_fec(h, s->fec_col[col_out_idx], PROMPEG_FEC_COL)) < 0)
  374. goto end;
  375. written += ret;
  376. }
  377. if (++s->packet_idx >= s->packet_idx_max) {
  378. s->packet_idx = 0;
  379. if (s->first)
  380. s->first = 0;
  381. }
  382. ret = written;
  383. end:
  384. av_free(bitstring);
  385. return ret;
  386. }
  387. static int prompeg_close(URLContext *h) {
  388. PrompegContext *s = h->priv_data;
  389. int i;
  390. ffurl_closep(&s->fec_col_hd);
  391. ffurl_closep(&s->fec_row_hd);
  392. if (s->fec_arr) {
  393. for (i = 0; i < s->fec_arr_len; i++) {
  394. av_free(s->fec_arr[i]->bitstring);
  395. av_freep(&s->fec_arr[i]);
  396. }
  397. av_freep(&s->fec_arr);
  398. }
  399. av_freep(&s->rtp_buf);
  400. return 0;
  401. }
  402. const URLProtocol ff_prompeg_protocol = {
  403. .name = "prompeg",
  404. .url_open = prompeg_open,
  405. .url_write = prompeg_write,
  406. .url_close = prompeg_close,
  407. .priv_data_size = sizeof(PrompegContext),
  408. .flags = URL_PROTOCOL_FLAG_NETWORK,
  409. .priv_data_class = &prompeg_class,
  410. };