1 /* Gstreamer
2  * Copyright (C) <2018> Collabora Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 #include <gst/check/gstcheck.h>
20 #include <gst/codecparsers/gsth265parser.h>
21 
22 unsigned char slice_eos_slice_eob[] = {
23   0x00, 0x00, 0x00, 0x01, 0x26, 0x01, 0xaf, 0x06, 0xb8, 0x63, 0xef, 0x3a,
24   0x7f, 0x3e, 0x53, 0xff, 0xff, 0xf2, 0x4a, 0xef, 0xff, 0xfe, 0x6a, 0x5d,
25   0x60, 0xbc, 0xf8, 0x29, 0xeb, 0x9c, 0x4a, 0xb5, 0xcc, 0x76, 0x30, 0xa0,
26   0x7c, 0xd3, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x19, 0x30,
27   0x00, 0x00, 0x00, 0x01, 0x48, 0x01,
28   0x00, 0x00, 0x00, 0x01, 0x26, 0x01, 0xaf, 0x06, 0xb8, 0x63, 0xef, 0x3a,
29   0x7f, 0x3e, 0x53, 0xff, 0xff, 0xf2, 0x4a, 0xef, 0xff, 0xfe, 0x6a, 0x5d,
30   0x60, 0xbc, 0xf8, 0x29, 0xeb, 0x9c, 0x4a, 0xb5, 0xcc, 0x76, 0x30, 0xa0,
31   0x7c, 0xd3, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x19, 0x30,
32   0x00, 0x00, 0x00, 0x01, 0x4a, 0x01,
33 };
34 
35 static const guint8 h265_vps_with_nonzero_max_layer_id[] = {
36   0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01,
37   0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
38   0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
39   0x5d, 0xac, 0x59
40 };
41 
GST_START_TEST(test_h265_parse_slice_eos_slice_eob)42 GST_START_TEST (test_h265_parse_slice_eos_slice_eob)
43 {
44   GstH265ParserResult res;
45   GstH265NalUnit nalu;
46   GstH265Parser *const parser = gst_h265_parser_new ();
47   const guint8 *buf = slice_eos_slice_eob;
48   guint n, buf_size = sizeof (slice_eos_slice_eob);
49 
50   res = gst_h265_parser_identify_nalu (parser, buf, 0, buf_size, &nalu);
51 
52   assert_equals_int (res, GST_H265_PARSER_OK);
53   assert_equals_int (nalu.type, GST_H265_NAL_SLICE_IDR_W_RADL);
54   assert_equals_int (nalu.size, 43);
55 
56   n = nalu.offset + nalu.size;
57   buf += n;
58   buf_size -= n;
59 
60   res = gst_h265_parser_identify_nalu (parser, buf, 0, buf_size, &nalu);
61 
62   assert_equals_int (res, GST_H265_PARSER_OK);
63   assert_equals_int (nalu.type, GST_H265_NAL_EOS);
64   assert_equals_int (nalu.size, 2);
65 
66   n = nalu.offset + nalu.size;
67   buf += n;
68   buf_size -= n;
69 
70   res = gst_h265_parser_identify_nalu (parser, buf, 0, buf_size, &nalu);
71 
72   assert_equals_int (res, GST_H265_PARSER_OK);
73   assert_equals_int (nalu.type, GST_H265_NAL_SLICE_IDR_W_RADL);
74   assert_equals_int (nalu.size, 43);
75 
76   n = nalu.offset + nalu.size;
77   buf += n;
78   buf_size -= n;
79 
80   res = gst_h265_parser_identify_nalu (parser, buf, 0, buf_size, &nalu);
81 
82   assert_equals_int (res, GST_H265_PARSER_OK);
83   assert_equals_int (nalu.type, GST_H265_NAL_EOB);
84   assert_equals_int (nalu.size, 2);
85 
86   gst_h265_parser_free (parser);
87 }
88 
89 GST_END_TEST;
90 
GST_START_TEST(test_h265_parse_slice_6bytes)91 GST_START_TEST (test_h265_parse_slice_6bytes)
92 {
93   GstH265ParserResult res;
94   GstH265NalUnit nalu;
95   GstH265Parser *const parser = gst_h265_parser_new ();
96   const guint8 *buf = slice_eos_slice_eob;
97 
98   res = gst_h265_parser_identify_nalu (parser, buf, 0, 6, &nalu);
99 
100   assert_equals_int (res, GST_H265_PARSER_NO_NAL_END);
101   assert_equals_int (nalu.type, GST_H265_NAL_SLICE_IDR_W_RADL);
102   assert_equals_int (nalu.size, 2);
103 
104   gst_h265_parser_free (parser);
105 }
106 
107 GST_END_TEST;
108 
GST_START_TEST(test_h265_base_profiles)109 GST_START_TEST (test_h265_base_profiles)
110 {
111   GstH265ProfileTierLevel ptl;
112 
113   memset (&ptl, 0, sizeof (ptl));
114 
115   ptl.profile_idc = 1;
116   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
117       GST_H265_PROFILE_MAIN);
118   ptl.profile_idc = 2;
119   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
120       GST_H265_PROFILE_MAIN_10);
121   ptl.profile_idc = 3;
122   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
123       GST_H265_PROFILE_MAIN_STILL_PICTURE);
124 
125   ptl.profile_idc = 42;
126   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
127       GST_H265_PROFILE_INVALID);
128 }
129 
130 GST_END_TEST;
131 
GST_START_TEST(test_h265_base_profiles_compat)132 GST_START_TEST (test_h265_base_profiles_compat)
133 {
134   GstH265ProfileTierLevel ptl;
135 
136   memset (&ptl, 0, sizeof (ptl));
137 
138   ptl.profile_compatibility_flag[1] = 1;
139   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
140       GST_H265_PROFILE_MAIN);
141   ptl.profile_compatibility_flag[1] = 0;
142 
143   ptl.profile_compatibility_flag[2] = 1;
144   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
145       GST_H265_PROFILE_MAIN_10);
146   ptl.profile_compatibility_flag[2] = 0;
147 
148   ptl.profile_compatibility_flag[3] = 1;
149   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
150       GST_H265_PROFILE_MAIN_STILL_PICTURE);
151   ptl.profile_compatibility_flag[3] = 0;
152 
153   ptl.profile_idc = 42;
154   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
155       GST_H265_PROFILE_INVALID);
156 }
157 
158 GST_END_TEST;
159 
160 static void
set_format_range_fields(GstH265ProfileTierLevel * ptl,guint8 max_12bit_constraint_flag,guint8 max_10bit_constraint_flag,guint8 max_8bit_constraint_flag,guint8 max_422chroma_constraint_flag,guint8 max_420chroma_constraint_flag,guint8 max_monochrome_constraint_flag,guint8 intra_constraint_flag,guint8 one_picture_only_constraint_flag,guint8 lower_bit_rate_constraint_flag)161 set_format_range_fields (GstH265ProfileTierLevel * ptl,
162     guint8 max_12bit_constraint_flag,
163     guint8 max_10bit_constraint_flag,
164     guint8 max_8bit_constraint_flag,
165     guint8 max_422chroma_constraint_flag,
166     guint8 max_420chroma_constraint_flag,
167     guint8 max_monochrome_constraint_flag,
168     guint8 intra_constraint_flag,
169     guint8 one_picture_only_constraint_flag,
170     guint8 lower_bit_rate_constraint_flag)
171 {
172   ptl->max_12bit_constraint_flag = max_12bit_constraint_flag;
173   ptl->max_10bit_constraint_flag = max_10bit_constraint_flag;
174   ptl->max_8bit_constraint_flag = max_8bit_constraint_flag;
175   ptl->max_422chroma_constraint_flag = max_422chroma_constraint_flag;
176   ptl->max_420chroma_constraint_flag = max_420chroma_constraint_flag;
177   ptl->max_monochrome_constraint_flag = max_monochrome_constraint_flag;
178   ptl->intra_constraint_flag = intra_constraint_flag;
179   ptl->one_picture_only_constraint_flag = one_picture_only_constraint_flag;
180   ptl->lower_bit_rate_constraint_flag = lower_bit_rate_constraint_flag;
181 }
182 
GST_START_TEST(test_h265_format_range_profiles_exact_match)183 GST_START_TEST (test_h265_format_range_profiles_exact_match)
184 {
185   /* Test all the combinations from Table A.2 */
186   GstH265ProfileTierLevel ptl;
187 
188   memset (&ptl, 0, sizeof (ptl));
189   ptl.profile_idc = 4;
190 
191   set_format_range_fields (&ptl, 1, 1, 1, 1, 1, 1, 0, 0, 1);
192   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
193       GST_H265_PROFILE_MONOCHROME);
194 
195   set_format_range_fields (&ptl, 1, 0, 0, 1, 1, 1, 0, 0, 1);
196   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
197       GST_H265_PROFILE_MONOCHROME_12);
198 
199   set_format_range_fields (&ptl, 0, 0, 0, 1, 1, 1, 0, 0, 1);
200   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
201       GST_H265_PROFILE_MONOCHROME_16);
202 
203   set_format_range_fields (&ptl, 1, 0, 0, 1, 1, 0, 0, 0, 1);
204   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
205       GST_H265_PROFILE_MAIN_12);
206 
207   set_format_range_fields (&ptl, 1, 1, 0, 1, 0, 0, 0, 0, 1);
208   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
209       GST_H265_PROFILE_MAIN_422_10);
210 
211   set_format_range_fields (&ptl, 1, 0, 0, 1, 0, 0, 0, 0, 1);
212   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
213       GST_H265_PROFILE_MAIN_422_12);
214 
215   set_format_range_fields (&ptl, 1, 1, 1, 0, 0, 0, 0, 0, 1);
216   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
217       GST_H265_PROFILE_MAIN_444);
218 
219   set_format_range_fields (&ptl, 1, 1, 0, 0, 0, 0, 0, 0, 1);
220   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
221       GST_H265_PROFILE_MAIN_444_10);
222 
223   set_format_range_fields (&ptl, 1, 0, 0, 0, 0, 0, 0, 0, 1);
224   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
225       GST_H265_PROFILE_MAIN_444_12);
226 
227   set_format_range_fields (&ptl, 1, 1, 1, 1, 1, 0, 1, 0, 0);
228   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
229       GST_H265_PROFILE_MAIN_INTRA);
230   set_format_range_fields (&ptl, 1, 1, 1, 1, 1, 0, 1, 0, 1);
231   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
232       GST_H265_PROFILE_MAIN_INTRA);
233 
234   set_format_range_fields (&ptl, 1, 1, 0, 1, 1, 0, 1, 0, 0);
235   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
236       GST_H265_PROFILE_MAIN_10_INTRA);
237   set_format_range_fields (&ptl, 1, 1, 0, 1, 1, 0, 1, 0, 1);
238   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
239       GST_H265_PROFILE_MAIN_10_INTRA);
240 
241   set_format_range_fields (&ptl, 1, 0, 0, 1, 1, 0, 1, 0, 0);
242   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
243       GST_H265_PROFILE_MAIN_12_INTRA);
244   set_format_range_fields (&ptl, 1, 0, 0, 1, 1, 0, 1, 0, 1);
245   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
246       GST_H265_PROFILE_MAIN_12_INTRA);
247 
248   set_format_range_fields (&ptl, 1, 1, 0, 1, 0, 0, 1, 0, 0);
249   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
250       GST_H265_PROFILE_MAIN_422_10_INTRA);
251   set_format_range_fields (&ptl, 1, 1, 0, 1, 0, 0, 1, 0, 1);
252   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
253       GST_H265_PROFILE_MAIN_422_10_INTRA);
254 
255   set_format_range_fields (&ptl, 1, 0, 0, 1, 0, 0, 1, 0, 0);
256   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
257       GST_H265_PROFILE_MAIN_422_12_INTRA);
258   set_format_range_fields (&ptl, 1, 0, 0, 1, 0, 0, 1, 0, 1);
259   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
260       GST_H265_PROFILE_MAIN_422_12_INTRA);
261 
262   set_format_range_fields (&ptl, 1, 1, 1, 0, 0, 0, 1, 0, 0);
263   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
264       GST_H265_PROFILE_MAIN_444_INTRA);
265   set_format_range_fields (&ptl, 1, 1, 1, 0, 0, 0, 1, 0, 1);
266   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
267       GST_H265_PROFILE_MAIN_444_INTRA);
268 
269   set_format_range_fields (&ptl, 1, 1, 0, 0, 0, 0, 1, 0, 0);
270   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
271       GST_H265_PROFILE_MAIN_444_10_INTRA);
272   set_format_range_fields (&ptl, 1, 1, 0, 0, 0, 0, 1, 0, 1);
273   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
274       GST_H265_PROFILE_MAIN_444_10_INTRA);
275 
276   set_format_range_fields (&ptl, 1, 0, 0, 0, 0, 0, 1, 0, 0);
277   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
278       GST_H265_PROFILE_MAIN_444_12_INTRA);
279   set_format_range_fields (&ptl, 1, 0, 0, 0, 0, 0, 1, 0, 1);
280   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
281       GST_H265_PROFILE_MAIN_444_12_INTRA);
282 
283   set_format_range_fields (&ptl, 0, 0, 0, 0, 0, 0, 1, 0, 0);
284   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
285       GST_H265_PROFILE_MAIN_444_16_INTRA);
286   set_format_range_fields (&ptl, 0, 0, 0, 0, 0, 0, 1, 0, 1);
287   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
288       GST_H265_PROFILE_MAIN_444_16_INTRA);
289 
290   set_format_range_fields (&ptl, 1, 1, 1, 0, 0, 0, 1, 1, 0);
291   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
292       GST_H265_PROFILE_MAIN_444_STILL_PICTURE);
293   set_format_range_fields (&ptl, 1, 1, 1, 0, 0, 0, 1, 1, 1);
294   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
295       GST_H265_PROFILE_MAIN_444_STILL_PICTURE);
296 
297   set_format_range_fields (&ptl, 0, 0, 0, 0, 0, 0, 1, 1, 0);
298   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
299       GST_H265_PROFILE_MAIN_444_16_STILL_PICTURE);
300   set_format_range_fields (&ptl, 0, 0, 0, 0, 0, 0, 1, 1, 1);
301   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
302       GST_H265_PROFILE_MAIN_444_16_STILL_PICTURE);
303 }
304 
305 GST_END_TEST;
306 
GST_START_TEST(test_h265_format_range_profiles_partial_match)307 GST_START_TEST (test_h265_format_range_profiles_partial_match)
308 {
309   /* Test matching compatible profiles from non-standard bitstream */
310   GstH265ProfileTierLevel ptl;
311 
312   memset (&ptl, 0, sizeof (ptl));
313   ptl.profile_idc = 4;
314 
315   set_format_range_fields (&ptl, 1, 1, 1, 1, 0, 0, 0, 0, 1);
316   g_assert_cmpuint (gst_h265_profile_tier_level_get_profile (&ptl), ==,
317       GST_H265_PROFILE_MAIN_444);
318 }
319 
320 GST_END_TEST;
321 
GST_START_TEST(test_h265_parse_vps)322 GST_START_TEST (test_h265_parse_vps)
323 {
324   /* Parsing non-zero vps_max_layer_id in VPS
325    * https://bugzilla.gnome.org/show_bug.cgi?id=797279 */
326   GstH265Parser *parser;
327   GstH265NalUnit nalu;
328   GstH265ParserResult res;
329   GstH265VPS vps;
330   GstH265Profile profile;
331 
332   parser = gst_h265_parser_new ();
333 
334   res = gst_h265_parser_identify_nalu_unchecked (parser,
335       h265_vps_with_nonzero_max_layer_id, 0,
336       sizeof (h265_vps_with_nonzero_max_layer_id), &nalu);
337 
338   assert_equals_int (res, GST_H265_PARSER_OK);
339   assert_equals_int (nalu.type, GST_H265_NAL_VPS);
340 
341   res = gst_h265_parser_parse_vps (parser, &nalu, &vps);
342   assert_equals_int (res, GST_H265_PARSER_OK);
343 
344   assert_equals_int (vps.id, 0);
345   assert_equals_int (vps.max_layers_minus1, 0);
346   assert_equals_int (vps.max_sub_layers_minus1, 0);
347   assert_equals_int (vps.temporal_id_nesting_flag, 1);
348 
349   profile = gst_h265_profile_tier_level_get_profile (&vps.profile_tier_level);
350 
351   assert_equals_int (profile, GST_H265_PROFILE_MAIN);
352   assert_equals_int (vps.sub_layer_ordering_info_present_flag, 1);
353 
354   assert_equals_int (vps.max_dec_pic_buffering_minus1[0], 1);
355   assert_equals_int (vps.max_num_reorder_pics[0], 0);
356   assert_equals_int (vps.max_latency_increase_plus1[0], 0);
357 
358   assert_equals_int (vps.max_layer_id, 5);
359   assert_equals_int (vps.num_layer_sets_minus1, 0);
360 
361   assert_equals_int (vps.timing_info_present_flag, 0);
362   assert_equals_int (vps.vps_extension, 0);
363 
364   gst_h265_parser_free (parser);
365 }
366 
367 GST_END_TEST;
368 
369 static Suite *
h265parser_suite(void)370 h265parser_suite (void)
371 {
372   Suite *s = suite_create ("H265 Parser library");
373 
374   TCase *tc_chain = tcase_create ("general");
375 
376   suite_add_tcase (s, tc_chain);
377   tcase_add_test (tc_chain, test_h265_parse_slice_eos_slice_eob);
378   tcase_add_test (tc_chain, test_h265_parse_slice_6bytes);
379   tcase_add_test (tc_chain, test_h265_base_profiles);
380   tcase_add_test (tc_chain, test_h265_base_profiles_compat);
381   tcase_add_test (tc_chain, test_h265_format_range_profiles_exact_match);
382   tcase_add_test (tc_chain, test_h265_format_range_profiles_partial_match);
383   tcase_add_test (tc_chain, test_h265_parse_vps);
384 
385   return s;
386 }
387 
388 GST_CHECK_MAIN (h265parser);
389