]> git.sesse.net Git - mlt/blob - src/framework/mlt_property.c
aea00e72bdfda1766bb66a114cb827b88ac04542
[mlt] / src / framework / mlt_property.c
1 /**
2  * \file mlt_property.c
3  * \brief Property class definition
4  * \see mlt_property_s
5  *
6  * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7  * \author Charles Yates <charles.yates@pandora.be>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "mlt_property.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30
31 /** Bit pattern used internally to indicated representations available.
32 */
33
34 typedef enum
35 {
36         mlt_prop_none = 0,    //!< not set
37         mlt_prop_int = 1,     //!< set as an integer
38         mlt_prop_string = 2,  //!< set as string or already converted to string
39         mlt_prop_position = 4,//!< set as a position
40         mlt_prop_double = 8,  //!< set as a floating point
41         mlt_prop_data = 16,   //!< set as opaque binary
42         mlt_prop_int64 = 32   //!< set as a 64-bit integer
43 }
44 mlt_property_type;
45
46 /** \brief Property class
47  *
48  * A property is like a variant or dynamic type. They are used for many things
49  * in MLT, but in particular they are the parameter mechanism for the plugins.
50  */
51
52 struct mlt_property_s
53 {
54         /// Stores a bit pattern of types available for this property
55         mlt_property_type types;
56
57         /// Atomic type handling
58         int prop_int;
59         mlt_position prop_position;
60         double prop_double;
61         int64_t prop_int64;
62
63         /// String handling
64         char *prop_string;
65
66         /// Generic type handling
67         void *data;
68         int length;
69         mlt_destructor destructor;
70         mlt_serialiser serialiser;
71 };
72
73 /** Construct a property and initialize it
74  * \public \memberof mlt_property_s
75  */
76
77 mlt_property mlt_property_init( )
78 {
79         mlt_property self = malloc( sizeof( struct mlt_property_s ) );
80         if ( self != NULL )
81         {
82                 self->types = 0;
83                 self->prop_int = 0;
84                 self->prop_position = 0;
85                 self->prop_double = 0;
86                 self->prop_int64 = 0;
87                 self->prop_string = NULL;
88                 self->data = NULL;
89                 self->length = 0;
90                 self->destructor = NULL;
91                 self->serialiser = NULL;
92         }
93         return self;
94 }
95
96 /** Clear (0/null) a property.
97  *
98  * Frees up any associated resources in the process.
99  * \private \memberof mlt_property_s
100  * \param self a property
101  */
102
103 static inline void mlt_property_clear( mlt_property self )
104 {
105         // Special case data handling
106         if ( self->types & mlt_prop_data && self->destructor != NULL )
107                 self->destructor( self->data );
108
109         // Special case string handling
110         if ( self->types & mlt_prop_string )
111                 free( self->prop_string );
112
113         // Wipe stuff
114         self->types = 0;
115         self->prop_int = 0;
116         self->prop_position = 0;
117         self->prop_double = 0;
118         self->prop_int64 = 0;
119         self->prop_string = NULL;
120         self->data = NULL;
121         self->length = 0;
122         self->destructor = NULL;
123         self->serialiser = NULL;
124 }
125
126 /** Set the property to an integer value.
127  *
128  * \public \memberof mlt_property_s
129  * \param self a property
130  * \param value an integer
131  * \return false
132  */
133
134 int mlt_property_set_int( mlt_property self, int value )
135 {
136         mlt_property_clear( self );
137         self->types = mlt_prop_int;
138         self->prop_int = value;
139         return 0;
140 }
141
142 /** Set the property to a floating point value.
143  *
144  * \public \memberof mlt_property_s
145  * \param self a property
146  * \param value a double precision floating point value
147  * \return false
148  */
149
150 int mlt_property_set_double( mlt_property self, double value )
151 {
152         mlt_property_clear( self );
153         self->types = mlt_prop_double;
154         self->prop_double = value;
155         return 0;
156 }
157
158 /** Set the property to a position value.
159  *
160  * Position is a relative time value in frame units.
161  * \public \memberof mlt_property_s
162  * \param self a property
163  * \param value a position value
164  * \return false
165  */
166
167 int mlt_property_set_position( mlt_property self, mlt_position value )
168 {
169         mlt_property_clear( self );
170         self->types = mlt_prop_position;
171         self->prop_position = value;
172         return 0;
173 }
174
175 /** Set the property to a string value.
176  *
177  * This makes a copy of the string you supply so you do not need to track
178  * a new reference to it.
179  * \public \memberof mlt_property_s
180  * \param self a property
181  * \param value the string to copy to the property
182  * \return true if it failed
183  */
184
185 int mlt_property_set_string( mlt_property self, const char *value )
186 {
187         if ( value != self->prop_string )
188         {
189                 mlt_property_clear( self );
190                 self->types = mlt_prop_string;
191                 if ( value != NULL )
192                         self->prop_string = strdup( value );
193         }
194         else
195         {
196                 self->types = mlt_prop_string;
197         }
198         return self->prop_string == NULL;
199 }
200
201 /** Set the property to a 64-bit integer value.
202  *
203  * \public \memberof mlt_property_s
204  * \param self a property
205  * \param value a 64-bit integer
206  * \return false
207  */
208
209 int mlt_property_set_int64( mlt_property self, int64_t value )
210 {
211         mlt_property_clear( self );
212         self->types = mlt_prop_int64;
213         self->prop_int64 = value;
214         return 0;
215 }
216
217 /** Set a property to an opaque binary value.
218  *
219  * This does not make a copy of the data. You can use a Properties object
220  * with its reference tracking and the destructor function to control
221  * the lifetime of the data. Otherwise, pass NULL for the destructor
222  * function and control the lifetime yourself.
223  * \public \memberof mlt_property_s
224  * \param self a property
225  * \param value an opaque pointer
226  * \param length the number of bytes pointed to by value (optional)
227  * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource)
228  * \param serialiser a function to use to convert this binary data to a string (optional)
229  * \return false
230  */
231
232 int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
233 {
234         if ( self->data == value )
235                 self->destructor = NULL;
236         mlt_property_clear( self );
237         self->types = mlt_prop_data;
238         self->data = value;
239         self->length = length;
240         self->destructor = destructor;
241         self->serialiser = serialiser;
242         return 0;
243 }
244
245 /** Convert a base 10 or base 16 string to an integer.
246  *
247  * The string must begin with '0x' to be interpreted as hexadecimal.
248  * Otherwise, it is interpreted as base 10.
249  * If the string begins with '#' it is interpreted as a hexadecimal color value
250  * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are
251  * always in the form RRGGBBAA where the alpha components are not optional.
252  * Applications and services should expect the binary color value in bytes to
253  * be in the following order: RGBA. This means they will have to cast the int
254  * to an unsigned int. This is especially important when they need to shift
255  * right to obtain RGB without alpha in order to make it do a logical instead
256  * of arithmetic shift.
257  *
258  * \private \memberof mlt_property_s
259  * \param value a string to convert
260  * \return the resultant integer
261  */
262 static inline int mlt_property_atoi( const char *value )
263 {
264         if ( value == NULL )
265                 return 0;
266         // Parse a hex color value as #RRGGBB or #AARRGGBB.
267         if ( value[0] == '#' )
268         {
269                 unsigned int rgb = strtoul( value + 1, NULL, 16 );
270                 unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff;
271                 return ( rgb << 8 ) | alpha;
272         }
273         // Do hex and decimal explicitly to avoid decimal value with leading zeros
274         // interpreted as octal.
275         else if ( value[0] == '0' && value[1] == 'x' )
276         {
277                 return strtoul( value + 2, NULL, 16 );
278         }
279         else
280         {
281                 return strtol( value, NULL, 10 );
282         }
283 }
284
285 /** Get the property as an integer.
286  *
287  * \public \memberof mlt_property_s
288  * \param self a property
289  * \return an integer value
290  */
291
292 int mlt_property_get_int( mlt_property self )
293 {
294         if ( self->types & mlt_prop_int )
295                 return self->prop_int;
296         else if ( self->types & mlt_prop_double )
297                 return ( int )self->prop_double;
298         else if ( self->types & mlt_prop_position )
299                 return ( int )self->prop_position;
300         else if ( self->types & mlt_prop_int64 )
301                 return ( int )self->prop_int64;
302         else if ( ( self->types & mlt_prop_string ) && self->prop_string )
303                 return mlt_property_atoi( self->prop_string );
304         return 0;
305 }
306
307 /** Get the property as a floating point.
308  *
309  * \public \memberof mlt_property_s
310  * \param self a property
311  * \return a floating point value
312  */
313
314 double mlt_property_get_double( mlt_property self )
315 {
316         if ( self->types & mlt_prop_double )
317                 return self->prop_double;
318         else if ( self->types & mlt_prop_int )
319                 return ( double )self->prop_int;
320         else if ( self->types & mlt_prop_position )
321                 return ( double )self->prop_position;
322         else if ( self->types & mlt_prop_int64 )
323                 return ( double )self->prop_int64;
324         else if ( ( self->types & mlt_prop_string ) && self->prop_string )
325                 return atof( self->prop_string );
326         return 0;
327 }
328
329 /** Get the property as a position.
330  *
331  * A position is an offset time in terms of frame units.
332  * \public \memberof mlt_property_s
333  * \param self a property
334  * \return the position in frames
335  */
336
337 mlt_position mlt_property_get_position( mlt_property self )
338 {
339         if ( self->types & mlt_prop_position )
340                 return self->prop_position;
341         else if ( self->types & mlt_prop_int )
342                 return ( mlt_position )self->prop_int;
343         else if ( self->types & mlt_prop_double )
344                 return ( mlt_position )self->prop_double;
345         else if ( self->types & mlt_prop_int64 )
346                 return ( mlt_position )self->prop_int64;
347         else if ( ( self->types & mlt_prop_string ) && self->prop_string )
348                 return ( mlt_position )atol( self->prop_string );
349         return 0;
350 }
351
352 /** Convert a string to a 64-bit integer.
353  *
354  * If the string begins with '0x' it is interpreted as a hexadecimal value.
355  * \private \memberof mlt_property_s
356  * \param value a string
357  * \return a 64-bit integer
358  */
359
360 static inline int64_t mlt_property_atoll( const char *value )
361 {
362         if ( value == NULL )
363                 return 0;
364         else if ( value[0] == '0' && value[1] == 'x' )
365                 return strtoll( value + 2, NULL, 16 );
366         else
367                 return strtoll( value, NULL, 10 );
368 }
369
370 /** Get the property as a signed integer.
371  *
372  * \public \memberof mlt_property_s
373  * \param self a property
374  * \return a 64-bit integer
375  */
376
377 int64_t mlt_property_get_int64( mlt_property self )
378 {
379         if ( self->types & mlt_prop_int64 )
380                 return self->prop_int64;
381         else if ( self->types & mlt_prop_int )
382                 return ( int64_t )self->prop_int;
383         else if ( self->types & mlt_prop_double )
384                 return ( int64_t )self->prop_double;
385         else if ( self->types & mlt_prop_position )
386                 return ( int64_t )self->prop_position;
387         else if ( ( self->types & mlt_prop_string ) && self->prop_string )
388                 return mlt_property_atoll( self->prop_string );
389         return 0;
390 }
391
392 /** Get the property as a string.
393  *
394  * The caller is not responsible for deallocating the returned string!
395  * The string is deallocated when the Property is closed.
396  * This tries its hardest to convert the property to string including using
397  * a serialization function for binary data, if supplied.
398  * \public \memberof mlt_property_s
399  * \param self a property
400  * \return a string representation of the property or NULL if failed
401  */
402
403 char *mlt_property_get_string( mlt_property self )
404 {
405         // Construct a string if need be
406         if ( ! ( self->types & mlt_prop_string ) )
407         {
408                 if ( self->types & mlt_prop_int )
409                 {
410                         self->types |= mlt_prop_string;
411                         self->prop_string = malloc( 32 );
412                         sprintf( self->prop_string, "%d", self->prop_int );
413                 }
414                 else if ( self->types & mlt_prop_double )
415                 {
416                         self->types |= mlt_prop_string;
417                         self->prop_string = malloc( 32 );
418                         sprintf( self->prop_string, "%f", self->prop_double );
419                 }
420                 else if ( self->types & mlt_prop_position )
421                 {
422                         self->types |= mlt_prop_string;
423                         self->prop_string = malloc( 32 );
424                         sprintf( self->prop_string, "%d", (int)self->prop_position );
425                 }
426                 else if ( self->types & mlt_prop_int64 )
427                 {
428                         self->types |= mlt_prop_string;
429                         self->prop_string = malloc( 32 );
430                         sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
431                 }
432                 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
433                 {
434                         self->types |= mlt_prop_string;
435                         self->prop_string = self->serialiser( self->data, self->length );
436                 }
437         }
438
439         // Return the string (may be NULL)
440         return self->prop_string;
441 }
442
443 /** Get the binary data from a property.
444  *
445  * This only works if you previously put binary data into the property.
446  * This does not return a copy of the data; it returns a pointer to it.
447  * If you supplied a destructor function when setting the binary data,
448  * the destructor is used when the Property is closed to free the memory.
449  * Therefore, only free the returned pointer if you did not supply a
450  * destructor function.
451  * \public \memberof mlt_property_s
452  * \param self a property
453  * \param[out] length the size of the binary object in bytes (optional)
454  * \return an opaque data pointer or NULL if not available
455  */
456
457 void *mlt_property_get_data( mlt_property self, int *length )
458 {
459         // Assign length if not NULL
460         if ( length != NULL )
461                 *length = self->length;
462
463         // Return the data (note: there is no conversion here)
464         return self->data;
465 }
466
467 /** Destroy a property and free all related resources.
468  *
469  * \public \memberof mlt_property_s
470  * \param self a property
471  */
472
473 void mlt_property_close( mlt_property self )
474 {
475         mlt_property_clear( self );
476         free( self );
477 }
478
479 /** Copy a property.
480  *
481  * A Property holding binary data only copies the data if a serialiser
482  * function was supplied when you set the Property.
483  * \public \memberof mlt_property_s
484  * \author Zach <zachary.drew@gmail.com>
485  * \param self a property
486  * \param that another property
487  */
488 void mlt_property_pass( mlt_property self, mlt_property that )
489 {
490         mlt_property_clear( self );
491
492         self->types = that->types;
493
494         if ( self->types & mlt_prop_int64 )
495                 self->prop_int64 = that->prop_int64;
496         else if ( self->types & mlt_prop_int )
497                 self->prop_int = that->prop_int;
498         else if ( self->types & mlt_prop_double )
499                 self->prop_double = that->prop_double;
500         else if ( self->types & mlt_prop_position )
501                 self->prop_position = that->prop_position;
502         else if ( self->types & mlt_prop_string )
503         {
504                 if ( that->prop_string != NULL )
505                         self->prop_string = strdup( that->prop_string );
506         }
507         else if ( self->types & mlt_prop_data && self->serialiser != NULL )
508         {
509                 self->types = mlt_prop_string;
510                 self->prop_string = self->serialiser( self->data, self->length );
511         }
512 }