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