• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2020> Mathieu Duponchelle <mathieu@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include <gst/check/gstcheck.h>
21 #include <gst/check/gstharness.h>
22 #include <gst/rtp/gstrtpbuffer.h>
23 #include <gst/base/base.h>
24 
25 typedef struct
26 {
27   guint16 seq;
28   guint16 len;
29   guint8 E;
30   guint8 pt;
31   guint32 mask;
32   guint32 timestamp;
33   guint8 N;
34   guint8 D;
35   guint8 type;
36   guint8 index;
37   guint8 offset;
38   guint8 NA;
39   guint8 seq_ext;
40   guint8 *payload;
41   guint payload_len;
42 } Rtp2DFecHeader;
43 
44 static void
parse_header(Rtp2DFecHeader * fec,guint8 * data,guint len)45 parse_header (Rtp2DFecHeader * fec, guint8 * data, guint len)
46 {
47   GstBitReader bits;
48 
49   fail_unless (len >= 16);
50 
51   gst_bit_reader_init (&bits, data, len);
52 
53   fec->seq = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
54   fec->len = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
55   fec->E = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1);
56   fec->pt = gst_bit_reader_get_bits_uint8_unchecked (&bits, 7);
57   fec->mask = gst_bit_reader_get_bits_uint32_unchecked (&bits, 24);
58   fec->timestamp = gst_bit_reader_get_bits_uint32_unchecked (&bits, 32);
59   fec->N = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1);
60   fec->D = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1);
61   fec->type = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);
62   fec->index = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3);
63   fec->offset = gst_bit_reader_get_bits_uint8_unchecked (&bits, 8);
64   fec->NA = gst_bit_reader_get_bits_uint8_unchecked (&bits, 8);
65   fec->seq_ext = gst_bit_reader_get_bits_uint8_unchecked (&bits, 8);
66   fec->payload = data + 16;
67   fec->payload_len = len - 16;
68 }
69 
70 static GstBuffer *
make_media_sample(guint16 seq,guint32 ts,guint8 * payload,guint payload_len)71 make_media_sample (guint16 seq, guint32 ts, guint8 * payload, guint payload_len)
72 {
73   GstBuffer *ret;
74   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
75   guint8 *data;
76 
77   ret = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
78 
79   gst_rtp_buffer_map (ret, GST_MAP_WRITE, &rtp);
80   gst_rtp_buffer_set_payload_type (&rtp, 33);
81   gst_rtp_buffer_set_seq (&rtp, seq);
82   gst_rtp_buffer_set_timestamp (&rtp, ts);
83   data = gst_rtp_buffer_get_payload (&rtp);
84   memcpy (data, payload, payload_len);
85   gst_rtp_buffer_unmap (&rtp);
86 
87   return ret;
88 }
89 
90 static void
pull_and_check(GstHarness * h,guint n_packets,guint16 seq,guint length_recovery,guint8 pt_recovery,guint32 ts_recovery,gboolean row,guint8 offset,guint8 NA,guint8 * payload,guint payload_len)91 pull_and_check (GstHarness * h, guint n_packets, guint16 seq,
92     guint length_recovery, guint8 pt_recovery, guint32 ts_recovery,
93     gboolean row, guint8 offset, guint8 NA, guint8 * payload, guint payload_len)
94 {
95   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
96   GstBuffer *buffer;
97   Rtp2DFecHeader fec;
98 
99   fail_unless_equals_int (gst_harness_buffers_in_queue (h), n_packets);
100   buffer = gst_harness_pull (h);
101   fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
102 
103   parse_header (&fec, gst_rtp_buffer_get_payload (&rtp),
104       gst_rtp_buffer_get_payload_len (&rtp));
105 
106   fail_unless_equals_int (fec.seq, seq);
107   fail_unless_equals_int (fec.pt, pt_recovery);
108   fail_unless_equals_int (fec.timestamp, ts_recovery);
109   fail_unless_equals_int (fec.D, row ? 1 : 0);
110   fail_unless_equals_int (fec.offset, offset);
111   fail_unless_equals_int (fec.NA, NA);
112   fail_unless_equals_int (fec.payload_len, payload_len);
113   fail_unless_equals_int (memcmp (fec.payload, payload, fec.payload_len), 0);
114 
115   gst_rtp_buffer_unmap (&rtp);
116   gst_buffer_unref (buffer);
117 }
118 
GST_START_TEST(test_row)119 GST_START_TEST (test_row)
120 {
121   GstHarness *h, *h_fec_1;
122   guint8 payload;
123   GstElement *enc = gst_element_factory_make ("rtpst2022-1-fecenc", NULL);
124 
125   g_object_set (enc, "columns", 3, "enable-column-fec", FALSE, NULL);
126   h = gst_harness_new_with_element (enc, "sink", "src");
127   h_fec_1 = gst_harness_new_with_element (h->element, NULL, "fec_1");
128 
129   gst_harness_set_src_caps_str (h, "application/x-rtp");
130 
131   payload = 0x37;
132   gst_harness_push (h, make_media_sample (0, 0, &payload, 1));
133   payload = 0x28;
134   gst_harness_push (h, make_media_sample (1, 0, &payload, 1));
135   payload = 0xff;
136   gst_harness_push (h, make_media_sample (2, 0, &payload, 1));
137 
138   payload = 0x37 ^ 0x28 ^ 0xff;
139   pull_and_check (h_fec_1, 1, 0, 1, 33, 0, TRUE, 1, 3, &payload, 1);
140 
141   gst_object_unref (enc);
142   gst_harness_teardown (h);
143   gst_harness_teardown (h_fec_1);
144 }
145 
146 GST_END_TEST;
147 
GST_START_TEST(test_columns)148 GST_START_TEST (test_columns)
149 {
150   GstHarness *h, *h_fec_0;
151   guint8 payload;
152   GstElement *enc = gst_element_factory_make ("rtpst2022-1-fecenc", NULL);
153 
154   g_object_set (enc, "columns", 3, "rows", 3, "enable-row-fec", FALSE, NULL);
155   h = gst_harness_new_with_element (enc, "sink", "src");
156   h_fec_0 = gst_harness_new_with_element (h->element, NULL, "fec_0");
157 
158   gst_harness_set_src_caps_str (h, "application/x-rtp");
159 
160   payload = 0x37;
161   gst_harness_push (h, make_media_sample (0, 0, &payload, 1));
162   payload = 0x28;
163   gst_harness_push (h, make_media_sample (1, 0, &payload, 1));
164   payload = 0xff;
165   gst_harness_push (h, make_media_sample (2, 0, &payload, 1));
166   payload = 0xde;
167   gst_harness_push (h, make_media_sample (3, 0, &payload, 1));
168   payload = 0xad;
169   gst_harness_push (h, make_media_sample (4, 0, &payload, 1));
170   payload = 0xbe;
171   gst_harness_push (h, make_media_sample (5, 0, &payload, 1));
172   payload = 0xef;
173   gst_harness_push (h, make_media_sample (6, 0, &payload, 1));
174   payload = 0x58;
175   gst_harness_push (h, make_media_sample (7, 0, &payload, 1));
176   payload = 0x92;
177   gst_harness_push (h, make_media_sample (8, 0, &payload, 1));
178 
179   /* Let's check distribution of the column FEC over the repair window
180    * We should receive column FEC packets upon pushing buffers with
181    * seqnums 9, 12 and 15
182    */
183 
184   /* At this point no column FEC should have been put out */
185   fail_unless_equals_int (gst_harness_buffers_in_queue (h_fec_0), 0);
186 
187   /* Now push the first buffer in the second 3 x 3 grid, it's at
188    * this point we expect to receive our first column FEC packet
189    */
190   gst_harness_push (h, make_media_sample (9, 0, &payload, 1));
191   payload = 0x37 ^ 0xde ^ 0xef;
192   pull_and_check (h_fec_0, 1, 0, 1, 33, 0, FALSE, 3, 3, &payload, 1);
193 
194   gst_harness_push (h, make_media_sample (10, 0, &payload, 1));
195   gst_harness_push (h, make_media_sample (11, 0, &payload, 1));
196   fail_unless_equals_int (gst_harness_buffers_in_queue (h_fec_0), 0);
197   gst_harness_push (h, make_media_sample (12, 0, &payload, 1));
198   payload = 0x28 ^ 0xad ^ 0x58;
199   pull_and_check (h_fec_0, 1, 1, 1, 33, 0, FALSE, 3, 3, &payload, 1);
200 
201   gst_harness_push (h, make_media_sample (13, 0, &payload, 1));
202   gst_harness_push (h, make_media_sample (14, 0, &payload, 1));
203   fail_unless_equals_int (gst_harness_buffers_in_queue (h_fec_0), 0);
204   gst_harness_push (h, make_media_sample (15, 0, &payload, 1));
205   payload = 0xff ^ 0xbe ^ 0x92;
206   pull_and_check (h_fec_0, 1, 2, 1, 33, 0, FALSE, 3, 3, &payload, 1);
207 
208   gst_object_unref (enc);
209   gst_harness_teardown (h);
210   gst_harness_teardown (h_fec_0);
211 }
212 
213 GST_END_TEST;
214 
215 static Suite *
st2022_1_dec_suite(void)216 st2022_1_dec_suite (void)
217 {
218   Suite *s = suite_create ("rtpst2022-1-fecdec");
219   TCase *tc_chain = tcase_create ("general");
220 
221   suite_add_tcase (s, tc_chain);
222 
223   tcase_add_test (tc_chain, test_row);
224   tcase_add_test (tc_chain, test_columns);
225 
226   return s;
227 }
228 
229 GST_CHECK_MAIN (st2022_1_dec)
230