1 /* GStreamer RTP H.265 unit test
2 *
3 * Copyright (C) 2017 Centricular Ltd
4 * @author: Tim-Philipp Müller <tim@centricular.com>
5 * Copyright (C) 2018 Collabora Ltd
6 * @author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gst/check/check.h>
28 #include <gst/app/app.h>
29 #include <gst/rtp/gstrtpbuffer.h>
30 #include <gst/rtp/gstrtph265types.h>
31
32 #define ALLOCATOR_CUSTOM_SYSMEM "CustomSysMem"
33
34 static GstAllocator *custom_sysmem_allocator; /* NULL */
35
36 /* Custom memory */
37
38 typedef struct
39 {
40 GstMemory mem;
41 guint8 *data;
42 guint8 *allocdata;
43 } CustomSysmem;
44
45 static CustomSysmem *
custom_sysmem_new(GstMemoryFlags flags,gsize maxsize,gsize align,gsize offset,gsize size)46 custom_sysmem_new (GstMemoryFlags flags, gsize maxsize, gsize align,
47 gsize offset, gsize size)
48 {
49 gsize aoffset, padding;
50 CustomSysmem *mem;
51
52 /* ensure configured alignment */
53 align |= gst_memory_alignment;
54 /* allocate more to compensate for alignment */
55 maxsize += align;
56
57 mem = g_new0 (CustomSysmem, 1);
58
59 mem->allocdata = g_malloc (maxsize);
60
61 mem->data = mem->allocdata;
62
63 /* do alignment */
64 if ((aoffset = ((guintptr) mem->data & align))) {
65 aoffset = (align + 1) - aoffset;
66 mem->data += aoffset;
67 maxsize -= aoffset;
68 }
69
70 if (offset && (flags & GST_MEMORY_FLAG_ZERO_PREFIXED))
71 memset (mem->data, 0, offset);
72
73 padding = maxsize - (offset + size);
74 if (padding && (flags & GST_MEMORY_FLAG_ZERO_PADDED))
75 memset (mem->data + offset + size, 0, padding);
76
77 gst_memory_init (GST_MEMORY_CAST (mem), flags, custom_sysmem_allocator,
78 NULL, maxsize, align, offset, size);
79
80 return mem;
81 }
82
83 static gpointer
custom_sysmem_map(CustomSysmem * mem,gsize maxsize,GstMapFlags flags)84 custom_sysmem_map (CustomSysmem * mem, gsize maxsize, GstMapFlags flags)
85 {
86 return mem->data;
87 }
88
89 static gboolean
custom_sysmem_unmap(CustomSysmem * mem)90 custom_sysmem_unmap (CustomSysmem * mem)
91 {
92 return TRUE;
93 }
94
95 static CustomSysmem *
custom_sysmem_copy(CustomSysmem * mem,gssize offset,gsize size)96 custom_sysmem_copy (CustomSysmem * mem, gssize offset, gsize size)
97 {
98 g_return_val_if_reached (NULL);
99 }
100
101 static CustomSysmem *
custom_sysmem_share(CustomSysmem * mem,gssize offset,gsize size)102 custom_sysmem_share (CustomSysmem * mem, gssize offset, gsize size)
103 {
104 g_return_val_if_reached (NULL);
105 }
106
107 static gboolean
custom_sysmem_is_span(CustomSysmem * mem1,CustomSysmem * mem2,gsize * offset)108 custom_sysmem_is_span (CustomSysmem * mem1, CustomSysmem * mem2, gsize * offset)
109 {
110 g_return_val_if_reached (FALSE);
111 }
112
113 /* Custom allocator */
114
115 typedef struct
116 {
117 GstAllocator allocator;
118 } CustomSysmemAllocator;
119
120 typedef struct
121 {
122 GstAllocatorClass allocator_class;
123 } CustomSysmemAllocatorClass;
124
125 GType custom_sysmem_allocator_get_type (void);
126 G_DEFINE_TYPE (CustomSysmemAllocator, custom_sysmem_allocator,
127 GST_TYPE_ALLOCATOR);
128
129 static GstMemory *
custom_sysmem_allocator_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params)130 custom_sysmem_allocator_alloc (GstAllocator * allocator, gsize size,
131 GstAllocationParams * params)
132 {
133 gsize maxsize = size + params->prefix + params->padding;
134
135 return (GstMemory *) custom_sysmem_new (params->flags,
136 maxsize, params->align, params->prefix, size);
137 }
138
139 static void
custom_sysmem_allocator_free(GstAllocator * allocator,GstMemory * mem)140 custom_sysmem_allocator_free (GstAllocator * allocator, GstMemory * mem)
141 {
142 CustomSysmem *csmem = (CustomSysmem *) mem;
143
144 g_free (csmem->allocdata);
145 g_free (csmem);
146 }
147
148 static void
custom_sysmem_allocator_class_init(CustomSysmemAllocatorClass * klass)149 custom_sysmem_allocator_class_init (CustomSysmemAllocatorClass * klass)
150 {
151 GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
152
153 allocator_class->alloc = custom_sysmem_allocator_alloc;
154 allocator_class->free = custom_sysmem_allocator_free;
155 }
156
157 static void
custom_sysmem_allocator_init(CustomSysmemAllocator * allocator)158 custom_sysmem_allocator_init (CustomSysmemAllocator * allocator)
159 {
160 GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
161
162 alloc->mem_type = ALLOCATOR_CUSTOM_SYSMEM;
163 alloc->mem_map = (GstMemoryMapFunction) custom_sysmem_map;
164 alloc->mem_unmap = (GstMemoryUnmapFunction) custom_sysmem_unmap;
165 alloc->mem_copy = (GstMemoryCopyFunction) custom_sysmem_copy;
166 alloc->mem_share = (GstMemoryShareFunction) custom_sysmem_share;
167 alloc->mem_is_span = (GstMemoryIsSpanFunction) custom_sysmem_is_span;
168 }
169
170 /* AppSink subclass proposing our custom allocator to upstream */
171
172 typedef struct
173 {
174 GstAppSink appsink;
175 } CMemAppSink;
176
177 typedef struct
178 {
179 GstAppSinkClass appsink;
180 } CMemAppSinkClass;
181
182 GType c_mem_app_sink_get_type (void);
183
184 G_DEFINE_TYPE (CMemAppSink, c_mem_app_sink, GST_TYPE_APP_SINK);
185
186 static void
c_mem_app_sink_init(CMemAppSink * cmemsink)187 c_mem_app_sink_init (CMemAppSink * cmemsink)
188 {
189 }
190
191 static gboolean
c_mem_app_sink_propose_allocation(GstBaseSink * sink,GstQuery * query)192 c_mem_app_sink_propose_allocation (GstBaseSink * sink, GstQuery * query)
193 {
194 gst_query_add_allocation_param (query, custom_sysmem_allocator, NULL);
195 return TRUE;
196 }
197
198 static void
c_mem_app_sink_class_init(CMemAppSinkClass * klass)199 c_mem_app_sink_class_init (CMemAppSinkClass * klass)
200 {
201 GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
202
203 basesink_class->propose_allocation = c_mem_app_sink_propose_allocation;
204 }
205
206 #define RTP_H265_FILE GST_TEST_FILES_PATH G_DIR_SEPARATOR_S "h265.rtp"
207
GST_START_TEST(test_rtph265depay_with_downstream_allocator)208 GST_START_TEST (test_rtph265depay_with_downstream_allocator)
209 {
210 GstElement *pipeline, *src, *depay, *sink;
211 GstMemory *mem;
212 GstSample *sample;
213 GstBuffer *buf;
214 GstCaps *caps;
215
216 custom_sysmem_allocator =
217 g_object_new (custom_sysmem_allocator_get_type (), NULL);
218
219 pipeline = gst_pipeline_new ("pipeline");
220
221 src = gst_element_factory_make ("appsrc", NULL);
222
223 caps = gst_caps_new_simple ("application/x-rtp",
224 "media", G_TYPE_STRING, "video",
225 "payload", G_TYPE_INT, 96,
226 "clock-rate", G_TYPE_INT, 90000,
227 "encoding-name", G_TYPE_STRING, "H265",
228 "ssrc", G_TYPE_UINT, 1990683810,
229 "timestamp-offset", G_TYPE_UINT, 3697583446UL,
230 "seqnum-offset", G_TYPE_UINT, 15568,
231 "a-framerate", G_TYPE_STRING, "30", NULL);
232 g_object_set (src, "format", GST_FORMAT_TIME, "caps", caps, NULL);
233 gst_bin_add (GST_BIN (pipeline), src);
234 gst_caps_unref (caps);
235
236 depay = gst_element_factory_make ("rtph265depay", NULL);
237 gst_bin_add (GST_BIN (pipeline), depay);
238
239 sink = g_object_new (c_mem_app_sink_get_type (), NULL);
240 gst_bin_add (GST_BIN (pipeline), sink);
241
242 gst_element_link_many (src, depay, sink, NULL);
243
244 gst_element_set_state (pipeline, GST_STATE_PAUSED);
245
246 {
247 gchar *data, *pdata;
248 gsize len;
249
250 fail_unless (g_file_get_contents (RTP_H265_FILE, &data, &len, NULL));
251 fail_unless (len > 2);
252
253 pdata = data;
254 while (len > 2) {
255 GstFlowReturn flow;
256 guint16 packet_len;
257
258 packet_len = GST_READ_UINT16_BE (pdata);
259 GST_INFO ("rtp packet length: %u (bytes left: %u)", packet_len,
260 (guint) len);
261 fail_unless (len >= 2 + packet_len);
262
263 flow = gst_app_src_push_buffer (GST_APP_SRC (src),
264 gst_buffer_new_memdup (pdata + 2, packet_len));
265
266 fail_unless_equals_int (flow, GST_FLOW_OK);
267
268 pdata += 2 + packet_len;
269 len -= 2 + packet_len;
270 }
271
272 g_free (data);
273 }
274
275 gst_app_src_end_of_stream (GST_APP_SRC (src));
276
277 sample = gst_app_sink_pull_preroll (GST_APP_SINK (sink));
278 fail_unless (sample != NULL);
279
280 buf = gst_sample_get_buffer (sample);
281
282 GST_LOG ("buffer has %u memories", gst_buffer_n_memory (buf));
283 GST_LOG ("buffer size: %u", (guint) gst_buffer_get_size (buf));
284
285 fail_unless (gst_buffer_n_memory (buf) > 0);
286 mem = gst_buffer_peek_memory (buf, 0);
287 fail_unless (mem != NULL);
288
289 GST_LOG ("buffer memory type: %s", mem->allocator->mem_type);
290 fail_unless (gst_memory_is_type (mem, ALLOCATOR_CUSTOM_SYSMEM));
291
292 gst_sample_unref (sample);
293
294 gst_element_set_state (pipeline, GST_STATE_NULL);
295
296 gst_object_unref (pipeline);
297
298 g_object_unref (custom_sysmem_allocator);
299 custom_sysmem_allocator = NULL;
300 }
301
302 GST_END_TEST;
303
304
305 static GstBuffer *
wrap_static_buffer_with_pts(guint8 * buf,gsize size,GstClockTime pts)306 wrap_static_buffer_with_pts (guint8 * buf, gsize size, GstClockTime pts)
307 {
308 GstBuffer *buffer;
309
310 buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
311 buf, size, 0, size, NULL, NULL);
312 GST_BUFFER_PTS (buffer) = pts;
313
314 return buffer;
315 }
316
317 static GstBuffer *
wrap_static_buffer(guint8 * buf,gsize size)318 wrap_static_buffer (guint8 * buf, gsize size)
319 {
320 return wrap_static_buffer_with_pts (buf, size, GST_CLOCK_TIME_NONE);
321 }
322
323 /* This was generated using pipeline:
324 * gst-launch-1.0 videotestsrc num-buffers=1 pattern=green \
325 * ! video/x-raw,width=64,height=64 ! x265enc ! h265parse \
326 * ! rtph265pay ! fakesink dump=1
327 */
328 /* RTP h265_idr + marker */
329 static guint8 rtp_h265_idr[] = {
330 0x80, 0xe0, 0x2c, 0x6a, 0xab, 0x7f, 0x71, 0xc0,
331 0x8d, 0x11, 0x33, 0x07, 0x28, 0x01, 0xaf, 0x05,
332 0x38, 0x4a, 0x03, 0x06, 0x7c, 0x7a, 0xb1, 0x8b,
333 0xff, 0xfe, 0xfd, 0xb7, 0xff, 0xff, 0xd1, 0xff,
334 0x40, 0x06, 0xd8, 0xd3, 0xb2, 0xf8
335 };
336
GST_START_TEST(test_rtph265depay_eos)337 GST_START_TEST (test_rtph265depay_eos)
338 {
339 GstHarness *h = gst_harness_new ("rtph265depay");
340 GstBuffer *buffer;
341 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
342 GstFlowReturn ret;
343
344 gst_harness_set_caps_str (h,
345 "application/x-rtp,media=video,clock-rate=90000,encoding-name=H265",
346 "video/x-h265,alignment=au,stream-format=byte-stream");
347
348 buffer = wrap_static_buffer (rtp_h265_idr, sizeof (rtp_h265_idr));
349 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_WRITE, &rtp));
350 gst_rtp_buffer_set_marker (&rtp, FALSE);
351 gst_rtp_buffer_unmap (&rtp);
352
353 ret = gst_harness_push (h, buffer);
354 fail_unless_equals_int (ret, GST_FLOW_OK);
355 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
356
357 fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
358 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
359
360 gst_harness_teardown (h);
361 }
362
363 GST_END_TEST;
364
365
GST_START_TEST(test_rtph265depay_marker_to_flag)366 GST_START_TEST (test_rtph265depay_marker_to_flag)
367 {
368 GstHarness *h = gst_harness_new ("rtph265depay");
369 GstBuffer *buffer;
370 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
371 GstFlowReturn ret;
372 guint16 seq;
373
374 gst_harness_set_caps_str (h,
375 "application/x-rtp,media=video,clock-rate=90000,encoding-name=H265",
376 "video/x-h265,alignment=au,stream-format=byte-stream");
377
378 buffer = wrap_static_buffer (rtp_h265_idr, sizeof (rtp_h265_idr));
379 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
380 fail_unless (gst_rtp_buffer_get_marker (&rtp));
381 seq = gst_rtp_buffer_get_seq (&rtp);
382 gst_rtp_buffer_unmap (&rtp);
383
384 ret = gst_harness_push (h, buffer);
385 fail_unless_equals_int (ret, GST_FLOW_OK);
386 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
387
388 buffer = wrap_static_buffer (rtp_h265_idr, sizeof (rtp_h265_idr));
389 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_WRITE, &rtp));
390 gst_rtp_buffer_set_marker (&rtp, FALSE);
391 gst_rtp_buffer_set_seq (&rtp, ++seq);
392 gst_rtp_buffer_unmap (&rtp);
393
394 ret = gst_harness_push (h, buffer);
395 fail_unless_equals_int (ret, GST_FLOW_OK);
396
397 /* the second NAL is blocked as there is no marker to let the payloader
398 * know it's a complete AU, we'll use an EOS to unblock it */
399 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
400 fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
401 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2);
402
403 buffer = gst_harness_pull (h);
404 fail_unless (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER));
405 gst_buffer_unref (buffer);
406
407 buffer = gst_harness_pull (h);
408 fail_if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER));
409 gst_buffer_unref (buffer);
410
411 gst_harness_teardown (h);
412 }
413
414 GST_END_TEST;
415
416 /* These were generated using pipeline:
417 * gst-launch-1.0 videotestsrc num-buffers=1 pattern=green \
418 * ! video/x-raw,width=256,height=256 \
419 * ! x265enc option-string="slices=2" \
420 * ! fakesink dump=1
421 */
422
423 static guint8 h265_vps[] = {
424 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01,
425 0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
426 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
427 0x3f, 0x95, 0x98, 0x09
428 };
429
430 static guint8 h265_sps[] = {
431 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x01,
432 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00,
433 0x03, 0x00, 0x00, 0x03, 0x00, 0x3f, 0xa0, 0x08,
434 0x08, 0x04, 0x05, 0x96, 0x56, 0x69, 0x24, 0xca,
435 0xff, 0xf0, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,
436 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x01,
437 0xe0, 0x80
438 };
439
440 static guint8 h265_pps[] = {
441 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0xc1, 0x72,
442 0xb4, 0x42, 0x40
443 };
444
445 /* IDR Slice 1 */
446 static guint8 h265_idr_slice_1[] = {
447 0x00, 0x00, 0x00, 0x01, 0x28, 0x01, 0xaf, 0x08,
448 0xa2, 0xe6, 0xa3, 0xc6, 0x53, 0x90, 0xea, 0xc8,
449 0x3f, 0xfe, 0xfa, 0xf9, 0x3f, 0xf2, 0x61, 0x98,
450 0xef, 0xf4, 0xe9, 0x97, 0xe7, 0xc2, 0x74, 0x78,
451 0x98, 0x10, 0x01, 0x21, 0xa4, 0x3c, 0x4c, 0x08,
452 0x00, 0x3e, 0x40, 0x92, 0x0c, 0x78
453 };
454
455 /* IDR Slice 2 */
456 static guint8 h265_idr_slice_2[] = {
457 0x00, 0x00, 0x01, 0x28, 0x01, 0x30, 0xf0, 0x8a,
458 0x2e, 0x60, 0xa3, 0xc6, 0x53, 0x90, 0xea, 0xc8,
459 0x3f, 0xfe, 0xfa, 0xf9, 0x3f, 0xf2, 0x61, 0x98,
460 0xef, 0xf4, 0xe9, 0x97, 0xe7, 0xc2, 0x74, 0x78,
461 0x98, 0x10, 0x01, 0x21, 0xa4, 0x3c, 0x4c, 0x08,
462 0x00, 0x3e, 0x40, 0x92, 0x0c, 0x78
463 };
464
465
GST_START_TEST(test_rtph265pay_two_slices_timestamp)466 GST_START_TEST (test_rtph265pay_two_slices_timestamp)
467 {
468 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
469 " aggregate-mode=zero-latency");
470 GstFlowReturn ret;
471 GstBuffer *buffer;
472 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
473
474 gst_harness_set_src_caps_str (h,
475 "video/x-h265,alignment=nal,stream-format=byte-stream");
476
477 ret = gst_harness_push (h, wrap_static_buffer_with_pts (h265_idr_slice_1,
478 sizeof (h265_idr_slice_1), 0));
479 fail_unless_equals_int (ret, GST_FLOW_OK);
480
481 ret = gst_harness_push (h, wrap_static_buffer_with_pts (h265_idr_slice_2,
482 sizeof (h265_idr_slice_2), 0));
483 fail_unless_equals_int (ret, GST_FLOW_OK);
484
485 ret = gst_harness_push (h, wrap_static_buffer_with_pts (h265_idr_slice_1,
486 sizeof (h265_idr_slice_1), GST_SECOND));
487 fail_unless_equals_int (ret, GST_FLOW_OK);
488
489 ret = gst_harness_push (h, wrap_static_buffer_with_pts (h265_idr_slice_2,
490 sizeof (h265_idr_slice_2), GST_SECOND));
491 fail_unless_equals_int (ret, GST_FLOW_OK);
492
493 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 4);
494
495 buffer = gst_harness_pull (h);
496 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
497 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
498 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
499 gst_rtp_buffer_unmap (&rtp);
500 gst_buffer_unref (buffer);
501
502 buffer = gst_harness_pull (h);
503 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
504 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
505 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
506 gst_rtp_buffer_unmap (&rtp);
507 gst_buffer_unref (buffer);
508
509 buffer = gst_harness_pull (h);
510 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
511 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), GST_SECOND);
512 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123 + 90000);
513 gst_rtp_buffer_unmap (&rtp);
514 gst_buffer_unref (buffer);
515
516 buffer = gst_harness_pull (h);
517 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
518 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), GST_SECOND);
519 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123 + 90000);
520 gst_rtp_buffer_unmap (&rtp);
521 gst_buffer_unref (buffer);
522
523 gst_harness_teardown (h);
524 }
525
526 GST_END_TEST;
527
GST_START_TEST(test_rtph265pay_marker_for_flag)528 GST_START_TEST (test_rtph265pay_marker_for_flag)
529 {
530 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
531 " aggregate-mode=zero-latency");
532 GstFlowReturn ret;
533 GstBuffer *buffer;
534 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
535
536 gst_harness_set_src_caps_str (h,
537 "video/x-h265,alignment=nal,stream-format=byte-stream");
538
539 ret = gst_harness_push (h, wrap_static_buffer (h265_idr_slice_1,
540 sizeof (h265_idr_slice_1)));
541 fail_unless_equals_int (ret, GST_FLOW_OK);
542
543 buffer = wrap_static_buffer (h265_idr_slice_2, sizeof (h265_idr_slice_2));
544 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_MARKER);
545 ret = gst_harness_push (h, buffer);
546 fail_unless_equals_int (ret, GST_FLOW_OK);
547
548 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2);
549
550 buffer = gst_harness_pull (h);
551 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
552 fail_if (gst_rtp_buffer_get_marker (&rtp));
553 gst_rtp_buffer_unmap (&rtp);
554 gst_buffer_unref (buffer);
555
556 buffer = gst_harness_pull (h);
557 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
558 fail_unless (gst_rtp_buffer_get_marker (&rtp));
559 gst_rtp_buffer_unmap (&rtp);
560 gst_buffer_unref (buffer);
561
562 gst_harness_teardown (h);
563 }
564
565 GST_END_TEST;
566
567
GST_START_TEST(test_rtph265pay_marker_for_au)568 GST_START_TEST (test_rtph265pay_marker_for_au)
569 {
570 GstHarness *h = gst_harness_new_parse
571 ("rtph265pay timestamp-offset=123 aggregate-mode=none");
572 GstFlowReturn ret;
573 GstBuffer *slice1, *slice2, *buffer;
574 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
575
576 gst_harness_set_src_caps_str (h,
577 "video/x-h265,alignment=au,stream-format=byte-stream");
578
579 slice1 = wrap_static_buffer (h265_idr_slice_1, sizeof (h265_idr_slice_1));
580 slice2 = wrap_static_buffer (h265_idr_slice_2, sizeof (h265_idr_slice_2));
581 buffer = gst_buffer_append (slice1, slice2);
582
583 ret = gst_harness_push (h, buffer);
584 fail_unless_equals_int (ret, GST_FLOW_OK);
585
586 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2);
587
588 buffer = gst_harness_pull (h);
589 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
590 fail_if (gst_rtp_buffer_get_marker (&rtp));
591 gst_rtp_buffer_unmap (&rtp);
592 gst_buffer_unref (buffer);
593
594 buffer = gst_harness_pull (h);
595 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
596 fail_unless (gst_rtp_buffer_get_marker (&rtp));
597 gst_rtp_buffer_unmap (&rtp);
598 gst_buffer_unref (buffer);
599
600 gst_harness_teardown (h);
601 }
602
603 GST_END_TEST;
604
605
GST_START_TEST(test_rtph265pay_marker_for_fragmented_au)606 GST_START_TEST (test_rtph265pay_marker_for_fragmented_au)
607 {
608 GstHarness *h =
609 gst_harness_new_parse ("rtph265pay timestamp-offset=123 mtu=40"
610 " aggregate-mode=zero-latency");
611 GstFlowReturn ret;
612 GstBuffer *slice1, *slice2, *buffer;
613 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
614 gint i;
615
616 gst_harness_set_src_caps_str (h,
617 "video/x-h265,alignment=au,stream-format=byte-stream");
618
619 slice1 = wrap_static_buffer (h265_idr_slice_1, sizeof (h265_idr_slice_1));
620 slice2 = wrap_static_buffer (h265_idr_slice_2, sizeof (h265_idr_slice_2));
621 buffer = gst_buffer_append (slice1, slice2);
622
623 ret = gst_harness_push (h, buffer);
624 fail_unless_equals_int (ret, GST_FLOW_OK);
625
626 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 4);
627
628 for (i = 0; i < 3; i++) {
629 buffer = gst_harness_pull (h);
630 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
631 fail_if (gst_rtp_buffer_get_marker (&rtp));
632 gst_rtp_buffer_unmap (&rtp);
633 gst_buffer_unref (buffer);
634 }
635
636 buffer = gst_harness_pull (h);
637 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
638 fail_unless (gst_rtp_buffer_get_marker (&rtp));
639 gst_rtp_buffer_unmap (&rtp);
640 gst_buffer_unref (buffer);
641
642 gst_harness_teardown (h);
643 }
644
645 GST_END_TEST;
646
GST_START_TEST(test_rtph265pay_aggregate_two_slices_per_buffer)647 GST_START_TEST (test_rtph265pay_aggregate_two_slices_per_buffer)
648 {
649 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
650 " name=p");
651 GstFlowReturn ret;
652 GstBuffer *buffer;
653 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
654 GstElement *e = gst_bin_get_by_name (GST_BIN (h->element), "p");
655 gint i;
656
657 gst_harness_set_src_caps_str (h,
658 "video/x-h265,alignment=nal,stream-format=byte-stream");
659
660 /* No aggregation latency mode */
661
662 g_object_set (e, "aggregate-mode", 0, NULL);
663
664 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
665 sizeof (h265_idr_slice_1), 0);
666 buffer = gst_buffer_append (buffer,
667 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
668 0));
669 ret = gst_harness_push (h, buffer);
670 fail_unless_equals_int (ret, GST_FLOW_OK);
671
672 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
673 sizeof (h265_idr_slice_1), 0);
674 buffer = gst_buffer_append (buffer,
675 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
676 0));
677 ret = gst_harness_push (h, buffer);
678 fail_unless_equals_int (ret, GST_FLOW_OK);
679
680 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 4);
681
682 for (i = 0; i < 4; i++) {
683 buffer = gst_harness_pull (h);
684 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
685 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
686 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
687 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 +
688 ((i % 2) ? (sizeof (h265_idr_slice_2) - 3) :
689 (sizeof (h265_idr_slice_1)) - 4));
690 gst_rtp_buffer_unmap (&rtp);
691 gst_buffer_unref (buffer);
692 }
693
694 /* Zero latency mode */
695 g_object_set (e, "aggregate-mode", 1, NULL);
696
697 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
698 sizeof (h265_idr_slice_1), 0);
699 buffer = gst_buffer_append (buffer,
700 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
701 0));
702 ret = gst_harness_push (h, buffer);
703 fail_unless_equals_int (ret, GST_FLOW_OK);
704
705 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
706 sizeof (h265_idr_slice_1), 0);
707 buffer = gst_buffer_append (buffer,
708 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
709 0));
710 ret = gst_harness_push (h, buffer);
711 fail_unless_equals_int (ret, GST_FLOW_OK);
712
713 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2);
714
715 for (i = 0; i < 2; i++) {
716 buffer = gst_harness_pull (h);
717 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
718 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
719 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
720 /* RTP header = 12, AP header = 2, 2 bytes length per NAL */
721 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
722 (2 + sizeof (h265_idr_slice_2) - 3) +
723 (2 + sizeof (h265_idr_slice_1) - 4));
724 gst_rtp_buffer_unmap (&rtp);
725 gst_buffer_unref (buffer);
726 }
727
728 /* Max aggregation */
729 g_object_set (e, "aggregate-mode", 2, NULL);
730
731 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
732 sizeof (h265_idr_slice_1), 0);
733 buffer = gst_buffer_append (buffer,
734 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
735 0));
736 ret = gst_harness_push (h, buffer);
737 fail_unless_equals_int (ret, GST_FLOW_OK);
738
739 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
740 sizeof (h265_idr_slice_1), 0);
741 buffer = gst_buffer_append (buffer,
742 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
743 0));
744 ret = gst_harness_push (h, buffer);
745 fail_unless_equals_int (ret, GST_FLOW_OK);
746
747 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0);
748
749 /* Push EOS to send it out */
750 gst_harness_push_event (h, gst_event_new_eos ());
751
752 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
753
754 buffer = gst_harness_pull (h);
755 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
756 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
757 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
758 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
759 2 * ((2 + sizeof (h265_idr_slice_2) - 3) +
760 (2 + sizeof (h265_idr_slice_1) - 4)));
761 gst_rtp_buffer_unmap (&rtp);
762 gst_buffer_unref (buffer);
763
764
765 g_object_unref (e);
766 gst_harness_teardown (h);
767 }
768
769 GST_END_TEST;
770
771 /* AUD */
772 static guint8 h265_aud[] = {
773 0x00, 0x00, 0x00, 0x01, (35 << 1), 0x00, 0x80
774 };
775
GST_START_TEST(test_rtph265pay_aggregate_with_aud)776 GST_START_TEST (test_rtph265pay_aggregate_with_aud)
777 {
778 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
779 " aggregate-mode=zero-latency");
780 GstFlowReturn ret;
781 GstBuffer *buffer;
782 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
783
784 gst_harness_set_src_caps_str (h,
785 "video/x-h265,alignment=nal,stream-format=byte-stream");
786
787 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
788 sizeof (h265_idr_slice_1), 0);
789 buffer = gst_buffer_append (buffer,
790 wrap_static_buffer_with_pts (h265_aud, sizeof (h265_aud), 0));
791 buffer = gst_buffer_append (buffer,
792 wrap_static_buffer_with_pts (h265_idr_slice_1, sizeof (h265_idr_slice_1),
793 0));
794
795 ret = gst_harness_push (h, buffer);
796 fail_unless_equals_int (ret, GST_FLOW_OK);
797
798 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2);
799
800 buffer = gst_harness_pull (h);
801 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
802 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
803 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
804 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 +
805 (sizeof (h265_idr_slice_1) - 4));
806 gst_rtp_buffer_unmap (&rtp);
807 gst_buffer_unref (buffer);
808
809 buffer = gst_harness_pull (h);
810 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
811 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
812 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
813 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
814 (2 + sizeof (h265_aud) - 4) + (2 + sizeof (h265_idr_slice_1) - 4));
815 gst_rtp_buffer_unmap (&rtp);
816 gst_buffer_unref (buffer);
817
818
819 gst_harness_teardown (h);
820 }
821
822 GST_END_TEST;
823
GST_START_TEST(test_rtph265pay_aggregate_with_ts_change)824 GST_START_TEST (test_rtph265pay_aggregate_with_ts_change)
825 {
826 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123 "
827 "aggregate-mode=max");
828 GstFlowReturn ret;
829 GstBuffer *buffer;
830 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
831
832 gst_harness_set_src_caps_str (h,
833 "video/x-h265,alignment=nal,stream-format=byte-stream");
834
835 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
836 sizeof (h265_idr_slice_1), 0);
837 buffer = gst_buffer_append (buffer,
838 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
839 0));
840 ret = gst_harness_push (h, buffer);
841 fail_unless_equals_int (ret, GST_FLOW_OK);
842
843 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
844 sizeof (h265_idr_slice_1), GST_SECOND);
845 buffer = gst_buffer_append (buffer,
846 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
847 GST_SECOND));
848 ret = gst_harness_push (h, buffer);
849 fail_unless_equals_int (ret, GST_FLOW_OK);
850
851 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
852
853 /* Push EOS to send the second one out */
854 gst_harness_push_event (h, gst_event_new_eos ());
855
856 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2);
857
858 buffer = gst_harness_pull (h);
859 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
860 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
861 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
862 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
863 (2 + sizeof (h265_idr_slice_2) - 3) +
864 (2 + sizeof (h265_idr_slice_1) - 4));
865 gst_rtp_buffer_unmap (&rtp);
866 gst_buffer_unref (buffer);
867
868 buffer = gst_harness_pull (h);
869 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
870 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), GST_SECOND);
871 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123 + 90000);
872 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
873 (2 + sizeof (h265_idr_slice_2) - 3) +
874 (2 + sizeof (h265_idr_slice_1) - 4));
875 gst_rtp_buffer_unmap (&rtp);
876 gst_buffer_unref (buffer);
877
878
879 gst_harness_teardown (h);
880 }
881
882 GST_END_TEST;
883
GST_START_TEST(test_rtph265pay_aggregate_with_discont)884 GST_START_TEST (test_rtph265pay_aggregate_with_discont)
885 {
886 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
887 " aggregate-mode=zero-latency");
888 GstFlowReturn ret;
889 GstBuffer *buffer;
890 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
891
892 gst_harness_set_src_caps_str (h,
893 "video/x-h265,alignment=nal,stream-format=byte-stream");
894
895 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
896 sizeof (h265_idr_slice_1), 0);
897 buffer = gst_buffer_append (buffer,
898 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
899 0));
900 ret = gst_harness_push (h, buffer);
901 fail_unless_equals_int (ret, GST_FLOW_OK);
902
903 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
904 sizeof (h265_idr_slice_1), 0);
905 buffer = gst_buffer_append (buffer,
906 wrap_static_buffer_with_pts (h265_idr_slice_2, sizeof (h265_idr_slice_2),
907 0));
908 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
909 ret = gst_harness_push (h, buffer);
910 fail_unless_equals_int (ret, GST_FLOW_OK);
911
912 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2);
913
914 buffer = gst_harness_pull (h);
915 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
916 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
917 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
918 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
919 (2 + sizeof (h265_idr_slice_2) - 3) +
920 (2 + sizeof (h265_idr_slice_1) - 4));
921 gst_rtp_buffer_unmap (&rtp);
922 gst_buffer_unref (buffer);
923
924 buffer = gst_harness_pull (h);
925 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
926 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
927 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123 + 0);
928 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
929 (2 + sizeof (h265_idr_slice_2) - 3) +
930 (2 + sizeof (h265_idr_slice_1) - 4));
931 gst_rtp_buffer_unmap (&rtp);
932 gst_buffer_unref (buffer);
933
934
935 gst_harness_teardown (h);
936 }
937
938 GST_END_TEST;
939
940 /* EOS */
941 static guint8 h265_eos[] = {
942 0x00, 0x00, 0x00, 0x01, (36 << 1), 0x00
943 };
944
945
GST_START_TEST(test_rtph265pay_aggregate_until_vcl)946 GST_START_TEST (test_rtph265pay_aggregate_until_vcl)
947 {
948 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
949 " name=p aggregate-mode=zero-latency");
950 GstFlowReturn ret;
951 GstBuffer *buffer;
952 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
953
954 gst_harness_set_src_caps_str (h,
955 "video/x-h265,alignment=nal,stream-format=byte-stream");
956
957 buffer = wrap_static_buffer_with_pts (h265_vps, sizeof (h265_vps), 0);
958 ret = gst_harness_push (h, buffer);
959 fail_unless_equals_int (ret, GST_FLOW_OK);
960
961 buffer = wrap_static_buffer_with_pts (h265_sps, sizeof (h265_sps), 0);
962 ret = gst_harness_push (h, buffer);
963 fail_unless_equals_int (ret, GST_FLOW_OK);
964
965 buffer = wrap_static_buffer_with_pts (h265_pps, sizeof (h265_pps), 0);
966 ret = gst_harness_push (h, buffer);
967 fail_unless_equals_int (ret, GST_FLOW_OK);
968
969 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
970 sizeof (h265_idr_slice_1), 0);
971 ret = gst_harness_push (h, buffer);
972 fail_unless_equals_int (ret, GST_FLOW_OK);
973
974 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
975
976 buffer = gst_harness_pull (h);
977 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
978 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
979 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
980 /* RTP header = 12, STAP header = 2, 2 bytes length per NAL */
981 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
982 (2 + sizeof (h265_vps) - 4) +
983 (2 + sizeof (h265_sps) - 4) +
984 (2 + sizeof (h265_pps) - 4) + (2 + sizeof (h265_idr_slice_1) - 4));
985 gst_rtp_buffer_unmap (&rtp);
986 gst_buffer_unref (buffer);
987
988 /* Push EOS now */
989
990 buffer = wrap_static_buffer_with_pts (h265_eos, sizeof (h265_eos), 0);
991 ret = gst_harness_push (h, buffer);
992 fail_unless_equals_int (ret, GST_FLOW_OK);
993
994 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
995
996 buffer = gst_harness_pull (h);
997 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
998 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
999 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
1000 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 +
1001 sizeof (h265_eos) - 4);
1002 gst_rtp_buffer_unmap (&rtp);
1003 gst_buffer_unref (buffer);
1004
1005 gst_harness_teardown (h);
1006 }
1007
1008 GST_END_TEST;
1009
1010
GST_START_TEST(test_rtph265pay_aggregate_verify_nalu_hdr)1011 GST_START_TEST (test_rtph265pay_aggregate_verify_nalu_hdr)
1012 {
1013 GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
1014 " name=p aggregate-mode=zero-latency");
1015 GstFlowReturn ret;
1016 GstBuffer *buffer;
1017 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
1018 guint8 *payload = NULL;
1019 gint paylen;
1020 guint nalu_type;
1021 guint nal_hdr_idx = 0;
1022 guint nal_size_idx;
1023 guint f_bit;
1024 guint max_f_bit;
1025 guint layer_id;
1026 guint layer_id_min;
1027 guint tid;
1028 guint tid_min;
1029 guint i;
1030
1031 gst_harness_set_src_caps_str (h,
1032 "video/x-h265,alignment=nal,stream-format=byte-stream");
1033
1034 buffer = wrap_static_buffer_with_pts (h265_vps, sizeof (h265_vps), 0);
1035 ret = gst_harness_push (h, buffer);
1036 fail_unless_equals_int (ret, GST_FLOW_OK);
1037
1038 buffer = wrap_static_buffer_with_pts (h265_sps, sizeof (h265_sps), 0);
1039 ret = gst_harness_push (h, buffer);
1040 fail_unless_equals_int (ret, GST_FLOW_OK);
1041
1042 buffer = wrap_static_buffer_with_pts (h265_pps, sizeof (h265_pps), 0);
1043 ret = gst_harness_push (h, buffer);
1044 fail_unless_equals_int (ret, GST_FLOW_OK);
1045
1046 buffer = wrap_static_buffer_with_pts (h265_idr_slice_1,
1047 sizeof (h265_idr_slice_1), 0);
1048 ret = gst_harness_push (h, buffer);
1049 fail_unless_equals_int (ret, GST_FLOW_OK);
1050
1051 fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1);
1052
1053 buffer = gst_harness_pull (h);
1054 fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
1055 fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0);
1056 fail_unless_equals_uint64 (gst_rtp_buffer_get_timestamp (&rtp), 123);
1057 /* RTP header = 12, STAP header = 2, 2 bytes length per NAL */
1058 fail_unless_equals_int (gst_buffer_get_size (buffer), 12 + 2 +
1059 (2 + sizeof (h265_vps) - 4) +
1060 (2 + sizeof (h265_sps) - 4) +
1061 (2 + sizeof (h265_pps) - 4) + (2 + sizeof (h265_idr_slice_1) - 4));
1062
1063 paylen = gst_rtp_buffer_get_payload_len (&rtp);
1064 payload = gst_rtp_buffer_get_payload (&rtp);
1065 fail_unless (payload);
1066
1067 /* Verify NAL unit type is 48. We need to shift to the rigth to get rid of the
1068 * first bit belonging to LayerID */
1069 nalu_type = ((0x7e & payload[nal_hdr_idx]) >> 1);
1070 fail_unless (nalu_type == 48);
1071
1072 /* The F bit MUST be cleared if all F bits of the aggregated NAL units
1073 * are zero; otherwise, it MUST be set. rfc7798 4.4.2 */
1074 f_bit = (0x80 & payload[nal_hdr_idx]);
1075 max_f_bit = 0;
1076
1077 /* The value of LayerId and TID MUST be equal to the lowest value of LayerId
1078 * resp TID of all the aggregated NAL units */
1079 layer_id = ((0x01 & payload[nal_hdr_idx]) << 5) |
1080 ((payload[nal_hdr_idx + 1] >> 3) & 0x1F);
1081 tid = payload[nal_hdr_idx + 1] & 0x7;
1082
1083 nal_hdr_idx = 4;
1084 nal_size_idx = 2;
1085 layer_id_min = 63;
1086 tid_min = 7;
1087 i = 0;
1088 while (nal_size_idx < paylen) {
1089 guint nal_type = ((0x7e & payload[nal_hdr_idx]) >> 1);
1090 if (i == 0) {
1091 fail_unless (nal_type == GST_H265_NAL_VPS);
1092 } else if (i == 1) {
1093 fail_unless (nal_type == GST_H265_NAL_SPS);
1094 } else if (i == 2) {
1095 fail_unless (nal_type == GST_H265_NAL_PPS);
1096 } else if (i == 3) {
1097 fail_unless (nal_type == GST_H265_NAL_SLICE_IDR_N_LP);
1098 }
1099
1100 if ((0x80 & payload[nal_hdr_idx]) > max_f_bit)
1101 max_f_bit = (0x80 & payload[nal_hdr_idx]);
1102
1103 if ((((0x01 & payload[nal_hdr_idx]) << 5) | ((payload[nal_hdr_idx + 1] >> 3)
1104 & 0x1F)) < layer_id_min)
1105 layer_id_min =
1106 ((0x01 & payload[nal_hdr_idx]) << 5) | ((payload[nal_hdr_idx + 1]
1107 >> 3) & 0x1F);
1108
1109 if ((payload[nal_hdr_idx + 1] & 0x7) < tid_min)
1110 tid_min = payload[nal_hdr_idx + 1] & 0x7;
1111
1112 nal_size_idx =
1113 (payload[nal_size_idx] << 8 | payload[nal_size_idx + 1]) +
1114 nal_size_idx + 2;
1115 nal_hdr_idx = nal_size_idx + 2;
1116 i++;
1117 }
1118
1119 fail_unless (nal_size_idx == paylen);
1120 fail_unless (max_f_bit == f_bit);
1121 fail_unless (layer_id_min == layer_id);
1122 fail_unless (tid_min == tid);
1123
1124 gst_rtp_buffer_unmap (&rtp);
1125 gst_buffer_unref (buffer);
1126
1127 gst_harness_teardown (h);
1128 }
1129
1130 GST_END_TEST;
1131 static Suite *
rtph265_suite(void)1132 rtph265_suite (void)
1133 {
1134 Suite *s = suite_create ("rtph265");
1135 TCase *tc_chain;
1136
1137 tc_chain = tcase_create ("rtph265depay");
1138 suite_add_tcase (s, tc_chain);
1139 tcase_add_test (tc_chain, test_rtph265depay_with_downstream_allocator);
1140 tcase_add_test (tc_chain, test_rtph265depay_eos);
1141 tcase_add_test (tc_chain, test_rtph265depay_marker_to_flag);
1142 /* TODO We need a sample to test with */
1143 /* tcase_add_test (tc_chain, test_rtph265depay_aggregate_marker); */
1144
1145 tc_chain = tcase_create ("rtph265pay");
1146 suite_add_tcase (s, tc_chain);
1147 tcase_add_test (tc_chain, test_rtph265pay_two_slices_timestamp);
1148 tcase_add_test (tc_chain, test_rtph265pay_marker_for_flag);
1149 tcase_add_test (tc_chain, test_rtph265pay_marker_for_au);
1150 tcase_add_test (tc_chain, test_rtph265pay_marker_for_fragmented_au);
1151 tcase_add_test (tc_chain, test_rtph265pay_aggregate_two_slices_per_buffer);
1152 tcase_add_test (tc_chain, test_rtph265pay_aggregate_with_aud);
1153 tcase_add_test (tc_chain, test_rtph265pay_aggregate_with_ts_change);
1154 tcase_add_test (tc_chain, test_rtph265pay_aggregate_with_discont);
1155 tcase_add_test (tc_chain, test_rtph265pay_aggregate_until_vcl);
1156 tcase_add_test (tc_chain, test_rtph265pay_aggregate_verify_nalu_hdr);
1157
1158 return s;
1159 }
1160
1161 GST_CHECK_MAIN (rtph265);
1162