PipeWire  0.3.64
filter.h
Go to the documentation of this file.
1 /* Simple Plugin API
2  *
3  * Copyright © 2018 Wim Taymans
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #ifndef SPA_POD_FILTER_H
26 #define SPA_POD_FILTER_H
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #include <errno.h>
33 #include <stdint.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include <spa/param/props.h>
39 #include <spa/pod/iter.h>
40 #include <spa/pod/builder.h>
41 #include <spa/pod/compare.h>
42 
48 static inline int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
49 {
50  void *val, *alt;
51  int i, nvals;
52  uint32_t type, size;
53 
54  nvals = SPA_POD_CHOICE_N_VALUES(choice);
55  type = SPA_POD_CHOICE_VALUE_TYPE(choice);
56  size = SPA_POD_CHOICE_VALUE_SIZE(choice);
57  alt = val = SPA_POD_CHOICE_VALUES(choice);
58 
59  switch (choice->body.type) {
60  case SPA_CHOICE_None:
61  break;
62  case SPA_CHOICE_Range:
63  case SPA_CHOICE_Step:
64  if (nvals > 1) {
65  alt = SPA_PTROFF(alt, size, void);
66  if (spa_pod_compare_value(type, val, alt, size) < 0)
67  memcpy(val, alt, size);
68  }
69  if (nvals > 2) {
70  alt = SPA_PTROFF(alt, size, void);
71  if (spa_pod_compare_value(type, val, alt, size) > 0)
72  memcpy(val, alt, size);
73  }
74  break;
75  case SPA_CHOICE_Flags:
76  case SPA_CHOICE_Enum:
77  {
78  void *best = NULL;
79 
80  for (i = 1; i < nvals; i++) {
81  alt = SPA_PTROFF(alt, size, void);
82  if (spa_pod_compare_value(type, val, alt, size) == 0) {
83  best = alt;
84  break;
85  }
86  if (best == NULL)
87  best = alt;
88  }
89  if (best)
90  memcpy(val, best, size);
91 
92  if (nvals <= 1)
93  choice->body.type = SPA_CHOICE_None;
94  break;
95  }
96  }
97  return 0;
98 }
99 
100 static inline int spa_pod_filter_flags_value(struct spa_pod_builder *b,
101  uint32_t type, const void *r1, const void *r2, uint32_t size)
102 {
103  switch (type) {
104  case SPA_TYPE_Int:
105  {
106  int32_t val = (*(int32_t *) r1) & (*(int32_t *) r2);
107  if (val == 0)
108  return 0;
109  spa_pod_builder_int(b, val);
110  break;
111  }
112  case SPA_TYPE_Long:
113  {
114  int64_t val = (*(int64_t *) r1) & (*(int64_t *) r2);
115  if (val == 0)
116  return 0;
117  spa_pod_builder_long(b, val);
118  break;
119  }
120  default:
121  return -ENOTSUP;
122  }
123  return 1;
124 }
125 
126 static inline int spa_pod_filter_is_step_of(uint32_t type, const void *r1,
127  const void *r2, uint32_t size)
128 {
129  switch (type) {
130  case SPA_TYPE_Int:
131  return *(int32_t *) r1 % *(int32_t *) r2 == 0;
132  case SPA_TYPE_Long:
133  return *(int64_t *) r1 % *(int64_t *) r2 == 0;
134  case SPA_TYPE_Rectangle:
135  {
136  const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1,
137  *rec2 = (struct spa_rectangle *) r2;
138 
139  return (rec1->width % rec2->width == 0 &&
140  rec1->height % rec2->height == 0);
141  }
142  default:
143  return -ENOTSUP;
144  }
145  return 0;
146 }
147 
148 static inline int
150  const struct spa_pod_prop *p1,
151  const struct spa_pod_prop *p2)
152 {
153  const struct spa_pod *v1, *v2;
154  struct spa_pod_choice *nc;
155  uint32_t j, k, nalt1, nalt2;
156  void *alt1, *alt2, *a1, *a2;
157  uint32_t type, size, p1c, p2c;
158  struct spa_pod_frame f;
159 
160  v1 = spa_pod_get_values(&p1->value, &nalt1, &p1c);
161  alt1 = SPA_POD_BODY(v1);
162  v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c);
163  alt2 = SPA_POD_BODY(v2);
164 
165  type = v1->type;
166  size = v1->size;
167 
168  /* incompatible property types */
169  if (type != v2->type || size != v2->size || p1->key != p2->key)
170  return -EINVAL;
171 
172  if (p1c == SPA_CHOICE_None || p1c == SPA_CHOICE_Flags) {
173  nalt1 = 1;
174  } else {
175  alt1 = SPA_PTROFF(alt1, size, void);
176  nalt1--;
177  }
178 
179  if (p2c == SPA_CHOICE_None || p2c == SPA_CHOICE_Flags) {
180  nalt2 = 1;
181  } else {
182  alt2 = SPA_PTROFF(alt2, size, void);
183  nalt2--;
184  }
185 
186  /* start with copying the property */
187  spa_pod_builder_prop(b, p1->key, p1->flags & p2->flags);
188  spa_pod_builder_push_choice(b, &f, 0, 0);
189  nc = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f);
190 
191  /* default value */
193 
194  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) ||
195  (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) ||
196  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_None) ||
197  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) {
198  int n_copied = 0;
199  /* copy all equal values but don't copy the default value again */
200  for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_PTROFF(a1, size, void)) {
201  for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
202  if (spa_pod_compare_value(type, a1, a2, size) == 0) {
203  if (p1c == SPA_CHOICE_Enum || j > 0)
204  spa_pod_builder_raw(b, a1, size);
205  n_copied++;
206  }
207  }
208  }
209  if (n_copied == 0)
210  return -EINVAL;
211  nc->body.type = SPA_CHOICE_Enum;
212  }
213 
214  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Range) ||
215  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Range)) {
216  int n_copied = 0;
217  /* copy all values inside the range */
218  for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
219  if (spa_pod_compare_value(type, a1, a2, size) < 0)
220  continue;
221  if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
222  continue;
223  spa_pod_builder_raw(b, a1, size);
224  n_copied++;
225  }
226  if (n_copied == 0)
227  return -EINVAL;
228  nc->body.type = SPA_CHOICE_Enum;
229  }
230 
231  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Step) ||
232  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Step)) {
233  int n_copied = 0;
234  for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
235  int res;
236  if (spa_pod_compare_value(type, a1, a2, size) < 0)
237  continue;
238  if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
239  continue;
240 
241  res = spa_pod_filter_is_step_of(type, a1, SPA_PTROFF(a2,size*2,void), size);
242  if (res == 0)
243  continue;
244  if (res == -ENOTSUP)
245  return -EINVAL;
246 
247  spa_pod_builder_raw(b, a1, size);
248  n_copied++;
249  }
250  if (n_copied == 0)
251  return -EINVAL;
252  nc->body.type = SPA_CHOICE_Enum;
253  }
254 
255  if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_None) ||
256  (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Enum)) {
257  int n_copied = 0;
258  /* copy all values inside the range */
259  for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
260  if (spa_pod_compare_value(type, a2, a1, size) < 0)
261  continue;
262  if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
263  continue;
264  spa_pod_builder_raw(b, a2, size);
265  n_copied++;
266  }
267  if (n_copied == 0)
268  return -EINVAL;
269  nc->body.type = SPA_CHOICE_Enum;
270  }
271 
272  if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Range) ||
273  (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Step) ||
274  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Range) ||
275  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Step)) {
276  if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
277  spa_pod_builder_raw(b, alt2, size);
278  else
279  spa_pod_builder_raw(b, alt1, size);
280 
281  alt1 = SPA_PTROFF(alt1,size,void);
282  alt2 = SPA_PTROFF(alt2,size,void);
283 
284  if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
285  spa_pod_builder_raw(b, alt1, size);
286  else
287  spa_pod_builder_raw(b, alt2, size);
288 
289  nc->body.type = SPA_CHOICE_Range;
290  }
291 
292  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Flags) ||
293  (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_None) ||
294  (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Flags)) {
295  if (spa_pod_filter_flags_value(b, type, alt1, alt2, size) != 1)
296  return -EINVAL;
297  nc->body.type = SPA_CHOICE_Flags;
298  }
299 
300  if (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Flags)
301  return -ENOTSUP;
302 
303  if (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Flags)
304  return -ENOTSUP;
305 
306  if ((p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_None) ||
307  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Enum)) {
308  int n_copied = 0;
309  for (j = 0, a1 = alt1, a2 = alt2; j < nalt2; j++, a2 = SPA_PTROFF(a1,size,void)) {
310  int res;
311  if (spa_pod_compare_value(type, a2, a1, size) < 0)
312  continue;
313  if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
314  continue;
315 
316  res = spa_pod_filter_is_step_of(type, a2, SPA_PTROFF(a1,size*2,void), size);
317  if (res == 0)
318  continue;
319  if (res == -ENOTSUP)
320  return -EINVAL;
321 
322  spa_pod_builder_raw(b, a2, size);
323  n_copied++;
324  }
325  if (n_copied == 0)
326  return -EINVAL;
327  nc->body.type = SPA_CHOICE_Enum;
328  }
329  if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Flags)
330  return -ENOTSUP;
331 
332  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Range)
333  return -ENOTSUP;
334  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Step)
335  return -ENOTSUP;
336  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Enum)
337  return -ENOTSUP;
338 
339  spa_pod_builder_pop(b, &f);
341 
342  return 0;
343 }
344 
345 static inline int spa_pod_filter_part(struct spa_pod_builder *b,
346  const struct spa_pod *pod, uint32_t pod_size,
347  const struct spa_pod *filter, uint32_t filter_size)
348 {
349  const struct spa_pod *pp, *pf;
350  int res = 0;
351 
352  pf = filter;
353 
354  SPA_POD_FOREACH(pod, pod_size, pp) {
355  bool do_copy = false, do_advance = false;
356  uint32_t filter_offset = 0;
357  struct spa_pod_frame f;
358 
359  switch (SPA_POD_TYPE(pp)) {
360  case SPA_TYPE_Object:
361  if (pf != NULL) {
362  struct spa_pod_object *op = (struct spa_pod_object *) pp;
363  struct spa_pod_object *of = (struct spa_pod_object *) pf;
364  const struct spa_pod_prop *p1, *p2;
365 
366  if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
367  return -EINVAL;
368 
369  spa_pod_builder_push_object(b, &f, op->body.type, op->body.id);
370  p2 = NULL;
371  SPA_POD_OBJECT_FOREACH(op, p1) {
372  p2 = spa_pod_object_find_prop(of, p2, p1->key);
373  if (p2 != NULL)
374  res = spa_pod_filter_prop(b, p1, p2);
375  else if ((p1->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
376  res = -EINVAL;
377  else
379  if (res < 0)
380  break;
381  }
382  if (res >= 0) {
383  p1 = NULL;
384  SPA_POD_OBJECT_FOREACH(of, p2) {
385  p1 = spa_pod_object_find_prop(op, p1, p2->key);
386  if (p1 != NULL)
387  continue;
388  if ((p2->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
389  res = -EINVAL;
390  if (res < 0)
391  break;
393  }
394  }
395  spa_pod_builder_pop(b, &f);
396  do_advance = true;
397  }
398  else
399  do_copy = true;
400  break;
401 
402  case SPA_TYPE_Struct:
403  if (pf != NULL) {
404  if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
405  return -EINVAL;
406 
407  filter_offset = sizeof(struct spa_pod_struct);
409  res = spa_pod_filter_part(b,
410  SPA_PTROFF(pp,filter_offset,const struct spa_pod),
411  SPA_POD_SIZE(pp) - filter_offset,
412  SPA_PTROFF(pf,filter_offset,const struct spa_pod),
413  SPA_POD_SIZE(pf) - filter_offset);
414  spa_pod_builder_pop(b, &f);
415  do_advance = true;
416  }
417  else
418  do_copy = true;
419  break;
420 
421  default:
422  if (pf != NULL) {
423  if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf))
424  return -EINVAL;
425  if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0)
426  return -EINVAL;
427  do_advance = true;
428  }
429  do_copy = true;
430  break;
431  }
432  if (do_copy)
434  if (do_advance) {
435  pf = (const struct spa_pod*)spa_pod_next(pf);
436  if (!spa_pod_is_inside(filter, filter_size, pf))
437  pf = NULL;
438  }
439  if (res < 0)
440  break;
441  }
442  return res;
443 }
444 
445 static inline int
447  struct spa_pod **result,
448  const struct spa_pod *pod,
449  const struct spa_pod *filter)
450 {
451  int res;
452  struct spa_pod_builder_state state;
453 
454  spa_return_val_if_fail(pod != NULL, -EINVAL);
455  spa_return_val_if_fail(b != NULL, -EINVAL);
456 
457  spa_pod_builder_get_state(b, &state);
458  if (filter == NULL)
459  res = spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod));
460  else
461  res = spa_pod_filter_part(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter));
462 
463  if (res < 0) {
464  spa_pod_builder_reset(b, &state);
465  } else if (result) {
466  *result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset);
467  if (*result == NULL)
468  res = -ENOSPC;
469  }
470  return res;
471 }
472 
477 #ifdef __cplusplus
478 } /* extern "C" */
479 #endif
480 
481 #endif /* SPA_POD_FILTER_H */
spa/pod/builder.h
spa/pod/compare.h
static int spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
Definition: builder.h:470
#define SPA_POD_CHOICE_VALUE_TYPE(choice)
Definition: pod.h:158
static int spa_pod_filter_flags_value(struct spa_pod_builder *b, uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: filter.h:105
static struct spa_pod * spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
Definition: iter.h:367
static const struct spa_pod_prop * spa_pod_object_find_prop(const struct spa_pod_object *pod, const struct spa_pod_prop *start, uint32_t key)
Definition: iter.h:408
static void * spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:188
static int spa_pod_compare_value(uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: compare.h:53
#define SPA_POD_PROP_FLAG_MANDATORY
is mandatory
Definition: pod.h:242
static int spa_pod_filter_is_step_of(uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: filter.h:131
#define SPA_POD_CHOICE_VALUE_SIZE(choice)
Definition: pod.h:160
#define SPA_POD_OBJECT_FOREACH(obj, iter)
Definition: iter.h:128
#define SPA_POD_BODY(pod)
Definition: pod.h:59
static void spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:98
#define SPA_POD_TYPE(pod)
Definition: pod.h:48
static int spa_pod_filter_part(struct spa_pod_builder *b, const struct spa_pod *pod, uint32_t pod_size, const struct spa_pod *filter, uint32_t filter_size)
Definition: filter.h:350
static int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
Definition: filter.h:53
static int spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:180
static int spa_pod_filter_prop(struct spa_pod_builder *b, const struct spa_pod_prop *p1, const struct spa_pod_prop *p2)
Definition: filter.h:154
static int spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
Definition: builder.h:206
static bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
Definition: iter.h:54
static int spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:442
static void spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:85
#define SPA_POD_FOREACH(pod, size, iter)
Definition: iter.h:115
static void * spa_pod_next(const void *iter)
Definition: iter.h:60
#define SPA_POD_CHOICE_VALUES(choice)
Definition: pod.h:164
#define SPA_POD_PROP_SIZE(prop)
Definition: pod.h:225
static struct spa_pod * spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:125
static int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:148
static int spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t type, uint32_t flags)
Definition: builder.h:426
static int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
Definition: builder.h:267
static int spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t type, uint32_t id)
Definition: builder.h:455
static int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
Definition: builder.h:276
#define SPA_POD_CHOICE_N_VALUES(choice)
Definition: pod.h:162
#define SPA_POD_SIZE(pod)
Definition: pod.h:50
static int spa_pod_filter(struct spa_pod_builder *b, struct spa_pod **result, const struct spa_pod *pod, const struct spa_pod *filter)
Definition: filter.h:451
static struct spa_pod * spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
Definition: builder.h:113
@ SPA_CHOICE_Step
range with step: default, min, max, step
Definition: pod.h:169
@ SPA_CHOICE_None
no choice, first value is current
Definition: pod.h:167
@ SPA_CHOICE_Flags
flags: default, possible flags,...
Definition: pod.h:171
@ SPA_CHOICE_Range
range: default, min, max
Definition: pod.h:168
@ SPA_CHOICE_Enum
list: default, alternative,...
Definition: pod.h:170
@ SPA_TYPE_Int
Definition: type.h:54
@ SPA_TYPE_Rectangle
Definition: type.h:60
@ SPA_TYPE_Long
Definition: type.h:55
@ SPA_TYPE_Object
Definition: type.h:65
@ SPA_TYPE_Struct
Definition: type.h:64
#define spa_return_val_if_fail(expr, val)
Definition: defs.h:373
#define SPA_PTROFF(ptr_, offset_, type_)
Return the address (buffer + offset) as pointer of type.
Definition: defs.h:210
spa/pod/iter.h
spa/utils/string.h
Definition: builder.h:52
Definition: builder.h:73
uint32_t type
type of choice, one of enum spa_choice_type
Definition: pod.h:175
Definition: pod.h:182
struct spa_pod_choice_body body
Definition: pod.h:184
struct spa_pod pod
Definition: pod.h:183
Definition: iter.h:47
uint32_t type
one of enum spa_type
Definition: pod.h:198
uint32_t id
id of the object, depends on the object type
Definition: pod.h:199
Definition: pod.h:203
struct spa_pod_object_body body
Definition: pod.h:205
Definition: pod.h:228
uint32_t key
key of property, list of valid keys depends on the object type
Definition: pod.h:229
uint32_t flags
flags for property
Definition: pod.h:245
struct spa_pod value
Definition: pod.h:246
Definition: pod.h:187
Definition: pod.h:63
uint32_t type
Definition: pod.h:65
uint32_t size
Definition: pod.h:64
Definition: defs.h:118
uint32_t width
Definition: defs.h:119
uint32_t height
Definition: defs.h:120