1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2017-2019
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / filters sub-project
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terfsess of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 #include "filter_session.h"
27 #include <gpac/constants.h>
28 //for binxml parsing
29 #include <gpac/xml.h>
30 
gf_props_parse_value(u32 type,const char * name,const char * value,const char * enum_values,char list_sep_char)31 GF_PropertyValue gf_props_parse_value(u32 type, const char *name, const char *value, const char *enum_values, char list_sep_char)
32 {
33 	GF_PropertyValue p;
34 	char *unit_sep=NULL;
35 	s32 unit = 0;
36 	memset(&p, 0, sizeof(GF_PropertyValue));
37 	p.value.data.size=0;
38 	p.type=type;
39 	if (!name) name="";
40 
41 	unit_sep = NULL;
42 	if (value) {
43 		u32 len = (u32) strlen(value);
44 		unit_sep = len ? strrchr("kKgGmM", value[len-1]) : NULL;
45 		if (unit_sep) {
46 			u8 unit_char = unit_sep[0];
47 			if ((unit_char=='k') || (unit_char=='K')) unit = 1000;
48 			else if ((unit_char=='m') || (unit_char=='M')) unit = 1000000;
49 			if ((unit_char=='G') || (unit_char=='g')) unit = 1000000000;
50 		}
51 	}
52 
53 	switch (p.type) {
54 	case GF_PROP_BOOL:
55 		if (!value || !strcmp(value, "yes") || !strcmp(value, "true") || !strcmp(value, "1")) {
56 			p.value.boolean = GF_TRUE;
57 		} else if ( !strcmp(value, "no") || !strcmp(value, "false") ) {
58 			p.value.boolean = GF_FALSE;
59 		} else {
60 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for boolean arg %s - using false\n", value, name));
61 			p.value.boolean = GF_FALSE;
62 		}
63 		break;
64 	case GF_PROP_SINT:
65 		if (value && !strcmp(value, "+I")) p.value.sint = GF_INT_MAX;
66 		else if (value && !strcmp(value, "-I")) p.value.sint = GF_INT_MIN;
67 		else if (!value || (sscanf(value, "%d", &p.value.sint)!=1)) {
68 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for int arg %s - using 0\n", value, name));
69 			p.value.sint = 0;
70 		} else if (unit) {
71 			p.value.sint *= unit;
72 		}
73 		break;
74 	case GF_PROP_UINT:
75 		if (value && !strcmp(value, "+I")) p.value.sint = 0xFFFFFFFF;
76 		else if (!value) {
77 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for unsigned int arg %s - using 0\n", value, name));
78 			p.value.uint = 0;
79 		} else if (enum_values && strchr(enum_values, '|')) {
80 			u32 a_len = (u32) strlen(value);
81 			u32 val = 0;
82 			char *str_start = (char *) enum_values;
83 			while (str_start) {
84 				u32 len;
85 				char *sep = strchr(str_start, '|');
86 				if (sep) {
87 					len = (u32) (sep - str_start);
88 				} else {
89 					len = (u32) strlen(str_start);
90 				}
91 				if ((a_len == len) && !strncmp(str_start, value, len))
92 					break;
93 				if (!sep) {
94 					str_start = NULL;
95 					break;
96 				}
97 				str_start = sep+1;
98 				val++;
99 			}
100 			if (!str_start) {
101 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for unsigned int arg %s enum %s - using 0\n", value, name, enum_values));
102 				p.value.uint = 0;
103 			} else {
104 				p.value.uint = val;
105 			}
106 		} else if (!strnicmp(value, "0x", 2)) {
107 			if (sscanf(value, "0x%x", &p.value.uint)!=1) {
108 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for unsigned int arg %s - using 0\n", value, name));
109 			} else if (unit) {
110 				p.value.uint *= unit;
111 			}
112 		} else if (sscanf(value, "%d", &p.value.uint)!=1) {
113 			if (strlen(value)==4) {
114 				p.value.uint = GF_4CC(value[0],value[1],value[2],value[3]);
115 			} else {
116 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for unsigned int arg %s - using 0\n", value, name));
117 			}
118 		} else if (unit) {
119 			p.value.uint *= unit;
120 		}
121 		break;
122 	case GF_PROP_LSINT:
123 		if (value && !strcmp(value, "+I")) p.value.longsint = 0x7FFFFFFFFFFFFFFFUL;
124 		else if (value && !strcmp(value, "-I")) p.value.longsint = 0x8000000000000000UL;
125 		else if (!value || (sscanf(value, ""LLD, &p.value.longsint)!=1) ) {
126 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for long int arg %s - using 0\n", value, name));
127 			p.value.uint = 0;
128 		} else if (unit) {
129 			p.value.longsint *= unit;
130 		}
131 		break;
132 	case GF_PROP_LUINT:
133 		if (value && !strcmp(value, "+I")) p.value.longuint = 0xFFFFFFFFFFFFFFFFUL;
134 		else if (!value || (sscanf(value, ""LLU, &p.value.longuint)!=1) ) {
135 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for long unsigned int arg %s - using 0\n", value, name));
136 			p.value.uint = 0;
137 		} else if (unit) {
138 			p.value.longuint *= unit;
139 		}
140 		break;
141 	case GF_PROP_FRACTION:
142 		if (!value) {
143 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for fraction arg %s - using 0/1\n", value, name));
144 			p.value.frac.num = 0;
145 			p.value.frac.den = 1;
146 		} else {
147 			if (sscanf(value, "%d/%u", &p.value.frac.num, &p.value.frac.den) != 2) {
148 				if (sscanf(value, "%d-%u", &p.value.frac.num, &p.value.frac.den) != 2) {
149 					u32 ret=0;
150 					p.value.frac.den=1;
151 					if (strchr(value, '.') || strchr(value, ',')) {
152 						Float v;
153 						ret = sscanf(value, "%g", &v);
154 						if (ret==1) {
155 							p.value.frac.num = (u32) (v*1000000);
156 							p.value.frac.den = 1000000;
157 						} else {
158 							ret = 0;
159 						}
160 					}
161 					if (!ret && (sscanf(value, "%d", &p.value.frac.num) != 1)) {
162 						GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for fraction arg %s - using 0/1\n", value, name));
163 						p.value.frac.num = 0;
164 						p.value.frac.den = 1;
165 					}
166 				}
167 			}
168 		}
169 		break;
170 	case GF_PROP_FRACTION64:
171 		if (!value) {
172 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for fraction arg %s - using 0/1\n", value, name));
173 			p.value.frac.num = 0;
174 			p.value.frac.den = 1;
175 		}
176 		else {
177 			if (sscanf(value, LLD"/"LLU, &p.value.lfrac.num, &p.value.lfrac.den) != 2) {
178 				if (sscanf(value, LLD"-"LLU, &p.value.lfrac.num, &p.value.lfrac.den) != 2) {
179 					u32 ret=0;
180 					p.value.lfrac.den = 1;
181 
182 					if (strchr(value, '.') || strchr(value, ',')) {
183 						Float v;
184 						ret = sscanf(value, "%g", &v);
185 						if (ret==1) {
186 							p.value.lfrac.num = (u64) (v*1000000);
187 							p.value.lfrac.den = 1000000;
188 						} else {
189 							ret = 0;
190 						}
191 					}
192 
193 					if (!ret && (sscanf(value, LLD, &p.value.lfrac.num) != 1)) {
194 						GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for fraction arg %s - using 0/1\n", value, name));
195 						p.value.lfrac.num = 0;
196 						p.value.lfrac.den = 1;
197 					}
198 				}
199 			}
200 		}
201 		break;
202 	case GF_PROP_FLOAT:
203 		if (value && !strcmp(value, "+I")) p.value.fnumber = FIX_MAX;
204 		else if (value && !strcmp(value, "-I")) p.value.fnumber = FIX_MIN;
205 		else if (!value) {
206 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for float arg %s - using 0\n", value, name));
207 			p.value.fnumber = 0;
208 		} else {
209 			Float f;
210 			if (sscanf(value, "%f", &f) != 1) {
211 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for float arg %s - using 0\n", value, name));
212 				p.value.fnumber = 0;
213 			} else {
214 				if (unit) f *= unit;
215 				p.value.fnumber = FLT2FIX(f);
216 			}
217 		}
218 		break;
219 	case GF_PROP_DOUBLE:
220 		if (value && !strcmp(value, "+I")) p.value.number = GF_MAX_DOUBLE;
221 		else if (value && !strcmp(value, "-I")) p.value.number = GF_MIN_DOUBLE;
222 		else if (!value || (sscanf(value, "%lg", &p.value.number) != 1) ) {
223 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for double arg %s - using 0\n", value, name));
224 			p.value.number = 0;
225 		} else if (unit) {
226 			p.value.number *= unit;
227 		}
228 		break;
229 	case GF_PROP_VEC2I:
230 		if (!value || (sscanf(value, "%dx%d", &p.value.vec2i.x, &p.value.vec2i.y) != 2)) {
231 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for vec2i arg %s - using {0,0}\n", value, name));
232 			p.value.vec2i.x = p.value.vec2i.y = 0;
233 		}
234 		break;
235 	case GF_PROP_VEC2:
236 		if (!value || (sscanf(value, "%lgx%lg", &p.value.vec2.x, &p.value.vec2.y) != 2)) {
237 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for vec2 arg %s - using {0,0}\n", value, name));
238 			p.value.vec2.x = p.value.vec2.y = 0;
239 		}
240 		break;
241 	case GF_PROP_VEC3I:
242 		if (!value || (sscanf(value, "%dx%dx%d", &p.value.vec3i.x, &p.value.vec3i.y, &p.value.vec3i.z) != 3)) {
243 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for vec3i arg %s - using {0,0,0}\n", value, name));
244 			p.value.vec3i.x = p.value.vec3i.y = p.value.vec3i.z = 0;
245 		}
246 		break;
247 	case GF_PROP_VEC3:
248 		if (!value || (sscanf(value, "%lgx%lgx%lg", &p.value.vec3.x, &p.value.vec3.y, &p.value.vec3.z) != 3)) {
249 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for vec3 arg %s - using {0,0,0}\n", value, name));
250 			p.value.vec3.x = p.value.vec3.y = p.value.vec3.z = 0;
251 		}
252 		break;
253 	case GF_PROP_VEC4I:
254 		if (!value || (sscanf(value, "%dx%dx%dx%d", &p.value.vec4i.x, &p.value.vec4i.y, &p.value.vec4i.z, &p.value.vec4i.w) != 4)) {
255 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for vec4i arg %s - using {0,0,0}\n", value, name));
256 			p.value.vec4i.x = p.value.vec4i.y = p.value.vec4i.z = p.value.vec4i.w = 0;
257 		}
258 		break;
259 	case GF_PROP_VEC4:
260 		if (!value || (sscanf(value, "%lgx%lgx%lgx%lg", &p.value.vec4.x, &p.value.vec4.y, &p.value.vec4.z, &p.value.vec4.w) != 4)) {
261 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for vec4 arg %s - using {0,0,0}\n", value, name));
262 			p.value.vec4.x = p.value.vec4.y = p.value.vec4.z = p.value.vec4.w = 0;
263 		}
264 		break;
265 	case GF_PROP_PIXFMT:
266 		p.value.uint = gf_pixel_fmt_parse(value);
267 		break;
268 	case GF_PROP_PCMFMT:
269 		p.value.uint = gf_audio_fmt_parse(value);
270 		break;
271 	case GF_PROP_NAME:
272 	case GF_PROP_STRING:
273 	case GF_PROP_STRING_NO_COPY:
274 		p.type=GF_PROP_STRING;
275 		if (value && !strnicmp(value, "file@", 5) ) {
276 			u8 *data;
277 			u32 len;
278 			GF_Err e = gf_file_load_data(value+5, (u8 **) &data, &len);
279 			if (e) {
280 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Cannot load data from file %s\n", value+5));
281 			} else {
282 				p.value.string = data;
283 			}
284 		} else if (value && !strnicmp(value, "bxml@", 5) ) {
285 			GF_Err e;
286 			GF_DOMParser *dom = gf_xml_dom_new();
287 			e = gf_xml_dom_parse(dom, value+5, NULL, NULL);
288 			if (e) {
289 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Cannot parse XML from file %s\n", value+5));
290 			} else {
291 				GF_XMLNode *root = gf_xml_dom_get_root_idx(dom, 0);
292 				//if no root, assume NULL
293 				if (root) {
294 					e = gf_xml_parse_bit_sequence(root, value+5, &p.value.data.ptr, &p.value.data.size);
295 				}
296 				if (e<0) {
297 					GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Failed to binarize XML file %s: %s\n", value+5, gf_error_to_string(e) ));
298 				} else {
299 					p.type=GF_PROP_DATA;
300 				}
301 			}
302 			gf_xml_dom_del(dom);
303 		} else {
304 			p.value.string = value ? gf_strdup(value) : NULL;
305 		}
306 		break;
307 	case GF_PROP_DATA:
308 	case GF_PROP_CONST_DATA:
309 	case GF_PROP_DATA_NO_COPY:
310 		if (!value) {
311 			p.value.data.ptr=NULL;
312 			p.value.data.size=0;
313 		} else if (sscanf(value, "%d@%p", &p.value.data.size,&p.value.data.ptr)==2) {
314 			p.type = GF_PROP_CONST_DATA;
315 		} else if (!strnicmp(value, "0x", 2) ) {
316 			u32 i;
317 			value += 2;
318 			p.value.data.size = (u32) strlen(value) / 2;
319 			p.value.data.ptr = gf_malloc(sizeof(char)*p.value.data.size);
320 			for (i=0; i<p.value.data.size; i++) {
321 				char szV[3];
322 				u32 res;
323 				szV[0] = value[2*i];
324 				szV[1] = value[2*i + 1];
325 				szV[2] = 0;
326 				sscanf(szV, "%x", &res);
327 				p.value.data.ptr[i] = res;
328 			}
329 		} else if (!strnicmp(value, "bxml@", 5) ) {
330 			GF_Err e;
331 			GF_DOMParser *dom = gf_xml_dom_new();
332 			e = gf_xml_dom_parse(dom, value+5, NULL, NULL);
333 			if (e) {
334 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Cannot parse XML from file %s\n", value+5));
335 			} else {
336 				GF_XMLNode *root = gf_xml_dom_get_root_idx(dom, 0);
337 				//if no root, assume NULL
338 				if (root) {
339 					e = gf_xml_parse_bit_sequence(root, value+5, &p.value.data.ptr, &p.value.data.size);
340 				}
341 				if (e<0) {
342 					GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Failed to binarize XML file %s: %s\n", value+5, gf_error_to_string(e) ));
343 				}
344 			}
345 			gf_xml_dom_del(dom);
346 		} else if (!strnicmp(value, "file@", 5) ) {
347 			GF_Err e = gf_file_load_data(value+5, (u8 **) &p.value.data.ptr, &p.value.data.size);
348 			if (e) {
349 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Cannot load data from file %s\n", value+5));
350 				p.value.data.ptr=NULL;
351 				p.value.data.size=0;
352 			}
353 		} else {
354 			p.value.data.size = (u32) strlen(value);
355 			if (p.value.data.size)
356 				p.value.data.ptr = gf_strdup(value);
357 			else
358 				p.value.data.ptr = NULL;
359 			p.type = GF_PROP_DATA;
360 		}
361 		break;
362 	case GF_PROP_POINTER:
363 		if (!value || (sscanf(value, "%p", &p.value.ptr) != 1) ) {
364 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %s for pointer arg %s - using 0\n", value, name));
365 		}
366 		break;
367 	case GF_PROP_STRING_LIST:
368 	{
369 		Bool is_xml = GF_FALSE;
370 		p.value.string_list = gf_list_new();
371 		char *v = (char *) value;
372 		if (v && v[0]=='<') is_xml = GF_TRUE;
373 		if (!list_sep_char) list_sep_char = ',';
374 		while (v) {
375 			u32 len=0;
376 			char *nv;
377 			char *sep = strchr(v, list_sep_char);
378 			if (sep && is_xml) {
379 				char *xml_end = strchr(v, '>');
380 				len = (u32) (sep - v);
381 				if (xml_end) {
382 					u32 xml_len = (u32) (xml_end - v);
383 					if (xml_len > len) {
384 						sep = strchr(xml_end, list_sep_char);
385 						//assigned below
386 //						if (sep)
387 //							len = (u32) (sep - v);
388 					}
389 				}
390 			}
391 			if (!sep)
392 			 	len = (u32) strlen(v);
393 			else
394 				len = (u32) (sep - v);
395 
396 			nv = gf_malloc(sizeof(char)*(len+1));
397 			strncpy(nv, v, sizeof(char)*len);
398 			nv[len] = 0;
399 			if (!strnicmp(nv, "file@", 5) ) {
400 				u8 *data;
401 				u32 flen;
402 				GF_Err e = gf_file_load_data(nv+5, (u8 **) &data, &flen);
403 				if (e) {
404 					GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Cannot load data from file %s\n", nv+5));
405 				} else {
406 					gf_list_add(p.value.string_list, data);
407 				}
408 				gf_free(nv);
409 			} else {
410 				gf_list_add(p.value.string_list, nv);
411 			}
412 			if (!sep) break;
413 			v = sep+1;
414 		}
415 	}
416 		break;
417 	case GF_PROP_UINT_LIST:
418 	{
419 		char *v = (char *) value;
420 		if (!list_sep_char) list_sep_char = ',';
421 		while (v && v[0]) {
422 			char szV[100];
423 			u32 val_uint=0, len=0;
424 			char *sep = strchr(v, list_sep_char);
425 			if (sep) {
426 				len = (u32) (sep - v);
427 			}
428 			if (!sep)
429 			 	len = (u32) strlen(v);
430 			if (len>=99) len=99;
431 			strncpy(szV, v, len);
432 			szV[len] = 0;
433 			sscanf(szV, "%u", &val_uint);
434 			p.value.uint_list.vals = gf_realloc(p.value.uint_list.vals, (p.value.uint_list.nb_items+1) * sizeof(u32));
435 			p.value.uint_list.vals[p.value.uint_list.nb_items] = val_uint;
436 			p.value.uint_list.nb_items++;
437 			if (!sep) break;
438 			v = sep+1;
439 		}
440 	}
441 		break;
442 	case GF_PROP_FORBIDEN:
443 	default:
444 		GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Forbidden property type %d for arg %s - ignoring\n", type, name));
445 		p.type=GF_PROP_FORBIDEN;
446 		break;
447 	}
448 //	if (unit_sep) unit_sep[0] = unit_char;
449 
450 	return p;
451 }
452 
gf_props_equal(const GF_PropertyValue * p1,const GF_PropertyValue * p2)453 Bool gf_props_equal(const GF_PropertyValue *p1, const GF_PropertyValue *p2)
454 {
455 	if (p1->type!=p2->type) {
456 		if ((p1->type == GF_PROP_STRING) && (p2->type == GF_PROP_NAME) ) {
457 		} else if ((p2->type == GF_PROP_STRING) && (p1->type == GF_PROP_NAME) ) {
458 		} else {
459 			return GF_FALSE;
460 		}
461 	}
462 
463 	switch (p1->type) {
464 	case GF_PROP_SINT: return (p1->value.sint==p2->value.sint) ? GF_TRUE : GF_FALSE;
465 	case GF_PROP_PIXFMT:
466 	case GF_PROP_PCMFMT:
467 	case GF_PROP_UINT:
468 	 	return (p1->value.uint==p2->value.uint) ? GF_TRUE : GF_FALSE;
469 	case GF_PROP_LSINT: return (p1->value.longsint==p2->value.longsint) ? GF_TRUE : GF_FALSE;
470 	case GF_PROP_LUINT: return (p1->value.longuint==p2->value.longuint) ? GF_TRUE : GF_FALSE;
471 	case GF_PROP_BOOL: return (p1->value.boolean==p2->value.boolean) ? GF_TRUE : GF_FALSE;
472 	case GF_PROP_FRACTION:
473 		return ((s64)p1->value.frac.num * (s64)p2->value.frac.den == (s64)p2->value.frac.num * (s64)p1->value.frac.den) ? GF_TRUE : GF_FALSE;
474 	case GF_PROP_FRACTION64:
475 		return ((s64)p1->value.lfrac.num * (s64)p2->value.lfrac.den == (s64)p2->value.lfrac.num * (s64)p1->value.lfrac.den) ? GF_TRUE : GF_FALSE;
476 
477 	case GF_PROP_FLOAT: return (p1->value.fnumber==p2->value.fnumber) ? GF_TRUE : GF_FALSE;
478 	case GF_PROP_DOUBLE: return (p1->value.number==p2->value.number) ? GF_TRUE : GF_FALSE;
479 	case GF_PROP_VEC2I:
480 		return ((p1->value.vec2i.x==p2->value.vec2i.x) && (p1->value.vec2i.y==p2->value.vec2i.y)) ? GF_TRUE : GF_FALSE;
481 	case GF_PROP_VEC2:
482 		return ((p1->value.vec2.x==p2->value.vec2.x) && (p1->value.vec2.y==p2->value.vec2.y)) ? GF_TRUE : GF_FALSE;
483 	case GF_PROP_VEC3I:
484 		return ((p1->value.vec3i.x==p2->value.vec3i.x) && (p1->value.vec3i.y==p2->value.vec3i.y) && (p1->value.vec3i.z==p2->value.vec3i.z)) ? GF_TRUE : GF_FALSE;
485 	case GF_PROP_VEC3:
486 		return ((p1->value.vec3.x==p2->value.vec3.x) && (p1->value.vec3.y==p2->value.vec3.y) && (p1->value.vec3.z==p2->value.vec3.z)) ? GF_TRUE : GF_FALSE;
487 	case GF_PROP_VEC4I:
488 		return ((p1->value.vec4i.x==p2->value.vec4i.x) && (p1->value.vec4i.y==p2->value.vec4i.y) && (p1->value.vec4i.z==p2->value.vec4i.z) && (p1->value.vec4i.w==p2->value.vec4i.w)) ? GF_TRUE : GF_FALSE;
489 	case GF_PROP_VEC4:
490 		return ((p1->value.vec4.x==p2->value.vec4.x) && (p1->value.vec4.y==p2->value.vec4.y) && (p1->value.vec4.z==p2->value.vec4.z) && (p1->value.vec4.w==p2->value.vec4.w)) ? GF_TRUE : GF_FALSE;
491 
492 
493 	case GF_PROP_STRING:
494 	case GF_PROP_NAME:
495 		if (!p1->value.string) return p2->value.string ? GF_FALSE : GF_TRUE;
496 		if (!p2->value.string) return GF_FALSE;
497 		if (!strcmp(p1->value.string, "*")) return GF_TRUE;
498 		if (!strcmp(p2->value.string, "*")) return GF_TRUE;
499 		if (strchr(p2->value.string, '|')) {
500 			u32 len = (u32) strlen(p1->value.string);
501 			char *cur = p2->value.string;
502 
503 			while (cur) {
504 				if (!strncmp(p1->value.string, cur, len) && (cur[len]=='|' || !cur[len]))
505 					return GF_TRUE;
506 				cur = strchr(cur, '|');
507 				if (cur) cur++;
508 			}
509 			return GF_FALSE;
510 		}
511 		if (strchr(p1->value.string, '|')) {
512 			u32 len = (u32) strlen(p2->value.string);
513 			char *cur = p1->value.string;
514 
515 			while (cur) {
516 				if (!strncmp(p2->value.string, cur, len) && (cur[len]=='|' || !cur[len]))
517 					return GF_TRUE;
518 				cur = strchr(cur, '|');
519 				if (cur) cur++;
520 			}
521 			return GF_FALSE;
522 		}
523 		assert(strchr(p1->value.string, '|')==NULL);
524 		return !strcmp(p1->value.string, p2->value.string) ? GF_TRUE : GF_FALSE;
525 
526 	case GF_PROP_DATA:
527 	case GF_PROP_CONST_DATA:
528 		if (!p1->value.data.ptr) return p2->value.data.ptr ? GF_FALSE : GF_TRUE;
529 		if (!p2->value.data.ptr) return GF_FALSE;
530 		if (p1->value.data.size != p2->value.data.size) return GF_FALSE;
531 		return !memcmp(p1->value.data.ptr, p2->value.data.ptr, p1->value.data.size) ? GF_TRUE : GF_FALSE;
532 
533 	case GF_PROP_STRING_LIST:
534 	{
535 		u32 c1, c2, i, j;
536 		c1 = gf_list_count(p1->value.string_list);
537 		c2 = gf_list_count(p2->value.string_list);
538 		if (c1 != c2) return GF_FALSE;
539 		for (i=0; i<c1; i++) {
540 			u32 found = 0;
541 			char *s1 = gf_list_get(p1->value.string_list, i);
542 			for (j=0; j<c2; j++) {
543 				char *s2 = gf_list_get(p2->value.string_list, j);
544 				if (s1 && s2 && !strcmp(s1, s2)) found++;
545 			}
546 			if (found!=1) return GF_FALSE;
547 		}
548 		return GF_TRUE;
549 	}
550 	case GF_PROP_UINT_LIST:
551 	{
552 		u32 i;
553 		if (p1->value.uint_list.nb_items != p2->value.uint_list.nb_items) return GF_FALSE;
554 		for (i=0; i<p1->value.uint_list.nb_items; i++) {
555 			if (p1->value.uint_list.vals[i] != p2->value.uint_list.vals[i]) return GF_FALSE;
556 		}
557 		return GF_TRUE;
558 	}
559 
560 	//user-managed pointer
561 	case GF_PROP_POINTER: return (p1->value.ptr==p2->value.ptr) ? GF_TRUE : GF_FALSE;
562 	default:
563 		GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Comparing forbidden property type %d\n", p1->type));
564 		break;
565 	}
566 	return GF_FALSE;
567 }
568 
569 #if GF_PROPS_HASHTABLE_SIZE
gf_props_hash_djb2(u32 p4cc,const char * str)570 GFINLINE u32 gf_props_hash_djb2(u32 p4cc, const char *str)
571 {
572 	u32 hash = 5381;
573 
574 	if (p4cc) {
575 		hash = ((hash << 5) + hash) + ((p4cc>>24)&0xFF);
576 		hash = ((hash << 5) + hash) + ((p4cc>>16)&0xFF);
577 		hash = ((hash << 5) + hash) + ((p4cc>>8)&0xFF);
578 		hash = ((hash << 5) + hash) + (p4cc&0xFF);
579 	} else {
580 		int c;
581 		while ( (c = *str++) )
582 			hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
583 
584 	}
585 	return (hash % GF_PROPS_HASHTABLE_SIZE);
586 }
587 #endif
588 
gf_props_new(GF_Filter * filter)589 GF_PropertyMap * gf_props_new(GF_Filter *filter)
590 {
591 	GF_PropertyMap *map;
592 
593 	map = gf_fq_pop(filter->session->prop_maps_reservoir);
594 
595 	if (!map) {
596 		GF_SAFEALLOC(map, GF_PropertyMap);
597 		if (!map) return NULL;
598 
599 		map->session = filter->session;
600 #if GF_PROPS_HASHTABLE_SIZE
601 #else
602 		map->properties = gf_list_new();
603 #endif
604 	}
605 	assert(!map->reference_count);
606 	map->reference_count = 1;
607 	return map;
608 }
609 
gf_props_reset_single(GF_PropertyValue * p)610 void gf_props_reset_single(GF_PropertyValue *p)
611 {
612 	if (p->type==GF_PROP_STRING) {
613 		gf_free(p->value.string);
614 		p->value.string = NULL;
615 	}
616 	else if (p->type==GF_PROP_DATA) {
617 		gf_free(p->value.data.ptr);
618 		p->value.data.ptr = NULL;
619 		p->value.data.size = 0;
620 	}
621 	else if (p->type==GF_PROP_UINT_LIST) {
622 		gf_free(p->value.uint_list.vals);
623 		p->value.uint_list.vals = NULL;
624 		p->value.uint_list.nb_items = 0;
625 	}
626 	else if (p->type==GF_PROP_STRING_LIST) {
627 		while (gf_list_count(p->value.string_list)) {
628 			char *str = gf_list_pop_back(p->value.string_list);
629 			gf_free(str);
630 		}
631 		gf_list_del(p->value.string_list);
632 		p->value.string_list = NULL;
633 	}
634 }
gf_props_del_property(GF_PropertyEntry * it)635 void gf_props_del_property(GF_PropertyEntry *it)
636 {
637 	assert(it->reference_count);
638 	if (safe_int_dec(&it->reference_count) == 0 ) {
639 		if (it->pname && it->name_alloc)
640 			gf_free(it->pname);
641 
642 		it->name_alloc = GF_FALSE;
643 
644 		if (it->prop.type==GF_PROP_STRING) {
645 			gf_free(it->prop.value.string);
646 			it->prop.value.string = NULL;
647 		}
648 		else if (it->prop.type==GF_PROP_DATA) {
649 			assert(it->alloc_size);
650 			//DATA props are collected at session level for future reuse
651 		}
652 		//string list are destroyed
653 		else if (it->prop.type==GF_PROP_STRING_LIST) {
654 			GF_List *l = it->prop.value.string_list;
655 			it->prop.value.string_list = NULL;
656 			while (gf_list_count(l)) {
657 				char *s = gf_list_pop_back(l);
658 				gf_free(s);
659 			}
660 			gf_list_del(l);
661 		}
662 		//string list are destroyed
663 		else if (it->prop.type==GF_PROP_UINT_LIST) {
664 			if (it->prop.value.uint_list.vals)
665 				gf_free(it->prop.value.uint_list.vals);
666 			it->prop.value.uint_list.nb_items = 0;
667 			it->prop.value.uint_list.vals = NULL;
668 		}
669 		it->prop.value.data.size = 0;
670 		if (it->alloc_size) {
671 			assert(it->prop.type==GF_PROP_DATA);
672 			if (it->session->prop_maps_entry_data_alloc_reservoir) {
673 				gf_fq_add(it->session->prop_maps_entry_data_alloc_reservoir, it);
674 			} else {
675 				if (it->prop.value.data.ptr) gf_free(it->prop.value.data.ptr);
676 				gf_free(it);
677 			}
678 		} else {
679 			if (it->session->prop_maps_entry_reservoir) {
680 				gf_fq_add(it->session->prop_maps_entry_reservoir, it);
681 			} else {
682 				gf_free(it);
683 			}
684 		}
685 	}
686 }
687 
gf_propmap_del(void * pmap)688 void gf_propmap_del(void *pmap)
689 {
690 #if GF_PROPS_HASHTABLE_SIZE
691 	gf_free(pamp);
692 #else
693 	GF_PropertyMap *map = pmap;
694 	gf_list_del(map->properties);
695 	gf_free(map);
696 #endif
697 
698 }
gf_props_reset(GF_PropertyMap * prop)699 void gf_props_reset(GF_PropertyMap *prop)
700 {
701 #if GF_PROPS_HASHTABLE_SIZE
702 	u32 i;
703 	for (i=0; i<GF_PROPS_HASHTABLE_SIZE; i++) {
704 		if (prop->hash_table[i]) {
705 			GF_List *l = prop->hash_table[i];
706 			while (gf_list_count(l)) {
707 				gf_props_del_property((GF_PropertyEntry *) gf_list_pop_back(l) );
708 			}
709 			prop->hash_table[i] = NULL;
710 			if (prop->session->prop_maps_list_reservoir) {
711 				gf_fq_add(prop->session->prop_maps_list_reservoir, l);
712 			} else {
713 				gf_list_del(l);
714 			}
715 		}
716 	}
717 #else
718 	while (gf_list_count(prop->properties)) {
719 		gf_props_del_property( (GF_PropertyEntry *) gf_list_pop_back(prop->properties) );
720 	}
721 #endif
722 }
723 
gf_props_del(GF_PropertyMap * map)724 void gf_props_del(GF_PropertyMap *map)
725 {
726 	assert(!map->pckrefs_reference_count || !map->reference_count);
727 	//we still have a ref
728 	if (map->pckrefs_reference_count || map->reference_count) return;
729 
730 	gf_props_reset(map);
731 	map->reference_count = 0;
732 	if (map->session->prop_maps_reservoir) {
733 		gf_fq_add(map->session->prop_maps_reservoir, map);
734 	} else {
735 		gf_list_del(map->properties);
736 		gf_free(map);
737 	}
738 }
739 
740 
741 
742 //purge existing property of same name
gf_props_remove_property(GF_PropertyMap * map,u32 hash,u32 p4cc,const char * name)743 void gf_props_remove_property(GF_PropertyMap *map, u32 hash, u32 p4cc, const char *name)
744 {
745 #if GF_PROPS_HASHTABLE_SIZE
746 	if (map->hash_table[hash]) {
747 		u32 i, count = gf_list_count(map->hash_table[hash]);
748 		for (i=0; i<count; i++) {
749 			GF_PropertyEntry *prop = gf_list_get(map->hash_table[hash], i);
750 			if ((p4cc && (p4cc==prop->p4cc)) || (name && prop->pname && !strcmp(prop->pname, name)) ) {
751 				gf_list_rem(map->hash_table[hash], i);
752 				gf_props_del_property(prop);
753 				break;
754 			}
755 		}
756 	}
757 #else
758 	u32 i, count = gf_list_count(map->properties);
759 	for (i=0; i<count; i++) {
760 		GF_PropertyEntry *prop = gf_list_get(map->properties, i);
761 		if ((p4cc && (p4cc==prop->p4cc)) || (name && prop->pname && !strcmp(prop->pname, name)) ) {
762 			gf_list_rem(map->properties, i);
763 			gf_props_del_property(prop);
764 			break;
765 		}
766 	}
767 #endif
768 }
769 
770 
771 #if GF_PROPS_HASHTABLE_SIZE
gf_props_get_list(GF_PropertyMap * map)772 GF_List *gf_props_get_list(GF_PropertyMap *map)
773 {
774 	GF_List *l;
775 
776 	l = gf_fq_pop(map->session->prop_maps_list_reservoir);
777 
778 	if (!l) l = gf_list_new();
779 	return l;
780 }
781 #endif
782 
gf_props_assign_value(GF_PropertyEntry * prop,const GF_PropertyValue * value,Bool is_old_prop)783 static void gf_props_assign_value(GF_PropertyEntry *prop, const GF_PropertyValue *value, Bool is_old_prop)
784 {
785 	char *src_ptr;
786 	//remember source pointer
787 	src_ptr = prop->prop.value.data.ptr;
788 
789 	if (is_old_prop) {
790 		gf_props_reset_single(&prop->prop);
791 	}
792 
793 	//copy prop value
794 	memcpy(&prop->prop, value, sizeof(GF_PropertyValue));
795 
796 	if (prop->prop.type == GF_PROP_STRING) {
797 		prop->prop.value.string = value->value.string ? gf_strdup(value->value.string) : NULL;
798 	} else if (prop->prop.type == GF_PROP_STRING_NO_COPY) {
799 		prop->prop.value.string = value->value.string;
800 		prop->prop.type = GF_PROP_STRING;
801 	} else if (prop->prop.type == GF_PROP_DATA) {
802 		//restore source pointer, realloc if needed
803 		prop->prop.value.data.ptr = src_ptr;
804 		if (prop->alloc_size < value->value.data.size) {
805 			prop->alloc_size = value->value.data.size;
806 			prop->prop.value.data.ptr = gf_realloc(prop->prop.value.data.ptr, sizeof(char) * value->value.data.size);
807 			assert(prop->alloc_size);
808 		}
809 		memcpy(prop->prop.value.data.ptr, value->value.data.ptr, value->value.data.size);
810 	} else if (prop->prop.type == GF_PROP_DATA_NO_COPY) {
811 		prop->prop.type = GF_PROP_DATA;
812 		prop->alloc_size = value->value.data.size;
813 		assert(prop->alloc_size);
814 	}
815 	else if (prop->prop.type == GF_PROP_UINT_LIST) {
816 		prop->prop.value.uint_list.vals = gf_malloc(sizeof(u32) * value->value.uint_list.nb_items);
817 		memcpy(prop->prop.value.uint_list.vals, value->value.uint_list.vals, sizeof(u32) * value->value.uint_list.nb_items);
818 		prop->prop.value.uint_list.nb_items = value->value.uint_list.nb_items;
819 	}
820 }
821 
gf_props_insert_property(GF_PropertyMap * map,u32 hash,u32 p4cc,const char * name,char * dyn_name,const GF_PropertyValue * value)822 GF_Err gf_props_insert_property(GF_PropertyMap *map, u32 hash, u32 p4cc, const char *name, char *dyn_name, const GF_PropertyValue *value)
823 {
824 	GF_PropertyEntry *prop;
825 #if GF_PROPS_HASHTABLE_SIZE
826 	u32 i, count;
827 #endif
828 	if ((value->type == GF_PROP_DATA) || (value->type == GF_PROP_DATA_NO_COPY)) {
829 		if (!value->value.data.ptr) {
830 			GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Attempt at defining data property %s with NULL pointer, not allowed\n", p4cc ? gf_4cc_to_str(p4cc) : name ? name : dyn_name ));
831 			return GF_BAD_PARAM;
832 		}
833 	}
834 #if GF_PROPS_HASHTABLE_SIZE
835 	if (! map->hash_table[hash] ) {
836 		map->hash_table[hash] = gf_props_get_list(map);
837 		if (!map->hash_table[hash]) return GF_OUT_OF_MEM;
838 	} else {
839 		count = gf_list_count(map->hash_table[hash]);
840 		if (count) {
841 			GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("PropertyMap hash collision for %s - %d entries before insertion:\n", p4cc ? gf_4cc_to_str(p4cc) : name ? name : dyn_name, gf_list_count(map->hash_table[hash]) ));
842 			for (i=0; i<count; i++) {
843 				GF_PropertyEntry *prop_c = gf_list_get(map->hash_table[hash], i);
844 				GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("\t%s\n\n", prop_c->pname ? prop_c->pname : gf_4cc_to_str(prop_c->p4cc)  ));
845 				assert(!prop_c->p4cc || (prop_c->p4cc != p4cc));
846 			}
847 		}
848 	}
849 #endif
850 	if ((value->type == GF_PROP_DATA) && value->value.data.ptr) {
851 		prop = gf_fq_pop(map->session->prop_maps_entry_data_alloc_reservoir);
852 	} else {
853 		prop = gf_fq_pop(map->session->prop_maps_entry_reservoir);
854 	}
855 
856 	if (!prop) {
857 		GF_SAFEALLOC(prop, GF_PropertyEntry);
858 		if (!prop) return GF_OUT_OF_MEM;
859 		prop->session = map->session;
860 	}
861 
862 	prop->reference_count = 1;
863 	prop->p4cc = p4cc;
864 	prop->pname = (char *) name;
865 	if (dyn_name) {
866 		prop->pname = gf_strdup(dyn_name);
867 		prop->name_alloc=GF_TRUE;
868 	}
869 
870 	gf_props_assign_value(prop, value, GF_FALSE);
871 
872 #if GF_PROPS_HASHTABLE_SIZE
873 	return gf_list_add(map->hash_table[hash], prop);
874 #else
875 	return gf_list_add(map->properties, prop);
876 #endif
877 
878 }
879 
gf_props_set_property(GF_PropertyMap * map,u32 p4cc,const char * name,char * dyn_name,const GF_PropertyValue * value)880 GF_Err gf_props_set_property(GF_PropertyMap *map, u32 p4cc, const char *name, char *dyn_name, const GF_PropertyValue *value)
881 {
882 	GF_Err e;
883 	u32 hash = gf_props_hash_djb2(p4cc, name ? name : dyn_name);
884 	gf_mx_p(map->session->info_mx);
885 	gf_props_remove_property(map, hash, p4cc, name ? name : dyn_name);
886 	if (!value)
887 		e = GF_OK;
888 	else
889 		e = gf_props_insert_property(map, hash, p4cc, name, dyn_name, value);
890 	gf_mx_v(map->session->info_mx);
891 	return e;
892 }
893 
gf_props_get_property_entry(GF_PropertyMap * map,u32 prop_4cc,const char * name)894 const GF_PropertyEntry *gf_props_get_property_entry(GF_PropertyMap *map, u32 prop_4cc, const char *name)
895 {
896 	u32 i, count;
897 	const GF_PropertyEntry *res=NULL;
898 #if GF_PROPS_HASHTABLE_SIZE
899 	u32 hash = gf_props_hash_djb2(prop_4cc, name);
900 	if (map->hash_table[hash] ) {
901 		count = gf_list_count(map->hash_table[hash]);
902 		for (i=0; i<count; i++) {
903 			GF_PropertyEntry *p = gf_list_get(map->hash_table[hash], i);
904 
905 			if ((prop_4cc && (p->p4cc==prop_4cc)) || (p->pname && name && !strcmp(p->pname, name)) ) {
906 				res = p;
907 				break;
908 			}
909 		}
910 	}
911 #else
912 	count = gf_list_count(map->properties);
913 	for (i=0; i<count; i++) {
914 		GF_PropertyEntry *p = gf_list_get(map->properties, i);
915 		if (!p) {
916 			GF_LOG(GF_LOG_WARNING, GF_LOG_FILTER, ("Concurrent read/write access to property map, cannot query property now\n"));
917 			return NULL;
918 		}
919 
920 		if ((prop_4cc && (p->p4cc==prop_4cc)) || (p->pname && name && !strcmp(p->pname, name)) ) {
921 			res = p;
922 			break;
923 		}
924 	}
925 #endif
926 	return res;
927 }
928 
gf_props_get_property(GF_PropertyMap * map,u32 prop_4cc,const char * name)929 const GF_PropertyValue *gf_props_get_property(GF_PropertyMap *map, u32 prop_4cc, const char *name)
930 {
931 	const GF_PropertyEntry *ent = gf_props_get_property_entry(map, prop_4cc, name);
932 	if (ent) return &ent->prop;
933 	return NULL;
934 }
935 
gf_props_merge_property(GF_PropertyMap * dst_props,GF_PropertyMap * src_props,gf_filter_prop_filter filter_prop,void * cbk)936 GF_Err gf_props_merge_property(GF_PropertyMap *dst_props, GF_PropertyMap *src_props, gf_filter_prop_filter filter_prop, void *cbk)
937 {
938 	GF_Err e;
939 	u32 i, count;
940 #if GF_PROPS_HASHTABLE_SIZE
941 	u32 idx;
942 #endif
943 	GF_List *list;
944 	dst_props->timescale = src_props->timescale;
945 
946 #if GF_PROPS_HASHTABLE_SIZE
947 	for (idx=0; idx<GF_PROPS_HASHTABLE_SIZE; idx++) {
948 		if (src_props->hash_table[idx]) {
949 			list = src_props->hash_table[idx];
950 #else
951 			list = src_props->properties;
952 #endif
953 			count = gf_list_count(list);
954 			for (i=0; i<count; i++) {
955 				GF_PropertyEntry *prop = gf_list_get(list, i);
956 				assert(prop->reference_count);
957 				if (!filter_prop || filter_prop(cbk, prop->p4cc, prop->pname, &prop->prop)) {
958 					safe_int_inc(&prop->reference_count);
959 
960 #if GF_PROPS_HASHTABLE_SIZE
961 					if (!dst_props->hash_table[idx]) {
962 						dst_props->hash_table[idx] = gf_props_get_list(dst_props);
963 						if (!dst_props->hash_table[idx]) return GF_OUT_OF_MEM;
964 					}
965 					e = gf_list_add(dst_props->hash_table[idx], prop);
966 					if (e) return e;
967 #else
968 					e = gf_list_add(dst_props->properties, prop);
969 					if (e) return e;
970 #endif
971 				}
972 			}
973 #if GF_PROPS_HASHTABLE_SIZE
974 		}
975 	}
976 #endif
977 	return GF_OK;
978 }
979 
gf_props_enum_property(GF_PropertyMap * props,u32 * io_idx,u32 * prop_4cc,const char ** prop_name)980 const GF_PropertyValue *gf_props_enum_property(GF_PropertyMap *props, u32 *io_idx, u32 *prop_4cc, const char **prop_name)
981 {
982 #if GF_PROPS_HASHTABLE_SIZE
983 	u32 i, nb_items = 0;
984 #endif
985 	u32 idx, count;
986 
987 	const GF_PropertyEntry *pe;
988 	if (!io_idx) return NULL;
989 
990 	idx = *io_idx;
991 	if (idx == 0xFFFFFFFF) return NULL;
992 
993 #if GF_PROPS_HASHTABLE_SIZE
994 	for (i=0; i<GF_PROPS_HASHTABLE_SIZE; i++) {
995 		if (props->hash_table[i]) {
996 			count = gf_list_count(props->hash_table[i]);
997 			nb_items+=count;
998 			if (idx >= count) {
999 				idx -= count;
1000 				continue;
1001 			}
1002 			pe = gf_list_get(props->hash_table[i], idx);
1003 			if (!pe) {
1004 				*io_idx = nb_items;
1005 				return NULL;
1006 			}
1007 			if (prop_4cc) *prop_4cc = pe->p4cc;
1008 			if (prop_name) *prop_name = pe->pname;
1009 			*io_idx = (*io_idx) + 1;
1010 			return &pe->prop;
1011 		}
1012 	}
1013 	*io_idx = nb_items;
1014 	return NULL;
1015 #else
1016 	count = gf_list_count(props->properties);
1017 	if (idx >= count) {
1018 		*io_idx = count;
1019 		return NULL;
1020 	}
1021 	pe = gf_list_get(props->properties, idx);
1022 	if (!pe) {
1023 		*io_idx = count;
1024 		return NULL;
1025 	}
1026 	if (prop_4cc) *prop_4cc = pe->p4cc;
1027 	if (prop_name) *prop_name = pe->pname;
1028 	*io_idx = (*io_idx) + 1;
1029 	return &pe->prop;
1030 #endif
1031 }
1032 
1033 typedef struct
1034 {
1035 	GF_PropType type;
1036 	const char *name;
1037 	const char *desc;
1038 } GF_PropTypeDef;
1039 
1040 GF_PropTypeDef PropTypes[] =
1041 {
1042 	{GF_PROP_SINT, "sint", "signed 32 bit integer"},
1043 	{GF_PROP_UINT, "uint", "unsigned 32 bit integer"},
1044 	{GF_PROP_LSINT, "lsint", "signed 64 bit integer"},
1045 	{GF_PROP_LUINT, "luint", "unsigned 32 bit integer"},
1046 	{GF_PROP_FRACTION, "frac", "32/32 bit fraction"},
1047 	{GF_PROP_FRACTION64, "lfrac", "64/64 bit fraction"},
1048 	{GF_PROP_BOOL, "bool", "boolean"},
1049 	{GF_PROP_FLOAT, "flt", "32 bit float number"},
1050 	{GF_PROP_DOUBLE, "dbl", "64 bit float number"},
1051 	{GF_PROP_NAME, "cstr", "const UTF-8 string"},
1052 	{GF_PROP_STRING, "str", "UTF-8 string"},
1053 	{GF_PROP_STRING_NO_COPY, "str", "UTF-8 string"},
1054 	{GF_PROP_DATA, "mem", "data buffer"},
1055 	{GF_PROP_DATA_NO_COPY, "mem", "data buffer"},
1056 	{GF_PROP_CONST_DATA, "cmem", "const data buffer"},
1057 	{GF_PROP_POINTER, "ptr", "32 or 64 bit pointer"},
1058 	{GF_PROP_VEC2I, "v2di", "2D 32-bit integer vector"},
1059 	{GF_PROP_VEC2, "v2df", "2D 32-bit float vector"},
1060 	{GF_PROP_VEC3I, "v3di", "3D 32-bit integer vector"},
1061 	{GF_PROP_VEC3, "v3df", "3D 32-bit float vector"},
1062 	{GF_PROP_VEC4I, "v4di", "4D 32-bit integer vector"},
1063 	{GF_PROP_VEC4, "v4df", "4D 32-bit float vector"},
1064 	{GF_PROP_PIXFMT, "pfmt", "raw pixel format"},
1065 	{GF_PROP_PCMFMT, "afmt", "raw audio format"},
1066 	{GF_PROP_STRING_LIST, "strl", "UTF-8 string list"},
1067 	{GF_PROP_UINT_LIST, "uintl", "unsigned 32 bit integer list"}
1068 };
1069 
1070 GF_EXPORT
gf_props_get_type_name(GF_PropType type)1071 const char *gf_props_get_type_name(GF_PropType type)
1072 {
1073 	u32 i, nb_props = sizeof(PropTypes) / sizeof(GF_PropTypeDef);
1074 	for (i=0; i<nb_props; i++) {
1075 		if (PropTypes[i].type == type) return PropTypes[i].name;
1076 	}
1077 	GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Unknown property type %d\n", type));
1078 	return "Undefined";
1079 }
1080 
1081 GF_EXPORT
gf_props_get_type_desc(GF_PropType type)1082 const char *gf_props_get_type_desc(GF_PropType type)
1083 {
1084 	u32 i, nb_props = sizeof(PropTypes) / sizeof(GF_PropTypeDef);
1085 	for (i=0; i<nb_props; i++) {
1086 		if (PropTypes[i].type == type) return PropTypes[i].desc;
1087 	}
1088 	GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Unknown property type %d\n", type));
1089 	return "Undefined";
1090 }
1091 
1092 GF_EXPORT
gf_props_parse_type(const char * name)1093 GF_PropType gf_props_parse_type(const char *name)
1094 {
1095 	u32 i, nb_props = sizeof(PropTypes) / sizeof(GF_PropTypeDef);
1096 	for (i=0; i<nb_props; i++) {
1097 		if (!strcmp(PropTypes[i].name, name)) return PropTypes[i].type;
1098 	}
1099 	GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Unknown property type %s\n", name));
1100 	return GF_PROP_FORBIDEN;
1101 }
1102 
1103 GF_BuiltInProperty GF_BuiltInProps [] =
1104 {
1105 	{ GF_PROP_PID_ID, "ID", "Stream ID", GF_PROP_UINT},
1106 	{ GF_PROP_PID_ESID, "ESID", "MPEG-4 ESID of pid", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1107 	{ GF_PROP_PID_ITEM_ID, "ItemID", "ID of image item in HEIF, same value as ID", GF_PROP_UINT},
1108 	{ GF_PROP_PID_SERVICE_ID, "ServiceID", "ID of parent service", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1109 	{ GF_PROP_PID_CLOCK_ID, "ClockID", "ID of clock reference pid", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1110 	{ GF_PROP_PID_DEPENDENCY_ID, "DependencyID", "ID of layer dependended on", GF_PROP_UINT},
1111 	{ GF_PROP_PID_SUBLAYER, "SubLayer", "pid is a sublayer of the stream depended on rather than an enhancement layer", GF_PROP_BOOL},
1112 	{ GF_PROP_PID_PLAYBACK_MODE, "PlaybackMode", "Playback mode supported:\n- 0: no time control\n- 1: play/pause/seek,speed=1\n- 2: play/pause/seek,speed>=0\n- 3: play/pause/seek, reverse playback", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1113 	{ GF_PROP_PID_SCALABLE, "Scalable", "Scalable stream", GF_PROP_BOOL},
1114 	{ GF_PROP_PID_TILE_BASE, "TileBase", "Tile base stream", GF_PROP_BOOL},
1115 	{ GF_PROP_PID_LANGUAGE, "Language", "Language code: ISO639 2/3 character code or RFC 4646", GF_PROP_NAME},
1116 	{ GF_PROP_PID_SERVICE_NAME, "ServiceName", "Name of parent service", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1117 	{ GF_PROP_PID_SERVICE_PROVIDER, "ServiceProvider", "Provider of parent service", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1118 	{ GF_PROP_PID_STREAM_TYPE, "StreamType", "Media stream type", GF_PROP_UINT},
1119 	{ GF_PROP_PID_SUBTYPE, "StreamSubtype", "Media subtype 4CC (auxiliary, pic sequence, etc ..)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1120 	{ GF_PROP_PID_ISOM_SUBTYPE, "ISOMSubtype", "ISOM media subtype 4CC (avc1 avc2...)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1121 	{ GF_PROP_PID_ORIG_STREAM_TYPE, "OrigStreamType", "Original stream type before encryption", GF_PROP_UINT},
1122 	{ GF_PROP_PID_CODECID, "CodecID", "Codec ID (MPEG-4 OTI or ISOBMFF 4CC)", GF_PROP_UINT},
1123 	{ GF_PROP_PID_IN_IOD, "InitialObjectDescriptor", "Indicates if pid is declared in the IOD for MPEG-4", GF_PROP_BOOL},
1124 	{ GF_PROP_PID_UNFRAMED, "Unframed", "Indicates that the media data is not framed, i.e. each packet is not a complete AU/frame or is not in internal format (eg annexB for avc/hevc, adts for aac)", GF_PROP_BOOL},
1125 	{ GF_PROP_PID_UNFRAMED_FULL_AU, "UnframedAU", "Indicates that the unframed media still has correct AU boundaries: one packet is one full AU, but the packet format might not be the internal one (eg annexB for avc/hevc, adts for aac)", GF_PROP_BOOL},
1126 	{ GF_PROP_PID_UNFRAMED_LATM, "LATM", "Indicates media is unframed AAC in LATM format", GF_PROP_BOOL},
1127 	{ GF_PROP_PID_DURATION, "Duration", "Media duration", GF_PROP_FRACTION64},
1128 	{ GF_PROP_PID_NB_FRAMES, "NumFrames", "Number of frames in the stream", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1129 	{ GF_PROP_PID_FRAME_SIZE, "ConstantFrameSize", "Size of the frames for constant frame size streams", GF_PROP_UINT},
1130 	{ GF_PROP_PID_TIMESHIFT_DEPTH, "TimeshiftDepth", "Depth of the timeshift buffer", GF_PROP_FRACTION, GF_PROP_FLAG_GSF_REM},
1131 	{ GF_PROP_PID_TIMESHIFT_TIME, "TimeshiftTime", "Time in the timeshift buffer in seconds - changes are signaled through pid info (no reconfigure)", GF_PROP_DOUBLE, GF_PROP_FLAG_GSF_REM},
1132 	{ GF_PROP_PID_TIMESHIFT_STATE, "TimeshiftState", "State of timeshift buffer: 0 is OK, 1 is underflow, 2 is overflow - changes are signaled through pid info (no reconfigure)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1133 	{ GF_PROP_PID_TIMESCALE, "Timescale", "Media timescale (a timestamp delta of N is N/timescale seconds)", GF_PROP_UINT},
1134 	{ GF_PROP_PID_PROFILE_LEVEL, "ProfileLevel", "MPEG-4 profile and level", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1135 	{ GF_PROP_PID_DECODER_CONFIG, "DecoderConfig", "Decoder configuration data", GF_PROP_DATA},
1136 	{ GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, "DecoderConfigEnhancement", "Decoder configuration data of the enhancement layer(s). Also used by 3GPP/Apple text streams to give the full sample description table used in SDP.", GF_PROP_DATA},
1137 	{ GF_PROP_PID_CONFIG_IDX, "DecoderConfigIndex", "1-based index of decoder config for ISO base media files", GF_PROP_UINT},
1138 	{ GF_PROP_PID_SAMPLE_RATE, "SampleRate", "Audio sample rate", GF_PROP_UINT},
1139 	{ GF_PROP_PID_SAMPLES_PER_FRAME, "SamplesPerFrame", "Number of audio sample in one coded frame", GF_PROP_UINT},
1140 	{ GF_PROP_PID_NUM_CHANNELS, "NumChannels", "Number of audio channels", GF_PROP_UINT},
1141 	{ GF_PROP_PID_AUDIO_BPS, "BPS", "Number of bits per sample in compressed source", GF_PROP_UINT},
1142 	{ GF_PROP_PID_CHANNEL_LAYOUT, "ChannelLayout", "Channel Layout mask", GF_PROP_LUINT},
1143 	{ GF_PROP_PID_AUDIO_FORMAT, "AudioFormat", "Audio sample format", GF_PROP_PCMFMT},
1144 	{ GF_PROP_PID_AUDIO_SPEED, "AudioPlaybackSpeed", "Audio playback speed, only used for audio output reconfiguration", GF_PROP_DOUBLE, GF_PROP_FLAG_GSF_REM},
1145 	{ GF_PROP_PID_DELAY, "Delay", "Delay of presentation compared to composition timestamps, in media timescale. Positive value imply holding (delaying) the stream. Negative value imply skipping the beginning of stream", GF_PROP_SINT},
1146 	{ GF_PROP_PID_CTS_SHIFT, "CTSShift", "CTS offset to apply in case of negative ctts", GF_PROP_UINT},
1147 	{ GF_PROP_PID_WIDTH, "Width", "Visual Width (video / text / graphics)", GF_PROP_UINT},
1148 	{ GF_PROP_PID_HEIGHT, "Height", "Visual Height (video / text / graphics)", GF_PROP_UINT},
1149 	{ GF_PROP_PID_PIXFMT, "PixelFormat", "Pixel format", GF_PROP_PIXFMT},
1150 	{ GF_PROP_PID_PIXFMT_WRAPPED, "PixelFormatWrapped", "Underlying pixel format of video stream if pixel format is external GL texture", GF_PROP_PIXFMT},
1151 	{ GF_PROP_PID_STRIDE, "Stride", "Image or Y/alpha plane stride", GF_PROP_UINT},
1152 	{ GF_PROP_PID_STRIDE_UV, "StrideUV", "UV plane or U/V planes stride", GF_PROP_UINT},
1153 	{ GF_PROP_PID_BIT_DEPTH_Y, "BitDepthLuma", "Bit depth for luma components", GF_PROP_UINT},
1154 	{ GF_PROP_PID_BIT_DEPTH_UV, "BitDepthChroma", "Bit depth for chroma components", GF_PROP_UINT},
1155 	{ GF_PROP_PID_FPS, "FPS", "Video framerate", GF_PROP_FRACTION},
1156 	{ GF_PROP_PID_INTERLACED, "Interlaced", "Video is interlaced", GF_PROP_BOOL},
1157 	{ GF_PROP_PID_SAR, "SAR", "Sample (ie pixel) aspect ratio", GF_PROP_FRACTION},
1158 	{ GF_PROP_PID_PAR, "PAR", "Picture aspect ratio", GF_PROP_FRACTION, GF_PROP_FLAG_GSF_REM},
1159 	{ GF_PROP_PID_WIDTH_MAX, "MaxWidth", "Maximum width (video / text / graphics) of all enhancement layers", GF_PROP_UINT},
1160 	{ GF_PROP_PID_HEIGHT_MAX, "MaxHeight", "Maximum height (video / text / graphics) of all enhancement layers", GF_PROP_UINT},
1161 	{ GF_PROP_PID_ZORDER, "ZOrder", "Z-order of the video, from 0 (first) to max int (last)", GF_PROP_UINT},
1162 	{ GF_PROP_PID_TRANS_X, "TransX", "Horizontal translation of the video", GF_PROP_SINT},
1163 	{ GF_PROP_PID_TRANS_Y, "TransY", "Vertical translation of the video", GF_PROP_SINT},
1164 	{ GF_PROP_PID_HIDDEN, "Hidden", "Indicates the PID is hidden in visual/audio rendering", GF_PROP_BOOL},
1165 
1166 	{ GF_PROP_PID_CROP_POS, "CropOrigin", "Position in source window, X,Y indicates coord in source", GF_PROP_VEC2I},
1167 	{ GF_PROP_PID_ORIG_SIZE, "OriginalSize", "Original resolution of video", GF_PROP_VEC2I},
1168 	{ GF_PROP_PID_SRD, "SRD", "Position and size of the video in the referential given by SRDRef", GF_PROP_VEC4I},
1169 	{ GF_PROP_PID_SRD_REF, "SRDRef", "Width and Height of the SRD referential", GF_PROP_VEC2I},
1170 	{ GF_PROP_PID_SRD_MAP, "SRDMap", "Mapping of input videos in reconstructed video, expressed as {Ox,Oy,Ow,Oh,Dx,Dy,Dw,Dh} per input, with:\n"
1171 	"- Ox,Oy,Ow,Oh: position and size of the input video (usually matching its `SRD` property), expressed in the output referential given by `SRDRef`\n"
1172 	"- Dx,Dy,Dw,Dh: Position and Size of the input video in the reconstructed output, expressed in the output referential given by `SRDRef`", GF_PROP_UINT_LIST},
1173 
1174 	{ GF_PROP_PID_ALPHA, "Alpha", "Indicates the video in this pid is an alpha map", GF_PROP_BOOL},
1175 	{ GF_PROP_PID_BITRATE, "Bitrate", "Bitrate in bps", GF_PROP_UINT},
1176 	{ GF_PROP_PID_MAXRATE, "Maxrate", "Max bitrate in bps", GF_PROP_UINT},
1177 	{ GF_PROP_PID_DBSIZE, "DBSize", "Decode buffer size in bytes", GF_PROP_UINT},
1178 	{ GF_PROP_PID_MEDIA_DATA_SIZE, "MediaDataSize", "Size in bytes of media data", GF_PROP_LUINT, GF_PROP_FLAG_GSF_REM},
1179 	{ GF_PROP_PID_CAN_DATAREF, "DataRef", "Data referencing is possible (each compressed frame is a continuous set of bytes in source, with no transformation)", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1180 	{ GF_PROP_PID_URL, "URL", "URL of source", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1181 	{ GF_PROP_PID_REMOTE_URL, "RemoteURL", "Remote URL of source - used for MPEG-4 systems", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1182 	{ GF_PROP_PID_REDIRECT_URL, "RedirectURL", "Redirection URL of source", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1183 	{ GF_PROP_PID_FILEPATH, "SourcePath", "Path of source file on file system", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1184 	{ GF_PROP_PID_MIME, "MIMEType", "MIME type of source", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1185 	{ GF_PROP_PID_FILE_EXT, "Extension", "File extension of source", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1186 	{ GF_PROP_PID_FILE_CACHED, "Cached", "indicates the file is completely cached", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1187 	{ GF_PROP_PID_DOWN_RATE, "DownloadRate", "Dowload rate of resource in bits per second - changes are signaled through pid info (no reconfigure)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1188 	{ GF_PROP_PID_DOWN_SIZE, "DownloadSize", "Size of resource in bytes", GF_PROP_LUINT, GF_PROP_FLAG_GSF_REM},
1189 	{ GF_PROP_PID_DOWN_BYTES, "DownBytes", "Number of bytes downloaded - changes are signaled through pid info (no reconfigure)", GF_PROP_LUINT, GF_PROP_FLAG_GSF_REM},
1190 	{ GF_PROP_PID_FILE_RANGE, "ByteRange", "Byte range of resource", GF_PROP_FRACTION64, GF_PROP_FLAG_GSF_REM},
1191 	{ GF_PROP_PID_DISABLE_PROGRESSIVE, "DisableProgressive", "indicates that some blocks in file need patching (replace or insertion) upon closing, potentially disabling progressive upload", GF_PROP_UINT, 0},
1192 	{ GF_PROP_PID_ISOM_BRANDS, "IsoAltBrands", "indicates ISOBMFF brands associated with PID/file", GF_PROP_UINT_LIST, GF_PROP_FLAG_GSF_REM},
1193 	{ GF_PROP_PID_ISOM_MBRAND, "IsoBrand", "indicates ISOBMFF major brand associated with PID/file", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1194 	{ GF_PROP_PID_ISOM_MOVIE_TIME, "MovieTime", "indicates ISOBMFF movie header duration and timescale", GF_PROP_FRACTION64, GF_PROP_FLAG_GSF_REM},
1195 	{ GF_PROP_PID_HAS_SYNC, "HasSync", "indicates ISOBMFF track has sync points", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1196 
1197 	{ GF_PROP_SERVICE_WIDTH, "ServiceWidth", "Display width of service", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1198 	{ GF_PROP_SERVICE_HEIGHT, "ServiceHeight", "Display height of service", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1199 	{ GF_PROP_PID_CAROUSEL_RATE, "CarouselRate", "Repeat rate in ms for systems carousel data", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1200 	{ GF_PROP_PID_UTC_TIME, "UTC", "UTC date and time of PID", GF_PROP_LUINT, GF_PROP_FLAG_GSF_REM},
1201 	{ GF_PROP_PID_UTC_TIMESTAMP, "UTCTimestamp", "Timestamp corresponding to UTC date and time", GF_PROP_LUINT, GF_PROP_FLAG_GSF_REM},
1202 	{ GF_PROP_PID_AUDIO_VOLUME, "AudioVolume", "Volume of audio", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1203 	{ GF_PROP_PID_AUDIO_PAN, "AudioPan", "Balance/Pan of audio", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1204 	{ GF_PROP_PID_AUDIO_PRIORITY, "AudioPriority", "Audio thread priority", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1205 	{ GF_PROP_PID_PROTECTION_SCHEME_TYPE, "ProtectionScheme", "Protection scheme type (4CC) used", GF_PROP_UINT},
1206 	{ GF_PROP_PID_PROTECTION_SCHEME_VERSION, "SchemeVersion", "Protection scheme version used", GF_PROP_UINT},
1207 	{ GF_PROP_PID_PROTECTION_SCHEME_URI, "SchemeURI", "Protection scheme URI", GF_PROP_STRING},
1208 	{ GF_PROP_PID_PROTECTION_KMS_URI, "KMS_URI", "URI for key management system", GF_PROP_STRING},
1209 	{ GF_PROP_PID_ISMA_SELECTIVE_ENC, "SelectiveEncryption", "Indicates if ISMA/OMA selective encryption is used", GF_PROP_BOOL},
1210 	{ GF_PROP_PID_ISMA_IV_LENGTH, "IVLength", "ISMA IV size", GF_PROP_UINT},
1211 	{ GF_PROP_PID_ISMA_KI_LENGTH, "KILength", "ISMA KeyIndication size", GF_PROP_UINT},
1212 	{ GF_PROP_PID_OMA_CRYPT_TYPE, "CryptType", "OMA encryption type", GF_PROP_UINT},
1213 	{ GF_PROP_PID_OMA_CID, "ContentID", "OMA Content ID", GF_PROP_STRING},
1214 	{ GF_PROP_PID_OMA_TXT_HDR, "TextualHeaders", "OMA textual headers", GF_PROP_STRING},
1215 	{ GF_PROP_PID_OMA_CLEAR_LEN, "PlaintextLen", "OMA size of plaintext data", GF_PROP_LUINT},
1216 	{ GF_PROP_PID_CRYPT_INFO, "CryptInfo", "URL (local file only) of crypt info file for this pid", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1217 	{ GF_PROP_PID_DECRYPT_INFO, "DecryptInfo", "URL (local file only) of crypt info file for this pid - see decrypter help", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1218 	{ GF_PROP_PCK_SENDER_NTP, "SenderNTP", "NTP time at sender side or grabber side", GF_PROP_LUINT, GF_PROP_FLAG_PCK | GF_PROP_FLAG_GSF_REM},
1219 	{ GF_PROP_PCK_RECEIVER_NTP, "ReceiverNTP", "Receiver NTP time (usually associated with the sender NTP property)", GF_PROP_LUINT, GF_PROP_FLAG_PCK | GF_PROP_FLAG_GSF_REM},
1220 
1221 	{ GF_PROP_PID_ENCRYPTED, "Encrypted", "Packets for the stream are by default encrypted (however the encryption state is carried in packet crypt flags) - changes are signaled through pid_set_info (no reconfigure)", GF_PROP_BOOL},
1222 	{ GF_PROP_PID_OMA_PREVIEW_RANGE, "OMAPreview", "OMA Preview range ", GF_PROP_LUINT},
1223 	{ GF_PROP_PID_CENC_PSSH, "CENC_PSSH", "PSSH blob for CENC, formatted as (u32)NbSystems [ (bin128)SystemID(u32)version(u32)KID_count[ (bin128)keyID ] (u32)priv_size(char*priv_size)priv_data]", GF_PROP_DATA},
1224 	{ GF_PROP_PCK_CENC_SAI, "CENC_SAI", "CENC SAI for the packet, formated as (char(IV_Size))IV(u16)NbSubSamples [(u16)ClearBytes(u32)CryptedBytes]", GF_PROP_DATA, GF_PROP_FLAG_PCK},
1225 	{ GF_PROP_PID_KID, "KID", "Key ID for packets of the PID - changes are signaled through pid_set_info (no reconfigure)", GF_PROP_DATA},
1226 	{ GF_PROP_PID_CENC_IV_SIZE, "IVSize", "IV size for packets of the PID", GF_PROP_UINT},
1227 	{ GF_PROP_PID_CENC_IV_CONST, "ConstantIV", "Constant IV for packets of the PID", GF_PROP_DATA},
1228 	{ GF_PROP_PID_CENC_PATTERN, "CENCPattern", "CENC crypt pattern, CENC pattern, skip as frac.num crypt as frac.den", GF_PROP_FRACTION},
1229 	{ GF_PROP_PID_CENC_STORE, "CENCStore", "Storage location 4CC of SAI data", GF_PROP_UINT},
1230 	{ GF_PROP_PID_CENC_STSD_MODE, "CENCstsdMode", "Mode for CENC sample description when using clear samples:\n"
1231 	"- 0: single sample description is used\n"
1232 	"- 1: a clear clone of the sample description is created, inserted before the CENC sample description\n"
1233 	"- 2: a clear clone of the sample description is created, inserted after the CENC sample description", GF_PROP_UINT},
1234 	{ GF_PROP_PID_AMR_MODE_SET, "AMRModeSet", "ModeSet for AMR and AMR-WideBand", GF_PROP_UINT},
1235 	{ GF_PROP_PCK_SUBS, "SubSampleInfo", "Binary blob describing N subsamples of the sample, formatted as N [(u32)flags(u32)size(u32)reserved(u8)priority(u8) discardable]", GF_PROP_DATA},
1236 	{ GF_PROP_PID_MAX_NALU_SIZE, "NALUMaxSize", "Max size of NAL units in stream - changes are signaled through pid_set_info (no reconfigure)", GF_PROP_UINT},
1237 	{ GF_PROP_PCK_FILENUM, "FileNumber", "Index of file when dumping to files", GF_PROP_UINT, GF_PROP_FLAG_PCK},
1238 	{ GF_PROP_PCK_FILENAME, "FileName", "Name of output file when dumping / dashing. Must be set on first packet belonging to new file", GF_PROP_STRING, GF_PROP_FLAG_PCK},
1239 	{ GF_PROP_PCK_IDXFILENAME, "IDXName", "Name of index file when dashing MPEG-2 TS. Must be set on first packet belonging to new file", GF_PROP_STRING, GF_PROP_FLAG_PCK},
1240 	{ GF_PROP_PCK_FILESUF, "FileSuffix", "File suffix name, replacement for $FS$ in tile templates", GF_PROP_STRING, GF_PROP_FLAG_PCK},
1241 
1242 	{ GF_PROP_PCK_EODS, "EODS", "End of DASH segment", GF_PROP_BOOL, GF_PROP_FLAG_PCK},
1243 	{ GF_PROP_PID_MAX_FRAME_SIZE, "MaxFrameSize", "Max size of frame in stream - changes are signaled through pid_set_info (no reconfigure)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1244 	{ GF_PROP_PID_AVG_FRAME_SIZE, "AvgFrameSize", "Average size of frame in stream (isobmff only, static property)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1245 	{ GF_PROP_PID_MAX_TS_DELTA, "MaxTSDelta", "Maximum DTS delta between frames (isobmff only, static property)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1246 	{ GF_PROP_PID_MAX_CTS_OFFSET, "MaxCTSOffset", "Maximum absolute CTS offset (isobmff only, static property)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1247 	{ GF_PROP_PID_CONSTANT_DURATION, "ConstantDuration", "Constant duration of samples, 0 means variable duration (isobmff only, static property)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1248 	{ GF_PROP_PID_ISOM_TRACK_TEMPLATE, "TrackTemplate", "ISOBMFF serialized track box for this PID, without any sample info (empty stbl and empty dref) - used by isomuxer to reinject specific boxes of input ISOBMFF track", GF_PROP_DATA, GF_PROP_FLAG_GSF_REM},
1249 	{ GF_PROP_PID_ISOM_TREX_TEMPLATE, "TrexTemplate", "ISOBMFF serialized trex box for this PID - used by isomuxer to remux empty init segments", GF_PROP_DATA, GF_PROP_FLAG_GSF_REM},
1250 	{ GF_PROP_PID_ISOM_STSD_TEMPLATE, "STSDTemplate", "ISOBMFF serialized sample description box (stsd entry) for this PID - used by isomuxer to reinject specific boxes of input ISOBMFF track", GF_PROP_DATA, GF_PROP_FLAG_GSF_REM},
1251 
1252 	{ GF_PROP_PID_ISOM_UDTA, "MovieUserData", "ISOBMFF serialized moov UDTA and other moov-level boxes (list) for this PID - used by isomuxer to reinject specific boxes of input ISOBMFF moov", GF_PROP_DATA, GF_PROP_FLAG_GSF_REM},
1253 	{ GF_PROP_PID_ISOM_HANDLER, "TrackHandler", "ISOBMFF track handler name", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1254 	{ GF_PROP_PID_ISOM_TRACK_FLAGS, "TrackFlags", "ISOBMFF track header flags", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1255 	{ GF_PROP_PID_ISOM_TRACK_MATRIX, "TrackMatrix", "ISOBMFF track header matrix", GF_PROP_UINT_LIST, GF_PROP_FLAG_GSF_REM},
1256 
1257 	{ GF_PROP_PID_PERIOD_ID, "Period", "ID of DASH period", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1258 	{ GF_PROP_PID_PERIOD_START, "PStart", "DASH Period start - cf dasher help", GF_PROP_DOUBLE, GF_PROP_FLAG_GSF_REM},
1259 	{ GF_PROP_PID_PERIOD_DUR, "PDur", "DASH Period duration - cf dasher help", GF_PROP_DOUBLE, GF_PROP_FLAG_GSF_REM},
1260 	{ GF_PROP_PID_REP_ID, "Representation", "ID of DASH representation", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1261 	{ GF_PROP_PID_AS_ID, "ASID", "ID of parent DASH AS", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1262 	{ GF_PROP_PID_MUX_SRC, "MuxSrc", "Name of mux source(s), set by dasher to direct its outputs", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1263 	{ GF_PROP_PID_DASH_MODE, "DashMode", "DASH mode to be used by muxer if any, set by dasher. 0 is no DASH, 1 is regular DASH, 2 is VoD", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1264 	{ GF_PROP_PID_DASH_DUR, "DashDur", "DASH target segment duration in seconds to muxer if any, set by dasher", GF_PROP_DOUBLE, GF_PROP_FLAG_GSF_REM},
1265 	{ GF_PROP_PID_DASH_MULTI_PID, NULL, "Pointer to the GF_List of input pids for multi-stsd entries segments, set by dasher", GF_PROP_POINTER, GF_PROP_FLAG_GSF_REM},
1266 	{ GF_PROP_PID_DASH_MULTI_PID_IDX, NULL, "1-based index of PID in the multi PID list, set by dasher", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1267 	{ GF_PROP_PID_DASH_MULTI_TRACK, NULL, "Pointer to the GF_List of input pids for multi-tracks segments, set by dasher", GF_PROP_POINTER, GF_PROP_FLAG_GSF_REM},
1268 	{ GF_PROP_PID_ROLE, "Role", "List of roles for this pid", GF_PROP_STRING_LIST, GF_PROP_FLAG_GSF_REM},
1269 	{ GF_PROP_PID_PERIOD_DESC, "PDesc", "List of descriptors for the DASH period containing this pid", GF_PROP_STRING_LIST, GF_PROP_FLAG_GSF_REM},
1270 	{ GF_PROP_PID_AS_COND_DESC, "ASDesc", "List of conditional descriptors for the DASH AdaptationSet containing this pid. If a pid with the same property type but different value is found, the pids will be in different AdaptationSets", GF_PROP_STRING_LIST, GF_PROP_FLAG_GSF_REM},
1271 	{ GF_PROP_PID_AS_ANY_DESC, "ASCDesc", "List of common descriptors for the DASH AdaptationSet containing this pid", GF_PROP_STRING_LIST, GF_PROP_FLAG_GSF_REM},
1272 	{ GF_PROP_PID_REP_DESC, "RDesc", "List of descriptors for the DASH Representation containing this pid", GF_PROP_STRING_LIST, GF_PROP_FLAG_GSF_REM},
1273 	{ GF_PROP_PID_BASE_URL, "BUrl", "List of base URLs for this pid", GF_PROP_STRING_LIST, GF_PROP_FLAG_GSF_REM},
1274 	{ GF_PROP_PID_TEMPLATE, "Template", "Template to use for DASH generation for this pid", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1275 	{ GF_PROP_PID_START_NUMBER, "StartNumber", "Start number to use for this pid - cf dasher help", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1276 	{ GF_PROP_PID_XLINK, "xlink", "Remote period URL for DASH - cf dasher help", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1277 	{ GF_PROP_PID_CLAMP_DUR, "CDur", "Max media duration to process from pid in DASH mode", GF_PROP_DOUBLE, GF_PROP_FLAG_GSF_REM},
1278 	{ GF_PROP_PID_HLS_PLAYLIST, "HLSPL", "Name of the HLS variant playlist for this media", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1279 	{ GF_PROP_PID_DASH_CUE, "DCue", "Name of a cue list file for this pid - see dasher help", GF_PROP_STRING, GF_PROP_FLAG_GSF_REM},
1280 	{ GF_PROP_PID_DASH_SEGMENTS, "DSegs", "Number of DASH segments defined by the DASH cue info", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1281 	{ GF_PROP_PID_SINGLE_SCALE, "SingleScale", "Indicates the movie header should use the media timescale of the first track added", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1282 	{ GF_PROP_PID_UDP, "RequireReorder", "Indicates the PID packets come from source with losses and reordering happening (UDP)", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1283 	{ GF_PROP_PID_PRIMARY_ITEM, "Primary", "Indicates this is a primary item in isobmf", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1284 
1285 	{ GF_PROP_PID_COLR_PRIMARIES, "ColorPrimaries", "Indicate color primaries for a visual pid (see ISO/IEC 23001-8 / 23091-2)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1286 	{ GF_PROP_PID_COLR_TRANSFER, "ColorTransfer", "Indicate color transfer characteristics for a visual pid (see ISO/IEC 23001-8 / 23091-2)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1287 	{ GF_PROP_PID_COLR_MX, "ColorMatrixCoef", "Indicate color matrix coeficient for a visual pid (see ISO/IEC 23001-8 / 23091-2)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1288 	{ GF_PROP_PID_COLR_RANGE, "FullRange", "Indicate color full range flag for a visual pid (see ISO/IEC 23001-8 / 23091-2)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1289 	{ GF_PROP_PID_COLR_CHROMALOC, "ChromaLoc", "Indicate chrom location for a visual pid (see ISO/IEC 23001-8 / 23091-2)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1290 	{ GF_PROP_PID_SRC_MAGIC, "SrcMagic", "Indicate a magic number to store in the track, only used by importers", GF_PROP_LUINT, GF_PROP_FLAG_GSF_REM},
1291 	{ GF_PROP_PID_TRACK_INDEX, "TrackIndex", "Indicate target track index in destination file, stored by lowest value first (not set by demuxers)", GF_PROP_LUINT, GF_PROP_FLAG_GSF_REM},
1292 	{ GF_PROP_NO_TS_LOOP, "NoTSLoop", "Indicate the timestamps on this PID are adjusted in case of loops (used by TS muxer output)", GF_PROP_BOOL, 0},
1293 
1294 
1295 	{ GF_PROP_PCK_FRAG_START, "FragStart", "Indicate if packet is a fragment start (value 1) or a segment start (value 2)", GF_PROP_UINT, GF_PROP_FLAG_GSF_REM},
1296 	{ GF_PROP_PCK_FRAG_RANGE, "FragRange", "Indicate start and end position in bytes of fragment if packet is a fragment or segment start", GF_PROP_FRACTION64, GF_PROP_FLAG_GSF_REM},
1297 	{ GF_PROP_PCK_SIDX_RANGE, "SIDXRange", "Indicate start and end position in bytes of sidx if packet is a fragment or segment start", GF_PROP_FRACTION64, GF_PROP_FLAG_GSF_REM},
1298 
1299 	{ GF_PROP_PCK_MOOF_TEMPLATE, "MoofTemplate", "Serialized moof box corresponding to the start of a movie fragment or segment (with styp and optionally sidx)", GF_PROP_DATA, GF_PROP_FLAG_GSF_REM},
1300 
1301 	{ GF_PROP_PID_RAWGRAB, "RawGrab", "Indicate PID is a raw media grabber (webcam, microphone, etc...)", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1302 	{ GF_PROP_PID_KEEP_AFTER_EOS, "KeepAfterEOS", "Indicate the PID must be kept alive after EOS (LASeR and BIFS)", GF_PROP_BOOL, GF_PROP_FLAG_GSF_REM},
1303 	{ GF_PROP_PID_COVER_ART, "CoverArt", "Indicate PID cover art image data. If associated data is NULL, the data is carried in the PID", GF_PROP_DATA, GF_PROP_FLAG_GSF_REM},
1304 
1305 };
1306 
1307 GF_EXPORT
gf_props_get_id(const char * name)1308 u32 gf_props_get_id(const char *name)
1309 {
1310 	u32 i, nb_props;
1311 	if (!name) return 0;
1312 	nb_props = sizeof(GF_BuiltInProps) / sizeof(GF_BuiltInProperty);
1313 	for (i=0; i<nb_props; i++) {
1314 		if (GF_BuiltInProps[i].name && !strcmp(GF_BuiltInProps[i].name, name)) return GF_BuiltInProps[i].type;
1315 	}
1316 	return 0;
1317 }
1318 
1319 GF_EXPORT
gf_props_get_description(u32 prop_idx)1320 const GF_BuiltInProperty *gf_props_get_description(u32 prop_idx)
1321 {
1322 	u32 nb_props = sizeof(GF_BuiltInProps) / sizeof(GF_BuiltInProperty);
1323 	if (prop_idx>=nb_props) return NULL;
1324 	return &GF_BuiltInProps[prop_idx];
1325 }
1326 
1327 GF_EXPORT
gf_props_4cc_get_name(u32 prop_4cc)1328 const char *gf_props_4cc_get_name(u32 prop_4cc)
1329 {
1330 	u32 i, nb_props = sizeof(GF_BuiltInProps) / sizeof(GF_BuiltInProperty);
1331 	for (i=0; i<nb_props; i++) {
1332 		if (GF_BuiltInProps[i].type==prop_4cc) return GF_BuiltInProps[i].name;
1333 	}
1334 	return NULL;
1335 }
1336 
1337 GF_EXPORT
gf_props_4cc_get_flags(u32 prop_4cc)1338 u8 gf_props_4cc_get_flags(u32 prop_4cc)
1339 {
1340 	u32 i, nb_props = sizeof(GF_BuiltInProps) / sizeof(GF_BuiltInProperty);
1341 	for (i=0; i<nb_props; i++) {
1342 		if (GF_BuiltInProps[i].type==prop_4cc) return GF_BuiltInProps[i].flags;
1343 	}
1344 	return 0;
1345 }
1346 
1347 GF_EXPORT
gf_props_4cc_get_type(u32 prop_4cc)1348 u32 gf_props_4cc_get_type(u32 prop_4cc)
1349 {
1350 	u32 i, nb_props = sizeof(GF_BuiltInProps) / sizeof(GF_BuiltInProperty);
1351 	for (i=0; i<nb_props; i++) {
1352 		if (GF_BuiltInProps[i].type==prop_4cc) return GF_BuiltInProps[i].data_type;
1353 	}
1354 	return GF_PROP_FORBIDEN;
1355 }
1356 
gf_props_4cc_check_props()1357 Bool gf_props_4cc_check_props()
1358 {
1359 	Bool res = GF_TRUE;
1360 	u32 i, j, nb_props = sizeof(GF_BuiltInProps) / sizeof(GF_BuiltInProperty);
1361 	for (i=0; i<nb_props; i++) {
1362 		for (j=i+1; j<nb_props; j++) {
1363 			if (GF_BuiltInProps[i].type==GF_BuiltInProps[j].type) {
1364 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Property %s and %s have the same code type %s\n", GF_BuiltInProps[i].name, GF_BuiltInProps[j].name, gf_4cc_to_str(GF_BuiltInProps[i].type) ));
1365 				res = GF_FALSE;
1366 			}
1367 		}
1368 	}
1369 	return res;
1370 }
1371 
gf_props_dump_val_ex(const GF_PropertyValue * att,char dump[GF_PROP_DUMP_ARG_SIZE],Bool dump_data,const char * min_max_enum,Bool is_4cc)1372 const char *gf_props_dump_val_ex(const GF_PropertyValue *att, char dump[GF_PROP_DUMP_ARG_SIZE], Bool dump_data, const char *min_max_enum, Bool is_4cc)
1373 {
1374 	switch (att->type) {
1375 	case GF_PROP_NAME:
1376 	case GF_PROP_STRING:
1377 	case GF_PROP_STRING_NO_COPY:
1378 		break;
1379 	default:
1380 		if (!dump) return NULL;
1381 		break;
1382 	}
1383 
1384 	dump[0] = 0;
1385 	switch (att->type) {
1386 	case GF_PROP_SINT:
1387 		sprintf(dump, "%d", att->value.sint);
1388 		break;
1389 	case GF_PROP_UINT:
1390 		if (min_max_enum && strchr(min_max_enum, '|') ) {
1391 			u32 enum_val = 0;
1392 			char *str_start = (char *) min_max_enum;
1393 			while (str_start) {
1394 				u32 len;
1395 				char *sep = strchr(str_start, '|');
1396 				if (sep) {
1397 					len = (u32) (sep - str_start);
1398 				} else {
1399 					len = (u32) strlen(str_start);
1400 				}
1401 				if (att->value.uint == enum_val) {
1402 					strncpy(dump, str_start, len);
1403 					dump[len]=0;
1404 					break;
1405 				}
1406 				if (!sep) break;
1407 				str_start = sep+1;
1408 				enum_val++;
1409 			}
1410 			if (!str_start) {
1411 				sprintf(dump, "%u", att->value.uint);
1412 				GF_LOG(GF_LOG_ERROR, GF_LOG_FILTER, ("Wrong argument value %d not found in enums %s - using integer dump\n", att->value.uint_list, min_max_enum));
1413 			}
1414 		} else {
1415 			sprintf(dump, "%u", att->value.uint);
1416 		}
1417 		break;
1418 	case GF_PROP_LSINT:
1419 		sprintf(dump, ""LLD, att->value.longsint);
1420 		break;
1421 	case GF_PROP_LUINT:
1422 		sprintf(dump, ""LLU, att->value.longuint);
1423 		break;
1424 	case GF_PROP_FRACTION:
1425 		//reduce fraction
1426 		if (att->value.frac.den && ((att->value.frac.num/att->value.frac.den) * att->value.frac.den == att->value.frac.num)) {
1427 			sprintf(dump, "%d", att->value.frac.num / att->value.frac.den);
1428 		} else {
1429 			sprintf(dump, "%d/%u", att->value.frac.num, att->value.frac.den);
1430 		}
1431 		break;
1432 	case GF_PROP_FRACTION64:
1433 		//reduce fraction
1434 		if (att->value.lfrac.den && ((att->value.lfrac.num/att->value.lfrac.den) * att->value.lfrac.den == att->value.lfrac.num)) {
1435 			sprintf(dump, LLD, att->value.lfrac.num / att->value.lfrac.den);
1436 		} else {
1437 			sprintf(dump, LLD"/"LLU, att->value.lfrac.num, att->value.lfrac.den);
1438 		}
1439 		break;
1440 	case GF_PROP_BOOL:
1441 		sprintf(dump, "%s", att->value.boolean ? "true" : "false");
1442 		break;
1443 	case GF_PROP_FLOAT:
1444 		sprintf(dump, "%f", FIX2FLT(att->value.fnumber) );
1445 		break;
1446 	case GF_PROP_DOUBLE:
1447 		sprintf(dump, "%g", att->value.number);
1448 		break;
1449 	case GF_PROP_VEC2I:
1450 		sprintf(dump, "%dx%d", att->value.vec2i.x, att->value.vec2i.y);
1451 		break;
1452 	case GF_PROP_VEC2:
1453 		sprintf(dump, "%lgx%lg", att->value.vec2.x, att->value.vec2.y);
1454 		break;
1455 	case GF_PROP_VEC3I:
1456 		sprintf(dump, "%dx%dx%d", att->value.vec3i.x, att->value.vec3i.y, att->value.vec3i.z);
1457 		break;
1458 	case GF_PROP_VEC3:
1459 		sprintf(dump, "%lgx%lgx%lg", att->value.vec3.x, att->value.vec3.y, att->value.vec3.y);
1460 		break;
1461 	case GF_PROP_VEC4I:
1462 		sprintf(dump, "%dx%dx%dx%d", att->value.vec4i.x, att->value.vec4i.y, att->value.vec4i.z, att->value.vec4i.w);
1463 		break;
1464 	case GF_PROP_VEC4:
1465 		sprintf(dump, "%lgx%lgx%lgx%lg", att->value.vec4.x, att->value.vec4.y, att->value.vec4.y, att->value.vec4.w);
1466 		break;
1467 	case GF_PROP_PIXFMT:
1468 		return gf_pixel_fmt_name(att->value.uint);
1469 	case GF_PROP_PCMFMT:
1470 		return gf_audio_fmt_name(att->value.uint);
1471 	case GF_PROP_NAME:
1472 	case GF_PROP_STRING:
1473 	case GF_PROP_STRING_NO_COPY:
1474 		return att->value.string;
1475 
1476 	case GF_PROP_DATA:
1477 	case GF_PROP_CONST_DATA:
1478 	case GF_PROP_DATA_NO_COPY:
1479 		if (dump_data && att->value.data.size < 40) {
1480 			u32 i;
1481 			sprintf(dump, "%d bytes 0x", att->value.data.size);
1482 			for (i=0; i<att->value.data.size; i++) {
1483 				sprintf(dump, "%02X", (unsigned char) att->value.data.ptr[i]);
1484 			}
1485 		} else {
1486 			sprintf(dump, "%d bytes (CRC32 0x%08X)", att->value.data.size, gf_crc_32(att->value.data.ptr, att->value.data.size));
1487 		}
1488 		break;
1489 	case GF_PROP_POINTER:
1490 		sprintf(dump, "%p", att->value.ptr);
1491 		break;
1492 	case GF_PROP_STRING_LIST:
1493 	{
1494 		u32 i, count = gf_list_count(att->value.string_list);
1495 		u32 len = GF_PROP_DUMP_ARG_SIZE-1;
1496 		dump[len]=0;
1497 		for (i=0; i<count; i++) {
1498 			char *s = gf_list_get(att->value.string_list, i);
1499 			if (!i) {
1500 				strncpy(dump, s, len);
1501 			} else {
1502 				strcat(dump, ",");
1503 				strncat(dump, s, len-1);
1504 			}
1505 			len = GF_PROP_DUMP_ARG_SIZE - 1 - (u32) strlen(dump);
1506 			if (len<=1) {
1507 				GF_LOG(GF_LOG_WARNING, GF_LOG_FILTER, ("String list is too large to fit in predefined property dump buffer of %d bytes, truncating\n", GF_PROP_DUMP_ARG_SIZE));
1508 				return dump;
1509 			}
1510 		}
1511 		return dump;
1512 	}
1513 	case GF_PROP_UINT_LIST:
1514 	{
1515 		u32 i, count = att->value.uint_list.nb_items;
1516 		u32 len = GF_PROP_DUMP_ARG_SIZE-1;
1517 		dump[len]=0;
1518 		for (i=0; i<count; i++) {
1519 			char szItem[1024];
1520 			if (is_4cc) {
1521 				sprintf(szItem, "%s", gf_4cc_to_str(att->value.uint_list.vals[i]) );
1522 			} else {
1523 				sprintf(szItem, "%u", att->value.uint_list.vals[i]);
1524 			}
1525 			if (!i) {
1526 				strncpy(dump, szItem, len);
1527 			} else {
1528 				strcat(dump, ",");
1529 				strncat(dump, szItem, len-1);
1530 			}
1531 			len = GF_PROP_DUMP_ARG_SIZE - 1 - (u32) strlen(dump);
1532 			if (len<=1) {
1533 				GF_LOG(GF_LOG_WARNING, GF_LOG_FILTER, ("Uint list is too large to fit in predefined property dump buffer of %d bytes, truncating\n", GF_PROP_DUMP_ARG_SIZE));
1534 				return dump;
1535 			}
1536 		}
1537 		return dump;
1538 	}
1539 	case GF_PROP_FORBIDEN:
1540 		sprintf(dump, "forbiden");
1541 		break;
1542 	case GF_PROP_LAST_DEFINED:
1543 		sprintf(dump, "lastDefined");
1544 		break;
1545 	}
1546 	return dump;
1547 }
1548 
1549 GF_EXPORT
gf_props_dump_val(const GF_PropertyValue * att,char dump[GF_PROP_DUMP_ARG_SIZE],Bool dump_data,const char * min_max_enum)1550 const char *gf_props_dump_val(const GF_PropertyValue *att, char dump[GF_PROP_DUMP_ARG_SIZE], Bool dump_data, const char *min_max_enum)
1551 {
1552 	return gf_props_dump_val_ex(att, dump, dump_data, min_max_enum, GF_FALSE);
1553 }
1554 
1555 GF_EXPORT
gf_props_dump(u32 p4cc,const GF_PropertyValue * att,char dump[GF_PROP_DUMP_ARG_SIZE],Bool dump_data)1556 const char *gf_props_dump(u32 p4cc, const GF_PropertyValue *att, char dump[GF_PROP_DUMP_ARG_SIZE], Bool dump_data)
1557 {
1558 	Bool is_4cc = GF_FALSE;
1559 
1560 	switch (p4cc) {
1561 	case GF_PROP_PID_STREAM_TYPE:
1562 	case GF_PROP_PID_ORIG_STREAM_TYPE:
1563 		return gf_stream_type_name(att->value.uint);
1564 	case GF_PROP_PID_CODECID:
1565 		return gf_codecid_name(att->value.uint);
1566 	case GF_PROP_PID_PIXFMT:
1567 		return gf_pixel_fmt_name(att->value.uint);
1568 	case GF_PROP_PID_AUDIO_FORMAT:
1569 		return gf_audio_fmt_name(att->value.uint);
1570 	case GF_PROP_PID_PROTECTION_SCHEME_TYPE:
1571 	case GF_PROP_PID_CENC_STORE:
1572 	case GF_PROP_PID_SUBTYPE:
1573 	case GF_PROP_PID_ISOM_SUBTYPE:
1574 	case GF_PROP_PID_ISOM_MBRAND:
1575 		return gf_4cc_to_str(att->value.uint);
1576 	case GF_PROP_PID_PLAYBACK_MODE:
1577 		if (att->value.uint == GF_PLAYBACK_MODE_SEEK) return "seek";
1578 		else if (att->value.uint == GF_PLAYBACK_MODE_REWIND) return "rewind";
1579 		else if (att->value.uint == GF_PLAYBACK_MODE_FASTFORWARD) return "forward";
1580 		else return "none";
1581 	case GF_PROP_PID_ISOM_BRANDS:
1582 		is_4cc = GF_TRUE;
1583 
1584 	default:
1585 		return gf_props_dump_val_ex(att, dump, dump_data, NULL, is_4cc);
1586 	}
1587 	return "";
1588 }
1589 
1590