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