• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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