input/item: slaves must have a valid priority
[vlc.git] / lib / media.c
1 /*****************************************************************************
2  * media.c: Libvlc API media descripor management
3  *****************************************************************************
4  * Copyright (C) 2007 VLC authors and VideoLAN
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 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 #include <assert.h>
29 #include <errno.h>
30
31 #include <vlc/libvlc.h>
32 #include <vlc/libvlc_media.h>
33 #include <vlc/libvlc_media_list.h> // For the subitems, here for convenience
34 #include <vlc/libvlc_events.h>
35
36 #include <vlc_common.h>
37 #include <vlc_input.h>
38 #include <vlc_meta.h>
39 #include <vlc_playlist.h> /* For the preparser */
40 #include <vlc_url.h>
41
42 #include "../src/libvlc.h"
43
44 #include "libvlc_internal.h"
45 #include "media_internal.h"
46 #include "media_list_internal.h"
47
48 static const vlc_meta_type_t libvlc_to_vlc_meta[] =
49 {
50     [libvlc_meta_Title]        = vlc_meta_Title,
51     [libvlc_meta_Artist]       = vlc_meta_Artist,
52     [libvlc_meta_Genre]        = vlc_meta_Genre,
53     [libvlc_meta_Copyright]    = vlc_meta_Copyright,
54     [libvlc_meta_Album]        = vlc_meta_Album,
55     [libvlc_meta_TrackNumber]  = vlc_meta_TrackNumber,
56     [libvlc_meta_Description]  = vlc_meta_Description,
57     [libvlc_meta_Rating]       = vlc_meta_Rating,
58     [libvlc_meta_Date]         = vlc_meta_Date,
59     [libvlc_meta_Setting]      = vlc_meta_Setting,
60     [libvlc_meta_URL]          = vlc_meta_URL,
61     [libvlc_meta_Language]     = vlc_meta_Language,
62     [libvlc_meta_NowPlaying]   = vlc_meta_NowPlaying,
63     [libvlc_meta_Publisher]    = vlc_meta_Publisher,
64     [libvlc_meta_EncodedBy]    = vlc_meta_EncodedBy,
65     [libvlc_meta_ArtworkURL]   = vlc_meta_ArtworkURL,
66     [libvlc_meta_TrackID]      = vlc_meta_TrackID,
67     [libvlc_meta_TrackTotal]   = vlc_meta_TrackTotal,
68     [libvlc_meta_Director]     = vlc_meta_Director,
69     [libvlc_meta_Season]       = vlc_meta_Season,
70     [libvlc_meta_Episode]      = vlc_meta_Episode,
71     [libvlc_meta_ShowName]     = vlc_meta_ShowName,
72     [libvlc_meta_Actors]       = vlc_meta_Actors,
73     [libvlc_meta_AlbumArtist]  = vlc_meta_AlbumArtist,
74     [libvlc_meta_DiscNumber]   = vlc_meta_DiscNumber,
75     [libvlc_meta_DiscTotal]    = vlc_meta_DiscTotal
76 };
77
78 static const libvlc_meta_t vlc_to_libvlc_meta[] =
79 {
80     [vlc_meta_Title]        = libvlc_meta_Title,
81     [vlc_meta_Artist]       = libvlc_meta_Artist,
82     [vlc_meta_Genre]        = libvlc_meta_Genre,
83     [vlc_meta_Copyright]    = libvlc_meta_Copyright,
84     [vlc_meta_Album]        = libvlc_meta_Album,
85     [vlc_meta_TrackNumber]  = libvlc_meta_TrackNumber,
86     [vlc_meta_Description]  = libvlc_meta_Description,
87     [vlc_meta_Rating]       = libvlc_meta_Rating,
88     [vlc_meta_Date]         = libvlc_meta_Date,
89     [vlc_meta_Setting]      = libvlc_meta_Setting,
90     [vlc_meta_URL]          = libvlc_meta_URL,
91     [vlc_meta_Language]     = libvlc_meta_Language,
92     [vlc_meta_NowPlaying]   = libvlc_meta_NowPlaying,
93     [vlc_meta_ESNowPlaying] = libvlc_meta_NowPlaying,
94     [vlc_meta_Publisher]    = libvlc_meta_Publisher,
95     [vlc_meta_EncodedBy]    = libvlc_meta_EncodedBy,
96     [vlc_meta_ArtworkURL]   = libvlc_meta_ArtworkURL,
97     [vlc_meta_TrackID]      = libvlc_meta_TrackID,
98     [vlc_meta_TrackTotal]   = libvlc_meta_TrackTotal,
99     [vlc_meta_Director]     = libvlc_meta_Director,
100     [vlc_meta_Season]       = libvlc_meta_Season,
101     [vlc_meta_Episode]      = libvlc_meta_Episode,
102     [vlc_meta_ShowName]     = libvlc_meta_ShowName,
103     [vlc_meta_Actors]       = libvlc_meta_Actors,
104     [vlc_meta_AlbumArtist]  = libvlc_meta_AlbumArtist,
105     [vlc_meta_DiscNumber]   = libvlc_meta_DiscNumber,
106     [vlc_meta_DiscTotal]    = libvlc_meta_DiscTotal
107 };
108
109 static libvlc_media_list_t *media_get_subitems( libvlc_media_t * p_md,
110                                                 bool b_create )
111 {
112     libvlc_media_list_t *p_subitems = NULL;
113
114     vlc_mutex_lock( &p_md->subitems_lock );
115     if( p_md->p_subitems == NULL && b_create )
116     {
117         p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
118         if( p_md->p_subitems != NULL )
119         {
120             p_md->p_subitems->b_read_only = true;
121             p_md->p_subitems->p_internal_md = p_md;
122         }
123     }
124     p_subitems = p_md->p_subitems;
125     vlc_mutex_unlock( &p_md->subitems_lock );
126     return p_subitems;
127 }
128
129 /**************************************************************************
130  * input_item_subitem_added (Private) (vlc event Callback)
131  **************************************************************************/
132 static void input_item_subitem_added( const vlc_event_t *p_event,
133                                        void * user_data )
134 {
135     libvlc_media_t * p_md = user_data;
136     libvlc_media_t * p_md_child;
137     libvlc_media_list_t *p_subitems;
138     libvlc_event_t event;
139
140     p_md_child = libvlc_media_new_from_input_item(
141                 p_md->p_libvlc_instance,
142                 p_event->u.input_item_subitem_added.p_new_child );
143
144     /* Add this to our media list */
145     p_subitems = media_get_subitems( p_md, true );
146     if( p_subitems != NULL )
147     {
148         libvlc_media_list_lock( p_subitems );
149         libvlc_media_list_internal_add_media( p_subitems, p_md_child );
150         libvlc_media_list_unlock( p_subitems );
151     }
152
153     /* Construct the event */
154     event.type = libvlc_MediaSubItemAdded;
155     event.u.media_subitem_added.new_child = p_md_child;
156
157     /* Send the event */
158     libvlc_event_send( p_md->p_event_manager, &event );
159     libvlc_media_release( p_md_child );
160 }
161
162 /**************************************************************************
163  * input_item_subitemtree_added (Private) (vlc event Callback)
164  **************************************************************************/
165 static void input_item_subitemtree_added( const vlc_event_t * p_event,
166                                           void * user_data )
167 {
168     VLC_UNUSED( p_event );
169     libvlc_media_t * p_md = user_data;
170     libvlc_event_t event;
171
172     /* Construct the event */
173     event.type = libvlc_MediaSubItemTreeAdded;
174     event.u.media_subitemtree_added.item = p_md;
175
176     /* Send the event */
177     libvlc_event_send( p_md->p_event_manager, &event );
178 }
179
180 /**************************************************************************
181  * input_item_meta_changed (Private) (vlc event Callback)
182  **************************************************************************/
183 static void input_item_meta_changed( const vlc_event_t *p_event,
184                                      void * user_data )
185 {
186     libvlc_media_t * p_md = user_data;
187     libvlc_event_t event;
188
189     /* Construct the event */
190     event.type = libvlc_MediaMetaChanged;
191     event.u.media_meta_changed.meta_type =
192         vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];
193
194     /* Send the event */
195     libvlc_event_send( p_md->p_event_manager, &event );
196 }
197
198 /**************************************************************************
199  * input_item_duration_changed (Private) (vlc event Callback)
200  **************************************************************************/
201 static void input_item_duration_changed( const vlc_event_t *p_event,
202                                          void * user_data )
203 {
204     libvlc_media_t * p_md = user_data;
205     libvlc_event_t event;
206
207     /* Construct the event */
208     event.type = libvlc_MediaDurationChanged;
209     event.u.media_duration_changed.new_duration =
210         from_mtime(p_event->u.input_item_duration_changed.new_duration);
211
212     /* Send the event */
213     libvlc_event_send( p_md->p_event_manager, &event );
214 }
215
216 static void send_preparsed_event(libvlc_media_t *media)
217 {
218     libvlc_event_t event;
219
220     /* Eventually notify libvlc_media_parse() */
221     vlc_mutex_lock(&media->parsed_lock);
222     if (media->is_parsed == true)
223     {
224         vlc_mutex_unlock(&media->parsed_lock);
225         return;
226     }
227     media->is_parsed = true;
228     vlc_cond_broadcast(&media->parsed_cond);
229     vlc_mutex_unlock(&media->parsed_lock);
230
231
232     /* Construct the event */
233     event.type = libvlc_MediaParsedChanged;
234     event.u.media_parsed_changed.new_status = true;
235
236     /* Send the event */
237     libvlc_event_send(media->p_event_manager, &event);
238 }
239
240 /**************************************************************************
241  * input_item_preparsed_changed (Private) (vlc event Callback)
242  **************************************************************************/
243 static void input_item_preparsed_changed(const vlc_event_t *p_event,
244                                          void * user_data)
245 {
246     VLC_UNUSED( p_event );
247     libvlc_media_t *media = user_data;
248     send_preparsed_event(media);
249 }
250
251 /**************************************************************************
252  * input_item_preparse_ended (Private) (vlc event Callback)
253  **************************************************************************/
254 static void input_item_preparse_ended( const vlc_event_t * p_event,
255                                        void * user_data )
256 {
257     VLC_UNUSED( p_event );
258     libvlc_media_t * p_md = user_data;
259     libvlc_media_list_t *p_subitems = media_get_subitems( p_md, false );
260     libvlc_event_t event;
261
262     event.type = libvlc_MediaParsedStatus;
263
264     vlc_mutex_lock(&p_md->parsed_lock);
265     switch (p_event->u.input_item_preparse_ended.new_status)
266     {
267         case ITEM_PREPARSE_SKIPPED:
268             p_md->parsed_status = libvlc_media_parse_skipped;
269             p_md->has_asked_preparse = false;
270             break;
271         case ITEM_PREPARSE_FAILED:
272             p_md->parsed_status = libvlc_media_parse_failed;
273             break;
274         case ITEM_PREPARSE_DONE:
275             p_md->parsed_status = libvlc_media_parse_done;
276             break;
277     }
278     event.u.media_parsed_status.new_status = p_md->parsed_status;
279     vlc_mutex_unlock(&p_md->parsed_lock);
280
281     if( p_subitems != NULL )
282     {
283         /* notify the media list */
284         libvlc_media_list_lock( p_subitems );
285         libvlc_media_list_internal_end_reached( p_subitems );
286         libvlc_media_list_unlock( p_subitems );
287     }
288
289     /* XXX: libVLC 2.2.0 compat: even if case of preparse failure,
290      * libvlc_MediaParsedChanged was sent with a true status. Therefore, send
291      * this event if it was not previously sent */
292     send_preparsed_event(p_md);
293
294     libvlc_event_send(p_md->p_event_manager, &event);
295 }
296
297 /**************************************************************************
298  * Install event handler (Private)
299  **************************************************************************/
300 static void install_input_item_observer( libvlc_media_t *p_md )
301 {
302     vlc_event_attach( &p_md->p_input_item->event_manager,
303                       vlc_InputItemSubItemAdded,
304                       input_item_subitem_added,
305                       p_md );
306     vlc_event_attach( &p_md->p_input_item->event_manager,
307                       vlc_InputItemMetaChanged,
308                       input_item_meta_changed,
309                       p_md );
310     vlc_event_attach( &p_md->p_input_item->event_manager,
311                       vlc_InputItemDurationChanged,
312                       input_item_duration_changed,
313                       p_md );
314     vlc_event_attach( &p_md->p_input_item->event_manager,
315                       vlc_InputItemPreparsedChanged,
316                       input_item_preparsed_changed,
317                       p_md );
318     vlc_event_attach( &p_md->p_input_item->event_manager,
319                       vlc_InputItemSubItemTreeAdded,
320                       input_item_subitemtree_added,
321                       p_md );
322     vlc_event_attach( &p_md->p_input_item->event_manager,
323                       vlc_InputItemPreparseEnded,
324                       input_item_preparse_ended,
325                       p_md );
326 }
327
328 /**************************************************************************
329  * Uninstall event handler (Private)
330  **************************************************************************/
331 static void uninstall_input_item_observer( libvlc_media_t *p_md )
332 {
333     vlc_event_detach( &p_md->p_input_item->event_manager,
334                       vlc_InputItemSubItemAdded,
335                       input_item_subitem_added,
336                       p_md );
337     vlc_event_detach( &p_md->p_input_item->event_manager,
338                       vlc_InputItemMetaChanged,
339                       input_item_meta_changed,
340                       p_md );
341     vlc_event_detach( &p_md->p_input_item->event_manager,
342                       vlc_InputItemDurationChanged,
343                       input_item_duration_changed,
344                       p_md );
345     vlc_event_detach( &p_md->p_input_item->event_manager,
346                       vlc_InputItemPreparsedChanged,
347                       input_item_preparsed_changed,
348                       p_md );
349     vlc_event_detach( &p_md->p_input_item->event_manager,
350                       vlc_InputItemSubItemTreeAdded,
351                       input_item_subitemtree_added,
352                       p_md );
353     vlc_event_detach( &p_md->p_input_item->event_manager,
354                       vlc_InputItemPreparseEnded,
355                       input_item_preparse_ended,
356                       p_md );
357 }
358
359 /**************************************************************************
360  * Create a new media descriptor object from an input_item
361  * (libvlc internal)
362  * That's the generic constructor
363  **************************************************************************/
364 libvlc_media_t * libvlc_media_new_from_input_item(
365                                    libvlc_instance_t *p_instance,
366                                    input_item_t *p_input_item )
367 {
368     libvlc_media_t * p_md;
369
370     if (!p_input_item)
371     {
372         libvlc_printerr( "No input item given" );
373         return NULL;
374     }
375
376     p_md = calloc( 1, sizeof(libvlc_media_t) );
377     if( !p_md )
378     {
379         libvlc_printerr( "Not enough memory" );
380         return NULL;
381     }
382
383     p_md->p_libvlc_instance = p_instance;
384     p_md->p_input_item      = p_input_item;
385     p_md->i_refcount        = 1;
386
387     vlc_cond_init(&p_md->parsed_cond);
388     vlc_mutex_init(&p_md->parsed_lock);
389     vlc_mutex_init(&p_md->subitems_lock);
390
391     p_md->state = libvlc_NothingSpecial;
392
393     /* A media descriptor can be a playlist. When you open a playlist
394      * It can give a bunch of item to read. */
395     p_md->p_subitems        = NULL;
396
397     p_md->p_event_manager = libvlc_event_manager_new( p_md );
398     if( unlikely(p_md->p_event_manager == NULL) )
399     {
400         free(p_md);
401         return NULL;
402     }
403
404     vlc_gc_incref( p_md->p_input_item );
405
406     install_input_item_observer( p_md );
407
408     libvlc_retain( p_instance );
409     return p_md;
410 }
411
412 /**************************************************************************
413  * Create a new media descriptor object
414  **************************************************************************/
415 libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
416                                            const char * psz_mrl )
417 {
418     input_item_t * p_input_item;
419     libvlc_media_t * p_md;
420
421     p_input_item = input_item_New( psz_mrl, NULL );
422
423     if (!p_input_item)
424     {
425         libvlc_printerr( "Not enough memory" );
426         return NULL;
427     }
428
429     p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
430
431     /* The p_input_item is retained in libvlc_media_new_from_input_item */
432     vlc_gc_decref( p_input_item );
433
434     return p_md;
435 }
436
437 libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
438                                        const char *path )
439 {
440     char *mrl = vlc_path2uri( path, NULL );
441     if( unlikely(mrl == NULL) )
442     {
443         libvlc_printerr( "%s", vlc_strerror_c(errno) );
444         return NULL;
445     }
446
447     libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl );
448     free( mrl );
449     return m;
450 }
451
452 libvlc_media_t *libvlc_media_new_fd( libvlc_instance_t *p_instance, int fd )
453 {
454     char mrl[16];
455     snprintf( mrl, sizeof(mrl), "fd://%d", fd );
456
457     return libvlc_media_new_location( p_instance, mrl );
458 }
459
460 libvlc_media_t *libvlc_media_new_callbacks(libvlc_instance_t *p_instance,
461                                            libvlc_media_open_cb open_cb,
462                                            libvlc_media_read_cb read_cb,
463                                            libvlc_media_seek_cb seek_cb,
464                                            libvlc_media_close_cb close_cb,
465                                            void *opaque)
466 {
467     libvlc_media_t *m = libvlc_media_new_location(p_instance, "imem://");
468     if (unlikely(m == NULL))
469         return NULL;
470
471     assert(read_cb != NULL);
472     input_item_AddOpaque(m->p_input_item, "imem-data", opaque);
473     input_item_AddOpaque(m->p_input_item, "imem-open", open_cb);
474     input_item_AddOpaque(m->p_input_item, "imem-read", read_cb);
475     input_item_AddOpaque(m->p_input_item, "imem-seek", seek_cb);
476     input_item_AddOpaque(m->p_input_item, "imem-close", close_cb);
477     return m;
478 }
479
480 /**************************************************************************
481  * Create a new media descriptor object
482  **************************************************************************/
483 libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
484                                            const char * psz_name )
485 {
486     input_item_t * p_input_item;
487     libvlc_media_t * p_md;
488     libvlc_media_list_t * p_subitems;
489
490     p_input_item = input_item_New( "vlc://nop", psz_name );
491
492     if (!p_input_item)
493     {
494         libvlc_printerr( "Not enough memory" );
495         return NULL;
496     }
497
498     p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
499
500     p_subitems = media_get_subitems( p_md, true );
501     if( p_subitems == NULL) {
502         libvlc_media_release( p_md );
503         return NULL;
504     }
505
506     return p_md;
507 }
508
509 /**************************************************************************
510  * Add an option to the media descriptor,
511  * that will be used to determine how the media_player will read the
512  * media. This allow to use VLC advanced reading/streaming
513  * options in a per-media basis
514  *
515  * The options are detailled in vlc --long-help, for instance "--sout-all"
516  **************************************************************************/
517 void libvlc_media_add_option( libvlc_media_t * p_md,
518                               const char * psz_option )
519 {
520     libvlc_media_add_option_flag( p_md, psz_option,
521                           VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
522 }
523
524 /**************************************************************************
525  * Same as libvlc_media_add_option but with configurable flags.
526  **************************************************************************/
527 void libvlc_media_add_option_flag( libvlc_media_t * p_md,
528                                    const char * ppsz_option,
529                                    unsigned i_flags )
530 {
531     input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
532 }
533
534 /**************************************************************************
535  * Delete a media descriptor object
536  **************************************************************************/
537 void libvlc_media_release( libvlc_media_t *p_md )
538 {
539     if (!p_md)
540         return;
541
542     p_md->i_refcount--;
543
544     if( p_md->i_refcount > 0 )
545         return;
546
547     uninstall_input_item_observer( p_md );
548
549     if( p_md->p_subitems )
550         libvlc_media_list_release( p_md->p_subitems );
551
552     vlc_gc_decref( p_md->p_input_item );
553
554     vlc_cond_destroy( &p_md->parsed_cond );
555     vlc_mutex_destroy( &p_md->parsed_lock );
556     vlc_mutex_destroy( &p_md->subitems_lock );
557
558     /* Construct the event */
559     libvlc_event_t event;
560     event.type = libvlc_MediaFreed;
561     event.u.media_freed.md = p_md;
562
563     /* Send the event */
564     libvlc_event_send( p_md->p_event_manager, &event );
565
566     libvlc_event_manager_release( p_md->p_event_manager );
567     libvlc_release( p_md->p_libvlc_instance );
568     free( p_md );
569 }
570
571 /**************************************************************************
572  * Retain a media descriptor object
573  **************************************************************************/
574 void libvlc_media_retain( libvlc_media_t *p_md )
575 {
576     assert (p_md);
577     p_md->i_refcount++;
578 }
579
580 /**************************************************************************
581  * Duplicate a media descriptor object
582  **************************************************************************/
583 libvlc_media_t *
584 libvlc_media_duplicate( libvlc_media_t *p_md_orig )
585 {
586     return libvlc_media_new_from_input_item(
587         p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
588 }
589
590 /**************************************************************************
591  * Get mrl from a media descriptor object
592  **************************************************************************/
593 char *
594 libvlc_media_get_mrl( libvlc_media_t * p_md )
595 {
596     assert( p_md );
597     return input_item_GetURI( p_md->p_input_item );
598 }
599
600 /**************************************************************************
601  * Getter for meta information
602  **************************************************************************/
603
604 char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
605 {
606     char *psz_meta = NULL;
607
608     if( e_meta == libvlc_meta_NowPlaying )
609     {
610         psz_meta = input_item_GetNowPlayingFb( p_md->p_input_item );
611     }
612     else
613     {
614         psz_meta = input_item_GetMeta( p_md->p_input_item,
615                                              libvlc_to_vlc_meta[e_meta] );
616         /* Should be integrated in core */
617         if( psz_meta == NULL && e_meta == libvlc_meta_Title
618          && p_md->p_input_item->psz_name != NULL )
619             psz_meta = strdup( p_md->p_input_item->psz_name );
620     }
621     return psz_meta;
622 }
623
624 /**************************************************************************
625  * Setter for meta information
626  **************************************************************************/
627
628 void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value )
629 {
630     assert( p_md );
631     input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value );
632 }
633
634 int libvlc_media_save_meta( libvlc_media_t *p_md )
635 {
636     assert( p_md );
637     vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
638     return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
639 }
640
641 /**************************************************************************
642  * Getter for state information
643  * Can be error, playing, buffering, NothingSpecial.
644  **************************************************************************/
645
646 libvlc_state_t
647 libvlc_media_get_state( libvlc_media_t *p_md )
648 {
649     assert( p_md );
650     return p_md->state;
651 }
652
653 /**************************************************************************
654  * Setter for state information (LibVLC Internal)
655  **************************************************************************/
656
657 void
658 libvlc_media_set_state( libvlc_media_t *p_md,
659                                    libvlc_state_t state )
660 {
661     libvlc_event_t event;
662
663     p_md->state = state;
664
665     /* Construct the event */
666     event.type = libvlc_MediaStateChanged;
667     event.u.media_state_changed.new_state = state;
668
669     /* Send the event */
670     libvlc_event_send( p_md->p_event_manager, &event );
671 }
672
673 /**************************************************************************
674  * subitems
675  **************************************************************************/
676 libvlc_media_list_t *
677 libvlc_media_subitems( libvlc_media_t * p_md )
678 {
679     libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true );
680     if( p_subitems )
681         libvlc_media_list_retain( p_subitems );
682     return p_subitems;
683 }
684
685 /**************************************************************************
686  * Getter for statistics information
687  **************************************************************************/
688 int libvlc_media_get_stats( libvlc_media_t *p_md,
689                             libvlc_media_stats_t *p_stats )
690 {
691     if( !p_md->p_input_item )
692         return false;
693
694     input_stats_t *p_itm_stats = p_md->p_input_item->p_stats;
695     vlc_mutex_lock( &p_itm_stats->lock );
696     p_stats->i_read_bytes = p_itm_stats->i_read_bytes;
697     p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate;
698
699     p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes;
700     p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate;
701     p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted;
702     p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity;
703
704     p_stats->i_decoded_video = p_itm_stats->i_decoded_video;
705     p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio;
706
707     p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures;
708     p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures;
709
710     p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers;
711     p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers;
712
713     p_stats->i_sent_packets = p_itm_stats->i_sent_packets;
714     p_stats->i_sent_bytes = p_itm_stats->i_sent_bytes;
715     p_stats->f_send_bitrate = p_itm_stats->f_send_bitrate;
716     vlc_mutex_unlock( &p_itm_stats->lock );
717     return true;
718 }
719
720 /**************************************************************************
721  * event_manager
722  **************************************************************************/
723 libvlc_event_manager_t *
724 libvlc_media_event_manager( libvlc_media_t * p_md )
725 {
726     assert( p_md );
727
728     return p_md->p_event_manager;
729 }
730
731 /**************************************************************************
732  * Get duration of media object (in ms)
733  **************************************************************************/
734 int64_t
735 libvlc_media_get_duration( libvlc_media_t * p_md )
736 {
737     assert( p_md );
738
739     if( !p_md->p_input_item )
740     {
741         libvlc_printerr( "No input item" );
742         return -1;
743     }
744
745     if (!input_item_IsPreparsed( p_md->p_input_item ))
746         return -1;
747
748     return from_mtime(input_item_GetDuration( p_md->p_input_item ));
749 }
750
751 static int media_parse(libvlc_media_t *media, bool b_async,
752                        libvlc_media_parse_flag_t parse_flag)
753 {
754     bool needed;
755
756     vlc_mutex_lock(&media->parsed_lock);
757     needed = !media->has_asked_preparse;
758     media->has_asked_preparse = true;
759     vlc_mutex_unlock(&media->parsed_lock);
760
761     if (needed)
762     {
763         libvlc_int_t *libvlc = media->p_libvlc_instance->p_libvlc_int;
764         input_item_t *item = media->p_input_item;
765         input_item_meta_request_option_t art_scope = META_REQUEST_OPTION_NONE;
766         input_item_meta_request_option_t parse_scope = META_REQUEST_OPTION_SCOPE_LOCAL;
767         int ret;
768
769         if (parse_flag & libvlc_media_fetch_local)
770             art_scope |= META_REQUEST_OPTION_SCOPE_LOCAL;
771         if (parse_flag & libvlc_media_fetch_network)
772             art_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
773         if (art_scope != META_REQUEST_OPTION_NONE) {
774             ret = libvlc_ArtRequest(libvlc, item, art_scope);
775             if (ret != VLC_SUCCESS)
776                 return ret;
777         }
778
779         if (parse_flag & libvlc_media_parse_network)
780             parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
781         if (parse_flag & libvlc_media_do_interact)
782             parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
783         ret = libvlc_MetaRequest(libvlc, item, parse_scope);
784         if (ret != VLC_SUCCESS)
785             return ret;
786     }
787     else
788         return VLC_EGENERIC;
789
790     if (!b_async)
791     {
792         vlc_mutex_lock(&media->parsed_lock);
793         while (!media->is_parsed)
794             vlc_cond_wait(&media->parsed_cond, &media->parsed_lock);
795         vlc_mutex_unlock(&media->parsed_lock);
796     }
797     return VLC_SUCCESS;
798 }
799
800 /**************************************************************************
801  * Parse the media and wait.
802  **************************************************************************/
803 void
804 libvlc_media_parse(libvlc_media_t *media)
805 {
806     media_parse( media, false, libvlc_media_fetch_local );
807 }
808
809 /**************************************************************************
810  * Parse the media but do not wait.
811  **************************************************************************/
812 void
813 libvlc_media_parse_async(libvlc_media_t *media)
814 {
815     media_parse( media, true, libvlc_media_fetch_local );
816 }
817
818 /**************************************************************************
819  * Parse the media asynchronously with options.
820  **************************************************************************/
821 int
822 libvlc_media_parse_with_options( libvlc_media_t *media,
823                                  libvlc_media_parse_flag_t parse_flag )
824 {
825     return media_parse( media, true, parse_flag ) == VLC_SUCCESS ? 0 : -1;
826 }
827
828 /**************************************************************************
829  * Get parsed status for media object.
830  **************************************************************************/
831 int
832 libvlc_media_is_parsed(libvlc_media_t *media)
833 {
834     bool parsed;
835
836     vlc_mutex_lock(&media->parsed_lock);
837     parsed = media->is_parsed;
838     vlc_mutex_unlock(&media->parsed_lock);
839     return parsed;
840 }
841
842 libvlc_media_parsed_status_t
843 libvlc_media_get_parsed_status(libvlc_media_t *media)
844 {
845     libvlc_media_parsed_status_t status;
846
847     vlc_mutex_lock(&media->parsed_lock);
848     status = media->parsed_status;
849     vlc_mutex_unlock(&media->parsed_lock);
850     return status;
851 }
852
853 /**************************************************************************
854  * Sets media descriptor's user_data. user_data is specialized data
855  * accessed by the host application, VLC.framework uses it as a pointer to
856  * an native object that references a libvlc_media_t pointer
857  **************************************************************************/
858 void
859 libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
860 {
861     assert( p_md );
862     p_md->p_user_data = p_new_user_data;
863 }
864
865 /**************************************************************************
866  * Get media descriptor's user_data. user_data is specialized data
867  * accessed by the host application, VLC.framework uses it as a pointer to
868  * an native object that references a libvlc_media_t pointer
869  **************************************************************************/
870 void *
871 libvlc_media_get_user_data( libvlc_media_t * p_md )
872 {
873     assert( p_md );
874     return p_md->p_user_data;
875 }
876
877 /**************************************************************************
878  * Get media descriptor's elementary streams description
879  **************************************************************************/
880 int
881 libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
882 {
883     assert( p_md );
884
885     input_item_t *p_input_item = p_md->p_input_item;
886     vlc_mutex_lock( &p_input_item->lock );
887
888     const int i_es = p_input_item->i_es;
889     *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL;
890
891     if( !*pp_es ) /* no ES, or OOM */
892     {
893         vlc_mutex_unlock( &p_input_item->lock );
894         return 0;
895     }
896
897     /* Fill array */
898     for( int i = 0; i < i_es; i++ )
899     {
900         libvlc_media_track_info_t *p_mes = *pp_es+i;
901         const es_format_t *p_es = p_input_item->es[i];
902
903         p_mes->i_codec = p_es->i_codec;
904         p_mes->i_id = p_es->i_id;
905
906         p_mes->i_profile = p_es->i_profile;
907         p_mes->i_level = p_es->i_level;
908
909         switch(p_es->i_cat)
910         {
911         case UNKNOWN_ES:
912         default:
913             p_mes->i_type = libvlc_track_unknown;
914             break;
915         case VIDEO_ES:
916             p_mes->i_type = libvlc_track_video;
917             p_mes->u.video.i_height = p_es->video.i_visible_height;
918             p_mes->u.video.i_width = p_es->video.i_visible_width;
919             break;
920         case AUDIO_ES:
921             p_mes->i_type = libvlc_track_audio;
922             p_mes->u.audio.i_channels = p_es->audio.i_channels;
923             p_mes->u.audio.i_rate = p_es->audio.i_rate;
924             break;
925         case SPU_ES:
926             p_mes->i_type = libvlc_track_text;
927             break;
928         }
929     }
930
931     vlc_mutex_unlock( &p_input_item->lock );
932     return i_es;
933 }
934
935 unsigned
936 libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es )
937 {
938     assert( p_md );
939
940     input_item_t *p_input_item = p_md->p_input_item;
941     vlc_mutex_lock( &p_input_item->lock );
942
943     const int i_es = p_input_item->i_es;
944     *pp_es = (i_es > 0) ? calloc( i_es, sizeof(**pp_es) ) : NULL;
945
946     if( !*pp_es ) /* no ES, or OOM */
947     {
948         vlc_mutex_unlock( &p_input_item->lock );
949         return 0;
950     }
951
952     /* Fill array */
953     for( int i = 0; i < i_es; i++ )
954     {
955         libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) );
956         if ( p_mes )
957         {
958             p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio),
959                                                sizeof(*p_mes->video)),
960                                                sizeof(*p_mes->subtitle)) );
961         }
962         if ( !p_mes || !p_mes->audio )
963         {
964             libvlc_media_tracks_release( *pp_es, i_es );
965             *pp_es = NULL;
966             free( p_mes );
967             vlc_mutex_unlock( &p_input_item->lock );
968             return 0;
969         }
970         (*pp_es)[i] = p_mes;
971
972         const es_format_t *p_es = p_input_item->es[i];
973
974         p_mes->i_codec = p_es->i_codec;
975         p_mes->i_original_fourcc = p_es->i_original_fourcc;
976         p_mes->i_id = p_es->i_id;
977
978         p_mes->i_profile = p_es->i_profile;
979         p_mes->i_level = p_es->i_level;
980
981         p_mes->i_bitrate = p_es->i_bitrate;
982         p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL;
983         p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL;
984
985         switch(p_es->i_cat)
986         {
987         case UNKNOWN_ES:
988         default:
989             p_mes->i_type = libvlc_track_unknown;
990             break;
991         case VIDEO_ES:
992             p_mes->i_type = libvlc_track_video;
993             p_mes->video->i_height = p_es->video.i_visible_height;
994             p_mes->video->i_width = p_es->video.i_visible_width;
995             p_mes->video->i_sar_num = p_es->video.i_sar_num;
996             p_mes->video->i_sar_den = p_es->video.i_sar_den;
997             p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate;
998             p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base;
999             break;
1000         case AUDIO_ES:
1001             p_mes->i_type = libvlc_track_audio;
1002             p_mes->audio->i_channels = p_es->audio.i_channels;
1003             p_mes->audio->i_rate = p_es->audio.i_rate;
1004             break;
1005         case SPU_ES:
1006             p_mes->i_type = libvlc_track_text;
1007             p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ?
1008                                             strdup(p_es->subs.psz_encoding) : NULL;
1009             break;
1010         }
1011     }
1012
1013     vlc_mutex_unlock( &p_input_item->lock );
1014     return i_es;
1015 }
1016
1017 /**************************************************************************
1018  * Get codec description from media elementary stream
1019  **************************************************************************/
1020 const char *
1021 libvlc_media_get_codec_description( libvlc_track_type_t i_type,
1022                                     uint32_t i_codec )
1023 {
1024     switch( i_type )
1025     {
1026         case libvlc_track_audio:
1027             return vlc_fourcc_GetDescription( AUDIO_ES, i_codec );
1028         case libvlc_track_video:
1029             return vlc_fourcc_GetDescription( VIDEO_ES, i_codec );
1030         case libvlc_track_text:
1031             return vlc_fourcc_GetDescription( SPU_ES, i_codec );
1032         case libvlc_track_unknown:
1033         default:
1034             return vlc_fourcc_GetDescription( UNKNOWN_ES, i_codec );
1035     }
1036 }
1037
1038 /**************************************************************************
1039  * Release media descriptor's elementary streams description array
1040  **************************************************************************/
1041 void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
1042 {
1043     for( unsigned i = 0; i < i_count; ++i )
1044     {
1045         if ( !p_tracks[i] )
1046             continue;
1047         free( p_tracks[i]->psz_language );
1048         free( p_tracks[i]->psz_description );
1049         switch( p_tracks[i]->i_type )
1050         {
1051         case libvlc_track_audio:
1052             break;
1053         case libvlc_track_video:
1054             break;
1055         case libvlc_track_text:
1056             free( p_tracks[i]->subtitle->psz_encoding );
1057             break;
1058         case libvlc_track_unknown:
1059         default:
1060             break;
1061         }
1062         free( p_tracks[i]->audio );
1063         free( p_tracks[i] );
1064     }
1065     free( p_tracks );
1066 }
1067
1068 /**************************************************************************
1069  * Get the media type of the media descriptor object
1070  **************************************************************************/
1071 libvlc_media_type_t libvlc_media_get_type( libvlc_media_t *p_md )
1072 {
1073     assert( p_md );
1074
1075     int i_type;
1076     input_item_t *p_input_item = p_md->p_input_item;
1077
1078     vlc_mutex_lock( &p_input_item->lock );
1079     i_type = p_md->p_input_item->i_type;
1080     vlc_mutex_unlock( &p_input_item->lock );
1081
1082     switch( i_type )
1083     {
1084     case ITEM_TYPE_FILE:
1085         return libvlc_media_type_file;
1086     case ITEM_TYPE_NODE:
1087     case ITEM_TYPE_DIRECTORY:
1088         return libvlc_media_type_directory;
1089     case ITEM_TYPE_DISC:
1090         return libvlc_media_type_disc;
1091     case ITEM_TYPE_STREAM:
1092         return libvlc_media_type_stream;
1093     case ITEM_TYPE_PLAYLIST:
1094         return libvlc_media_type_playlist;
1095     default:
1096         return libvlc_media_type_unknown;
1097     }
1098 }
1099
1100 int libvlc_media_slaves_add( libvlc_media_t *p_md,
1101                              libvlc_media_slave_type_t i_type,
1102                              unsigned int i_priority,
1103                              const char *psz_uri )
1104 {
1105     assert( p_md && psz_uri );
1106     input_item_t *p_input_item = p_md->p_input_item;
1107
1108     enum slave_type i_input_slave_type;
1109     switch( i_type )
1110     {
1111     case libvlc_media_slave_type_subtitle:
1112         i_input_slave_type = SLAVE_TYPE_SPU;
1113         break;
1114     case libvlc_media_slave_type_audio:
1115         i_input_slave_type = SLAVE_TYPE_AUDIO;
1116     default:
1117         vlc_assert_unreachable();
1118         return -1;
1119     }
1120
1121     enum slave_priority i_input_slave_priority;
1122     switch( i_priority )
1123     {
1124     case 0:
1125         i_input_slave_priority = SLAVE_PRIORITY_MATCH_NONE;
1126         break;
1127     case 1:
1128         i_input_slave_priority = SLAVE_PRIORITY_MATCH_RIGHT;
1129         break;
1130     case 2:
1131         i_input_slave_priority = SLAVE_PRIORITY_MATCH_LEFT;
1132         break;
1133     case 3:
1134         i_input_slave_priority = SLAVE_PRIORITY_MATCH_ALL;
1135         break;
1136     default:
1137     case 4:
1138         i_input_slave_priority = SLAVE_PRIORITY_USER;
1139         break;
1140     }
1141
1142     input_item_slave_t *p_slave = input_item_slave_New( psz_uri,
1143                                                       i_input_slave_type,
1144                                                       i_input_slave_priority );
1145     if( p_slave == NULL )
1146         return -1;
1147     return input_item_AddSlave( p_input_item, p_slave ) == VLC_SUCCESS ? 0 : -1;
1148 }
1149
1150 void libvlc_media_slaves_clear( libvlc_media_t *p_md )
1151 {
1152     assert( p_md );
1153     input_item_t *p_input_item = p_md->p_input_item;
1154
1155     vlc_mutex_lock( &p_input_item->lock );
1156     for( int i = 0; i < p_input_item->i_slaves; i++ )
1157         input_item_slave_Delete( p_input_item->pp_slaves[i] );
1158     TAB_CLEAN( p_input_item->i_slaves, p_input_item->pp_slaves );
1159     vlc_mutex_unlock( &p_input_item->lock );
1160 }
1161
1162 unsigned int libvlc_media_slaves_get( libvlc_media_t *p_md,
1163                                       libvlc_media_slave_t ***ppp_slaves )
1164 {
1165     assert( p_md && ppp_slaves );
1166     input_item_t *p_input_item = p_md->p_input_item;
1167
1168     vlc_mutex_lock( &p_input_item->lock );
1169
1170     int i_count = p_input_item->i_slaves;
1171     if( i_count <= 0 )
1172         return vlc_mutex_unlock( &p_input_item->lock ), 0;
1173
1174     libvlc_media_slave_t **pp_slaves = calloc( i_count, sizeof(*pp_slaves) );
1175     if( pp_slaves == NULL )
1176         return vlc_mutex_unlock( &p_input_item->lock ), 0;
1177
1178     for( int i = 0; i < i_count; ++i )
1179     {
1180         input_item_slave_t *p_item_slave = p_input_item->pp_slaves[i];
1181         assert( p_item_slave->i_priority >= SLAVE_PRIORITY_MATCH_NONE );
1182
1183         libvlc_media_slave_t *p_slave = malloc( sizeof(*p_slave) +
1184                                                 strlen( p_item_slave->psz_uri )
1185                                                 + 1 );
1186
1187         if( p_slave == NULL )
1188         {
1189             libvlc_media_slaves_release(pp_slaves, i);
1190             return vlc_mutex_unlock( &p_input_item->lock ), 0;
1191         }
1192         strcpy( p_slave->psz_uri, p_item_slave->psz_uri );
1193
1194         switch( p_item_slave->i_type )
1195         {
1196         case SLAVE_TYPE_SPU:
1197             p_slave->i_type = libvlc_media_slave_type_subtitle;
1198             break;
1199         case SLAVE_TYPE_AUDIO:
1200             p_slave->i_type = libvlc_media_slave_type_audio;
1201             break;
1202         default:
1203             vlc_assert_unreachable();
1204         }
1205
1206         switch( p_item_slave->i_priority )
1207         {
1208         case SLAVE_PRIORITY_MATCH_NONE:
1209             p_slave->i_priority = 0;
1210             break;
1211         case SLAVE_PRIORITY_MATCH_RIGHT:
1212             p_slave->i_priority = 1;
1213             break;
1214         case SLAVE_PRIORITY_MATCH_LEFT:
1215             p_slave->i_priority = 2;
1216             break;
1217         case SLAVE_PRIORITY_MATCH_ALL:
1218             p_slave->i_priority = 3;
1219             break;
1220         case SLAVE_PRIORITY_USER:
1221             p_slave->i_priority = 4;
1222             break;
1223         default:
1224             vlc_assert_unreachable();
1225         }
1226         pp_slaves[i] = p_slave;
1227     }
1228     vlc_mutex_unlock( &p_input_item->lock );
1229
1230     *ppp_slaves = pp_slaves;
1231     return i_count;
1232 }
1233
1234 void libvlc_media_slaves_release( libvlc_media_slave_t **pp_slaves,
1235                                   unsigned int i_count )
1236 {
1237     assert( pp_slaves );
1238     for( unsigned int i = 0; i < i_count; ++i )
1239         free(pp_slaves[i]);
1240     free(pp_slaves);
1241 }