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