]> git.sesse.net Git - vlc/blob - src/misc/media_library.c
Add NV12/NV21 as YUV formats
[vlc] / src / misc / media_library.c
1 /*****************************************************************************
2  * media_library.c: SQL-based media library: ML creators and destructors
3  *****************************************************************************
4  * Copyright (C) 2009-2010 VLC authors and VideoLAN and AUTHORS
5  * $Id$
6  *
7  * Authors: Srikanth Raju <srikiraju at gmail dot com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #if defined(MEDIA_LIBRARY)
29
30 #include <assert.h>
31 #include <vlc_media_library.h>
32 #include <vlc_modules.h>
33 #include "../libvlc.h"
34
35 /**
36  * @brief Destroy the medialibrary object
37  * @param Parent object that holds the media library object
38  */
39 void ml_Destroy( vlc_object_t * p_this )
40 {
41     media_library_t* p_ml = ( media_library_t* )p_this;
42     module_unneed( p_ml, p_ml->p_module );
43 }
44
45
46 /**
47  * Atomically set the reference count to 1.
48  * @param p_gc reference counted object
49  * @param pf_destruct destruction calback
50  * @return p_gc.
51  */
52 static void *ml_gc_init (ml_gc_object_t *p_gc, void (*pf_destruct) (ml_gc_object_t *))
53 {
54     /* There is no point in using the GC if there is no destructor... */
55     assert (pf_destruct);
56     p_gc->pf_destructor = pf_destruct;
57
58     p_gc->pool = false;
59     p_gc->refs = 1;
60     return p_gc;
61 }
62
63
64
65 /**
66  * @brief Create an instance of the media library
67  * @param p_this Parent object
68  * @param psz_name Name which is passed to module_need (not needed)
69  * @return p_ml created and attached, module loaded. NULL if
70  * not able to load
71  */
72 media_library_t *ml_Create( vlc_object_t *p_this, char *psz_name )
73 {
74     media_library_t *p_ml;
75
76     p_ml = ( media_library_t * ) vlc_custom_create(
77                                 p_this, sizeof( media_library_t ),
78                                 "media-library" );
79     if( !p_ml )
80     {
81         msg_Err( p_this, "unable to create media library object" );
82         return NULL;
83     }
84
85     p_ml->p_module = module_need( p_ml, "media-library", psz_name, false );
86     if( !p_ml->p_module )
87     {
88         vlc_object_release( p_ml );
89         msg_Err( p_this, "Media Library provider not found" );
90         return NULL;
91     }
92
93     return p_ml;
94 }
95
96 #undef ml_Get
97 /**
98  * @brief Acquire a reference to the media library singleton
99  * @param p_this Object that holds the reference
100  * @return media_library_t The ml object. NULL if not compiled with
101  * media library or if unable to load
102  */
103 media_library_t* ml_Get( vlc_object_t* p_this )
104 {
105     media_library_t* p_ml;
106     vlc_mutex_lock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
107     p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
108     assert( VLC_OBJECT( p_ml ) != p_this );
109     if( p_ml == NULL &&
110         !var_GetBool( p_this->p_libvlc, "load-media-library-on-startup" ) )
111     {
112         libvlc_priv (p_this->p_libvlc)->p_ml
113             = ml_Create( VLC_OBJECT( p_this->p_libvlc ), NULL );
114         p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
115     }
116     vlc_mutex_unlock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
117     return p_ml;
118 }
119
120 /**
121  * @brief Destructor for ml_media_t
122  */
123 static void media_Destroy( ml_gc_object_t *p_gc )
124 {
125     ml_media_t* p_media = ml_priv( p_gc, ml_media_t );
126     vlc_mutex_destroy( &p_media->lock );
127     ml_FreeMediaContent( p_media );
128     free( p_media );
129 }
130
131 /**
132  * @brief Object constructor for ml_media_t
133  * @param p_ml The media library object
134  * @param id If 0, this item isn't in database. If non zero, it is and
135  * it will be a singleton
136  * @param select Type of object
137  * @param reload Whether to reload from database
138  */
139 ml_media_t* media_New( media_library_t* p_ml, int id,
140         ml_select_e select, bool reload )
141 {
142     if( id == 0 )
143     {
144         ml_media_t* p_media = NULL;
145         p_media = ( ml_media_t* )calloc( 1, sizeof( ml_media_t ) );
146         ml_gc_init( &p_media->ml_gc_data, media_Destroy );
147         vlc_mutex_init( &p_media->lock );
148         return p_media;
149     }
150     else
151         return p_ml->functions.pf_GetMedia( p_ml, id, select, reload );
152 }
153
154 #undef ml_UpdateSimple
155 /**
156  * @brief Update a given table
157  * @param p_media_library The media library object
158  * @param selected_type The table to update
159  * @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
160  * @param id The id of the row to update
161  * @param ... The update data. [SelectType [RoleType] Value] ... ML_END
162  */
163 int ml_UpdateSimple( media_library_t *p_media_library,
164                                      ml_select_e selected_type,
165                                      const char* psz_lvalue,
166                                      int id, ... )
167 {
168     ml_element_t *update;
169     vlc_array_t *array = vlc_array_new();
170     int i_ret = VLC_SUCCESS;
171
172     va_list args;
173     va_start( args, id );
174
175     ml_select_e sel;
176     do {
177         update = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
178         sel = ( ml_select_e ) va_arg( args, int );
179         update->criteria = sel;
180         if( sel == ML_PEOPLE )
181         {
182             update->lvalue.str = va_arg( args, char* );
183             update->value.str = va_arg( args, char* );
184             vlc_array_append( array, update );
185         }
186         else if( sel == ML_PEOPLE_ID )
187         {
188            update->lvalue.str = va_arg( args, char* );
189            update->value.i = va_arg( args, int );
190            vlc_array_append( array, update );
191         }
192         else if( sel == ML_PEOPLE_ROLE )
193         {
194 #ifndef NDEBUG
195             msg_Dbg( p_media_library,
196                      "this argument is invalid for Update: %d",
197                      (int)sel );
198 #endif
199         }
200         else
201         {
202             switch( ml_AttributeIsString( sel ) )
203             {
204                 case -1:
205                     if( sel != ML_END )
206                     {
207 #ifndef NDEBUG
208                         msg_Dbg( p_media_library,
209                                  "this argument is invalid for Update: %d",
210                                  (int)sel );
211 #endif
212                         i_ret = VLC_EBADVAR;
213                     }
214                     else if( sel == ML_END )
215                         vlc_array_append( array, update );
216                     break;
217                 case 1:
218                     update->value.str = va_arg( args, char* );
219                     vlc_array_append( array, update );
220                     break;
221                 case 0:
222                     update->value.i = va_arg( args, int );
223                     vlc_array_append( array, update );
224                     break;
225             }
226         }
227     } while( sel != ML_END );
228
229     va_end( args );
230
231     ml_ftree_t* p_where = NULL;
232     ml_ftree_t* find = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
233     find->criteria = ML_ID;
234     find->value.i = id ;
235     find->comp = ML_COMP_EQUAL;
236     p_where = ml_FtreeFastAnd( p_where, find );
237
238     /* Let's update the database ! */
239     if( i_ret == VLC_SUCCESS )
240         i_ret = ml_Update( p_media_library, selected_type, psz_lvalue,
241                             p_where, array );
242
243     /* Destroying array */
244     for( int i = 0; i < vlc_array_count( array ); i++ )
245     {
246         free( vlc_array_item_at_index( array, i ) );
247     }
248     vlc_array_destroy( array );
249     ml_FreeFindTree( p_where );
250
251     return i_ret;
252 }
253
254 /**
255  * @brief Connect up a find tree
256  * @param op operator to connect with
257  * If op = ML_OP_NONE, then you are connecting to a tree consisting of
258  * only SPECIAL nodes.
259  * If op = ML_OP_NOT, then right MUST be NULL
260  * op must not be ML_OP_SPECIAL, @see ml_FtreeSpec
261  * @param left part of the tree
262  * @param right part of the tree
263  * @return Pointer to new tree
264  * @note Use the helpers!
265  */
266 ml_ftree_t* ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left,
267         ml_ftree_t* right )
268 {
269     /* Use this Op for fresh trees (with only special nodes/none at all!) */
270     if( op == ML_OP_NONE )
271     {
272         assert( ml_FtreeHasOp( left ) == 0 );
273         if( left == NULL )
274             return right;
275         /* Percolate down tree only for special nodes */
276         assert( left->op == ML_OP_SPECIAL );
277         if( left->left == NULL )
278         {
279             left->left = right;
280             return left;
281         }
282         else
283         {
284             return ml_OpConnectChilds( ML_OP_NONE, left->left, right );
285         }
286     }
287     else if( op == ML_OP_NOT )
288     {
289         assert( right == NULL && left != NULL );
290         assert( ml_FtreeHasOp( left ) > 0 );
291     }
292     else if( op == ML_OP_SPECIAL )
293     {
294         assert( 0 );
295     }
296     else
297     {
298         assert( right != NULL && left != NULL );
299         assert( ml_FtreeHasOp( left ) > 0 );
300         assert( ml_FtreeHasOp( right ) > 0 );
301     }
302     ml_ftree_t* p_parent = (ml_ftree_t *) calloc( 1, sizeof( ml_ftree_t ) );
303     p_parent->op = op;
304     p_parent->left = left;
305     p_parent->right = right;
306     return p_parent;
307 }
308
309 #undef ml_FtreeSpec
310 /**
311  * @brief Attaches a special node to a tree
312  * @param tree Tree to attach special node to
313  * @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
314  * @param limit Limit used if LIMIT criteria used
315  * @param Sort string used if SORT criteria is used
316  * @return Pointer to new tree
317  * @note Use the helpers
318  */
319 ml_ftree_t* ml_FtreeSpec( ml_ftree_t* tree,
320                                           ml_select_e crit,
321                                           int limit,
322                                           char* sort )
323 {
324     assert( crit == ML_SORT_ASC || crit == ML_LIMIT || crit == ML_SORT_DESC ||
325             crit == ML_DISTINCT );
326     ml_ftree_t* right = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
327     right->criteria = crit;
328     if( crit == ML_LIMIT )
329         right->value.i = limit;
330     else if( crit == ML_SORT_ASC || crit == ML_SORT_DESC )
331         right->value.str = strdup( sort );
332     right->op = ML_OP_NONE;
333     ml_ftree_t* p_parent = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
334     p_parent->right = right;
335     p_parent->op = ML_OP_SPECIAL;
336     p_parent->left = tree;
337     return p_parent;
338 }
339
340
341 /**
342  * @brief Returns a person list of given type
343  * @param p_ml The ML object
344  * @param p_media The Media object
345  * @param i_type The person type
346  * @note This function is thread safe
347  */
348 ml_person_t*  ml_GetPersonsFromMedia( media_library_t* p_ml,
349                                                     ml_media_t* p_media,
350                                                     const char *psz_role )
351 {
352     VLC_UNUSED( p_ml );
353     assert( p_media != NULL );
354     ml_person_t* p_return = NULL;
355     ml_LockMedia( p_media );
356     ml_person_t* p_person = p_media->p_people;
357     while( p_person )
358     {
359         if( strcmp( p_person->psz_role, psz_role ) == 0 )
360         {
361             int i_ret = ml_CreateAppendPerson( &p_return, p_person );
362             if( i_ret != VLC_SUCCESS )
363             {
364                 ml_UnlockMedia( p_media );
365                 ml_FreePeople( p_return );
366                 return NULL;
367             }
368         }
369         p_person = p_person->p_next;
370     }
371     ml_UnlockMedia( p_media );
372     //TODO: Fill up empty names + clean up list
373     return p_return;
374 }
375
376 /**
377  * @brief Delete a certain type of people from a media
378  * @param p_media Media to delete from
379  * @param i_type Type of person to delete
380  * @note This function is threadsafe
381  */
382 void ml_DeletePersonTypeFromMedia( ml_media_t* p_media, const char *psz_role )
383 {
384     assert( p_media );
385     ml_LockMedia( p_media );
386     ml_person_t* p_prev = NULL;
387     ml_person_t* p_person = p_media->p_people;
388
389     while( p_person )
390     {
391         if( strcmp( p_person->psz_role, psz_role ) == 0 )
392         {
393             if( p_prev == NULL )
394             {
395                 p_media->p_people = p_person->p_next;
396                 p_person->p_next = NULL;
397                 ml_FreePeople( p_person );
398                 p_person = p_media->p_people;
399             }
400             else
401             {
402                 p_prev->p_next = p_person->p_next;
403                 p_person->p_next = NULL;
404                 ml_FreePeople( p_person );
405                 p_person = p_prev->p_next;
406             }
407         }
408         else
409         {
410             p_prev = p_person;
411             p_person = p_person->p_next;
412         }
413     }
414     ml_UnlockMedia( p_media );
415 }
416
417 #endif /* MEDIA_LIBRARY */