]> git.sesse.net Git - vlc/blob - src/control/media.c
be921277a164515faf284e11cbbb2cc401139145
[vlc] / src / control / media.c
1 /*****************************************************************************
2  * media.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/libvlc_media.h>
26 #include <vlc/libvlc_media_list.h> // For the subitems, here for convenience
27 #include <vlc/libvlc_events.h>
28
29 #include <vlc_common.h>
30 #include <vlc_input.h>
31 #include <vlc_meta.h>
32 #include <vlc_playlist.h> /* For the preparser */
33
34 #include "libvlc.h"
35
36 #include "libvlc_internal.h"
37 #include "media_internal.h"
38
39 static const vlc_meta_type_t libvlc_to_vlc_meta[] =
40 {
41     [libvlc_meta_Title]        = vlc_meta_Title,
42     [libvlc_meta_Artist]       = vlc_meta_Artist,
43     [libvlc_meta_Genre]        = vlc_meta_Genre,
44     [libvlc_meta_Copyright]    = vlc_meta_Copyright,
45     [libvlc_meta_Album]        = vlc_meta_Album,
46     [libvlc_meta_TrackNumber]  = vlc_meta_TrackNumber,
47     [libvlc_meta_Description]  = vlc_meta_Description,
48     [libvlc_meta_Rating]       = vlc_meta_Rating,
49     [libvlc_meta_Date]         = vlc_meta_Date,
50     [libvlc_meta_Setting]      = vlc_meta_Setting,
51     [libvlc_meta_URL]          = vlc_meta_URL,
52     [libvlc_meta_Language]     = vlc_meta_Language,
53     [libvlc_meta_NowPlaying]   = vlc_meta_NowPlaying,
54     [libvlc_meta_Publisher]    = vlc_meta_Publisher,
55     [libvlc_meta_EncodedBy]    = vlc_meta_EncodedBy,
56     [libvlc_meta_ArtworkURL]   = vlc_meta_ArtworkURL,
57     [libvlc_meta_TrackID]      = vlc_meta_TrackID
58 };
59
60 static const libvlc_meta_t vlc_to_libvlc_meta[] =
61 {
62     [vlc_meta_Title]        = libvlc_meta_Title,
63     [vlc_meta_Artist]       = libvlc_meta_Artist,
64     [vlc_meta_Genre]        = libvlc_meta_Genre,
65     [vlc_meta_Copyright]    = libvlc_meta_Copyright,
66     [vlc_meta_Album]        = libvlc_meta_Album,
67     [vlc_meta_TrackNumber]  = libvlc_meta_TrackNumber,
68     [vlc_meta_Description]  = libvlc_meta_Description,
69     [vlc_meta_Rating]       = libvlc_meta_Rating,
70     [vlc_meta_Date]         = libvlc_meta_Date,
71     [vlc_meta_Setting]      = libvlc_meta_Setting,
72     [vlc_meta_URL]          = libvlc_meta_URL,
73     [vlc_meta_Language]     = libvlc_meta_Language,
74     [vlc_meta_NowPlaying]   = libvlc_meta_NowPlaying,
75     [vlc_meta_Publisher]    = libvlc_meta_Publisher,
76     [vlc_meta_EncodedBy]    = libvlc_meta_EncodedBy,
77     [vlc_meta_ArtworkURL]   = libvlc_meta_ArtworkURL,
78     [vlc_meta_TrackID]      = libvlc_meta_TrackID
79 };
80
81 /**************************************************************************
82  * input_item_subitem_added (Private) (vlc event Callback)
83  **************************************************************************/
84 static void input_item_subitem_added( const vlc_event_t *p_event,
85                                        void * user_data )
86 {
87     libvlc_media_t * p_md = user_data;
88     libvlc_media_t * p_md_child;
89     libvlc_event_t event;
90
91     p_md_child = libvlc_media_new_from_input_item(
92                 p_md->p_libvlc_instance,
93                 p_event->u.input_item_subitem_added.p_new_child, NULL );
94
95     /* Add this to our media list */
96     if( !p_md->p_subitems )
97     {
98         p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance, NULL );
99         libvlc_media_list_set_media( p_md->p_subitems, p_md, NULL );
100     }
101     if( p_md->p_subitems )
102     {
103         libvlc_media_list_add_media( p_md->p_subitems, p_md_child, NULL );
104     }
105
106     /* Construct the event */
107     event.type = libvlc_MediaSubItemAdded;
108     event.u.media_subitem_added.new_child = p_md_child;
109
110     /* Send the event */
111     libvlc_event_send( p_md->p_event_manager, &event );
112     libvlc_media_release( p_md_child );
113 }
114
115 /**************************************************************************
116  * input_item_meta_changed (Private) (vlc event Callback)
117  **************************************************************************/
118 static void input_item_meta_changed( const vlc_event_t *p_event,
119                                      void * user_data )
120 {
121     libvlc_media_t * p_md = user_data;
122     libvlc_event_t event;
123
124     /* Construct the event */
125     event.type = libvlc_MediaMetaChanged;
126     event.u.media_meta_changed.meta_type =
127         vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];
128
129     /* Send the event */
130     libvlc_event_send( p_md->p_event_manager, &event );
131 }
132
133 /**************************************************************************
134  * input_item_duration_changed (Private) (vlc event Callback)
135  **************************************************************************/
136 static void input_item_duration_changed( const vlc_event_t *p_event,
137                                          void * user_data )
138 {
139     libvlc_media_t * p_md = user_data;
140     libvlc_event_t event;
141
142     /* Construct the event */
143     event.type = libvlc_MediaDurationChanged;
144     event.u.media_duration_changed.new_duration = 
145         p_event->u.input_item_duration_changed.new_duration;
146
147     /* Send the event */
148     libvlc_event_send( p_md->p_event_manager, &event );
149 }
150
151 /**************************************************************************
152  * input_item_preparsed_changed (Private) (vlc event Callback)
153  **************************************************************************/
154 static void input_item_preparsed_changed( const vlc_event_t *p_event,
155                                           void * user_data )
156 {
157     libvlc_media_t * p_md = user_data;
158     libvlc_event_t event;
159
160     /* Construct the event */
161     event.type = libvlc_MediaPreparsedChanged;
162     event.u.media_preparsed_changed.new_status = 
163         p_event->u.input_item_preparsed_changed.new_status;
164
165     /* Send the event */
166     libvlc_event_send( p_md->p_event_manager, &event );
167 }
168
169 /**************************************************************************
170  * Install event handler (Private)
171  **************************************************************************/
172 static void install_input_item_observer( libvlc_media_t *p_md )
173 {
174     vlc_event_attach( &p_md->p_input_item->event_manager,
175                       vlc_InputItemSubItemAdded,
176                       input_item_subitem_added,
177                       p_md );
178     vlc_event_attach( &p_md->p_input_item->event_manager,
179                       vlc_InputItemMetaChanged,
180                       input_item_meta_changed,
181                       p_md );
182     vlc_event_attach( &p_md->p_input_item->event_manager,
183                       vlc_InputItemDurationChanged,
184                       input_item_duration_changed,
185                       p_md );
186     vlc_event_attach( &p_md->p_input_item->event_manager,
187                       vlc_InputItemPreparsedChanged,
188                       input_item_preparsed_changed,
189                       p_md );
190 }
191
192 /**************************************************************************
193  * Uninstall event handler (Private)
194  **************************************************************************/
195 static void uninstall_input_item_observer( libvlc_media_t *p_md )
196 {
197     vlc_event_detach( &p_md->p_input_item->event_manager,
198                       vlc_InputItemSubItemAdded,
199                       input_item_subitem_added,
200                       p_md );
201     vlc_event_detach( &p_md->p_input_item->event_manager,
202                       vlc_InputItemMetaChanged,
203                       input_item_meta_changed,
204                       p_md );
205     vlc_event_detach( &p_md->p_input_item->event_manager,
206                       vlc_InputItemDurationChanged,
207                       input_item_duration_changed,
208                       p_md );
209     vlc_event_detach( &p_md->p_input_item->event_manager,
210                       vlc_InputItemPreparsedChanged,
211                       input_item_preparsed_changed,
212                       p_md );
213 }
214
215 /**************************************************************************
216  * Preparse if not already done (Private)
217  **************************************************************************/
218 static void preparse_if_needed( libvlc_media_t *p_md )
219 {
220     /* XXX: need some locking here */
221     if (!p_md->b_preparsed)
222     {
223         playlist_PreparseEnqueue(
224                 libvlc_priv (p_md->p_libvlc_instance->p_libvlc_int)->p_playlist,
225                 p_md->p_input_item, pl_Unlocked );
226         p_md->b_preparsed = true;
227     }
228 }
229
230 /**************************************************************************
231  * Create a new media descriptor object from an input_item
232  * (libvlc internal)
233  * That's the generic constructor
234  **************************************************************************/
235 libvlc_media_t * libvlc_media_new_from_input_item(
236                                    libvlc_instance_t *p_instance,
237                                    input_item_t *p_input_item,
238                                    libvlc_exception_t *p_e )
239 {
240     libvlc_media_t * p_md;
241
242     if (!p_input_item)
243     {
244         libvlc_exception_raise( p_e, "No input item given" );
245         return NULL;
246     }
247
248     p_md = malloc( sizeof(libvlc_media_t) );
249     if( !p_md )
250     {
251         libvlc_exception_raise( p_e, "Not enough memory" );
252         return NULL;
253     }
254
255     p_md->p_libvlc_instance = p_instance;
256     p_md->p_input_item      = p_input_item;
257     p_md->b_preparsed       = false;
258     p_md->i_refcount        = 1;
259     p_md->p_user_data       = NULL;
260
261     p_md->state = libvlc_NothingSpecial;
262
263     /* A media descriptor can be a playlist. When you open a playlist
264      * It can give a bunch of item to read. */
265     p_md->p_subitems        = NULL;
266
267     p_md->p_event_manager = libvlc_event_manager_new( p_md, p_instance, p_e );
268     libvlc_event_manager_register_event_type( p_md->p_event_manager,
269         libvlc_MediaMetaChanged, p_e );
270     libvlc_event_manager_register_event_type( p_md->p_event_manager,
271         libvlc_MediaSubItemAdded, p_e );
272     libvlc_event_manager_register_event_type( p_md->p_event_manager,
273         libvlc_MediaFreed, p_e );
274     libvlc_event_manager_register_event_type( p_md->p_event_manager,
275         libvlc_MediaDurationChanged, p_e );
276     libvlc_event_manager_register_event_type( p_md->p_event_manager,
277         libvlc_MediaStateChanged, p_e );
278
279     vlc_gc_incref( p_md->p_input_item );
280
281     install_input_item_observer( p_md );
282
283     return p_md;
284 }
285
286 /**************************************************************************
287  * Create a new media descriptor object
288  **************************************************************************/
289 libvlc_media_t * libvlc_media_new(
290                                    libvlc_instance_t *p_instance,
291                                    const char * psz_mrl,
292                                    libvlc_exception_t *p_e )
293 {
294     input_item_t * p_input_item;
295     libvlc_media_t * p_md;
296
297     p_input_item = input_item_New( p_instance->p_libvlc_int, psz_mrl, NULL );
298
299     if (!p_input_item)
300     {
301         libvlc_exception_raise( p_e, "Can't create md's input_item" );
302         return NULL;
303     }
304
305     p_md = libvlc_media_new_from_input_item( p_instance,
306                 p_input_item, p_e );
307
308     /* The p_input_item is retained in libvlc_media_new_from_input_item */
309     vlc_gc_decref( p_input_item );
310
311     return p_md;
312 }
313
314 /**************************************************************************
315  * Create a new media descriptor object
316  **************************************************************************/
317 libvlc_media_t * libvlc_media_new_as_node(
318                                    libvlc_instance_t *p_instance,
319                                    const char * psz_name,
320                                    libvlc_exception_t *p_e )
321 {
322     input_item_t * p_input_item;
323     libvlc_media_t * p_md;
324
325     p_input_item = input_item_New( p_instance->p_libvlc_int, "vlc://nop", psz_name );
326
327     if (!p_input_item)
328     {
329         libvlc_exception_raise( p_e, "Can't create md's input_item" );
330         return NULL;
331     }
332
333     p_md = libvlc_media_new_from_input_item( p_instance,
334                 p_input_item, p_e );
335
336     p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance, NULL );
337
338     return p_md;
339 }
340
341 /**************************************************************************
342  * Add an option to the media descriptor,
343  * that will be used to determine how the media_player will read the
344  * media. This allow to use VLC advanced reading/streaming
345  * options in a per-media basis
346  *
347  * The options are detailled in vlc --long-help, for instance "--sout-all"
348  **************************************************************************/
349 void libvlc_media_add_option(
350                                    libvlc_media_t * p_md,
351                                    const char * ppsz_option,
352                                    libvlc_exception_t *p_e )
353 {
354     VLC_UNUSED(p_e);
355     input_item_AddOption( p_md->p_input_item, ppsz_option,
356                           VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
357 }
358
359 /**************************************************************************
360  * Same as libvlc_media_add_option but with untrusted source.
361  **************************************************************************/
362 void libvlc_media_add_option_untrusted(
363                                    libvlc_media_t * p_md,
364                                    const char * ppsz_option,
365                                    libvlc_exception_t *p_e )
366 {
367     VLC_UNUSED(p_e);
368     input_item_AddOption( p_md->p_input_item, ppsz_option,
369                           VLC_INPUT_OPTION_UNIQUE );
370 }
371
372
373 /**************************************************************************
374  * Delete a media descriptor object
375  **************************************************************************/
376 void libvlc_media_release( libvlc_media_t *p_md )
377 {
378     if (!p_md)
379         return;
380
381     p_md->i_refcount--;
382
383     if( p_md->i_refcount > 0 )
384         return;
385
386     if( p_md->p_subitems )
387         libvlc_media_list_release( p_md->p_subitems );
388
389     uninstall_input_item_observer( p_md );
390     vlc_gc_decref( p_md->p_input_item );
391
392     /* Construct the event */
393     libvlc_event_t event;
394     event.type = libvlc_MediaFreed;
395     event.u.media_freed.md = p_md;
396
397     /* Send the event */
398     libvlc_event_send( p_md->p_event_manager, &event );
399
400     libvlc_event_manager_release( p_md->p_event_manager );
401
402     free( p_md );
403 }
404
405 /**************************************************************************
406  * Retain a media descriptor object
407  **************************************************************************/
408 void libvlc_media_retain( libvlc_media_t *p_md )
409 {
410     if (!p_md)
411         return;
412
413     p_md->i_refcount++;
414 }
415
416 /**************************************************************************
417  * Duplicate a media descriptor object
418  **************************************************************************/
419 libvlc_media_t *
420 libvlc_media_duplicate( libvlc_media_t *p_md_orig )
421 {
422     return libvlc_media_new_from_input_item(
423         p_md_orig->p_libvlc_instance, p_md_orig->p_input_item, NULL );
424 }
425
426 /**************************************************************************
427  * Get mrl from a media descriptor object
428  **************************************************************************/
429 char *
430 libvlc_media_get_mrl( libvlc_media_t * p_md,
431                                  libvlc_exception_t * p_e )
432 {
433     VLC_UNUSED(p_e);
434     return input_item_GetURI( p_md->p_input_item );
435 }
436
437 /**************************************************************************
438  * Getter for meta information
439  **************************************************************************/
440
441 char * libvlc_media_get_meta( libvlc_media_t *p_md,
442                                          libvlc_meta_t e_meta,
443                                          libvlc_exception_t *p_e )
444 {
445     char * psz_meta;
446     VLC_UNUSED(p_e);
447
448     /* XXX: locking */
449
450     preparse_if_needed( p_md );
451
452     psz_meta = input_item_GetMeta( p_md->p_input_item,
453                                    libvlc_to_vlc_meta[e_meta] );
454
455     if( e_meta == libvlc_meta_ArtworkURL && !psz_meta )
456     {
457         playlist_AskForArtEnqueue(
458                 libvlc_priv(p_md->p_libvlc_instance->p_libvlc_int)->p_playlist,
459                 p_md->p_input_item, pl_Unlocked );
460     }
461
462     /* Should be integrated in core */
463     if( !psz_meta && e_meta == libvlc_meta_Title && p_md->p_input_item->psz_name )
464     {
465         free( psz_meta );
466         return strdup( p_md->p_input_item->psz_name );
467     }
468
469     return psz_meta;
470 }
471
472 /**************************************************************************
473  * Getter for state information
474  * Can be error, playing, buffering, NothingSpecial.
475  **************************************************************************/
476
477 libvlc_state_t
478 libvlc_media_get_state( libvlc_media_t *p_md,
479                                    libvlc_exception_t *p_e )
480 {
481     VLC_UNUSED(p_e);
482     return p_md->state;
483 }
484
485 /**************************************************************************
486  * Setter for state information (LibVLC Internal)
487  **************************************************************************/
488
489 void
490 libvlc_media_set_state( libvlc_media_t *p_md,
491                                    libvlc_state_t state,
492                                    libvlc_exception_t *p_e )
493 {
494     libvlc_event_t event;
495     VLC_UNUSED(p_e);
496
497     p_md->state = state;
498
499     /* Construct the event */
500     event.type = libvlc_MediaStateChanged;
501     event.u.media_state_changed.new_state = state;
502
503     /* Send the event */
504     libvlc_event_send( p_md->p_event_manager, &event );
505 }
506
507 /**************************************************************************
508  * subitems
509  **************************************************************************/
510 libvlc_media_list_t *
511 libvlc_media_subitems( libvlc_media_t * p_md,
512                                   libvlc_exception_t * p_e )
513 {
514     VLC_UNUSED(p_e);
515
516     if( p_md->p_subitems )
517         libvlc_media_list_retain( p_md->p_subitems );
518     return p_md->p_subitems;
519 }
520
521 /**************************************************************************
522  * event_manager
523  **************************************************************************/
524 libvlc_event_manager_t *
525 libvlc_media_event_manager( libvlc_media_t * p_md,
526                                        libvlc_exception_t * p_e )
527 {
528     VLC_UNUSED(p_e);
529
530     return p_md->p_event_manager;
531 }
532
533 /**************************************************************************
534  * Get duration of media object.
535  **************************************************************************/
536 int64_t
537 libvlc_media_get_duration( libvlc_media_t * p_md,
538                                       libvlc_exception_t * p_e )
539 {
540     VLC_UNUSED(p_e);
541
542     if( !p_md || !p_md->p_input_item)
543     {
544         libvlc_exception_raise( p_e, "No input item" );
545         return -1;
546     }
547
548     return input_item_GetDuration( p_md->p_input_item );
549 }
550
551 /**************************************************************************
552  * Get preparsed status for media object.
553  **************************************************************************/
554 int
555 libvlc_media_is_preparsed( libvlc_media_t * p_md,
556                                        libvlc_exception_t * p_e )
557 {
558     VLC_UNUSED(p_e);
559
560     if( !p_md || !p_md->p_input_item)
561     {
562         libvlc_exception_raise( p_e, "No input item" );
563         return false;
564     }
565
566     return input_item_IsPreparsed( p_md->p_input_item );
567 }
568
569 /**************************************************************************
570  * Sets media descriptor's user_data. user_data is specialized data 
571  * accessed by the host application, VLC.framework uses it as a pointer to 
572  * an native object that references a libvlc_media_t pointer
573  **************************************************************************/
574 void 
575 libvlc_media_set_user_data( libvlc_media_t * p_md,
576                                        void * p_new_user_data,
577                                        libvlc_exception_t * p_e )
578 {
579     VLC_UNUSED(p_e);
580
581     if( p_md )
582     {
583         p_md->p_user_data = p_new_user_data;
584     }
585 }
586
587 /**************************************************************************
588  * Get media descriptor's user_data. user_data is specialized data 
589  * accessed by the host application, VLC.framework uses it as a pointer to 
590  * an native object that references a libvlc_media_t pointer
591  **************************************************************************/
592 void *
593 libvlc_media_get_user_data( libvlc_media_t * p_md,
594                                        libvlc_exception_t * p_e )
595 {
596     VLC_UNUSED(p_e);
597
598     if( p_md )
599     {
600         return p_md->p_user_data;
601     }
602     else
603     {
604         return NULL;
605     }
606 }