1 /* GStreamer
2  *
3  * Copyright (C) 2015 Pexip AS
4  *   @author Stian Selnes <stian@pexip.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #include <gst/check/check.h>
23 #include <gst/check/gstharness.h>
24 #include <gst/rtp/gstrtpbuffer.h>
25 
26 #define RTP_H263_CAPS_STR(p)                                            \
27   "application/x-rtp,media=video,encoding-name=H263,clock-rate=90000,"  \
28   "payload=" G_STRINGIFY(p)
29 
30 #define H263P_RTP_CAPS_STR(p)                                           \
31   "application/x-rtp,media=video,encoding-name=H263-1998,clock-rate=90000," \
32   "payload="G_STRINGIFY(p)
33 
34 static gboolean
have_element(const gchar * element_name)35 have_element (const gchar * element_name)
36 {
37   GstElement *element;
38   gboolean ret;
39 
40   element = gst_element_factory_make (element_name, NULL);
41   ret = element != NULL;
42 
43   if (element)
44     gst_object_unref (element);
45 
46   return ret;
47 }
48 
49 static GstBuffer *
create_rtp_buffer(guint8 * data,gsize size,guint ts,gint seqnum)50 create_rtp_buffer (guint8 * data, gsize size, guint ts, gint seqnum)
51 {
52   GstBuffer *buf = gst_rtp_buffer_new_copy_data (data, size);
53   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
54 
55   GST_BUFFER_PTS (buf) = (ts) * (GST_SECOND / 30);
56 
57   gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtp);
58   gst_rtp_buffer_set_seq (&rtp, seqnum);
59   gst_rtp_buffer_unmap (&rtp);
60 
61   return buf;
62 }
63 
GST_START_TEST(test_h263depay_start_packet_too_small_mode_a)64 GST_START_TEST (test_h263depay_start_packet_too_small_mode_a)
65 {
66   GstHarness *h = gst_harness_new ("rtph263depay");
67   guint8 packet[] = {
68     0x80, 0xa2, 0x17, 0x62, 0x57, 0xbb, 0x48, 0x98, 0x4a, 0x59, 0xe8, 0xdc,
69     0x00, 0x00, 0x80, 0x00
70   };
71 
72   gst_harness_set_src_caps_str (h, RTP_H263_CAPS_STR (34));
73   fail_unless_equals_int (GST_FLOW_OK,
74       gst_harness_push (h, create_rtp_buffer (packet, sizeof (packet), 0, 0)));
75 
76   /* Packet should be dropped and depayloader not crash */
77   fail_unless_equals_int (0, gst_harness_buffers_received (h));
78 
79   gst_harness_teardown (h);
80 }
81 
82 GST_END_TEST;
83 
GST_START_TEST(test_h263depay_start_packet_too_small_mode_b)84 GST_START_TEST (test_h263depay_start_packet_too_small_mode_b)
85 {
86   GstHarness *h = gst_harness_new ("rtph263depay");
87   guint8 packet[] = {
88     0x80, 0xa2, 0x17, 0x62, 0x57, 0xbb, 0x48, 0x98, 0x4a, 0x59, 0xe8, 0xdc,
89     0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00
90   };
91 
92   gst_harness_set_src_caps_str (h, RTP_H263_CAPS_STR (34));
93   fail_unless_equals_int (GST_FLOW_OK,
94       gst_harness_push (h, create_rtp_buffer (packet, sizeof (packet), 0, 0)));
95 
96   /* Packet should be dropped and depayloader not crash */
97   fail_unless_equals_int (0, gst_harness_buffers_received (h));
98 
99   gst_harness_teardown (h);
100 }
101 
102 GST_END_TEST;
103 
GST_START_TEST(test_h263depay_start_packet_too_small_mode_c)104 GST_START_TEST (test_h263depay_start_packet_too_small_mode_c)
105 {
106   GstHarness *h = gst_harness_new ("rtph263depay");
107   guint8 packet[] = {
108     0x80, 0xa2, 0x17, 0x62, 0x57, 0xbb, 0x48, 0x98, 0x4a, 0x59, 0xe8, 0xdc,
109     0xc0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
110   };
111 
112   gst_harness_set_src_caps_str (h, RTP_H263_CAPS_STR (34));
113   fail_unless_equals_int (GST_FLOW_OK,
114       gst_harness_push (h, create_rtp_buffer (packet, sizeof (packet), 0, 0)));
115 
116   /* Packet should be dropped and depayloader not crash */
117   fail_unless_equals_int (0, gst_harness_buffers_received (h));
118 
119   gst_harness_teardown (h);
120 }
121 
122 GST_END_TEST;
123 
GST_START_TEST(test_h263pay_mode_b_snow)124 GST_START_TEST (test_h263pay_mode_b_snow)
125 {
126   /* Payloading one large frame (like snow) is more likely to use mode b and
127    * trigger issues in valgrind seen previously like double free, invalid read
128    * etc. */
129   GstHarness *h;
130   guint frames = 1;
131   guint i;
132 
133   if (!have_element ("avenc_h263"))
134     return;
135 
136   h = gst_harness_new_parse
137       ("avenc_h263 rtp-payload-size=1 ! rtph263pay mtu=1350 ");
138   gst_harness_add_src_parse (h,
139       "videotestsrc pattern=snow is-live=1 ! "
140       "capsfilter caps=\"video/x-raw,format=I420,width=176,height=144\"", TRUE);
141 
142   for (i = 0; i < frames; i++)
143     gst_harness_push_from_src (h);
144   fail_unless (gst_harness_buffers_received (h) >= frames);
145 
146   gst_harness_teardown (h);
147 }
148 
149 GST_END_TEST;
150 
151 /* gst_rtp_buffer_get_payload() may return a copy of the payload. This test
152  * makes sure that the rtph263pdepay also produces the correct output in this
153  * case. */
GST_START_TEST(test_h263pdepay_fragmented_memory_non_writable_buffer)154 GST_START_TEST (test_h263pdepay_fragmented_memory_non_writable_buffer)
155 {
156   GstHarness *h;
157   GstBuffer *header_buf, *payload_buf, *buf;
158   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
159   guint8 header[] = {
160     0x04, 0x00
161   };
162   guint8 payload[] = {
163     0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
164   };
165   guint8 frame[] = {
166     0x00, 0x00, 0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
167   };
168 
169   h = gst_harness_new ("rtph263pdepay");
170   gst_harness_set_src_caps_str (h, "application/x-rtp, media=video, "
171       "clock-rate=90000, encoding-name=H263-1998");
172 
173   /* Packet with M=1, P=1 */
174   header_buf = gst_rtp_buffer_new_allocate (sizeof (header), 0, 0);
175   gst_rtp_buffer_map (header_buf, GST_MAP_WRITE, &rtp);
176   gst_rtp_buffer_set_marker (&rtp, TRUE);
177   memcpy (gst_rtp_buffer_get_payload (&rtp), header, sizeof (header));
178   gst_rtp_buffer_unmap (&rtp);
179 
180   payload_buf = gst_buffer_new_allocate (NULL, sizeof (payload), NULL);
181   gst_buffer_fill (payload_buf, 0, payload, sizeof (payload));
182   buf = gst_buffer_append (header_buf, payload_buf);
183 
184   gst_harness_push (h, gst_buffer_ref (buf));
185   gst_buffer_unref (buf);
186 
187   buf = gst_harness_pull (h);
188   fail_unless (gst_buffer_memcmp (buf, 0, frame, sizeof (frame)) == 0);
189   gst_buffer_unref (buf);
190 
191   gst_harness_teardown (h);
192 }
193 
194 GST_END_TEST;
195 
196 /* gst_rtp_buffer_get_payload() may return a copy of the payload. This test
197  * makes sure that the rtph263pdepay also produces the correct output in this
198  * case. */
GST_START_TEST(test_h263pdepay_fragmented_memory_non_writable_buffer_split_frame)199 GST_START_TEST
200     (test_h263pdepay_fragmented_memory_non_writable_buffer_split_frame) {
201   GstHarness *h;
202   GstBuffer *header_buf, *payload_buf, *buf;
203   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
204   guint8 header[] = {
205     0x04, 0x00
206   };
207   guint8 payload[] = {
208     0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
209   };
210   guint8 frame[] = {
211     0x00, 0x00, 0x80, 0x02, 0x1c, 0xb8, 0x01, 0x00, 0x11, 0xe0, 0x44, 0xc4
212   };
213 
214   h = gst_harness_new ("rtph263pdepay");
215   gst_harness_set_src_caps_str (h, "application/x-rtp, media=video, "
216       "clock-rate=90000, encoding-name=H263-1998");
217 
218   /* First packet, M=0, P=1 */
219   header_buf = gst_rtp_buffer_new_allocate (sizeof (header), 0, 0);
220   gst_rtp_buffer_map (header_buf, GST_MAP_WRITE, &rtp);
221   gst_rtp_buffer_set_marker (&rtp, FALSE);
222   gst_rtp_buffer_set_seq (&rtp, 0);
223   memcpy (gst_rtp_buffer_get_payload (&rtp), header, sizeof (header));
224   gst_rtp_buffer_unmap (&rtp);
225 
226   payload_buf = gst_buffer_new_allocate (NULL, sizeof (payload), NULL);
227   gst_buffer_fill (payload_buf, 0, payload, sizeof (payload));
228   buf = gst_buffer_append (header_buf, payload_buf);
229 
230   gst_harness_push (h, gst_buffer_ref (buf));
231   gst_buffer_unref (buf);
232   fail_unless_equals_int (gst_harness_buffers_received (h), 0);
233 
234   /* Second packet, M=1, P=1 */
235   header_buf = gst_rtp_buffer_new_allocate (sizeof (header), 0, 0);
236   gst_rtp_buffer_map (header_buf, GST_MAP_WRITE, &rtp);
237   gst_rtp_buffer_set_marker (&rtp, TRUE);
238   gst_rtp_buffer_set_seq (&rtp, 1);
239   memcpy (gst_rtp_buffer_get_payload (&rtp), header, sizeof (header));
240   gst_rtp_buffer_unmap (&rtp);
241 
242   payload_buf = gst_buffer_new_allocate (NULL, sizeof (payload), NULL);
243   gst_buffer_memset (payload_buf, 0, 0, 10);
244   buf = gst_buffer_append (header_buf, payload_buf);
245 
246   gst_harness_push (h, gst_buffer_ref (buf));
247   gst_buffer_unref (buf);
248   fail_unless_equals_int (gst_harness_buffers_received (h), 1);
249 
250   buf = gst_harness_pull (h);
251   fail_unless (gst_buffer_memcmp (buf, 0, frame, sizeof (frame)) == 0);
252   gst_buffer_unref (buf);
253 
254   gst_harness_teardown (h);
255 }
256 
257 GST_END_TEST;
258 
GST_START_TEST(test_h263pdepay_dont_push_empty_frame)259 GST_START_TEST (test_h263pdepay_dont_push_empty_frame)
260 {
261   GstHarness *h = gst_harness_new ("rtph263pdepay");
262 
263   /* Packet that only contains header information and an extra picture header
264    * (PLEN > 0). Partly handcrafted packet. Originally this packet did not
265    * have P=1 (hence it was not start of a picture). With both P=1 and M=1 we
266    * only need one packet to reproduce the issue where trying to push an empty
267    * frame when PLEN is set */
268   guint8 packet[] = {
269     0x80, 0xe8, 0xbc, 0xaa, 0x14, 0x12, 0x16, 0x5c, 0xb8, 0x4e, 0x39, 0x04,
270     0x25, 0x00, 0x54, 0x39, 0xd0, 0x12, 0x06, 0x9e, 0xb5, 0x0a, 0xf5, 0xe8,
271     0x32, 0xeb, 0xd0, 0x6b, 0xd6, 0xa2, 0xfa, 0xd4, 0x3d, 0xd7, 0xa0, 0x2b,
272     0x24, 0x97, 0xc3, 0xbf, 0xc0, 0xbb, 0xd7, 0xa0,
273   };
274 
275   gst_harness_set_src_caps_str (h, H263P_RTP_CAPS_STR (100));
276 
277   fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h,
278           create_rtp_buffer (packet, sizeof (packet), 0, 0)));
279 
280   fail_unless_equals_int (gst_harness_buffers_received (h), 0);
281 
282   gst_harness_teardown (h);
283 }
284 
285 GST_END_TEST;
286 
GST_START_TEST(test_h263ppay_non_fixed_caps)287 GST_START_TEST (test_h263ppay_non_fixed_caps)
288 {
289   GstHarness *h;
290   guint8 frame[] = {
291     0x00, 0x00, 0x80, 0x06, 0x1c, 0xa8, 0x01, 0x04, 0x91, 0xe0, 0x37, 0xff,
292     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
293   };
294 
295   h = gst_harness_new_parse ("rtph263ppay");
296 
297   /* Set non-fixed caps after payloader */
298   gst_harness_set_caps_str (h, "video/x-h263, variant=(string)itu",
299       "application/x-rtp, clock-rate=[1, MAX]");
300 
301   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
302           frame, sizeof (frame), 0, sizeof (frame), NULL, NULL));
303 
304   fail_unless_equals_int (1, gst_harness_buffers_received (h));
305 
306   gst_harness_teardown (h);
307 }
308 
309 GST_END_TEST;
310 
311 static Suite *
rtph263_suite(void)312 rtph263_suite (void)
313 {
314   Suite *s = suite_create ("rtph263");
315   TCase *tc_chain;
316 
317   suite_add_tcase (s, (tc_chain = tcase_create ("h263depay")));
318   tcase_add_test (tc_chain, test_h263depay_start_packet_too_small_mode_a);
319   tcase_add_test (tc_chain, test_h263depay_start_packet_too_small_mode_b);
320   tcase_add_test (tc_chain, test_h263depay_start_packet_too_small_mode_c);
321 
322   suite_add_tcase (s, (tc_chain = tcase_create ("h263pay")));
323   tcase_add_test (tc_chain, test_h263pay_mode_b_snow);
324 
325   suite_add_tcase (s, (tc_chain = tcase_create ("h263pdepay")));
326   tcase_add_test (tc_chain,
327       test_h263pdepay_fragmented_memory_non_writable_buffer);
328   tcase_add_test (tc_chain,
329       test_h263pdepay_fragmented_memory_non_writable_buffer_split_frame);
330   tcase_add_test (tc_chain, test_h263pdepay_dont_push_empty_frame);
331 
332   suite_add_tcase (s, (tc_chain = tcase_create ("h263ppay")));
333   tcase_add_test (tc_chain, test_h263ppay_non_fixed_caps);
334 
335   return s;
336 }
337 
338 GST_CHECK_MAIN (rtph263);
339