Skip to content

Commit b5ade41

Browse files
calvarisDivya-563
authored andcommitted
gst1-plugins-good: qtdemux fix crash in cenc sample grouping
1 parent 3ff5d55 commit b5ade41

File tree

2 files changed

+426
-0
lines changed

2 files changed

+426
-0
lines changed
Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
diff -ruN a/gst/isomp4/fourcc.h b/gst/isomp4/fourcc.h
2+
--- a/gst/isomp4/fourcc.h 2022-02-08 08:51:37.000000000 +0100
3+
+++ b/gst/isomp4/fourcc.h 2022-02-02 15:56:36.000000000 +0100
4+
@@ -392,6 +392,9 @@
5+
#define FOURCC_tenc GST_MAKE_FOURCC('t','e','n','c')
6+
#define FOURCC_cenc GST_MAKE_FOURCC('c','e','n','c')
7+
#define FOURCC_cbcs GST_MAKE_FOURCC('c','b','c','s')
8+
+#define FOURCC_sbgp GST_MAKE_FOURCC('s','b','g','p')
9+
+#define FOURCC_sgpd GST_MAKE_FOURCC('s','g','p','d')
10+
+#define FOURCC_seig GST_MAKE_FOURCC('s','e','i','g')
11+
12+
G_END_DECLS
13+
14+
diff -ruN a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
15+
--- a/gst/isomp4/qtdemux.c 2022-02-08 08:51:37.000000000 +0100
16+
+++ b/gst/isomp4/qtdemux.c 2022-02-08 08:59:44.000000000 +0100
17+
@@ -464,6 +464,11 @@
18+
{
19+
GstStructure *default_properties;
20+
21+
+ /* sample groups */
22+
+ GPtrArray *track_group_properties;
23+
+ GPtrArray *fragment_group_properties;
24+
+ GPtrArray *sample_to_group_map;
25+
+
26+
/* @crypto_info holds one GstStructure per sample */
27+
GPtrArray *crypto_info;
28+
};
29+
@@ -2729,6 +2734,12 @@
30+
gst_structure_free (info->default_properties);
31+
if (info->crypto_info)
32+
g_ptr_array_free (info->crypto_info, TRUE);
33+
+ if (info->fragment_group_properties)
34+
+ g_ptr_array_free (info->fragment_group_properties, TRUE);
35+
+ if (info->track_group_properties)
36+
+ g_ptr_array_free (info->track_group_properties, TRUE);
37+
+ if (info->sample_to_group_map)
38+
+ g_ptr_array_free (info->sample_to_group_map, FALSE);
39+
}
40+
g_free (stream->protection_scheme_info);
41+
stream->protection_scheme_info = NULL;
42+
@@ -3834,6 +3845,7 @@
43+
QtDemuxStream * stream, guint sample_index)
44+
{
45+
QtDemuxCencSampleSetInfo *info = NULL;
46+
+ GstStructure * properties = NULL;
47+
48+
g_return_val_if_fail (stream != NULL, NULL);
49+
g_return_val_if_fail (stream->protected, NULL);
50+
@@ -3841,9 +3853,252 @@
51+
52+
info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
53+
54+
- /* Currently, cenc properties for groups of samples are not supported, so
55+
- * simply return a copy of the default sample properties */
56+
- return gst_structure_copy (info->default_properties);
57+
+ /* First check if the sample is associated with the 'seig' sample group. */
58+
+ if (info->sample_to_group_map && (sample_index < info->sample_to_group_map->len))
59+
+ properties = g_ptr_array_index (info->sample_to_group_map, sample_index);
60+
+
61+
+ /* If not, use the default properties for this sample. */
62+
+ if (!properties)
63+
+ properties = info->default_properties;
64+
+
65+
+ return gst_structure_copy (properties);
66+
+}
67+
+
68+
+static gboolean
69+
+qtdemux_parse_sbgp (GstQTDemux * qtdemux, QtDemuxStream * stream,
70+
+ GstByteReader * br, guint32 group, GPtrArray ** sample_to_group_array,
71+
+ GstStructure * default_properties, GPtrArray * tack_properties_array,
72+
+ GPtrArray * group_properties_array)
73+
+{
74+
+ guint32 flags = 0;
75+
+ guint8 version = 0;
76+
+ guint32 count = 0;
77+
+ const guint8 * grouping_type_data = NULL;
78+
+ guint32 grouping_type = 0;
79+
+
80+
+ g_return_val_if_fail (qtdemux != NULL, FALSE);
81+
+ g_return_val_if_fail (stream != NULL, FALSE);
82+
+ g_return_val_if_fail (br != NULL, FALSE);
83+
+ g_return_val_if_fail (*sample_to_group_array == NULL, FALSE);
84+
+
85+
+ if (!gst_byte_reader_get_uint32_be (br, &flags))
86+
+ return FALSE;
87+
+
88+
+ if (!gst_byte_reader_get_data (br, 4, &grouping_type_data))
89+
+ return FALSE;
90+
+
91+
+ grouping_type = QT_FOURCC (grouping_type_data);
92+
+ if (grouping_type != group) {
93+
+ /* There may be other groups, so just log this... */
94+
+ GST_DEBUG_OBJECT (qtdemux, "Unsupported grouping type: '%"
95+
+ GST_FOURCC_FORMAT "'", GST_FOURCC_ARGS (grouping_type));
96+
+ return FALSE;
97+
+ }
98+
+
99+
+ version = (flags >> 24);
100+
+ if (version > 0) {
101+
+ GST_WARNING_OBJECT (qtdemux, "Unsupported 'sbgp' box version: %hhu",
102+
+ version);
103+
+ return FALSE;
104+
+ }
105+
+
106+
+ if (!gst_byte_reader_get_uint32_be (br, &count))
107+
+ return FALSE;
108+
+
109+
+ GST_LOG_OBJECT (qtdemux, "flags: %08x, type: '%" GST_FOURCC_FORMAT
110+
+ "', count: %u", flags, GST_FOURCC_ARGS (grouping_type), count);
111+
+
112+
+ if (count > 0)
113+
+ (*sample_to_group_array) = g_ptr_array_sized_new (count);
114+
+
115+
+ while (count--) {
116+
+ guint32 samples;
117+
+ guint32 index;
118+
+ GstStructure * properties = NULL;
119+
+
120+
+ if (!gst_byte_reader_get_uint32_be (br, &samples))
121+
+ return FALSE;
122+
+
123+
+ if (!gst_byte_reader_get_uint32_be (br, &index))
124+
+ return FALSE;
125+
+
126+
+ if (index > 0x10000) {
127+
+ /* Index is referring the current fragment. */
128+
+ index -= 0x10001;
129+
+ if (index < group_properties_array->len)
130+
+ properties = g_ptr_array_index (group_properties_array, index);
131+
+ else
132+
+ GST_ERROR_OBJECT (qtdemux, "invalid group index %u", index);
133+
+ } else if (index > 0) {
134+
+ /* Index is referring to the whole track. */
135+
+ index--;
136+
+ if (index < tack_properties_array->len)
137+
+ properties = g_ptr_array_index (tack_properties_array, index);
138+
+ else
139+
+ GST_ERROR_OBJECT (qtdemux, "invalid group index %u", index);
140+
+ } else {
141+
+ /* If zero, then this range of samples does not belong to this group,
142+
+ perhaps to another one or to none at all. */
143+
+ }
144+
+
145+
+ GST_INFO_OBJECT (qtdemux, "assigning group '%" GST_FOURCC_FORMAT
146+
+ "' index %i for the next %i samples: %" GST_PTR_FORMAT,
147+
+ GST_FOURCC_ARGS (grouping_type), index, samples, properties);
148+
+
149+
+ while (samples--)
150+
+ g_ptr_array_add (*sample_to_group_array, properties);
151+
+ }
152+
+
153+
+ return TRUE;
154+
+}
155+
+
156+
+static gboolean
157+
+qtdemux_parse_sgpd(GstQTDemux * qtdemux, QtDemuxStream * stream,
158+
+ GstByteReader * br, guint32 group, GPtrArray ** properties)
159+
+{
160+
+ guint32 flags = 0;
161+
+ guint8 version = 0;
162+
+ guint32 default_length = 0;
163+
+ guint32 count = 0;
164+
+ const guint8 * grouping_type_data = NULL;
165+
+ guint32 grouping_type = 0;
166+
+ const guint32 min_entry_size = 20;
167+
+
168+
+ g_return_val_if_fail (qtdemux != NULL, FALSE);
169+
+ g_return_val_if_fail (stream != NULL, FALSE);
170+
+ g_return_val_if_fail (br != NULL, FALSE);
171+
+ g_return_val_if_fail (*properties == NULL, FALSE);
172+
+
173+
+ if (!gst_byte_reader_get_uint32_be (br, &flags))
174+
+ return FALSE;
175+
+
176+
+ if (!gst_byte_reader_get_data (br, 4, &grouping_type_data))
177+
+ return FALSE;
178+
+
179+
+ grouping_type = QT_FOURCC (grouping_type_data);
180+
+ if (grouping_type != group) {
181+
+ GST_DEBUG_OBJECT (qtdemux, "Unhandled grouping type: '%"
182+
+ GST_FOURCC_FORMAT "'", GST_FOURCC_ARGS (grouping_type));
183+
+ return FALSE;
184+
+ }
185+
+
186+
+ version = (flags >> 24);
187+
+ if (version == 1) {
188+
+ if (!gst_byte_reader_get_uint32_be (br, &default_length))
189+
+ return FALSE;
190+
+ } else if (version > 1) {
191+
+ GST_WARNING_OBJECT (qtdemux, "Unsupported 'sgpd' box version: %hhu",
192+
+ version);
193+
+ return FALSE;
194+
+ }
195+
+
196+
+ if (!gst_byte_reader_get_uint32_be (br, &count))
197+
+ return FALSE;
198+
+
199+
+ GST_LOG_OBJECT(qtdemux, "flags: %08x, type: '%" GST_FOURCC_FORMAT
200+
+ "', count: %u", flags, GST_FOURCC_ARGS (grouping_type), count);
201+
+
202+
+ if (count)
203+
+ (*properties) = g_ptr_array_sized_new (count);
204+
+
205+
+ for (guint32 index = 0; index < count; index++) {
206+
+ GstStructure *props = NULL;
207+
+ guint32 length = default_length;
208+
+ const guint8 *entry_data = NULL;
209+
+ guint8 is_encrypted = 0;
210+
+ guint8 iv_size = 0;
211+
+ guint8 constant_iv_size = 0;
212+
+ const guint8 *kid = NULL;
213+
+ guint8 crypt_byte_block = 0;
214+
+ guint8 skip_byte_block = 0;
215+
+ const guint8 *constant_iv = NULL;
216+
+ GstBuffer *kid_buf;
217+
+
218+
+ if ((version == 1) && (length == 0)) {
219+
+ if (!gst_byte_reader_get_uint32_be (br, &length))
220+
+ return FALSE;
221+
+ }
222+
+
223+
+ if (G_UNLIKELY (length < min_entry_size)) {
224+
+ GST_ERROR_OBJECT (qtdemux, "Invalid entry size: %u", length);
225+
+ return FALSE;
226+
+ }
227+
+
228+
+ if (!gst_byte_reader_get_data (br, length, &entry_data))
229+
+ return FALSE;
230+
+
231+
+ /* Follows tenc format... */
232+
+ is_encrypted = QT_UINT8 (entry_data + 2);
233+
+ iv_size = QT_UINT8 (entry_data + 3);
234+
+ kid = (entry_data + 4);
235+
+
236+
+ if (stream->protection_scheme_type == FOURCC_cbcs) {
237+
+ guint8 possible_pattern_info;
238+
+
239+
+ if (iv_size == 0) {
240+
+ if (G_UNLIKELY (length < min_entry_size + 1)) {
241+
+ GST_ERROR_OBJECT (qtdemux, "Invalid entry size: %u", length);
242+
+ return FALSE;
243+
+ }
244+
+
245+
+ constant_iv_size = QT_UINT8 (entry_data + 20);
246+
+ if (G_UNLIKELY ((constant_iv_size) != 8 && (constant_iv_size != 16))) {
247+
+ GST_ERROR_OBJECT (qtdemux,
248+
+ "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
249+
+ return FALSE;
250+
+ }
251+
+
252+
+ if (G_UNLIKELY (length < min_entry_size + 1 + constant_iv_size)) {
253+
+ GST_ERROR_OBJECT (qtdemux, "Invalid entry size: %u", length);
254+
+ return FALSE;
255+
+ }
256+
+
257+
+ constant_iv = (entry_data + 21);
258+
+ }
259+
+
260+
+ possible_pattern_info = QT_UINT8 (entry_data + 1);
261+
+ crypt_byte_block = ((possible_pattern_info >> 4) & 0x0f);
262+
+ skip_byte_block = (possible_pattern_info & 0x0f);
263+
+ }
264+
+
265+
+ kid_buf = _gst_buffer_new_wrapped ((guint8 *) kid, 16, NULL);
266+
+
267+
+ props = gst_structure_new ("application/x-cenc",
268+
+ "iv_size", G_TYPE_UINT, iv_size,
269+
+ "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
270+
+ "kid", GST_TYPE_BUFFER, kid_buf, NULL);
271+
+
272+
+ gst_buffer_unref (kid_buf);
273+
+
274+
+ if (stream->protection_scheme_type == FOURCC_cbcs) {
275+
+ if ((crypt_byte_block != 0) || (skip_byte_block != 0)) {
276+
+ gst_structure_set (props,
277+
+ "crypt_byte_block", G_TYPE_UINT, crypt_byte_block,
278+
+ "skip_byte_block", G_TYPE_UINT, skip_byte_block, NULL);
279+
+ }
280+
+
281+
+ if (constant_iv != NULL) {
282+
+ GstBuffer *constant_iv_buf = _gst_buffer_new_wrapped (
283+
+ (guint8 *) constant_iv, constant_iv_size, NULL);
284+
+ gst_structure_set (props,
285+
+ "constant_iv_size", G_TYPE_UINT, constant_iv_size,
286+
+ "iv", GST_TYPE_BUFFER, constant_iv_buf, NULL);
287+
+ gst_buffer_unref (constant_iv_buf);
288+
+ }
289+
+
290+
+ gst_structure_set (props, "cipher-mode", G_TYPE_STRING, "cbcs", NULL);
291+
+ } else {
292+
+ gst_structure_set (props, "cipher-mode", G_TYPE_STRING, "cenc", NULL);
293+
+ }
294+
+
295+
+ GST_INFO_OBJECT(qtdemux, "properties for group '%"
296+
+ GST_FOURCC_FORMAT "' at index %u: %" GST_PTR_FORMAT,
297+
+ GST_FOURCC_ARGS (grouping_type), index, props);
298+
+
299+
+ g_ptr_array_add (*properties, props);
300+
+ }
301+
+
302+
+ return TRUE;
303+
}
304+
305+
/* Parses the sizes of sample auxiliary information contained within a stream,
306+
@@ -4210,6 +4465,50 @@
307+
&ds_size, &ds_flags, &base_offset))
308+
goto missing_tfhd;
309+
310+
+ /* Sample grouping support */
311+
+ if (stream != NULL && stream->protected && (stream->protection_scheme_type == FOURCC_cenc
312+
+ || stream->protection_scheme_type == FOURCC_cbcs)) {
313+
+ QtDemuxCencSampleSetInfo *info = stream->protection_scheme_info;
314+
+ GNode *sbgp_node, *sgpd_node;
315+
+ GstByteReader sgpd_data, sbgp_data;
316+
+
317+
+ if (info->fragment_group_properties) {
318+
+ g_ptr_array_free (info->fragment_group_properties, TRUE);
319+
+ info->fragment_group_properties = NULL;
320+
+ }
321+
+
322+
+ if (info->sample_to_group_map) {
323+
+ g_ptr_array_free (info->sample_to_group_map, FALSE);
324+
+ info->sample_to_group_map = NULL;
325+
+ }
326+
+
327+
+ /* Check if sample grouping information is present for this segment. */
328+
+ /* However look only for 'seig' (CENC encryption) grouping type... */
329+
+ sgpd_node = qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_sgpd,
330+
+ &sgpd_data);
331+
+ while (sgpd_node) {
332+
+ if (qtdemux_parse_sgpd(qtdemux, stream, &sgpd_data, FOURCC_seig,
333+
+ &info->fragment_group_properties)) {
334+
+ /* CENC encryption grouping found, don't look further. */
335+
+ break;
336+
+ }
337+
+ sgpd_node = qtdemux_tree_get_sibling_by_type_full (sgpd_node,
338+
+ FOURCC_sgpd, &sgpd_data);
339+
+ }
340+
+
341+
+ sbgp_node = qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_sbgp,
342+
+ &sbgp_data);
343+
+ while (sbgp_node) {
344+
+ if (qtdemux_parse_sbgp (qtdemux, stream, &sbgp_data, FOURCC_seig,
345+
+ &info->sample_to_group_map, info->default_properties,
346+
+ info->track_group_properties, info->fragment_group_properties)) {
347+
+ break;
348+
+ }
349+
+ sbgp_node = qtdemux_tree_get_sibling_by_type_full (sbgp_node,
350+
+ FOURCC_sgpd, &sbgp_data);
351+
+ }
352+
+ }
353+
+
354+
/* The following code assumes at most a single set of sample auxiliary
355+
* data in the fragment (consisting of a saiz box and a corresponding saio
356+
* box); in theory, however, there could be multiple sets of sample
357+
@@ -12771,7 +13070,30 @@
358+
359+
stsd_entry_data += len;
360+
remaining_stsd_len -= len;
361+
+ }
362+
+
363+
+ /* Sample grouping support */
364+
+ if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
365+
+ || stream->protection_scheme_type == FOURCC_cbcs)) {
366+
+ QtDemuxCencSampleSetInfo *info = stream->protection_scheme_info;
367+
+ GNode *sgpd_node;
368+
+ GstByteReader sgpd_data;
369+
+
370+
+ if (info->track_group_properties) {
371+
+ g_ptr_array_free (info->fragment_group_properties, TRUE);
372+
+ info->fragment_group_properties = NULL;
373+
+ }
374+
375+
+ sgpd_node = qtdemux_tree_get_child_by_type_full (stbl, FOURCC_sgpd,
376+
+ &sgpd_data);
377+
+ while (sgpd_node) {
378+
+ if (qtdemux_parse_sgpd(qtdemux, stream, &sgpd_data, FOURCC_seig,
379+
+ &info->track_group_properties)) {
380+
+ break;
381+
+ }
382+
+ sgpd_node = qtdemux_tree_get_sibling_by_type_full (sgpd_node,
383+
+ FOURCC_sgpd, &sgpd_data);
384+
+ }
385+
}
386+
387+
/* collect sample information */
388+
diff -ruN a/gst/isomp4/qtdemux_types.c b/gst/isomp4/qtdemux_types.c
389+
--- a/gst/isomp4/qtdemux_types.c 2019-04-19 11:16:25.000000000 +0200
390+
+++ b/gst/isomp4/qtdemux_types.c 2022-02-07 11:13:17.000000000 +0100
391+
@@ -212,6 +212,8 @@
392+
{FOURCC_schi, "scheme information", QT_FLAG_CONTAINER},
393+
{FOURCC_pssh, "protection system specific header", 0},
394+
{FOURCC_tenc, "track encryption", 0},
395+
+ {FOURCC_sgpd, "sample group description", 0},
396+
+ {FOURCC_sbgp, "sample to group", 0},
397+
{FOURCC_stpp, "XML subtitle sample entry", 0},
398+
{FOURCC_clcp, "Closed Caption", 0},
399+
{FOURCC_av01, "AV1 Sample Entry", 0},

0 commit comments

Comments
 (0)