• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  *
3  * Copyright (C) 2016 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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <gst/check/check.h>
26 #include <gst/check/gstharness.h>
27 
28 #define RTP_VP9_CAPS_STR \
29   "application/x-rtp,media=video,encoding-name=VP9,clock-rate=90000,payload=96"
30 
GST_START_TEST(test_depay_flexible_mode)31 GST_START_TEST (test_depay_flexible_mode)
32 {
33   /* b-bit, e-bit, f-bit and marker bit set */
34   /* First packet of first frame, handcrafted to also set the e-bit and marker
35    * bit in addition to changing the seqnum */
36   guint8 intra[] = {
37     0x80, 0xf4, 0x00, 0x00, 0x49, 0xb5, 0xbe, 0x32, 0xb1, 0x01, 0x64, 0xd1,
38     0xbc, 0x98, 0xbf, 0x00, 0x83, 0x49, 0x83, 0x42, 0x00, 0x77, 0xf0, 0x43,
39     0x71, 0xd8, 0xe0, 0x90, 0x70, 0x66, 0x80, 0x60, 0x0e, 0xf0, 0x5f, 0xfd,
40   };
41   /* b-bit, e-bit, p-bit, f-bit and marker bit set */
42   /* First packet of second frame, handcrafted to also set the e-bit and
43    * marker bit in addition to changing the seqnum */
44   guint8 inter[] = {
45     0x80, 0xf4, 0x00, 0x01, 0x49, 0xb6, 0x02, 0xc0, 0xb1, 0x01, 0x64, 0xd1,
46     0xfc, 0x98, 0xc0, 0x00, 0x02, 0x87, 0x01, 0x00, 0x09, 0x3f, 0x1c, 0x12,
47     0x0e, 0x0c, 0xd0, 0x1b, 0xa7, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xda, 0x11,
48   };
49 
50   GstHarness *h = gst_harness_new ("rtpvp9depay");
51   gst_harness_set_src_caps_str (h, RTP_VP9_CAPS_STR);
52 
53   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
54           intra, sizeof (intra), 0, sizeof (intra), NULL, NULL));
55   fail_unless_equals_int (1, gst_harness_buffers_received (h));
56 
57   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
58           inter, sizeof (inter), 0, sizeof (inter), NULL, NULL));
59   fail_unless_equals_int (2, gst_harness_buffers_received (h));
60 
61   gst_harness_teardown (h);
62 }
63 
64 GST_END_TEST;
65 
GST_START_TEST(test_depay_non_flexible_mode)66 GST_START_TEST (test_depay_non_flexible_mode)
67 {
68   /* b-bit, e-bit and  marker bit set. f-bit NOT set */
69   /* First packet of first frame, handcrafted to also set the e-bit and marker
70    * bit in addition to changing the seqnum */
71   guint8 intra[] = {
72     0x80, 0xf4, 0x00, 0x00, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
73     0x8c, 0x98, 0xc0, 0x87, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
74     0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
75   };
76   /* b-bit, e-bit, p-bit  and marker bit set. f-bit NOT set */
77   /* First packet of second frame, handcrafted to also set the e-bit and
78    * marker bit in addition to changing the seqnum */
79   guint8 inter[] = {
80     0x80, 0xf4, 0x00, 0x01, 0x49, 0x88, 0xe5, 0x38, 0xa0, 0x6c, 0x65, 0x6c,
81     0xcc, 0x98, 0xc1, 0x87, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
82     0xd0, 0x1b, 0x97, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0x8a, 0x9f, 0x01, 0xbc
83   };
84 
85   GstHarness *h = gst_harness_new ("rtpvp9depay");
86   gst_harness_set_src_caps_str (h, RTP_VP9_CAPS_STR);
87 
88   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
89           intra, sizeof (intra), 0, sizeof (intra), NULL, NULL));
90   fail_unless_equals_int (1, gst_harness_buffers_received (h));
91 
92   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
93           inter, sizeof (inter), 0, sizeof (inter), NULL, NULL));
94   fail_unless_equals_int (2, gst_harness_buffers_received (h));
95 
96   gst_harness_teardown (h);
97 }
98 
99 GST_END_TEST;
100 
101 static guint8 intra_picid6336_seqnum0[] = {
102   0x80, 0xf4, 0x00, 0x00, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
103   0x8c, 0x98, 0xc0, 0x87, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
104   0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
105 };
106 
107 static guint8 intra_picid24_seqnum0[] = {
108   0x80, 0xf4, 0x00, 0x00, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
109   0x8c, 0x18, 0x87, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
110   0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
111 };
112 
113 static guint8 intra_nopicid_seqnum0[] = {
114   0x80, 0xf4, 0x00, 0x00, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
115   0x0c, 0x87, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
116   0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
117 };
118 
119 enum
120 {
121   BT_PLAIN_PICID_NONE,
122   BT_PLAIN_PICID_7,
123   BT_PLAIN_PICID_15,
124   /* Commented out for now, until added VP9 equvivalents.
125      BT_TS_PICID_NONE,
126      BT_TS_PICID_7,
127      BT_TS_PICID_15,
128      BT_TS_PICID_7_NO_TLOPICIDX,
129      BT_TS_PICID_7_NO_TID_Y_KEYIDX
130    */
131 };
132 
133 static GstBuffer *
create_rtp_vp9_buffer_full(guint seqnum,guint picid,guint buffer_type,GstClockTime buf_pts,gboolean B_bit_start_of_frame,gboolean marker_bit)134 create_rtp_vp9_buffer_full (guint seqnum, guint picid, guint buffer_type,
135     GstClockTime buf_pts, gboolean B_bit_start_of_frame, gboolean marker_bit)
136 {
137   static struct BufferTemplate
138   {
139     guint8 *template;
140     gsize size;
141     gint picid_bits;
142   } templates[] = {
143     {
144     intra_nopicid_seqnum0, sizeof (intra_nopicid_seqnum0), 0}
145     , {
146     intra_picid24_seqnum0, sizeof (intra_picid24_seqnum0), 7}
147     , {
148     intra_picid6336_seqnum0, sizeof (intra_picid6336_seqnum0), 15}
149     ,
150         /*
151            { intra_nopicid_seqnum0_tl1_sync_tl0picidx12,
152            sizeof (intra_nopicid_seqnum0_tl1_sync_tl0picidx12),
153            0
154            },
155            { intra_picid24_seqnum0_tl1_sync_tl0picidx12,
156            sizeof (intra_picid24_seqnum0_tl1_sync_tl0picidx12),
157            7
158            },
159            { intra_picid6336_seqnum0_tl1_sync_tl0picidx12,
160            sizeof (intra_picid6336_seqnum0_tl1_sync_tl0picidx12),
161            15
162            },
163            { intra_picid24_seqnum0_tl1_sync_no_tl0picidx,
164            sizeof (intra_picid24_seqnum0_tl1_sync_no_tl0picidx),
165            7
166            },
167            { intra_picid24_seqnum0_notyk_tl0picidx12,
168            sizeof (intra_picid24_seqnum0_notyk_tl0picidx12),
169            7
170            }
171          */
172   };
173   struct BufferTemplate *template = &templates[buffer_type];
174   guint8 *packet = g_memdup2 (template->template, template->size);
175   GstBuffer *ret;
176 
177   packet[2] = (seqnum >> 8) & 0xff;
178   packet[3] = (seqnum >> 0) & 0xff;
179 
180   /* We're forcing the E-bit (EndOfFrame) together with the RTP marker bit here, which is a bit of a hack.
181    * If we're to enable spatial scalability tests, we need to take that into account when setting the E bit.
182    */
183   if (marker_bit) {
184     packet[1] |= 0x80;
185     packet[12] |= 0x4;
186   } else {
187     packet[1] &= ~0x80;
188     packet[12] &= ~0x4;
189   }
190 
191   if (B_bit_start_of_frame)
192     packet[12] |= 0x8;
193   else
194     packet[12] &= ~0x8;
195 
196   if (template->picid_bits == 7) {
197     /* Prerequisites for this to be correct:
198        ((packet[12] & 0x80) == 0x80); I bit set
199      */
200     g_assert ((packet[12] & 0x80) == 0x80);
201     packet[13] = picid & 0x7f;
202 
203   } else if (template->picid_bits == 15) {
204     /* Prerequisites for this to be correct:
205        ((packet[12] & 0x80) == 0x80); I bit set
206      */
207     g_assert ((packet[12] & 0x80) == 0x80);
208     packet[13] = ((picid >> 8) & 0xff) | 0x80;
209     packet[14] = (picid >> 0) & 0xff;
210   }
211 
212   ret = gst_buffer_new_wrapped (packet, template->size);
213   GST_BUFFER_PTS (ret) = buf_pts;
214   return ret;
215 }
216 
217 static GstBuffer *
create_rtp_vp9_buffer(guint seqnum,guint picid,guint buffer_type,GstClockTime buf_pts)218 create_rtp_vp9_buffer (guint seqnum, guint picid, guint buffer_type,
219     GstClockTime buf_pts)
220 {
221   return create_rtp_vp9_buffer_full (seqnum, picid, buffer_type, buf_pts, TRUE,
222       TRUE);
223 }
224 
225 typedef struct _DepayGapEventTestData
226 {
227   gint seq_num;
228   gint picid;
229   guint buffer_type;
230 } DepayGapEventTestData;
231 
232 typedef struct
233 {
234   gint seq_num;
235   gint picid;
236   guint buffer_type;
237   gboolean s_bit;
238   gboolean marker_bit;
239 } DepayGapEventTestDataFull;
240 
241 static void
test_depay_gap_event_base(const DepayGapEventTestData * data,gboolean send_lost_event,gboolean expect_gap_event,int iter)242 test_depay_gap_event_base (const DepayGapEventTestData * data,
243     gboolean send_lost_event, gboolean expect_gap_event, int iter)
244 {
245   GstEvent *event;
246   GstClockTime pts = 0;
247   GstHarness *h = gst_harness_new ("rtpvp9depay");
248   if (send_lost_event == FALSE && expect_gap_event) {
249     /* Expect picture ID gaps to be concealed, so tell the element to do so. */
250     g_object_set (h->element, "hide-picture-id-gap", TRUE, NULL);
251   }
252   gst_harness_set_src_caps_str (h, RTP_VP9_CAPS_STR);
253 
254   gst_harness_push (h, create_rtp_vp9_buffer (data[0].seq_num, data[0].picid,
255           data[0].buffer_type, pts));
256   pts += 33 * GST_MSECOND;
257 
258   /* Preparation before pushing gap event. Getting rid of all events which
259    * came by this point - segment, caps, etc */
260   for (gint i = 0; i < 3; i++)
261     gst_event_unref (gst_harness_pull_event (h));
262   fail_unless_equals_int (gst_harness_events_in_queue (h), 0);
263 
264   if (send_lost_event) {
265     gst_harness_push_event (h,
266         gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
267             gst_structure_new ("GstRTPPacketLost", "timestamp", G_TYPE_UINT64,
268                 pts, "duration", G_TYPE_UINT64, 33 * GST_MSECOND,
269                 "might-have-been-fec", G_TYPE_BOOLEAN, TRUE, NULL)));
270     pts += 33 * GST_MSECOND;
271   }
272 
273   gst_harness_push (h, create_rtp_vp9_buffer (data[1].seq_num, data[1].picid,
274           data[1].buffer_type, pts));
275   fail_unless_equals_int (2, gst_harness_buffers_received (h));
276 
277   if (expect_gap_event) {
278     gboolean noloss = FALSE;
279 
280     /* Making sure the GAP event was pushed downstream */
281     event = gst_harness_pull_event (h);
282     fail_unless_equals_string ("gap",
283         gst_event_type_get_name (GST_EVENT_TYPE (event)));
284     gst_structure_get_boolean (gst_event_get_structure (event),
285         "no-packet-loss", &noloss);
286 
287     /* If we didn't send GstRTPPacketLost event, the gap
288      * event should indicate that with 'no-packet-loss' parameter */
289     fail_unless_equals_int (noloss, !send_lost_event);
290     gst_event_unref (event);
291   }
292 
293   fail_unless_equals_int (gst_harness_events_in_queue (h), 0);
294 
295   gst_harness_teardown (h);
296 }
297 
298 static const DepayGapEventTestData stop_gap_events_test_data[][2] = {
299   /* 7bit picture ids */
300   {{100, 24, BT_PLAIN_PICID_7}, {102, 25, BT_PLAIN_PICID_7}},
301 
302   /* 15bit picture ids */
303   {{100, 250, BT_PLAIN_PICID_15}, {102, 251, BT_PLAIN_PICID_15}},
304 
305   /* 7bit picture ids wrap */
306   {{100, 127, BT_PLAIN_PICID_7}, {102, 0, BT_PLAIN_PICID_7}},
307 
308   /* 15bit picture ids wrap */
309   {{100, 32767, BT_PLAIN_PICID_15}, {102, 0, BT_PLAIN_PICID_15}},
310 
311   /* 7bit to 15bit picture id */
312   {{100, 127, BT_PLAIN_PICID_7}, {102, 128, BT_PLAIN_PICID_15}},
313 };
314 
GST_START_TEST(test_depay_stop_gap_events)315 GST_START_TEST (test_depay_stop_gap_events)
316 {
317   test_depay_gap_event_base (&stop_gap_events_test_data[__i__][0], TRUE, FALSE,
318       __i__);
319 }
320 
321 GST_END_TEST;
322 
323 /* Packet loss + lost picture ids */
324 static const DepayGapEventTestData resend_gap_event_test_data[][2] = {
325   /* 7bit picture ids */
326   {{100, 24, BT_PLAIN_PICID_7}, {102, 26, BT_PLAIN_PICID_7}},
327 
328   /* 15bit picture ids */
329   {{100, 250, BT_PLAIN_PICID_15}, {102, 252, BT_PLAIN_PICID_15}},
330 
331   /* 7bit picture ids wrap */
332   {{100, 127, BT_PLAIN_PICID_7}, {102, 1, BT_PLAIN_PICID_7}},
333 
334   /* 15bit picture ids wrap */
335   {{100, 32767, BT_PLAIN_PICID_15}, {102, 1, BT_PLAIN_PICID_15}},
336 
337   /* 7bit to 15bit picture id */
338   {{100, 126, BT_PLAIN_PICID_7}, {102, 129, BT_PLAIN_PICID_15}},
339 };
340 
GST_START_TEST(test_depay_resend_gap_event)341 GST_START_TEST (test_depay_resend_gap_event)
342 {
343   test_depay_gap_event_base (&resend_gap_event_test_data[__i__][0], TRUE, TRUE,
344       __i__);
345 }
346 
347 GST_END_TEST;
348 
GST_START_TEST(test_depay_svc_merge_layers)349 GST_START_TEST (test_depay_svc_merge_layers)
350 {
351   /* This simulates a simple SVC stream, for simplicity we handcraft a couple
352    * of rtp packets. */
353 
354   /* First packet contains a complete base layer I-frame (s-bit and e-bit).
355    * Note the marker bit is not set to indicate that there will be more
356    * packets for this picture. */
357   guint8 layer0[] = {
358     0x80, 0x74, 0x00, 0x00, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
359     0xac, 0x80, 0x01, 0x00, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
360     0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
361   };
362   /* s-bit, e-bit, d-bit and sid=1 set to indicate a complete enhancement
363    * frame. marker bit set to indicate last packet of picture. */
364   guint8 layer1_with_marker[] = {
365     0x80, 0xf4, 0x00, 0x01, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
366     0xac, 0x80, 0x01, 0x03, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
367     0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
368   };
369 
370   GstBuffer *buf;
371   GstHarness *h = gst_harness_new ("rtpvp9depay");
372   gst_harness_set_src_caps_str (h, RTP_VP9_CAPS_STR);
373 
374   /* The first packet contains a complete base layer frame that. Since the
375    * marker bit is not set, it will wait for an enhancement layer before it
376    * pushes it downstream. */
377   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
378           layer0, sizeof (layer0), 0, sizeof (layer0), NULL, NULL));
379   fail_unless_equals_int (0, gst_harness_buffers_received (h));
380 
381   /* Next packet contains a complete enhancement frame. The picture is
382    * complete (marker bit set) and can be pushed */
383   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
384           layer1_with_marker, sizeof (layer1_with_marker), 0,
385           sizeof (layer1_with_marker), NULL, NULL));
386   fail_unless_equals_int (1, gst_harness_buffers_received (h));
387 
388   /* The buffer should contain both layer 0 and layer 1. */
389   buf = gst_harness_pull (h);
390   fail_unless_equals_int (19 * 2, gst_buffer_get_size (buf));
391   gst_buffer_unref (buf);
392 
393   gst_harness_teardown (h);
394 }
395 
396 GST_END_TEST;
397 
398 
GST_START_TEST(test_depay_svc_forgive_invalid_sid)399 GST_START_TEST (test_depay_svc_forgive_invalid_sid)
400 {
401   /* This simulates an invalid stream received from FF61 and Chromium 66
402    * (Electron). The RTP header signals the same spatial layer ID for all
403    * packets of a picture (SID=0), but the s-bit, e-bit and d-bit suggests
404    * there is a second layer. The conservative approach would be to drop the
405    * enhancement layers since we don't want to push a bitstream we're
406    * uncertain of to the decoder. However, this reduces the quality
407    * significantly and also sometimes results in an encoder/decoder mismatch
408    * (altough it shouldn't). */
409 
410   /* The first packet contains a complete base layer frame. Since the
411    * marker bit is not set, it will wait for an enhancement layer before it
412    * pushes it downstream. s-bit, e-bit set, no marker*/
413   guint8 layer0[] = {
414     0x80, 0x74, 0x00, 0x00, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
415     0xac, 0x80, 0x01, 0x00, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
416     0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
417   };
418 
419   /* Next packet contains a complete enhancement frame. The picture is
420    * complete (marker bit set) and picture can be pushed. However, the SID is
421    * invalid (SID=0, but should be SID=1). Let's forgive that and push the
422    * packet downstream anyway. s-bit, e-bit, d-bit and sid=0 and marker
423    * bit. */
424   guint8 layer1_with_sid0_and_marker[] = {
425     0x80, 0xf4, 0x00, 0x01, 0x49, 0x88, 0xd9, 0xf8, 0xa0, 0x6c, 0x65, 0x6c,
426     0xac, 0x80, 0x01, 0x01, 0x01, 0x02, 0x49, 0x3f, 0x1c, 0x12, 0x0e, 0x0c,
427     0xd0, 0x1b, 0xb9, 0x80, 0x80, 0xb0, 0x18, 0x0f, 0xa6, 0x4d, 0x01, 0xa5
428   };
429 
430   GstBuffer *buf;
431   GstHarness *h = gst_harness_new ("rtpvp9depay");
432   gst_harness_set_src_caps_str (h, RTP_VP9_CAPS_STR);
433 
434   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
435           layer0, sizeof (layer0), 0, sizeof (layer0), NULL, NULL));
436   fail_unless_equals_int (0, gst_harness_buffers_received (h));
437 
438   gst_harness_push (h, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
439           layer1_with_sid0_and_marker, sizeof (layer1_with_sid0_and_marker), 0,
440           sizeof (layer1_with_sid0_and_marker), NULL, NULL));
441   fail_unless_equals_int (1, gst_harness_buffers_received (h));
442 
443   /* The buffer should contain both layer 0 and layer 1. */
444   buf = gst_harness_pull (h);
445   fail_unless_equals_int (19 * 2, gst_buffer_get_size (buf));
446   gst_buffer_unref (buf);
447 
448   gst_harness_teardown (h);
449 }
450 
451 GST_END_TEST;
452 
453 static Suite *
rtpvp9_suite(void)454 rtpvp9_suite (void)
455 {
456   Suite *s = suite_create ("rtpvp9");
457   TCase *tc_chain;
458   suite_add_tcase (s, (tc_chain = tcase_create ("vp9depay")));
459   tcase_add_test (tc_chain, test_depay_flexible_mode);
460   tcase_add_test (tc_chain, test_depay_non_flexible_mode);
461   tcase_add_loop_test (tc_chain, test_depay_stop_gap_events, 0,
462       G_N_ELEMENTS (stop_gap_events_test_data));
463   tcase_add_loop_test (tc_chain, test_depay_resend_gap_event, 0,
464       G_N_ELEMENTS (resend_gap_event_test_data));
465   tcase_add_test (tc_chain, test_depay_svc_merge_layers);
466   tcase_add_test (tc_chain, test_depay_svc_forgive_invalid_sid);
467 
468   return s;
469 }
470 
471 GST_CHECK_MAIN (rtpvp9);
472