]> git.sesse.net Git - vlc/blob - src/control/media_descriptor.c
45f76dab771575879f1be267c2a713cbc269a827
[vlc] / src / control / media_descriptor.c
1 /*****************************************************************************
2  * media_descriptor.c: Libvlc API media descripor management
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include <vlc/libvlc.h>
25 #include <vlc_input.h>
26 #include <vlc_meta.h>
27
28 /* For the preparser */
29 #include <vlc_playlist.h>
30
31 #include "libvlc_internal.h"
32
33 static const vlc_meta_type_t libvlc_to_vlc_meta[] =
34 {
35     [libvlc_meta_Title]        = vlc_meta_Title,
36     [libvlc_meta_Artist]       = vlc_meta_Artist,
37     [libvlc_meta_Genre]        = vlc_meta_Genre,
38     [libvlc_meta_Copyright]    = vlc_meta_Copyright,
39     [libvlc_meta_Album]        = vlc_meta_Album,
40     [libvlc_meta_TrackNumber]  = vlc_meta_TrackNumber,
41     [libvlc_meta_Description]  = vlc_meta_Description,
42     [libvlc_meta_Rating]       = vlc_meta_Rating,
43     [libvlc_meta_Date]         = vlc_meta_Date,
44     [libvlc_meta_Setting]      = vlc_meta_Setting,
45     [libvlc_meta_URL]          = vlc_meta_URL,
46     [libvlc_meta_Language]     = vlc_meta_Language,
47     [libvlc_meta_NowPlaying]   = vlc_meta_NowPlaying,
48     [libvlc_meta_Publisher]    = vlc_meta_Publisher,
49     [libvlc_meta_EncodedBy]    = vlc_meta_EncodedBy,
50     [libvlc_meta_ArtworkURL]   = vlc_meta_ArtworkURL,
51     [libvlc_meta_TrackID]      = vlc_meta_TrackID
52 };
53
54 static const libvlc_meta_t vlc_to_libvlc_meta[] =
55 {
56     [vlc_meta_Title]        = libvlc_meta_Title,
57     [vlc_meta_Artist]       = libvlc_meta_Artist,
58     [vlc_meta_Genre]        = libvlc_meta_Genre,
59     [vlc_meta_Copyright]    = libvlc_meta_Copyright,
60     [vlc_meta_Album]        = libvlc_meta_Album,
61     [vlc_meta_TrackNumber]  = libvlc_meta_TrackNumber,
62     [vlc_meta_Description]  = libvlc_meta_Description,
63     [vlc_meta_Rating]       = libvlc_meta_Rating,
64     [vlc_meta_Date]         = libvlc_meta_Date,
65     [vlc_meta_Setting]      = libvlc_meta_Setting,
66     [vlc_meta_URL]          = libvlc_meta_URL,
67     [vlc_meta_Language]     = libvlc_meta_Language,
68     [vlc_meta_NowPlaying]   = libvlc_meta_NowPlaying,
69     [vlc_meta_Publisher]    = libvlc_meta_Publisher,
70     [vlc_meta_EncodedBy]    = libvlc_meta_EncodedBy,
71     [vlc_meta_ArtworkURL]   = libvlc_meta_ArtworkURL,
72     [vlc_meta_TrackID]      = libvlc_meta_TrackID
73 };
74
75 /**************************************************************************
76  * input_item_subitem_added (Private) (vlc event Callback)
77  **************************************************************************/
78 static void input_item_subitem_added( const vlc_event_t *p_event,
79                                        void * user_data )
80 {
81     libvlc_media_descriptor_t * p_md = user_data;
82     libvlc_media_descriptor_t * p_md_child;
83     libvlc_event_t event;
84
85     p_md_child = libvlc_media_descriptor_new_from_input_item(
86                 p_md->p_libvlc_instance, 
87                 p_event->u.input_item_subitem_added.p_new_child, NULL );
88
89     /* Add this to our media list */
90     if( !p_md->p_subitems )
91     {
92         p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance, NULL );
93         libvlc_media_list_set_media_descriptor( p_md->p_subitems, p_md, NULL );
94     }
95     if( p_md->p_subitems )
96     {
97         libvlc_media_list_add_media_descriptor( p_md->p_subitems, p_md_child, NULL );
98     }
99
100     /* Construct the event */
101     event.type = libvlc_MediaDescriptorSubItemAdded;
102     event.u.media_descriptor_subitem_added.new_child = p_md_child;
103
104     /* Send the event */
105     libvlc_event_send( p_md->p_event_manager, &event );
106     libvlc_media_descriptor_release( p_md_child );
107 }
108
109 /**************************************************************************
110  * input_item_meta_changed (Private) (vlc event Callback)
111  **************************************************************************/
112 static void input_item_meta_changed( const vlc_event_t *p_event,
113                                      void * user_data )
114 {
115     libvlc_media_descriptor_t * p_md = user_data;
116     libvlc_event_t event;
117
118     /* Construct the event */
119     event.type = libvlc_MediaDescriptorMetaChanged;
120     event.u.media_descriptor_meta_changed.meta_type =
121         vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];
122
123     /* Send the event */
124     libvlc_event_send( p_md->p_event_manager, &event );
125 }
126
127
128 /**************************************************************************
129  * Install event handler (Private)
130  **************************************************************************/
131 static void install_input_item_observer( libvlc_media_descriptor_t *p_md )
132 {
133     vlc_event_attach( &p_md->p_input_item->event_manager,
134                       vlc_InputItemSubItemAdded,
135                       input_item_subitem_added,
136                       p_md );
137     vlc_event_attach( &p_md->p_input_item->event_manager,
138                       vlc_InputItemMetaChanged,
139                       input_item_meta_changed,
140                       p_md );
141 }
142
143 /**************************************************************************
144  * Uninstall event handler (Private)
145  **************************************************************************/
146 static void uninstall_input_item_observer( libvlc_media_descriptor_t *p_md )
147 {
148     vlc_event_detach( &p_md->p_input_item->event_manager,
149                       vlc_InputItemSubItemAdded,
150                       input_item_subitem_added,
151                       p_md );
152     vlc_event_detach( &p_md->p_input_item->event_manager,
153                       vlc_InputItemMetaChanged,
154                       input_item_meta_changed,
155                       p_md );
156 }
157
158 /**************************************************************************
159  * Preparse if not already done (Private)
160  **************************************************************************/
161 static void preparse_if_needed( libvlc_media_descriptor_t *p_md )
162 {
163     /* XXX: need some locking here */
164     if (!p_md->b_preparsed)
165     {
166         playlist_PreparseEnqueue(
167                 p_md->p_libvlc_instance->p_libvlc_int->p_playlist,
168                 p_md->p_input_item );
169         playlist_AskForArtEnqueue(
170                 p_md->p_libvlc_instance->p_libvlc_int->p_playlist,
171                 p_md->p_input_item );
172
173         p_md->b_preparsed = VLC_TRUE;
174     }
175 }
176
177 /**************************************************************************
178  * Create a new media descriptor object from an input_item
179  * (libvlc internal)
180  * That's the generic constructor
181  **************************************************************************/
182 libvlc_media_descriptor_t * libvlc_media_descriptor_new_from_input_item(
183                                    libvlc_instance_t *p_instance,
184                                    input_item_t *p_input_item,
185                                    libvlc_exception_t *p_e )
186 {
187     libvlc_media_descriptor_t * p_md;
188
189     if (!p_input_item)
190     {
191         libvlc_exception_raise( p_e, "No input item given" );
192         return NULL;
193     }
194
195     p_md = malloc( sizeof(libvlc_media_descriptor_t) );
196     p_md->p_libvlc_instance = p_instance;
197     p_md->p_input_item      = p_input_item;
198     p_md->b_preparsed       = VLC_FALSE;
199     p_md->i_refcount        = 1;
200
201     /* A media descriptor can be a playlist. When you open a playlist
202      * It can give a bunch of item to read. */
203     p_md->p_subitems        = NULL;
204
205     vlc_dictionary_init( &p_md->tags, 1 );
206
207     p_md->p_event_manager = libvlc_event_manager_new( p_md, p_instance, p_e );
208     libvlc_event_manager_register_event_type( p_md->p_event_manager, 
209         libvlc_MediaDescriptorMetaChanged, p_e );
210     libvlc_event_manager_register_event_type( p_md->p_event_manager, 
211         libvlc_MediaDescriptorSubItemAdded, p_e );
212
213     vlc_gc_incref( p_md->p_input_item );
214
215     install_input_item_observer( p_md );
216
217     return p_md;
218 }
219
220 /**************************************************************************
221  * Create a new media descriptor object
222  **************************************************************************/
223 libvlc_media_descriptor_t * libvlc_media_descriptor_new(
224                                    libvlc_instance_t *p_instance,
225                                    const char * psz_mrl,
226                                    libvlc_exception_t *p_e )
227 {
228     input_item_t * p_input_item;
229     libvlc_media_descriptor_t * p_md;
230
231     p_input_item = input_ItemNew( p_instance->p_libvlc_int, psz_mrl, NULL );
232
233     if (!p_input_item)
234     {
235         libvlc_exception_raise( p_e, "Can't create md's input_item" );
236         return NULL;
237     }
238
239     p_md = libvlc_media_descriptor_new_from_input_item( p_instance,
240                 p_input_item, p_e );
241
242     return p_md;
243 }
244
245 /**************************************************************************
246  * Delete a media descriptor object
247  **************************************************************************/
248 void libvlc_media_descriptor_release( libvlc_media_descriptor_t *p_md )
249 {
250     int i;
251     if (!p_md)
252         return;
253
254     p_md->i_refcount--;
255
256     if( p_md->i_refcount > 0 )
257         return;
258
259     if( p_md->p_subitems )
260         libvlc_media_list_release( p_md->p_subitems );
261
262     uninstall_input_item_observer( p_md );
263     vlc_gc_decref( p_md->p_input_item );
264
265     char ** all_keys = vlc_dictionary_all_keys( &p_md->tags );
266     for( i = 0; all_keys[i]; i++ )
267     {
268         int j;
269         struct libvlc_tags_storage_t * p_ts = vlc_dictionary_value_for_key( &p_md->tags, all_keys[i] );
270         for( j = 0; j < p_ts->i_count; j++ )
271         {
272             free( p_ts->ppsz_tags[j] );
273             free( p_ts->ppsz_tags );
274         }
275         free( p_ts );
276     }
277     vlc_dictionary_clear( &p_md->tags );
278     free( p_md );
279 }
280
281 /**************************************************************************
282  * Retain a media descriptor object
283  **************************************************************************/
284 void libvlc_media_descriptor_retain( libvlc_media_descriptor_t *p_md )
285 {
286     if (!p_md)
287         return;
288
289     p_md->i_refcount++;
290 }
291
292 /**************************************************************************
293  * Duplicate a media descriptor object
294  **************************************************************************/
295 libvlc_media_descriptor_t *
296 libvlc_media_descriptor_duplicate( libvlc_media_descriptor_t *p_md_orig )
297 {
298     return libvlc_media_descriptor_new_from_input_item(
299         p_md_orig->p_libvlc_instance, p_md_orig->p_input_item, NULL );
300 }
301
302 /**************************************************************************
303  * Retain a media descriptor object
304  **************************************************************************/
305 char *
306 libvlc_media_descriptor_get_mrl( libvlc_media_descriptor_t * p_md,
307                                  libvlc_exception_t * p_e )
308 {
309     (void)p_e;
310     return input_item_GetURI( p_md->p_input_item );
311 }
312
313 /**************************************************************************
314  * Getter for meta information
315  **************************************************************************/
316
317 char * libvlc_media_descriptor_get_meta( libvlc_media_descriptor_t *p_md,
318                                          libvlc_meta_t e_meta,
319                                          libvlc_exception_t *p_e )
320 {
321     char * psz_meta;
322
323     /* XXX: locking */
324
325     preparse_if_needed( p_md );
326
327     psz_meta = input_item_GetMeta( p_md->p_input_item,
328                                    libvlc_to_vlc_meta[e_meta] );
329
330     /* Should be integrated in core */
331     if( !psz_meta && e_meta == libvlc_meta_Title && p_md->p_input_item->psz_name )
332     {
333         free( psz_meta );
334         return strdup( p_md->p_input_item->psz_name );
335     }
336
337     return psz_meta;
338 }
339
340 /**************************************************************************
341  * Add a tag
342  **************************************************************************/
343 void libvlc_media_descriptor_add_tag( libvlc_media_descriptor_t *p_md,
344                                       const char * key,
345                                       const libvlc_tag_t tag,
346                                       libvlc_exception_t *p_e )
347 {
348     struct libvlc_tags_storage_t * p_ts;
349
350     if( !tag || !key )
351         return;
352     
353     p_ts = vlc_dictionary_value_for_key( &p_md->tags, key );
354
355     if( !p_ts )
356     {
357         p_ts = malloc(sizeof(struct libvlc_tags_storage_t));
358         memset( p_ts, 0, sizeof(struct libvlc_tags_storage_t) );
359     }
360     p_ts->i_count++;
361
362     if( !p_ts->ppsz_tags )
363         p_ts->ppsz_tags = malloc(sizeof(char*)*(p_ts->i_count));
364     else
365         p_ts->ppsz_tags = realloc(p_ts->ppsz_tags, sizeof(char*)*(p_ts->i_count));
366         
367     p_ts->ppsz_tags[p_ts->i_count-1] = strdup( tag );
368 }
369
370
371 /**************************************************************************
372  * Remove a tag
373  **************************************************************************/
374 void libvlc_media_descriptor_remove_tag( libvlc_media_descriptor_t *p_md,
375                                          const char * key,
376                                          const libvlc_tag_t tag,
377                                          libvlc_exception_t *p_e )
378 {
379     struct libvlc_tags_storage_t * p_ts;
380     int i;
381
382     if( !tag || !key )
383         return;
384     
385     p_ts = vlc_dictionary_value_for_key( &p_md->tags, key );
386
387     if( !p_ts )
388         return;
389
390     for( i = 0; i < p_ts->i_count; i++ )
391     {
392         if( !strcmp( p_ts->ppsz_tags[i], tag ) )
393         {
394             free( p_ts->ppsz_tags[i] );
395             memcpy( p_ts->ppsz_tags + i + 1, p_ts->ppsz_tags + i, (p_ts->i_count - i - 2)*sizeof(char*) );
396             /* Don't dealloc, the memory will be regain if we add a new tag */
397             p_ts->i_count--;
398             return;
399         }
400     }
401 }
402
403 /**************************************************************************
404  * Get tags count
405  **************************************************************************/
406 int libvlc_media_descriptor_tags_count_for_key( libvlc_media_descriptor_t *p_md,
407                                                  const char * key,
408                                                  libvlc_exception_t *p_e )
409 {
410     struct libvlc_tags_storage_t * p_ts;
411
412     if( !key )
413         return 0;
414     
415     p_ts = vlc_dictionary_value_for_key( &p_md->tags, key );
416
417     if( !p_ts )
418         return 0;
419     return p_ts->i_count;
420 }
421
422 /**************************************************************************
423  * Get a tag
424  **************************************************************************/
425 libvlc_tag_t
426 libvlc_media_descriptor_tag_at_index_for_key( libvlc_media_descriptor_t *p_md,
427                                               int i,
428                                               const char * key,
429                                               libvlc_exception_t *p_e )
430 {
431     struct libvlc_tags_storage_t * p_ts;
432
433     if( !key )
434         return NULL;
435     
436     p_ts = vlc_dictionary_value_for_key( &p_md->tags, key );
437
438     if( !p_ts )
439         return NULL;
440     
441     return strdup( p_ts->ppsz_tags[i] );
442 }
443
444 /**************************************************************************
445  * subitems
446  **************************************************************************/
447 libvlc_media_list_t *
448 libvlc_media_descriptor_subitems( libvlc_media_descriptor_t * p_md,
449                                   libvlc_exception_t * p_e )
450 {
451     if( p_md->p_subitems )
452         libvlc_media_list_retain( p_md->p_subitems );
453     return p_md->p_subitems;
454 }
455
456 /**************************************************************************
457  * event_manager
458  **************************************************************************/
459 libvlc_event_manager_t *
460 libvlc_media_descriptor_event_manager( libvlc_media_descriptor_t * p_md,
461                                        libvlc_exception_t * p_e )
462 {
463     return p_md->p_event_manager;
464 }