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 /**
23 * @file
24 * Pro-MPEG Code of Practice #3 Release 2 FEC protocol
25 * @author Vlad Tarca <vlad.tarca@gmail.com>
26 */
27
28 /*
29 * Reminder:
30
31 [RFC 2733] FEC Packet Structure
32
33 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 | RTP Header |
35 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 | FEC Header |
37 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 | FEC Payload |
39 | |
40 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41
42
43 [RFC 3550] RTP header
44
45 0 1 2 3
46 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
47 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 |V=2|P|X| CC |M| PT | sequence number |
49 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 | timestamp |
51 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 | synchronization source (SSRC) identifier |
53 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
54 | contributing source (CSRC) identifiers |
55 | .... |
56 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57
58 [RFC 3550] RTP header extension (after CSRC)
59
60 0 1 2 3
61 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
62 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 | defined by profile | length |
64 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 | header extension |
66 | .... |
67 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68
69 [Pro-MPEG COP3] FEC Header
70
71 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 | SNBase low bits | length recovery |
73 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 |E| PT recovery | mask |
75 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 | TS recovery |
77 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 |X|D|type |index| offset | NA |SNBase ext bits|
79 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80
81 */
82
89 #include "config.h"
91
92 #define PROMPEG_RTP_PT 0x60
93 #define PROMPEG_FEC_COL 0x0
94 #define PROMPEG_FEC_ROW 0x1
95
101
119
120 #define OFFSET(x) offsetof(PrompegContext, x)
121 #define E AV_OPT_FLAG_ENCODING_PARAM
122
124 {
"ttl",
"Time to live (in milliseconds, multicast only)",
OFFSET(ttl),
AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags =
E },
128 };
129
135 };
136
137 static void xor_fast(
const uint8_t *in1,
const uint8_t *in2, uint8_t *
out,
int size) {
139
140 #if HAVE_FAST_64BIT
141 uint64_t v1, v2;
142
143 n =
size /
sizeof (uint64_t);
144 s = n *
sizeof (uint64_t);
145
146 for (
i = 0;
i < n;
i++) {
150 in1 += 8;
151 in2 += 8;
153 }
154 #else
155 uint32_t v1, v2;
156
157 n =
size /
sizeof (uint32_t);
158 s = n *
sizeof (uint32_t);
159
160 for (
i = 0;
i < n;
i++) {
164 in1 += 4;
165 in2 += 4;
167 }
168 #endif
169
171
172 for (
i = 0;
i < n;
i++) {
174 }
175 }
176
178 uint8_t **bitstring) {
181
182 if (
size < 12 || (buf[0] & 0xc0) != 0x80 || (buf[1] & 0x7f) != 0x21) {
185 }
186 if (
size !=
s->packet_size) {
189 }
190
192 if (!*bitstring) {
195 }
197
198 // P, X, CC
199 b[0] = buf[0] & 0x3f;
200 // M, PT
202 // Timestamp
207 /*
208 * length_recovery: the unsigned network-ordered sum of lengths of CSRC,
209 * padding, extension and media payload
210 */
212 // Payload
213 memcpy(
b + 8, buf + 12,
s->length_recovery);
214
215 return 0;
216 }
217
221 uint8_t *buf =
s->rtp_buf;
// zero-filled
223 uint16_t sn;
225
227
228 // V, P, X, CC
229 buf[0] = 0x80 | (
b[0] & 0x3f);
230 // M, PT
232 // SN
234 // TS
236 // CSRC=0
237 //AV_WB32(buf + 8, 0);
238 // SNBase low bits
240 // Length recovery
243 // E=1, PT recovery
244 buf[16] = 0x80 |
b[1];
245 // Mask=0
246 //buf[17] = 0x0;
247 //buf[18] = 0x0;
248 //buf[19] = 0x0;
249 // TS recovery
254 // X=0, D, type=0, index=0
256 // offset
258 // NA
260 // SNBase ext bits=0
261 //buf[27] = 0x0;
262 // Payload
263 memcpy(buf + 28,
b + 8,
s->length_recovery);
264
268 }
269
273 int rtp_port;
274 char hostname[256];
275 char buf[1024];
276
277 s->fec_col_hd =
NULL;
278 s->fec_row_hd =
NULL;
279
280 if (
s->l *
s->d > 100) {
283 }
284
287
288 if (rtp_port < 1 || rtp_port > UINT16_MAX - 4) {
291 }
292
295 }
296
299 &udp_opts,
h->protocol_whitelist,
h->protocol_blacklist,
h) < 0)
303 &udp_opts,
h->protocol_whitelist,
h->protocol_blacklist,
h) < 0)
305
306 h->max_packet_size =
s->fec_col_hd->max_packet_size;
308
311 return 0;
312
318 }
319
324
327
328 if (size < 12 || size > UINT16_MAX + 12) {
331 }
332
334 s->packet_idx_max =
s->l *
s->d;
335 s->packet_size =
size;
336 s->length_recovery =
size - 12;
337 s->rtp_buf_size = 28 +
s->length_recovery;
// 12 + 16: RTP + FEC headers
338 s->bitstring_size = 8 +
s->length_recovery;
// 8: P, X, CC, M, PT, SN, TS
339 s->fec_arr_len = 1 + 2 *
s->l;
// row + column tmp + column out
340
344 } else {
346 s->rtp_col_sn =
seed & 0x0fff;
347 s->rtp_row_sn = (
seed >> 16) & 0x0fff;
348 }
349
353 }
354 for (
i = 0;
i <
s->fec_arr_len;
i++) {
356 if (!
s->fec_arr[
i]) {
358 }
360 if (!
s->fec_arr[
i]->bitstring) {
363 }
364 }
365 s->fec_row = *
s->fec_arr;
366 s->fec_col =
s->fec_arr + 1;
367 s->fec_col_tmp =
s->fec_arr + 1 +
s->l;
368
372 }
373 memset(
s->rtp_buf, 0,
s->rtp_buf_size);
374
377
378 return 0;
379
383 }
384
388 uint8_t *bitstring =
NULL;
389 int col_idx, col_out_idx, row_idx;
391
393 goto end;
394
396 goto end;
397
398 col_idx =
s->packet_idx %
s->l;
399 row_idx =
s->packet_idx /
s->l %
s->d;
400
401 // FEC' (row) send block-aligned, xor
402 if (col_idx == 0) {
403 if (!
s->first ||
s->packet_idx > 0) {
405 goto end;
406 }
407 memcpy(
s->fec_row->bitstring, bitstring,
s->bitstring_size);
410 } else {
411 xor_fast(
s->fec_row->bitstring, bitstring,
s->fec_row->bitstring,
413 }
414
415 // FEC (column) xor
416 if (row_idx == 0) {
418 // swap fec_col and fec_col_tmp
419 fec_tmp =
s->fec_col[col_idx];
420 s->fec_col[col_idx] =
s->fec_col_tmp[col_idx];
421 s->fec_col_tmp[col_idx] = fec_tmp;
422 }
423 memcpy(
s->fec_col_tmp[col_idx]->bitstring, bitstring,
s->bitstring_size);
424 s->fec_col_tmp[col_idx]->sn =
AV_RB16(buf + 2);
425 s->fec_col_tmp[col_idx]->ts =
AV_RB32(buf + 4);
426 } else {
427 xor_fast(
s->fec_col_tmp[col_idx]->bitstring, bitstring,
428 s->fec_col_tmp[col_idx]->bitstring,
s->bitstring_size);
429 }
430
431 // FEC (column) send block-aligned
432 if (!
s->first &&
s->packet_idx %
s->d == 0) {
433 col_out_idx =
s->packet_idx /
s->d;
435 goto end;
436 }
437
438 if (++
s->packet_idx >=
s->packet_idx_max) {
442 }
443
445
446 end:
449 }
450
454
457
459 for (
i = 0;
i <
s->fec_arr_len;
i++) {
462 }
464 }
466
467 return 0;
468 }
469
478 };