]> git.sesse.net Git - vlc/blob - include/vlc_media_library.h
Atom: use volatile keyword
[vlc] / include / vlc_media_library.h
1 /*****************************************************************************
2  * vlc_media_library.h: SQL-based media library
3  *****************************************************************************
4  * Copyright (C) 2008-2010 the VideoLAN Team and AUTHORS
5  * $Id$
6  *
7  * Authors: Antoine Lejeune <phytos@videolan.org>
8  *          Jean-Philippe André <jpeg@videolan.org>
9  *          Rémi Duraffort <ivoire@videolan.org>
10  *          Adrien Maglo <magsoft@videolan.org>
11  *          Srikanth Raju <srikiraju at gmail dot com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #ifndef VLC_MEDIA_LIBRARY_H
29 # define VLC_MEDIA_LIBRARY_H
30
31 # ifdef __cplusplus
32 extern "C" {
33 # endif
34
35 #include <vlc_common.h>
36 #include <assert.h>
37 #include <vlc_playlist.h>
38
39 /*****************************************************************************
40  * ML Enums
41  *****************************************************************************/
42
43 #define ML_PERSON_ARTIST        "Artist"
44 #define ML_PERSON_ALBUM_ARTIST  "Album Artist"
45 #define ML_PERSON_ENCODER       "Encoder"
46 #define ML_PERSON_PUBLISHER     "Publisher"
47
48
49 #define ml_priv( gc, t ) ((t *)(((char *)(gc)) - offsetof(t, ml_gc_data)))
50
51 /** List of Query select types.
52  * In a query array or variable argument list, each select type is followed
53  * by an argument (X) of variable type (char* or int, @see ml_element_t).
54  * These types can be used either in the query list or in the result array.
55  * Some types are reserved for the result array:
56  */
57 typedef enum
58 {
59     ML_ALBUM = 1,              /**< Album Title */
60     ML_ALBUM_ID,               /**< Album ID */
61     ML_ALBUM_COVER,            /**< Album Cover art url */
62     /* FIXME: Remove ML_ARTIST */
63     ML_ARTIST,                 /**< Artist, interpreted as ML_PEOPLE
64                                     && ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
65     ML_ARTIST_ID,              /**< Artist ID, interpreted as ML_PEOPLE_ID
66                                     && ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
67     ML_COMMENT,                /**< Comment about media */
68     ML_COUNT_MEDIA,            /**< Number of medias */
69     ML_COUNT_ALBUM,            /**< Number of albums */
70     ML_COUNT_PEOPLE,           /**< Number of people */
71     ML_COVER,                  /**< Cover art url */
72     ML_DURATION,               /**< Duration in ms */
73     ML_DISC_NUMBER,            /**< Disc number of the track */
74     ML_EXTRA,                  /**< Extra/comment (string) on the media */
75     ML_FIRST_PLAYED,           /**< First time media was played */
76     ML_FILESIZE,               /**< Size of the media file */
77     ML_GENRE,                  /**< Genre of the media (if any) */
78     ML_ID,                     /**< Media ID */
79     ML_IMPORT_TIME,            /**< Date when media was imported */
80     ML_LANGUAGE,               /**< Language */
81     ML_LAST_PLAYED,            /**< Last play UNIX timestamp */
82     ML_LAST_SKIPPED,           /**< Time when media was last skipped */
83     ML_ORIGINAL_TITLE,         /**< Media original title (if any) */
84     ML_PEOPLE,                 /**< Any People associated with this media */
85     ML_PEOPLE_ID,              /**< Id of a person */
86     ML_PEOPLE_ROLE,            /**< Person role */
87     ML_PLAYED_COUNT,           /**< Media play count */
88     ML_PREVIEW,                /**< Url of the video preview */
89     ML_SKIPPED_COUNT,          /**< Number of times skipped */
90     ML_SCORE,                  /**< Computed media score */
91     ML_TITLE,                  /**< Media title */
92     ML_TRACK_NUMBER,           /**< Media track number (if any) */
93     ML_TYPE,                   /**< Media type. @see ml_type_e */
94     ML_URI,                    /**< Media full URI. */
95     ML_VOTE,                   /**< Media user vote value */
96     ML_YEAR,                   /**< Media publishing year */
97     ML_DIRECTORY,              /**< Monitored directory */
98     ML_MEDIA,                  /**< Full media descriptor. @see ml_media_t */
99     ML_MEDIA_SPARSE,           /**< Sparse media. @see ml_media_t */
100     ML_MEDIA_EXTRA,            /**< Sparse + Extra = Full media */
101
102     /* Some special elements */
103     ML_LIMIT     = -1,         /**< Limit a query to X results */
104     ML_SORT_DESC = -2,         /**< Sort a query descending on argument X */
105     ML_SORT_ASC  = -3,         /**< Sort a query ascending on argument X */
106     ML_DISTINCT  = -4,         /**< Add DISTINCT to SELECT statements. */
107     ML_END       = -42         /**< End of argument list */
108 } ml_select_e;
109
110 /** Media types (audio, video, etc...) */
111 typedef enum
112 {
113     ML_UNKNOWN   = 0,       /**< Unknown media type */
114     ML_AUDIO     = 1 << 0,  /**< Audio only media */
115     ML_VIDEO     = 1 << 1,  /**< Video media. May contain audio channels */
116     ML_STREAM    = 1 << 2,  /**< Streamed media = not a local file */
117     ML_NODE      = 1 << 3,  /**< Nodes like simple nodes, directories, playlists, etc */
118     ML_REMOVABLE = 1 << 4,  /**< Removable media: CD/DVD/Card/... */
119 } ml_type_e;
120
121 /** Query result item/list type: integers, strings, medias, timestamps */
122 typedef enum {
123     ML_TYPE_INT,        /**< Object is an int */
124     ML_TYPE_PSZ,        /**< A string char* */
125     ML_TYPE_TIME,       /**< A timestamp mtime_t */
126     ML_TYPE_MEDIA,      /**< A pointer to a media ml_media_t* */
127 } ml_result_type_e;
128
129 /** Arguments for VLC Control for the media library */
130 typedef enum
131 {
132     ML_SET_DATABASE,      /**< arg1 = char *psz_host
133                                arg2 = int i_port
134                                arg3 = char *psz_user
135                                arg4 = char *psz_pass */
136     ML_INIT_DATABASE,     /**< No arg */
137     ML_ADD_INPUT_ITEM,    /**< arg1 = input_item_t* */
138     ML_ADD_PLAYLIST_ITEM, /**< arg1 = playlist_item_t * */
139     ML_ADD_MONITORED,     /**< arg1 = char* */
140     ML_DEL_MONITORED,     /**< arg1 = char* */
141     ML_GET_MONITORED,     /**< arg1 = vlc_array_t* */
142 } ml_control_e;
143
144 /* Operations that can be specified between find conditions */
145 typedef enum
146 {
147     ML_OP_NONE = 0,       /**< This is to specify an actual condition */
148     ML_OP_AND,            /**< AND condition */
149     ML_OP_OR,             /**< OR condition */
150     ML_OP_NOT,            /**< NOT condition */
151     ML_OP_SPECIAL         /**< This is for inclusion of
152                             *  special stuffs like LIMIT */
153 } ml_op_e;
154
155 /* Comparison operators used in a single find condition */
156 typedef enum
157 {
158     ML_COMP_NONE = 0,
159     ML_COMP_LESSER,              ///< <
160     ML_COMP_LESSER_OR_EQUAL,     ///< <=
161     ML_COMP_EQUAL,               ///< ==
162     ML_COMP_GREATER_OR_EQUAL,    ///< >=
163     ML_COMP_GREATER,             ///< >
164     ML_COMP_HAS,                 ///< "Contains", equivalent to SQL "LIKE %x%"
165     ML_COMP_STARTS_WITH,         ///< Equivalent to SQL "LIKE %x"
166     ML_COMP_ENDS_WITH,           ///< Equivalent to SQL "LIKE x%"
167 } ml_comp_e;
168
169 /*****************************************************************************
170  * ML Structures and types
171  *****************************************************************************/
172
173 typedef struct media_library_t media_library_t;
174 typedef struct media_library_sys_t media_library_sys_t;
175
176 typedef struct ml_media_t      ml_media_t;
177 typedef struct ml_result_t     ml_result_t;
178 typedef struct ml_element_t    ml_element_t;
179 typedef struct ml_person_t     ml_person_t;
180 typedef struct ml_ftree_t      ml_ftree_t;
181
182
183 typedef struct ml_gc_object_t
184 {
185     vlc_spinlock_t spin;
186     bool           pool;
187     uintptr_t      refs;
188     void          (*pf_destructor) (struct ml_gc_object_t *);
189 } ml_gc_object_t;
190
191 #define ML_GC_MEMBERS ml_gc_object_t ml_gc_data;
192
193 /** Main structure of the media library. VLC object. */
194 struct media_library_t
195 {
196     VLC_COMMON_MEMBERS
197
198     module_t             *p_module;  /**< the media library module */
199     media_library_sys_t  *p_sys;     /**< internal struture */
200
201     /** Member functions */
202     struct
203     {
204         /**< Search in the database */
205         int ( * pf_Find )            ( media_library_t *p_media_library,
206                                        vlc_array_t *p_result_array,
207                                        va_list args );
208
209         /**< Search in the database using an array of arguments */
210         int ( * pf_FindAdv )         ( media_library_t *p_media_library,
211                                        vlc_array_t *p_result_array,
212                                        ml_select_e selected_type,
213                                        const char *psz_lvalue,
214                                        ml_ftree_t *tree );
215
216         /**< Update the database using an array of arguments */
217         int ( * pf_Update )          ( media_library_t *p_media_library,
218                                        ml_select_e selected_type,
219                                        const char *psz_lvalue,
220                                        ml_ftree_t *where,
221                                        vlc_array_t *changes );
222
223         /**< Delete many medias in the database */
224         int ( * pf_Delete )    ( media_library_t *p_media_library,
225                                        vlc_array_t *p_array );
226
227         /**< Control the media library */
228         int ( * pf_Control ) ( media_library_t *p_media_library,
229                                int i_query, va_list args );
230
231         /**< Create associated input item */
232         input_item_t* ( * pf_InputItemFromMedia ) (
233                     media_library_t *p_media_library, int i_media );
234
235         /**< Get a media */
236         ml_media_t* ( * pf_GetMedia ) (
237                     media_library_t *p_media_library, int i_media,
238                     ml_select_e select, bool reload );
239     } functions;
240 };
241
242
243 /**
244  * @brief Structure to describe a media
245  *
246  * This is the main structure holding the meta data in ML.
247  * @see b_sparse indicates whether the media struct has valid values
248  * in its Extra fields. Otherwise, it must be loaded with the API
249  * function.
250  * @see i_id indicates whether this struct is saved in the ML if i_id > 0
251  * Otherwise, it can be added to the database
252  */
253 struct ml_media_t
254 {
255     ML_GC_MEMBERS
256     vlc_mutex_t     lock;               /**< Mutex for multithreaded access */
257     bool            b_sparse;           /**< Specifies if media is loaded fully */
258     ml_type_e       i_type;             /**< Type of the media (ml_type_e) */
259     int8_t          i_vote;             /**< User vote */
260     int16_t         i_disc_number;      /**< Disc number of media */
261     int16_t         i_track_number;     /**< Track number */
262     int16_t         i_year;             /**< Year of release */
263     int32_t         i_id;               /**< Media ID in the database */
264     int32_t         i_score;            /**< Score computed about the media */
265     int32_t         i_album_id;         /**< Album id */
266     int32_t         i_played_count;     /**< How many time the media was played */
267     int32_t         i_skipped_count;    /**< No. of times file was skipped */
268     int32_t         i_bitrate;          /**< Extra: Bitrate of the media */
269     int32_t         i_samplerate;       /**< Extra: Samplerate of the media */
270     int32_t         i_bpm;              /**< Extra: Beats per minute */
271     char            *psz_uri;           /**< URI to find the media */
272     char            *psz_title;         /**< Title of the media */
273     char            *psz_orig_title;    /**< Original title (mainly for movies) */
274     char            *psz_album;         /**< Name of the album */
275     char            *psz_cover;         /**< URI of the cover */
276     char            *psz_genre;         /**< Genre of the media */
277     char            *psz_preview;       /**< Preview thumbnail for video, if any */
278     char            *psz_comment;       /**< Comment or description about media */
279     char            *psz_language;      /**< Extra: Language */
280     char            *psz_extra;         /**< Extra: Some extra datas like lyrics */
281     ml_person_t     *p_people;          /**< Extra: People associated with this
282                                              media This meta holds only one
283                                              artist if b_sparse = true */
284     int64_t         i_filesize;         /**< Size of the file */
285     mtime_t         i_duration;         /**< Duration in microseconds */
286     mtime_t         i_last_played;      /**< Time when the media was last played */
287     mtime_t         i_last_skipped;     /**< Time when the media was last skipped */
288     mtime_t         i_first_played;     /**< First played */
289     mtime_t         i_import_time;      /**< Time when media was added */
290
291 };
292
293
294 /**
295  * @brief Main communication struct between GUI and sql_media_library.
296  * Generic representation of an ML/SQL query result.
297  */
298 struct ml_result_t
299 {
300     int32_t          id;        /**< Media/Album/Artist... ID (if any) */
301     ml_result_type_e type;      /**< Type of value */
302     union
303     {
304         /* Classical results */
305         int             i;
306         char           *psz;
307         mtime_t         time;
308
309         /* Complex result: media descriptor */
310         ml_media_t     *p_media;
311     } value;                    /**< Value of the result obtained */
312 };
313
314
315 /**
316  * @brief Element of a query: criteria type/value pair
317  * Used for update and delete queries
318  */
319 struct ml_element_t
320 {
321     ml_select_e    criteria;    /**< SELECT criteria type. @see ml_select_e */
322     union
323     {
324         int     i;
325         char*   str;
326     } value;                    /**< SELECT criteria value (string or int) */
327     union
328     {
329         int     i;
330         char*   str;
331     } lvalue;                   /**< Refer to @see ml_ftree_t lvalue docs */
332 };
333
334 /**
335  * Binary tree used to parse the WHERE condition for a search
336  *
337  * Let [expr] indicate a valid expression
338  * [expr] = [expr] AND [expr], where the left and right are respective
339  * [expr] = [expr] OR [expr]
340  * [expr] = [expr] NOT [NULL]
341  * [expr] = [expr] SPEC [spec_expr]
342  * [expr] = [criteria=val]
343  * [spec_expr] = [DISTINCT/LIMIT/ASC/DESC = val ]
344  */
345 struct ml_ftree_t
346 {
347     ml_op_e         op;         /**< Operator. ML_OP_NONE means this is a leaf
348                                   *  node. Criteria and value gives its data.
349                                   *  ML_OP_SPECIAL specifies a special node
350                                   *  that does not form a part of the WHERE.
351                                   *  The right node consists of the data
352                                   *  with its criteria set to the special val
353                                   *  and the left node is the corresponding
354                                   *  subtree of the parent node.
355                                   *  ML_OP_NOT only left sub tree is considered
356                                   *  ML_OP_AND and ML_OP_OR consider both
357                                   *  left and right subtrees */
358     ml_ftree_t      *left;      /**< Left child of Bin tree */
359     ml_ftree_t      *right;     /**< Right child of Bin tree */
360     ml_select_e     criteria;   /**< SELECT criteria type @see ml_select_e
361                                   *  The criteria value is considered only when
362                                   *  op = ML_OP_NONE i.e. in leaf nodes */
363     ml_comp_e       comp;       /**< Condition between type and value */
364     union
365     {
366         int     i;
367         char    *str;
368     } value;                    /**< SELECT criteria value ( string or int ) */
369     union
370     {
371         int     i;
372         char    *str;
373     } lvalue;                   /**< Used as key value for people types/roles.
374                                      An empty string "" denotes ANY person role.
375                                      NULL is used for all other criterias */
376 };
377
378
379 /**
380  * Person class. Implemented as a linked list
381  */
382 struct ml_person_t
383 {
384     char               *psz_role;   /**< Type of person */
385     char               *psz_name;   /**< Name of the person */
386     int                 i_id;       /**< ID in the database */
387     ml_person_t        *p_next;     /**< Next person in list */
388 };
389
390
391 /*****************************************************************************
392  * ML Function headers
393  *****************************************************************************/
394
395 /**
396  * @brief Acquire a reference to the media library singleton
397  * @param p_this The object holding the media library
398  * @return The media library object. NULL if the media library
399  * object could not be loaded
400  */
401 VLC_EXPORT( media_library_t*, __ml_Hold, ( vlc_object_t* p_this ) );
402 #define ml_Hold( a ) __ml_Hold( VLC_OBJECT(a) )
403
404 /**
405  * @brief Discard your ref to media library
406  * @param p_this The object holding the media library
407  */
408 VLC_EXPORT( void, __ml_Release, ( vlc_object_t* p_this ) );
409 #define ml_Release(a) __ml_Release( VLC_OBJECT(a))
410
411 /**
412  * @brief Create a Media Library VLC object.
413  * @param p_this Parent to attach the ML object to.
414  * @param psz_name Name for the module
415  * @return The ML object.
416  */
417 VLC_EXPORT( media_library_t*, __ml_Create, ( vlc_object_t *p_this, char* psz_name ) );
418
419 /**
420  * @brief Destructor for the Media library singleton
421  * @param p_this Parent the ML object is attached to
422  */
423 VLC_EXPORT( void, __ml_Destroy, ( vlc_object_t* p_this ) );
424
425 /**
426  * @brief Control the Media Library
427  * @param p_media_library the media library object
428  * @param i_type one of ml_control_e values @see ml_control_e.
429  * @param ... optional arguments.
430  * @return VLC_SUCCESS or an error
431  */
432 static inline int ml_ControlVa( media_library_t *p_media_library,
433                                 ml_control_e i_type, va_list args )
434 {
435     return p_media_library->functions.pf_Control( p_media_library,
436                                                   i_type,
437                                                   args );
438 }
439
440 /**
441  * @brief Control the Media Library
442  * @param i_type one of ml_control_e values @see ml_control_e.
443  * Variable arguments list equivalent
444  */
445 #define ml_Control( a, b, args... )     __ml_Control( a, b, ## args )
446 static inline int __ml_Control( media_library_t *p_media_library,
447                                 ml_control_e i_type, ... )
448 {
449     va_list args;
450     int returned;
451
452     va_start( args, i_type );
453     returned = ml_ControlVa( p_media_library, i_type, args );
454     va_end( args );
455
456     return returned;
457 }
458
459 /**
460  * @brief Determine an attribute's type (int or string)
461  * @param meta Attribute to test @see ml_select_e
462  * @return -1 if invalid, 0 if this is an integer, 1 if this is a string
463  */
464 static inline int ml_AttributeIsString( ml_select_e meta )
465 {
466     switch( meta )
467     {
468     /* Strings */
469     case ML_ALBUM:
470     case ML_ARTIST:
471     case ML_COMMENT:
472     case ML_COVER:
473     case ML_EXTRA:
474     case ML_GENRE:
475     case ML_LANGUAGE:
476     case ML_PREVIEW:
477     case ML_PEOPLE:
478     case ML_PEOPLE_ROLE:
479     case ML_ORIGINAL_TITLE:
480     case ML_TITLE:
481     case ML_URI:
482         return 1;
483
484     /* Integers */
485     case ML_ALBUM_ID:
486     case ML_ARTIST_ID:
487     case ML_DURATION:
488     case ML_DISC_NUMBER:
489     case ML_COUNT_MEDIA:
490     case ML_COUNT_ALBUM:
491     case ML_COUNT_PEOPLE:
492     case ML_FILESIZE:
493     case ML_FIRST_PLAYED:
494     case ML_ID:
495     case ML_IMPORT_TIME:
496     case ML_LAST_PLAYED:
497     case ML_LIMIT:
498     case ML_PLAYED_COUNT:
499     case ML_PEOPLE_ID:
500     case ML_SCORE:
501     case ML_SKIPPED_COUNT:
502     case ML_TRACK_NUMBER:
503     case ML_TYPE:
504     case ML_VOTE:
505     case ML_YEAR:
506         return 0;
507
508     /* Invalid or no following value (in a SELECT statement) */
509     default:
510         return -1;
511     }
512 }
513
514 /* Reference Counting Functions */
515 /**
516  * @brief Increment reference count of media
517  * @param p_media The media object
518  */
519 static inline void ml_gc_incref( ml_media_t* p_media )
520 {
521     unsigned refs;
522     ml_gc_object_t* p_gc = &p_media->ml_gc_data;
523     assert( p_gc );
524
525     vlc_spin_lock (&p_gc->spin);
526     refs = ++p_gc->refs;
527     vlc_spin_unlock (&p_gc->spin);
528     assert (refs != 1); /* there had to be a reference already */
529 }
530
531 /**
532  * @brief Decrease reference count of media
533  * @param p_media The media object
534  */
535 static inline void ml_gc_decref( ml_media_t* p_media )
536 {
537     /* The below code is from vlc_release(). */
538     unsigned refs;
539     bool pool;
540     ml_gc_object_t* p_gc = &p_media->ml_gc_data;
541     assert( p_gc );
542
543     vlc_spin_lock (&p_gc->spin);
544     assert( p_gc->refs != 0 );
545     refs = --p_gc->refs;
546     pool = p_gc->pool;
547     assert( ( refs != 0 && p_gc->pool == true ) || ( refs == 0 && p_gc->pool == false )  );
548     vlc_spin_unlock (&p_gc->spin);
549
550     if( refs == 0 && pool == false )
551     {
552         vlc_spin_destroy (&p_gc->spin);
553         p_gc->pf_destructor (p_gc);
554     }
555 }
556
557 /*****************************************************************************
558  * ML Free Functions
559  *****************************************************************************/
560
561 /**
562  * @brief Free a person object
563  * @param p_media Person object to free
564  * @note This function is NOT threadsafe
565  */
566 static inline void ml_FreePeople( ml_person_t *p_person )
567 {
568     if( p_person == NULL )
569         return;
570     ml_FreePeople( p_person->p_next );
571     free( p_person->psz_name );
572     free( p_person->psz_role );
573     free( p_person );
574 }
575
576 /**
577  * @brief Free only the content of a media. @see ml_media_t
578  * @param p_media Media object
579  * @note This function is NOT threadsafe.
580  */
581 static inline void ml_FreeMediaContent( ml_media_t *p_media )
582 {
583     free( p_media->psz_uri );
584     free( p_media->psz_title );
585     free( p_media->psz_orig_title );
586     free( p_media->psz_cover );
587     free( p_media->psz_comment );
588     free( p_media->psz_extra );
589     free( p_media->psz_genre );
590     free( p_media->psz_album );
591     free( p_media->psz_preview );
592     free( p_media->psz_language );
593     ml_FreePeople( p_media->p_people );
594     p_media->b_sparse = true;
595     p_media->i_id = 0;
596     p_media->i_type = ML_UNKNOWN;
597     p_media->i_album_id = 0;
598     p_media->i_disc_number = 0;
599     p_media->i_track_number = 0;
600     p_media->i_year = 0;
601     p_media->i_vote = 0;
602     p_media->i_score = 0;
603     p_media->i_filesize = 0;
604     p_media->i_duration = 0;
605     p_media->i_played_count = 0;
606     p_media->i_last_played = 0;
607     p_media->i_skipped_count = 0;
608     p_media->i_last_skipped = 0;
609     p_media->i_first_played = 0;
610     p_media->i_import_time = 0;
611     p_media->i_bitrate = 0;
612     p_media->i_samplerate = 0;
613     p_media->i_bpm = 0;
614 }
615
616 /**
617  * @brief Free a result item. @see ml_result_t
618  * @param p_result Result item to free
619  * @note This will free any strings and decref medias.
620  */
621 static inline void ml_FreeResult( ml_result_t *p_result )
622 {
623     if( p_result )
624     {
625         switch( p_result->type )
626         {
627             case ML_TYPE_PSZ:
628                 free( p_result->value.psz );
629                 break;
630             case ML_TYPE_MEDIA:
631                 ml_gc_decref( p_result->value.p_media );
632                 break;
633             default:
634                 break;
635         }
636         free( p_result );
637     }
638 }
639
640
641 /**
642  * @brief Free a ml_element_t item.
643  * @param p_find Find object to free
644  * @see ml_element_t */
645 static inline void ml_FreeElement( ml_element_t *p_elt )
646 {
647     if( p_elt )
648     {
649         if( ml_AttributeIsString( p_elt->criteria ) )
650         {
651             free( p_elt->value.str );
652         }
653         if( p_elt->criteria == ML_PEOPLE )
654         {
655             free( p_elt->lvalue.str );
656         }
657         free( p_elt );
658     }
659 }
660
661
662 /**
663  * @brief Destroy a vlc_array_t of ml_result_t
664  * @param ml_result_array The result array to free
665  * @note Frees all results and contents of the results
666  */
667 static inline void ml_DestroyResultArray( vlc_array_t *p_result_array )
668 {
669     for( int i = 0; i < vlc_array_count( p_result_array ); i++ )
670     {
671         ml_FreeResult( ( ml_result_t* ) vlc_array_item_at_index(
672                 p_result_array, i ) );
673     }
674 }
675
676
677
678 /*****************************************************************************
679  * ML Object Management Functions
680  *****************************************************************************/
681
682 /** Helpers for locking and unlocking */
683 #define ml_LockMedia( a )      vlc_mutex_lock( &a->lock )
684 #define ml_UnlockMedia( a )    vlc_mutex_unlock( &a->lock )
685
686 /**
687  * @brief Object constructor for ml_media_t
688  * @param p_ml The media library object
689  * @param id If 0, this item isn't in database. If non zero, it is and
690  * it will be a singleton
691  * @param select Type of object
692  * @param reload Whether to reload from database
693  */
694 VLC_EXPORT( ml_media_t*, media_New, ( media_library_t* p_ml, int id,
695         ml_select_e select, bool reload ) );
696
697
698 /* Forward declaration */
699 static inline int ml_CopyPersons( ml_person_t** a, ml_person_t* b );
700
701 /**
702  * @brief Copy all members of a ml_media_t to another.
703  * @param b Destination media, already allocated
704  * @param a Source media, cannot be NULL, const
705  * @note This does not check memory allocation (for strdup). It is threadsafe
706  * @todo Free b content, before inserting a?
707  */
708 static inline int ml_CopyMedia( ml_media_t *b, ml_media_t *a )
709 {
710     if( !a || !b ) return VLC_EGENERIC;
711     assert( a != b );
712     ml_LockMedia( a );
713     ml_LockMedia( b );
714     b->b_sparse = a->b_sparse;
715     b->i_id = a->i_id;
716     b->i_type = a->i_type;
717     b->i_album_id = a->i_album_id;
718     b->i_disc_number = a->i_disc_number;
719     b->i_track_number = a->i_track_number;
720     b->i_year = a->i_year;
721     b->i_vote = a->i_vote;
722     b->i_score = a->i_score;
723     b->i_filesize = a->i_filesize;
724     b->i_duration = a->i_duration;
725     b->i_played_count = a->i_played_count;
726     b->i_last_played = a->i_last_played;
727     b->i_skipped_count = a->i_skipped_count;
728     b->i_last_skipped = a->i_last_skipped;
729     b->i_first_played = a->i_first_played;
730     b->i_import_time = a->i_import_time;
731     b->i_bitrate = a->i_bitrate;
732     b->i_samplerate = a->i_samplerate;
733     b->i_bpm = a->i_bpm;
734     free( b->psz_uri );
735     if( a->psz_uri )
736         b->psz_uri = strdup( a->psz_uri );
737     free( b->psz_title );
738     if( a->psz_title )
739         b->psz_title = strdup( a->psz_title );
740     free( b->psz_orig_title );
741     if( a->psz_orig_title )
742         b->psz_orig_title = strdup( a->psz_orig_title );
743     free( b->psz_album );
744     if( a->psz_album )
745         b->psz_album = strdup( a->psz_album );
746     free( b->psz_cover );
747     if( a->psz_cover )
748         b->psz_cover = strdup( a->psz_cover );
749     free( b->psz_genre );
750     if( a->psz_genre )
751         b->psz_genre = strdup( a->psz_genre );
752     free( b->psz_comment );
753     if( a->psz_comment )
754         b->psz_comment = strdup( a->psz_comment );
755     free( b->psz_extra );
756     if( a->psz_extra )
757         b->psz_extra = strdup( a->psz_extra );
758     free( b->psz_preview );
759     if( a->psz_preview )
760         b->psz_preview = strdup( a->psz_preview );
761     free( b->psz_language );
762     if( a->psz_language )
763         b->psz_language = strdup( a->psz_language );
764     ml_FreePeople( b->p_people );
765     if( a->p_people )        ml_CopyPersons( &( b->p_people ), a->p_people );
766     ml_UnlockMedia( b );
767     ml_UnlockMedia( a );
768     return VLC_SUCCESS;
769 }
770
771 /*****************************************************************************
772  * ML Find Tree Related Functions
773  *****************************************************************************/
774 #define ml_FreeFindTree( tree )          ml_GenericFreeFindTree( tree, true )
775 #define ml_ShallowFreeFindTree( tree )   ml_GenericFreeFindTree( tree, false )
776 /**
777  * @brief Free a find tree
778  * @param Find tree to free
779  * @param true to free any associated strings, false to not free them
780  */
781 static inline void ml_GenericFreeFindTree( ml_ftree_t* tree, bool freestrings )
782 {
783     if( tree == NULL )
784         return;
785     if( tree->left )
786     {
787         ml_GenericFreeFindTree( tree->left, freestrings );
788         free( tree->left );
789     }
790     if( tree->right )
791     {
792         ml_GenericFreeFindTree( tree->right, freestrings );
793         free( tree->right );
794     }
795     if( tree->op == ML_OP_NONE && ml_AttributeIsString( tree->criteria )
796             && freestrings == true)
797     {
798         free( tree->value.str );
799         if( tree->criteria == ML_PEOPLE )
800             free( tree->lvalue.str );
801     }
802 }
803
804 /**
805  * @brief Checks if a given find tree has leaf nodes
806  * @param Find tree
807  * @return Number of leaf nodes
808  */
809 static inline int ml_FtreeHasOp( ml_ftree_t* tree )
810 {
811     if( tree == NULL )
812         return 0;
813     if( tree->criteria > 0 && tree->op == ML_OP_NONE )
814         return 1;
815     else
816         return ml_FtreeHasOp( tree->left ) + ml_FtreeHasOp( tree->right );
817 }
818
819
820 /**
821  * @brief Connect up a find tree
822  * @param op operator to connect with
823  * If op = ML_OP_NONE, then you are connecting to a tree consisting of
824  * only SPECIAL nodes.
825  * If op = ML_OP_NOT, then right MUST be NULL
826  * op must not be ML_OP_SPECIAL, @see __ml_FtreeSpec
827  * @param left part of the tree
828  * @param right part of the tree
829  * @return Pointer to new tree
830  * @note Use the helpers!
831  */
832 VLC_EXPORT( ml_ftree_t*, ml_OpConnectChilds, ( ml_op_e op, ml_ftree_t* left,
833         ml_ftree_t* right ) );
834
835 /**
836  * @brief Attaches a special node to a tree
837  * @param tree Tree to attach special node to
838  * @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
839  * @param limit Limit used if LIMIT criteria used
840  * @param Sort string used if SORT criteria is used
841  * @return Pointer to new tree
842  * @note Use the helpers
843  */
844 VLC_EXPORT( ml_ftree_t*, __ml_FtreeSpec, ( ml_ftree_t* tree,
845                                           ml_select_e crit,
846                                           int limit,
847                                           char* sort ) );
848
849 /**
850  * @brief This function gives quick sequential adding capability
851  * @param left Tree to add to. This may be NULL
852  * @param right Tree to append. May not be NULL
853  * @return Pointer to new tree.*/
854 static inline ml_ftree_t* ml_FtreeFastAnd( ml_ftree_t* left,
855                                            ml_ftree_t* right )
856 {
857     if( ml_FtreeHasOp( left ) == 0 )
858     {
859         return ml_OpConnectChilds( ML_OP_NONE, left, right );
860     }
861     else
862     {
863         return ml_OpConnectChilds( ML_OP_AND, left, right );
864     }
865 }
866 #define ml_FtreeAnd( left, right ) ml_OpConnectChilds( ML_OP_AND, left, right )
867 #define ml_FtreeOr( left, right )  ml_OpConnectChilds( ML_OP_OR, left, right )
868 #define ml_FtreeNot( left )        ml_OpConnectChilds( ML_OP_NOT, left, NULL )
869
870 #define ml_FtreeSpecAsc( tree, str )        __ml_FtreeSpec( tree, ML_SORT_ASC, 0, str )
871 #define ml_FtreeSpecDesc( tree, str )       __ml_FtreeSpec( tree, ML_SORT_DESC, 0, str )
872 #define ml_FtreeSpecLimit( tree, limit )    __ml_FtreeSpec( tree, ML_LIMIT, limit, NULL )
873 #define ml_FtreeSpecDistinct( tree )        __ml_FtreeSpec( tree, ML_DISTINCT, 0, NULL )
874
875
876 /*****************************************************************************
877  * ML Core Functions
878  *****************************************************************************/
879
880 /**
881  * @brief Create input item from media
882  * @param p_media_library This ML instance.
883  * @param i_media_id ID of the media to use to create an input_item.
884  * @return The media item.
885  */
886 static inline input_item_t* ml_CreateInputItem(
887         media_library_t *p_media_library, int i_media_id )
888 {
889     return p_media_library->functions.pf_InputItemFromMedia( p_media_library,
890                                                              i_media_id );
891 }
892
893 /**
894  * @brief Search in the database according some criterias
895  *
896  * @param p_media_library the media library object
897  * @param result a pointer to a result array
898  * @param ... parameters to select the data
899  * @return VLC_SUCCESS or an error
900  */
901 static inline int __ml_Find( media_library_t *p_media_library,
902                              vlc_array_t *p_result_array, ... )
903 {
904     va_list args;
905     int returned;
906
907     va_start( args, p_result_array );
908     returned = p_media_library->functions.pf_Find( p_media_library,
909                                                    p_result_array, args );
910     va_end( args );
911
912     return returned;
913 }
914
915
916 /**
917  * @brief Search in the database according some criterias (threaded)
918  * @param p_media_library the media library object
919  * @param result_array a pointer to a result array
920  * @param result_type type of data to retrieve
921  * @param psz_lvalue This should contain any necessary lvalue/key
922  * for the given result_type. Used for ML_PEOPLE. Otherwise NULL
923  * @param args parameters to select the data
924  * @return VLC_SUCCESS or an error
925  */
926 static inline int ml_FindAdv( media_library_t *p_media_library,
927                               vlc_array_t *p_result_array,
928                               ml_select_e result_type,
929                               char* psz_lvalue,
930                               ml_ftree_t *tree )
931 {
932     return p_media_library->functions.pf_FindAdv( p_media_library,
933                                                   p_result_array,
934                                                   result_type,
935                                                   psz_lvalue,
936                                                   tree );
937 }
938
939
940 /**
941  * @brief Find a value in the ML database, fill p_result with it.
942  * @param p_media_library Media library object
943  * @param p_result Object to put result into
944  * @param Args [ SelectType [ PersonType ] Value ] ... ML_END
945  * @note Do not use this function directly.
946  */
947 static inline int __ml_GetValue( media_library_t *p_media_library,
948                                   ml_result_t *p_result,
949                                   va_list args )
950 {
951     vlc_array_t *p_result_array = vlc_array_new();
952     int i_ret = p_media_library->functions.pf_Find( p_media_library,
953                                                     p_result_array,
954                                                     args );
955     if( i_ret != VLC_SUCCESS )
956         goto exit;
957     if( vlc_array_count( p_result_array ) > 0 )
958         memcpy( p_result,
959                 ( ml_result_t* ) vlc_array_item_at_index( p_result_array, 0 ),
960                 sizeof( ml_result_t) );
961     else
962         i_ret = VLC_EGENERIC;
963
964 exit:
965     /* Note: Do not free the results, because of memcpy */
966     vlc_array_destroy( p_result_array );
967     return i_ret;
968 }
969
970 /**
971  * @brief Search an INTEGER in the database
972  * This uses a Query but returns only one integer (>0), or an error code.
973  *
974  * @param p_media_library the media library object
975  * @param va_args parameters to select the data
976  * @return Found INTEGER >= 0 or an error
977  */
978 #define ml_GetInt( ml, ... ) __ml_GetInt( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
979 static inline int __ml_GetInt( media_library_t *p_media_library, ... )
980 {
981     va_list args;
982     va_start( args, p_media_library );
983     ml_result_t result;
984     int i_ret = __ml_GetValue( p_media_library, &result, args );
985     va_end( args );
986     if( i_ret != VLC_SUCCESS )
987         return i_ret;
988     else
989         return result.value.i;
990 }
991
992
993 /**
994  * @brief Search a string (VARCHAR) in the database
995  * This uses a Query but returns only one integer (>0), or an error code.
996  *
997  * @param p_media_library the media library object
998  * @param va_args parameters to select the data
999  * @return Found string, or NULL if not found or in case of error
1000  */
1001 #define ml_FindPsz( ml, ... ) __ml_GetPsz( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
1002 static inline char* __ml_GetPsz( media_library_t *p_media_library, ... )
1003 {
1004     va_list args;
1005     va_start( args, p_media_library );
1006     ml_result_t result;
1007     int i_ret = __ml_GetValue( p_media_library, &result, args );
1008     va_end( args );
1009     if( i_ret != VLC_SUCCESS )
1010         return NULL;
1011     else
1012         return result.value.psz; // no need to duplicate
1013 }
1014
1015 /**
1016  * @brief Generic update in Media Library database
1017  *
1018  * @param p_media_library the media library object
1019  * @param selected_type the type of the element we're selecting
1020  * @param where list of ids/uris to be changed
1021  * @param changes list of changes to make in the entries
1022  * @return VLC_SUCCESS or VLC_EGENERIC
1023  */
1024 static inline int ml_Update( media_library_t *p_media_library,
1025                              ml_select_e selected_type,
1026                              const char* psz_lvalue,
1027                              ml_ftree_t *where,
1028                              vlc_array_t *changes )
1029 {
1030     return p_media_library->functions.pf_Update( p_media_library,
1031                                                  selected_type, psz_lvalue,
1032                                                  where, changes );
1033 }
1034
1035 /**
1036  * @brief Update a given table
1037  * @param p_media_library The media library object
1038  * @param selected_type The table to update
1039  * @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
1040  * @param id The id of the row to update
1041  * @param ... The update data. [SelectType [RoleType] Value]
1042  */
1043 #define ml_UpdateSimple( ml, sel, lval, id, ... ) \
1044         __ml_UpdateSimple( ml, sel, lval, id, __VA_ARGS__, ML_END )
1045 VLC_EXPORT( int, __ml_UpdateSimple, ( media_library_t *p_media_library,
1046                                      ml_select_e selected_type,
1047                                      const char* psz_lvalue,
1048                                      int id, ... ) );
1049
1050 /**
1051  * @brief Generic DELETE function
1052  * Delete a media and all its references which don't point
1053  * to anything else.
1054  *
1055  * @param p_media_library This media_library_t object
1056  * @param id the id of the media to delete
1057  * @return VLC_SUCCESS or VLC_EGENERIC
1058  */
1059 static inline int
1060 ml_DeleteSimple( media_library_t *p_media_library, int id )
1061 {
1062     vlc_array_t* p_where = vlc_array_new();
1063     ml_element_t* p_find = (ml_element_t *) calloc( 1, sizeof( ml_element_t ) );
1064     p_find->criteria = ML_ID;
1065     p_find->value.i = id;
1066     vlc_array_append( p_where, p_find );
1067     int i_return =  p_media_library->functions.pf_Delete( p_media_library,
1068             p_where );
1069     free( p_find );
1070     vlc_array_destroy( p_where );
1071     return i_return;
1072 }
1073
1074 /**
1075  * @brief Delete many medias in the media library
1076  * @param p_media_library Media library object
1077  * @param p_array Array of ids to delete
1078  * @return VLC_SUCCESS or VLC_EGENERIC
1079  */
1080 static inline int
1081 ml_Delete( media_library_t *p_media_library, vlc_array_t* p_array )
1082 {
1083     return p_media_library->functions.pf_Delete( p_media_library,
1084                                                         p_array );
1085 }
1086
1087
1088 /*****************************************************************************
1089  * ML Person Related Functions
1090  *****************************************************************************/
1091
1092 /**
1093  * @brief Create and append a person object to the given list
1094  * @param pp_person pointer to person list. Set the address to null to create new list
1095  * @param i_role The role of the person
1096  * @param psz_name The name string. Will be strdup'd
1097  * @param i_id The id in the database
1098  * @note This function is NOT thread safe. Please lock any associated media
1099  */
1100 static inline int ml_CreateAppendPersonAdv( ml_person_t **pp_person,
1101         const char* psz_role, const char* psz_name, int i_id )
1102 {
1103     assert( i_id || ( psz_name && *psz_name && psz_role && *psz_role ) );
1104     if( !pp_person )
1105         return VLC_EGENERIC;
1106     if( *pp_person != NULL )
1107         return ml_CreateAppendPersonAdv( &((**pp_person).p_next),
1108                                          psz_role, psz_name, i_id);
1109     *pp_person = ( ml_person_t * ) calloc( 1, sizeof( ml_person_t ) );
1110     (*pp_person)->psz_name = (psz_name && *psz_name) ? strdup( psz_name ): NULL;
1111     (*pp_person)->psz_role = (psz_role && *psz_role) ? strdup( psz_role ): NULL;
1112     (*pp_person)->i_id = i_id;
1113     (*pp_person)->p_next = NULL;
1114     return VLC_SUCCESS;
1115 }
1116
1117 /**
1118  * @brief Create and append a person object to the given list
1119  * @param pp_person pointer to person list.
1120  * Set the address to NULL to create a new list
1121  * @param personfrom Person object to copy from
1122  * @note Ignores the next variable and copies only the variables.
1123  * Uses ml_CreateAppendPersonAdv
1124  * @note This function is NOT threadsafe
1125  */
1126 static inline int ml_CreateAppendPerson( ml_person_t **pp_person,
1127                                          ml_person_t *p_personfrom )
1128 {
1129     return ml_CreateAppendPersonAdv( pp_person,
1130                                      p_personfrom->psz_role,
1131                                      p_personfrom->psz_name,
1132                                      p_personfrom->i_id );
1133 }
1134
1135 /**
1136  * @brief Copy one person list into another
1137  * @param a To list
1138  * @param b From list
1139  * @note On errors, you have to free any allocated persons yourself
1140  * @note This function is NOT threadsafe. Please ensure your medias are locked
1141  */
1142 static inline int ml_CopyPersons( ml_person_t** a, ml_person_t* b )
1143 {
1144     int i_ret;
1145     while( b )
1146     {
1147         i_ret = ml_CreateAppendPerson( a, b );
1148         if( i_ret != VLC_SUCCESS )
1149             return i_ret;
1150         b = b->p_next;
1151     }
1152     return VLC_SUCCESS;
1153 }
1154
1155
1156 /**
1157  * @brief Returns a person list of given type
1158  * @param p_ml The ML object
1159  * @param p_media The Media object
1160  * @param i_type The person type
1161  * @note This function is thread safe
1162  */
1163 VLC_EXPORT( ml_person_t*, ml_GetPersonsFromMedia, ( media_library_t* p_ml,
1164                                                     ml_media_t* p_media,
1165                                                     const char *psz_role ) );
1166
1167
1168 #define ml_GetAlbumArtistsFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ALBUM_ARTIST );
1169 #define ml_GetArtistsFromMedia( a, b )      ml_GetPersonsFromMedia( a, b, ML_PERSON_ARTIST );
1170 #define ml_GetEncodersFromMedia( a, b )     ml_GetPersonsFromMedia( a, b, ML_PERSON_ENCODER );
1171 #define ml_GetPublishersFromMedia( a, b )   ml_GetPersonsFromMedia( a, b, ML_PERSON_PUBLISHER );
1172
1173 /**
1174  * @brief Delete a certain type of people from a media
1175  * @param p_media Media to delete from
1176  * @param i_type Type of person to delete
1177  * @note This function is threadsafe
1178  */
1179 VLC_EXPORT( void, ml_DeletePersonTypeFromMedia, ( ml_media_t* p_media,
1180                                                  const char *psz_role ) );
1181
1182
1183 /**
1184  * @brief Creates and adds the playlist based on a given find tree
1185  * @param p_ml Media library object
1186  * @param p_tree Find tree to create SELECT
1187  */
1188
1189 VLC_EXPORT( void, ml_PlaySmartPlaylistBasedOn, ( media_library_t* p_ml,
1190                                                 ml_ftree_t* p_tree ) );
1191
1192
1193 /**
1194  * Convenience Macros
1195  */
1196
1197 /**
1198  * Get information using the *media* ID. This returns only 1 information.
1199  * @note You have to free the string returned (if that's a string!).
1200  */
1201 #define ml_GetAlbumById( a, id )            ml_GetPsz( a, ML_ALBUM, ML_ID, id )
1202 #define ml_GetArtistById( a, id )           ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ARTIST, ML_ID, id )
1203 #define ml_GetCoverUriById( a, id )         ml_GetPsz( a, ML_COVER, ML_ID, id )
1204 #define ml_GetEncoderById( a, id )          ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ENCODER, ML_ID, id )
1205 #define ml_GetExtraById( a, id )            ml_GetPsz( a, ML_EXTRA, ML_ID, id )
1206 #define ml_GetGenreById( a, id )            ml_GetPsz( a, ML_GENRE, ML_ID, id )
1207 #define ml_GetOriginalTitleById( a, id )    ml_GetPsz( a, ML_ORIGINAL_TITLE, ML_ID, id )
1208 #define ml_GetPublisherById( a, id )        ml_GetPsz( a, ML_PEOPLE, ML_PERSON_PUBLISHER, ML_ID, id )
1209 #define ml_GetTitleById( a, id )            ml_GetPsz( a, ML_TITLE, ML_ID, id )
1210 #define ml_GetUriById( a, id )              ml_GetPsz( a, ML_URI, ML_ID, id )
1211
1212 #define ml_GetAlbumIdById( a, id )          ml_GetInt( a, ML_ALBUM_ID, ML_ID, id )
1213 #define ml_GetArtistIdById( a, id )         ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ARTIST, ML_ID, id )
1214 #define ml_GetDurationById( a, id )         ml_GetInt( a, ML_DURATION, ML_ID, id )
1215 #define ml_GetEncoderIdById( a, id )        ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ENCODER, ML_ID, id )
1216 #define ml_GetLastPlayedById( a, id )       ml_GetInt( a, ML_LAST_PLAYED, ML_ID, id )
1217 #define ml_GetPlayedCountById( a, id )      ml_GetInt( a, ML_PLAYED_COUNT, ML_ID, id )
1218 #define ml_GetPublisherIdById( a, id )      ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_PUBLISHER, ML_ID, id )
1219 #define ml_GetScoreById( a, id )            ml_GetInt( a, ML_SCORE, ML_ID, id )
1220 #define ml_GetTrackNumberById( a, id )      ml_GetInt( a, ML_TRACK_NUMBER, ML_ID, id )
1221 #define ml_GetTypeById( a, id )             ml_GetInt( a, ML_TYPE, ML_ID, id )
1222 #define ml_GetYearById( a, id )             ml_GetInt( a, ML_YEAR, ML_ID, id )
1223 #define ml_GetVoteById( a, id )             ml_GetInt( a, ML_VOTE, ML_ID, id )
1224
1225 /** Albums handling */
1226 #define ml_GetAlbumId( a, b )               ml_GetInt( a, ML_ALBUM_ID, ML_ALBUM, b )
1227
1228 /** People handling */
1229 #define ml_GetArtistId( a, b )              ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ARTIST, ML_PERSON, ML_PERSON_ARTIST, b )
1230 #define ml_GetEncoderId( a, b )             ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ENCODER, ML_PERSON, ML_PERSON_ENCODER, b )
1231 #define ml_GetPublisherId( a, b )           ml_GetInt( a, ML_PERSON_ID, ML_PERSON_PUBLISHER, ML_PERSON, ML_PERSON_PUBLISHER, b )
1232
1233 /** Counts handling */
1234 #define ml_GetMediaCount( a, ... )          __ml_GetInt( a, ML_COUNT_MEDIA,      __VA_ARGS__, ML_END )
1235 #define ml_GetAlbumCount( a, ... )          __ml_GetInt( a, ML_COUNT_ALBUM,      __VA_ARGS__, ML_END )
1236 #define ml_GetPeopleCount( a, ... )         __ml_GetInt( a, ML_COUNT_PEOPLE,     __VA_ARGS__, ML_END )
1237
1238 #define ml_Find( a, b, ... )                __ml_Find( a, b, __VA_ARGS__, ML_END )
1239
1240 #define ml_FindAlbum( a, b, ... )           __ml_Find( a, b, ML_ALBUM,           __VA_ARGS__, ML_END )
1241 #define ml_FindArtist( a, b, ... )          __ml_Find( a, b, ML_PERSON, ML_PERSON_ARTIST, __VA_ARGS__, ML_END )
1242 #define ml_FindEncoder( a, b, ... )         __ml_Find( a, b, ML_PERSON, ML_PERSON_ENCODER, __VA_ARGS__, ML_END )
1243 #define ml_FindGenre( a, b, ... )           __ml_Find( a, b, ML_GENRE,           __VA_ARGS__, ML_END )
1244 #define ml_FindMedia( a, b, ... )           __ml_Find( a, b, ML_MEDIA,           __VA_ARGS__, ML_END )
1245 #define ml_FindOriginalTitle( a, b, ... )   __ml_Find( a, b, ML_ORIGINAL_TITLE,  __VA_ARGS__, ML_END )
1246 #define ml_FindPublisher( a, b, ... )       __ml_Find( a, b, ML_PERSON, ML_PERSON_PUBLISHER, __VA_ARGS__, ML_END )
1247 #define ml_FindTitle( a, b, ... )           __ml_Find( a, b, ML_TITLE,           __VA_ARGS__, ML_END )
1248 #define ml_FindType( a, b, ... )            __ml_Find( a, b, ML_TYPE,            __VA_ARGS__, ML_END )
1249 #define ml_FindUri( a, b, ... )             __ml_Find( a, b, ML_URI,             __VA_ARGS__, ML_END )
1250 #define ml_FindYear( a, b, ... )            __ml_Find( a, b, ML_YEAR,            __VA_ARGS__, ML_END )
1251
1252 #define ml_FindAllAlbums( a, b )            ml_FindAlbum( a, b,         ML_DISTINCT )
1253 #define ml_FindAllArtists( a, b )           ml_FindArtist( a, b,        ML_DISTINCT )
1254 #define ml_FindAllGenres( a, b )            ml_FindGenre( a, b,         ML_DISTINCT )
1255 #define ml_FindAllMedias( a, b )            ml_FindMedia( a, b,         ML_DISTINCT )
1256 #define ml_FindAllOriginalTitles( a, b )    ml_FindOriginalTitle( a, b, ML_DISTINCT )
1257 #define ml_FindAllPublishers( a, b, ... )   ml_FindPublisher( a, b,     ML_DISTINCT )
1258 #define ml_FindAllTitles( a, b )            ml_FindTitle( a, b,         ML_DISTINCT )
1259 #define ml_FindAllTypes( a, b )             ml_FindType( a, b,          ML_DISTINCT )
1260 #define ml_FindAllUris( a, b )              ml_FindUri( a, b,           ML_DISTINCT )
1261 #define ml_FindAllYears( a, b )             ml_FindYear( a, b,          ML_DISTINCT )
1262
1263 #define ml_FindAlbumAdv( a, b, c )          ml_FindAdv( a, b, ML_ALBUM,         NULL, c )
1264 #define ml_FindArtistAdv( a, b, c )         ml_FindAdv( a, b, ML_PERSON,        ML_PERSON_ARTIST, c )
1265 #define ml_FindEncoderAdv( a, b, c )        ml_FindAdv( a, b, ML_PERSON,        ML_PERSON_ENCODER, c )
1266 #define ml_FindGenreAdv( a, b, c )          ml_FindAdv( a, b, ML_GENRE,         NULL, c )
1267 #define ml_FindMediaAdv( a, b, c )          ml_FindAdv( a, b, ML_MEDIA,         NULL, c )
1268 #define ml_FindOriginalTitleAdv( a, b, c )  ml_FindAdv( a, b, ML_ORIGINAL_TITLE,NULL, c )
1269 #define ml_FindPublisherAdv( a, b, c )      ml_FindAdv( a, b, ML_PUBLISHER,     ML_PERSON_PUBLISHER, c )
1270 #define ml_FindTitleAdv( a, b, c )          ml_FindAdv( a, b, ML_TITLE,         NULL, c )
1271 #define ml_FindTypeAdv( a, b, c )           ml_FindAdv( a, b, ML_TYPE,          NULL, c )
1272 #define ml_FindUriAdv( a, b, c )            ml_FindAdv( a, b, ML_URI,           NULL, c )
1273 #define ml_FindYearAdv( a, b, c )           ml_FindAdv( a, b, ML_YEAR,          NULL, c )
1274
1275
1276
1277 #ifdef __cplusplus
1278 }
1279 #endif /* C++ */
1280
1281 #endif /* VLC_MEDIA_LIBRARY_H */