libvlc: add libvlc_media_parse_stop
[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_parsed_changed( libvlc_media_t *p_md,
217                                  libvlc_media_parsed_status_t new_status )
218 {
219     libvlc_event_t event;
220
221     vlc_mutex_lock( &p_md->parsed_lock );
222     if( p_md->parsed_status == new_status )
223     {
224         vlc_mutex_unlock( &p_md->parsed_lock );
225         return;
226     }
227
228     /* Legacy: notify libvlc_media_parse */
229     if( !p_md->is_parsed )
230     {
231         p_md->is_parsed = true;
232         vlc_cond_broadcast( &p_md->parsed_cond );
233     }
234
235     p_md->parsed_status = new_status;
236     if( p_md->parsed_status == libvlc_media_parsed_status_skipped )
237         p_md->has_asked_preparse = false;
238
239     vlc_mutex_unlock( &p_md->parsed_lock );
240
241     if( new_status == libvlc_media_parsed_status_done )
242     {
243         libvlc_media_list_t *p_subitems = media_get_subitems( p_md, false );
244         if( p_subitems != NULL )
245         {
246             /* notify the media list */
247             libvlc_media_list_lock( p_subitems );
248             libvlc_media_list_internal_end_reached( p_subitems );
249             libvlc_media_list_unlock( p_subitems );
250         }
251     }
252
253     /* Construct the event */
254     event.type = libvlc_MediaParsedChanged;
255     event.u.media_parsed_changed.new_status = new_status;
256
257     /* Send the event */
258     libvlc_event_send( p_md->p_event_manager, &event );
259 }
260
261 /**************************************************************************
262  * input_item_preparse_ended (Private) (vlc event Callback)
263  **************************************************************************/
264 static void input_item_preparse_ended( const vlc_event_t * p_event,
265                                        void * user_data )
266 {
267     libvlc_media_t * p_md = user_data;
268     libvlc_media_parsed_status_t new_status;
269
270     switch( p_event->u.input_item_preparse_ended.new_status )
271     {
272         case ITEM_PREPARSE_SKIPPED:
273             new_status = libvlc_media_parsed_status_skipped;
274             break;
275         case ITEM_PREPARSE_FAILED:
276             new_status = libvlc_media_parsed_status_failed;
277             break;
278         case ITEM_PREPARSE_TIMEOUT:
279             new_status = libvlc_media_parsed_status_timeout;
280             break;
281         case ITEM_PREPARSE_DONE:
282             new_status = libvlc_media_parsed_status_done;
283             break;
284         default:
285             return;
286     }
287     send_parsed_changed( p_md, new_status );
288 }
289
290 /**************************************************************************
291  * Install event handler (Private)
292  **************************************************************************/
293 static void install_input_item_observer( libvlc_media_t *p_md )
294 {
295     vlc_event_attach( &p_md->p_input_item->event_manager,
296                       vlc_InputItemSubItemAdded,
297                       input_item_subitem_added,
298                       p_md );
299     vlc_event_attach( &p_md->p_input_item->event_manager,
300                       vlc_InputItemMetaChanged,
301                       input_item_meta_changed,
302                       p_md );
303     vlc_event_attach( &p_md->p_input_item->event_manager,
304                       vlc_InputItemDurationChanged,
305                       input_item_duration_changed,
306                       p_md );
307     vlc_event_attach( &p_md->p_input_item->event_manager,
308                       vlc_InputItemSubItemTreeAdded,
309                       input_item_subitemtree_added,
310                       p_md );
311     vlc_event_attach( &p_md->p_input_item->event_manager,
312                       vlc_InputItemPreparseEnded,
313                       input_item_preparse_ended,
314                       p_md );
315 }
316
317 /**************************************************************************
318  * Uninstall event handler (Private)
319  **************************************************************************/
320 static void uninstall_input_item_observer( libvlc_media_t *p_md )
321 {
322     vlc_event_detach( &p_md->p_input_item->event_manager,
323                       vlc_InputItemSubItemAdded,
324                       input_item_subitem_added,
325                       p_md );
326     vlc_event_detach( &p_md->p_input_item->event_manager,
327                       vlc_InputItemMetaChanged,
328                       input_item_meta_changed,
329                       p_md );
330     vlc_event_detach( &p_md->p_input_item->event_manager,
331                       vlc_InputItemDurationChanged,
332                       input_item_duration_changed,
333                       p_md );
334     vlc_event_detach( &p_md->p_input_item->event_manager,
335                       vlc_InputItemSubItemTreeAdded,
336                       input_item_subitemtree_added,
337                       p_md );
338     vlc_event_detach( &p_md->p_input_item->event_manager,
339                       vlc_InputItemPreparseEnded,
340                       input_item_preparse_ended,
341                       p_md );
342 }
343
344 /**************************************************************************
345  * Create a new media descriptor object from an input_item
346  * (libvlc internal)
347  * That's the generic constructor
348  **************************************************************************/
349 libvlc_media_t * libvlc_media_new_from_input_item(
350                                    libvlc_instance_t *p_instance,
351                                    input_item_t *p_input_item )
352 {
353     libvlc_media_t * p_md;
354
355     if (!p_input_item)
356     {
357         libvlc_printerr( "No input item given" );
358         return NULL;
359     }
360
361     p_md = calloc( 1, sizeof(libvlc_media_t) );
362     if( !p_md )
363     {
364         libvlc_printerr( "Not enough memory" );
365         return NULL;
366     }
367
368     p_md->p_libvlc_instance = p_instance;
369     p_md->p_input_item      = p_input_item;
370     p_md->i_refcount        = 1;
371
372     vlc_cond_init(&p_md->parsed_cond);
373     vlc_mutex_init(&p_md->parsed_lock);
374     vlc_mutex_init(&p_md->subitems_lock);
375
376     p_md->state = libvlc_NothingSpecial;
377
378     /* A media descriptor can be a playlist. When you open a playlist
379      * It can give a bunch of item to read. */
380     p_md->p_subitems        = NULL;
381
382     p_md->p_event_manager = libvlc_event_manager_new( p_md );
383     if( unlikely(p_md->p_event_manager == NULL) )
384     {
385         free(p_md);
386         return NULL;
387     }
388
389     vlc_gc_incref( p_md->p_input_item );
390
391     install_input_item_observer( p_md );
392
393     libvlc_retain( p_instance );
394     return p_md;
395 }
396
397 /**************************************************************************
398  * Create a new media descriptor object
399  **************************************************************************/
400 libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
401                                            const char * psz_mrl )
402 {
403     input_item_t * p_input_item;
404     libvlc_media_t * p_md;
405
406     p_input_item = input_item_New( psz_mrl, NULL );
407
408     if (!p_input_item)
409     {
410         libvlc_printerr( "Not enough memory" );
411         return NULL;
412     }
413
414     p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
415
416     /* The p_input_item is retained in libvlc_media_new_from_input_item */
417     vlc_gc_decref( p_input_item );
418
419     return p_md;
420 }
421
422 libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
423                                        const char *path )
424 {
425     char *mrl = vlc_path2uri( path, NULL );
426     if( unlikely(mrl == NULL) )
427     {
428         libvlc_printerr( "%s", vlc_strerror_c(errno) );
429         return NULL;
430     }
431
432     libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl );
433     free( mrl );
434     return m;
435 }
436
437 libvlc_media_t *libvlc_media_new_fd( libvlc_instance_t *p_instance, int fd )
438 {
439     char mrl[16];
440     snprintf( mrl, sizeof(mrl), "fd://%d", fd );
441
442     return libvlc_media_new_location( p_instance, mrl );
443 }
444
445 libvlc_media_t *libvlc_media_new_callbacks(libvlc_instance_t *p_instance,
446                                            libvlc_media_open_cb open_cb,
447                                            libvlc_media_read_cb read_cb,
448                                            libvlc_media_seek_cb seek_cb,
449                                            libvlc_media_close_cb close_cb,
450                                            void *opaque)
451 {
452     libvlc_media_t *m = libvlc_media_new_location(p_instance, "imem://");
453     if (unlikely(m == NULL))
454         return NULL;
455
456     assert(read_cb != NULL);
457     input_item_AddOpaque(m->p_input_item, "imem-data", opaque);
458     input_item_AddOpaque(m->p_input_item, "imem-open", open_cb);
459     input_item_AddOpaque(m->p_input_item, "imem-read", read_cb);
460     input_item_AddOpaque(m->p_input_item, "imem-seek", seek_cb);
461     input_item_AddOpaque(m->p_input_item, "imem-close", close_cb);
462     return m;
463 }
464
465 /**************************************************************************
466  * Create a new media descriptor object
467  **************************************************************************/
468 libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
469                                            const char * psz_name )
470 {
471     input_item_t * p_input_item;
472     libvlc_media_t * p_md;
473     libvlc_media_list_t * p_subitems;
474
475     p_input_item = input_item_New( "vlc://nop", psz_name );
476
477     if (!p_input_item)
478     {
479         libvlc_printerr( "Not enough memory" );
480         return NULL;
481     }
482
483     p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
484     input_item_Release( p_input_item );
485
486     p_subitems = media_get_subitems( p_md, true );
487     if( p_subitems == NULL) {
488         libvlc_media_release( p_md );
489         return NULL;
490     }
491
492     return p_md;
493 }
494
495 /**************************************************************************
496  * Add an option to the media descriptor,
497  * that will be used to determine how the media_player will read the
498  * media. This allow to use VLC advanced reading/streaming
499  * options in a per-media basis
500  *
501  * The options are detailled in vlc --long-help, for instance "--sout-all"
502  **************************************************************************/
503 void libvlc_media_add_option( libvlc_media_t * p_md,
504                               const char * psz_option )
505 {
506     libvlc_media_add_option_flag( p_md, psz_option,
507                           VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
508 }
509
510 /**************************************************************************
511  * Same as libvlc_media_add_option but with configurable flags.
512  **************************************************************************/
513 void libvlc_media_add_option_flag( libvlc_media_t * p_md,
514                                    const char * ppsz_option,
515                                    unsigned i_flags )
516 {
517     input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
518 }
519
520 /**************************************************************************
521  * Delete a media descriptor object
522  **************************************************************************/
523 void libvlc_media_release( libvlc_media_t *p_md )
524 {
525     if (!p_md)
526         return;
527
528     p_md->i_refcount--;
529
530     if( p_md->i_refcount > 0 )
531         return;
532
533     uninstall_input_item_observer( p_md );
534
535     /* Cancel asynchronous parsing (if any) */
536     libvlc_MetadataCancel( p_md->p_libvlc_instance->p_libvlc_int, p_md );
537
538     if( p_md->p_subitems )
539         libvlc_media_list_release( p_md->p_subitems );
540
541     vlc_gc_decref( p_md->p_input_item );
542
543     vlc_cond_destroy( &p_md->parsed_cond );
544     vlc_mutex_destroy( &p_md->parsed_lock );
545     vlc_mutex_destroy( &p_md->subitems_lock );
546
547     /* Construct the event */
548     libvlc_event_t event;
549     event.type = libvlc_MediaFreed;
550     event.u.media_freed.md = p_md;
551
552     /* Send the event */
553     libvlc_event_send( p_md->p_event_manager, &event );
554
555     libvlc_event_manager_release( p_md->p_event_manager );
556     libvlc_release( p_md->p_libvlc_instance );
557     free( p_md );
558 }
559
560 /**************************************************************************
561  * Retain a media descriptor object
562  **************************************************************************/
563 void libvlc_media_retain( libvlc_media_t *p_md )
564 {
565     assert (p_md);
566     p_md->i_refcount++;
567 }
568
569 /**************************************************************************
570  * Duplicate a media descriptor object
571  **************************************************************************/
572 libvlc_media_t *
573 libvlc_media_duplicate( libvlc_media_t *p_md_orig )
574 {
575     return libvlc_media_new_from_input_item(
576         p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
577 }
578
579 /**************************************************************************
580  * Get mrl from a media descriptor object
581  **************************************************************************/
582 char *
583 libvlc_media_get_mrl( libvlc_media_t * p_md )
584 {
585     assert( p_md );
586     return input_item_GetURI( p_md->p_input_item );
587 }
588
589 /**************************************************************************
590  * Getter for meta information
591  **************************************************************************/
592
593 char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
594 {
595     char *psz_meta = NULL;
596
597     if( e_meta == libvlc_meta_NowPlaying )
598     {
599         psz_meta = input_item_GetNowPlayingFb( p_md->p_input_item );
600     }
601     else
602     {
603         psz_meta = input_item_GetMeta( p_md->p_input_item,
604                                              libvlc_to_vlc_meta[e_meta] );
605         /* Should be integrated in core */
606         if( psz_meta == NULL && e_meta == libvlc_meta_Title
607          && p_md->p_input_item->psz_name != NULL )
608             psz_meta = strdup( p_md->p_input_item->psz_name );
609     }
610     return psz_meta;
611 }
612
613 /**************************************************************************
614  * Setter for meta information
615  **************************************************************************/
616
617 void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value )
618 {
619     assert( p_md );
620     input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value );
621 }
622
623 int libvlc_media_save_meta( libvlc_media_t *p_md )
624 {
625     assert( p_md );
626     vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
627     return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
628 }
629
630 /**************************************************************************
631  * Getter for state information
632  * Can be error, playing, buffering, NothingSpecial.
633  **************************************************************************/
634
635 libvlc_state_t
636 libvlc_media_get_state( libvlc_media_t *p_md )
637 {
638     assert( p_md );
639     return p_md->state;
640 }
641
642 /**************************************************************************
643  * Setter for state information (LibVLC Internal)
644  **************************************************************************/
645
646 void
647 libvlc_media_set_state( libvlc_media_t *p_md,
648                                    libvlc_state_t state )
649 {
650     libvlc_event_t event;
651
652     p_md->state = state;
653
654     /* Construct the event */
655     event.type = libvlc_MediaStateChanged;
656     event.u.media_state_changed.new_state = state;
657
658     /* Send the event */
659     libvlc_event_send( p_md->p_event_manager, &event );
660 }
661
662 /**************************************************************************
663  * subitems
664  **************************************************************************/
665 libvlc_media_list_t *
666 libvlc_media_subitems( libvlc_media_t * p_md )
667 {
668     libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true );
669     if( p_subitems )
670         libvlc_media_list_retain( p_subitems );
671     return p_subitems;
672 }
673
674 /**************************************************************************
675  * Getter for statistics information
676  **************************************************************************/
677 int libvlc_media_get_stats( libvlc_media_t *p_md,
678                             libvlc_media_stats_t *p_stats )
679 {
680     if( !p_md->p_input_item )
681         return false;
682
683     input_stats_t *p_itm_stats = p_md->p_input_item->p_stats;
684     vlc_mutex_lock( &p_itm_stats->lock );
685     p_stats->i_read_bytes = p_itm_stats->i_read_bytes;
686     p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate;
687
688     p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes;
689     p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate;
690     p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted;
691     p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity;
692
693     p_stats->i_decoded_video = p_itm_stats->i_decoded_video;
694     p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio;
695
696     p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures;
697     p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures;
698
699     p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers;
700     p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers;
701
702     p_stats->i_sent_packets = p_itm_stats->i_sent_packets;
703     p_stats->i_sent_bytes = p_itm_stats->i_sent_bytes;
704     p_stats->f_send_bitrate = p_itm_stats->f_send_bitrate;
705     vlc_mutex_unlock( &p_itm_stats->lock );
706     return true;
707 }
708
709 /**************************************************************************
710  * event_manager
711  **************************************************************************/
712 libvlc_event_manager_t *
713 libvlc_media_event_manager( libvlc_media_t * p_md )
714 {
715     assert( p_md );
716
717     return p_md->p_event_manager;
718 }
719
720 /**************************************************************************
721  * Get duration of media object (in ms)
722  **************************************************************************/
723 int64_t
724 libvlc_media_get_duration( libvlc_media_t * p_md )
725 {
726     assert( p_md );
727
728     if( !p_md->p_input_item )
729     {
730         libvlc_printerr( "No input item" );
731         return -1;
732     }
733
734     if (!input_item_IsPreparsed( p_md->p_input_item ))
735         return -1;
736
737     return from_mtime(input_item_GetDuration( p_md->p_input_item ));
738 }
739
740 static int media_parse(libvlc_media_t *media, bool b_async,
741                        libvlc_media_parse_flag_t parse_flag, int timeout)
742 {
743     bool needed;
744
745     vlc_mutex_lock(&media->parsed_lock);
746     needed = !media->has_asked_preparse;
747     media->has_asked_preparse = true;
748     if (needed)
749         media->is_parsed = false;
750     vlc_mutex_unlock(&media->parsed_lock);
751
752     if (needed)
753     {
754         libvlc_int_t *libvlc = media->p_libvlc_instance->p_libvlc_int;
755         input_item_t *item = media->p_input_item;
756         input_item_meta_request_option_t art_scope = META_REQUEST_OPTION_NONE;
757         input_item_meta_request_option_t parse_scope = META_REQUEST_OPTION_SCOPE_LOCAL;
758         int ret;
759
760         if (parse_flag & libvlc_media_fetch_local)
761             art_scope |= META_REQUEST_OPTION_SCOPE_LOCAL;
762         if (parse_flag & libvlc_media_fetch_network)
763             art_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
764         if (art_scope != META_REQUEST_OPTION_NONE) {
765             ret = libvlc_ArtRequest(libvlc, item, art_scope);
766             if (ret != VLC_SUCCESS)
767                 return ret;
768         }
769
770         if (parse_flag & libvlc_media_parse_network)
771             parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
772         if (parse_flag & libvlc_media_do_interact)
773             parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
774         ret = libvlc_MetadataRequest(libvlc, item, parse_scope, timeout, media);
775         if (ret != VLC_SUCCESS)
776             return ret;
777     }
778     else
779         return VLC_EGENERIC;
780
781     if (!b_async)
782     {
783         vlc_mutex_lock(&media->parsed_lock);
784         while (!media->is_parsed)
785             vlc_cond_wait(&media->parsed_cond, &media->parsed_lock);
786         vlc_mutex_unlock(&media->parsed_lock);
787     }
788     return VLC_SUCCESS;
789 }
790
791 /**************************************************************************
792  * Parse the media and wait.
793  **************************************************************************/
794 void
795 libvlc_media_parse(libvlc_media_t *media)
796 {
797     media_parse( media, false, libvlc_media_fetch_local, -1 );
798 }
799
800 /**************************************************************************
801  * Parse the media but do not wait.
802  **************************************************************************/
803 void
804 libvlc_media_parse_async(libvlc_media_t *media)
805 {
806     media_parse( media, true, libvlc_media_fetch_local, -1 );
807 }
808
809 /**************************************************************************
810  * Parse the media asynchronously with options.
811  **************************************************************************/
812 int
813 libvlc_media_parse_with_options( libvlc_media_t *media,
814                                  libvlc_media_parse_flag_t parse_flag,
815                                  int timeout )
816 {
817     return media_parse( media, true, parse_flag, timeout ) == VLC_SUCCESS ? 0 : -1;
818 }
819
820 void
821 libvlc_media_parse_stop( libvlc_media_t *media )
822 {
823     libvlc_MetadataCancel( media->p_libvlc_instance->p_libvlc_int, media );
824 }
825
826 /**************************************************************************
827  * Get parsed status for media object.
828  **************************************************************************/
829 int
830 libvlc_media_is_parsed(libvlc_media_t *media)
831 {
832     bool parsed;
833
834     vlc_mutex_lock(&media->parsed_lock);
835     parsed = media->is_parsed;
836     vlc_mutex_unlock(&media->parsed_lock);
837     return parsed;
838 }
839
840 libvlc_media_parsed_status_t
841 libvlc_media_get_parsed_status(libvlc_media_t *media)
842 {
843     libvlc_media_parsed_status_t status;
844
845     vlc_mutex_lock(&media->parsed_lock);
846     status = media->parsed_status;
847     vlc_mutex_unlock(&media->parsed_lock);
848     return status;
849 }
850
851 /**************************************************************************
852  * Sets media descriptor's user_data. user_data is specialized data
853  * accessed by the host application, VLC.framework uses it as a pointer to
854  * an native object that references a libvlc_media_t pointer
855  **************************************************************************/
856 void
857 libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
858 {
859     assert( p_md );
860     p_md->p_user_data = p_new_user_data;
861 }
862
863 /**************************************************************************
864  * Get media descriptor's user_data. user_data is specialized data
865  * accessed by the host application, VLC.framework uses it as a pointer to
866  * an native object that references a libvlc_media_t pointer
867  **************************************************************************/
868 void *
869 libvlc_media_get_user_data( libvlc_media_t * p_md )
870 {
871     assert( p_md );
872     return p_md->p_user_data;
873 }
874
875 /**************************************************************************
876  * Get media descriptor's elementary streams description
877  **************************************************************************/
878 int
879 libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
880 {
881     assert( p_md );
882
883     input_item_t *p_input_item = p_md->p_input_item;
884     vlc_mutex_lock( &p_input_item->lock );
885
886     const int i_es = p_input_item->i_es;
887     *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL;
888
889     if( !*pp_es ) /* no ES, or OOM */
890     {
891         vlc_mutex_unlock( &p_input_item->lock );
892         return 0;
893     }
894
895     /* Fill array */
896     for( int i = 0; i < i_es; i++ )
897     {
898         libvlc_media_track_info_t *p_mes = *pp_es+i;
899         const es_format_t *p_es = p_input_item->es[i];
900
901         p_mes->i_codec = p_es->i_codec;
902         p_mes->i_id = p_es->i_id;
903
904         p_mes->i_profile = p_es->i_profile;
905         p_mes->i_level = p_es->i_level;
906
907         switch(p_es->i_cat)
908         {
909         case UNKNOWN_ES:
910         default:
911             p_mes->i_type = libvlc_track_unknown;
912             break;
913         case VIDEO_ES:
914             p_mes->i_type = libvlc_track_video;
915             p_mes->u.video.i_height = p_es->video.i_visible_height;
916             p_mes->u.video.i_width = p_es->video.i_visible_width;
917             break;
918         case AUDIO_ES:
919             p_mes->i_type = libvlc_track_audio;
920             p_mes->u.audio.i_channels = p_es->audio.i_channels;
921             p_mes->u.audio.i_rate = p_es->audio.i_rate;
922             break;
923         case SPU_ES:
924             p_mes->i_type = libvlc_track_text;
925             break;
926         }
927     }
928
929     vlc_mutex_unlock( &p_input_item->lock );
930     return i_es;
931 }
932
933 unsigned
934 libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es )
935 {
936     assert( p_md );
937
938     input_item_t *p_input_item = p_md->p_input_item;
939     vlc_mutex_lock( &p_input_item->lock );
940
941     const int i_es = p_input_item->i_es;
942     *pp_es = (i_es > 0) ? calloc( i_es, sizeof(**pp_es) ) : NULL;
943
944     if( !*pp_es ) /* no ES, or OOM */
945     {
946         vlc_mutex_unlock( &p_input_item->lock );
947         return 0;
948     }
949
950     /* Fill array */
951     for( int i = 0; i < i_es; i++ )
952     {
953         libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) );
954         if ( p_mes )
955         {
956             p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio),
957                                                sizeof(*p_mes->video)),
958                                                sizeof(*p_mes->subtitle)) );
959         }
960         if ( !p_mes || !p_mes->audio )
961         {
962             libvlc_media_tracks_release( *pp_es, i_es );
963             *pp_es = NULL;
964             free( p_mes );
965             vlc_mutex_unlock( &p_input_item->lock );
966             return 0;
967         }
968         (*pp_es)[i] = p_mes;
969
970         const es_format_t *p_es = p_input_item->es[i];
971
972         p_mes->i_codec = p_es->i_codec;
973         p_mes->i_original_fourcc = p_es->i_original_fourcc;
974         p_mes->i_id = p_es->i_id;
975
976         p_mes->i_profile = p_es->i_profile;
977         p_mes->i_level = p_es->i_level;
978
979         p_mes->i_bitrate = p_es->i_bitrate;
980         p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL;
981         p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL;
982
983         switch(p_es->i_cat)
984         {
985         case UNKNOWN_ES:
986         default:
987             p_mes->i_type = libvlc_track_unknown;
988             break;
989         case VIDEO_ES:
990             p_mes->i_type = libvlc_track_video;
991             p_mes->video->i_height = p_es->video.i_visible_height;
992             p_mes->video->i_width = p_es->video.i_visible_width;
993             p_mes->video->i_sar_num = p_es->video.i_sar_num;
994             p_mes->video->i_sar_den = p_es->video.i_sar_den;
995             p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate;
996             p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base;
997             break;
998         case AUDIO_ES:
999             p_mes->i_type = libvlc_track_audio;
1000             p_mes->audio->i_channels = p_es->audio.i_channels;
1001             p_mes->audio->i_rate = p_es->audio.i_rate;
1002             break;
1003         case SPU_ES:
1004             p_mes->i_type = libvlc_track_text;
1005             p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ?
1006                                             strdup(p_es->subs.psz_encoding) : NULL;
1007             break;
1008         }
1009     }
1010
1011     vlc_mutex_unlock( &p_input_item->lock );
1012     return i_es;
1013 }
1014
1015 /**************************************************************************
1016  * Get codec description from media elementary stream
1017  **************************************************************************/
1018 const char *
1019 libvlc_media_get_codec_description( libvlc_track_type_t i_type,
1020                                     uint32_t i_codec )
1021 {
1022     switch( i_type )
1023     {
1024         case libvlc_track_audio:
1025             return vlc_fourcc_GetDescription( AUDIO_ES, i_codec );
1026         case libvlc_track_video:
1027             return vlc_fourcc_GetDescription( VIDEO_ES, i_codec );
1028         case libvlc_track_text:
1029             return vlc_fourcc_GetDescription( SPU_ES, i_codec );
1030         case libvlc_track_unknown:
1031         default:
1032             return vlc_fourcc_GetDescription( UNKNOWN_ES, i_codec );
1033     }
1034 }
1035
1036 /**************************************************************************
1037  * Release media descriptor's elementary streams description array
1038  **************************************************************************/
1039 void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
1040 {
1041     for( unsigned i = 0; i < i_count; ++i )
1042     {
1043         if ( !p_tracks[i] )
1044             continue;
1045         free( p_tracks[i]->psz_language );
1046         free( p_tracks[i]->psz_description );
1047         switch( p_tracks[i]->i_type )
1048         {
1049         case libvlc_track_audio:
1050             break;
1051         case libvlc_track_video:
1052             break;
1053         case libvlc_track_text:
1054             free( p_tracks[i]->subtitle->psz_encoding );
1055             break;
1056         case libvlc_track_unknown:
1057         default:
1058             break;
1059         }
1060         free( p_tracks[i]->audio );
1061         free( p_tracks[i] );
1062     }
1063     free( p_tracks );
1064 }
1065
1066 /**************************************************************************
1067  * Get the media type of the media descriptor object
1068  **************************************************************************/
1069 libvlc_media_type_t libvlc_media_get_type( libvlc_media_t *p_md )
1070 {
1071     assert( p_md );
1072
1073     int i_type;
1074     input_item_t *p_input_item = p_md->p_input_item;
1075
1076     vlc_mutex_lock( &p_input_item->lock );
1077     i_type = p_md->p_input_item->i_type;
1078     vlc_mutex_unlock( &p_input_item->lock );
1079
1080     switch( i_type )
1081     {
1082     case ITEM_TYPE_FILE:
1083         return libvlc_media_type_file;
1084     case ITEM_TYPE_NODE:
1085     case ITEM_TYPE_DIRECTORY:
1086         return libvlc_media_type_directory;
1087     case ITEM_TYPE_DISC:
1088         return libvlc_media_type_disc;
1089     case ITEM_TYPE_STREAM:
1090         return libvlc_media_type_stream;
1091     case ITEM_TYPE_PLAYLIST:
1092         return libvlc_media_type_playlist;
1093     default:
1094         return libvlc_media_type_unknown;
1095     }
1096 }
1097
1098 int libvlc_media_slaves_add( libvlc_media_t *p_md,
1099                              libvlc_media_slave_type_t i_type,
1100                              unsigned int i_priority,
1101                              const char *psz_uri )
1102 {
1103     assert( p_md && psz_uri );
1104     input_item_t *p_input_item = p_md->p_input_item;
1105
1106     enum slave_type i_input_slave_type;
1107     switch( i_type )
1108     {
1109     case libvlc_media_slave_type_subtitle:
1110         i_input_slave_type = SLAVE_TYPE_SPU;
1111         break;
1112     case libvlc_media_slave_type_audio:
1113         i_input_slave_type = SLAVE_TYPE_AUDIO;
1114         break;
1115     default:
1116         vlc_assert_unreachable();
1117         return -1;
1118     }
1119
1120     enum slave_priority i_input_slave_priority;
1121     switch( i_priority )
1122     {
1123     case 0:
1124         i_input_slave_priority = SLAVE_PRIORITY_MATCH_NONE;
1125         break;
1126     case 1:
1127         i_input_slave_priority = SLAVE_PRIORITY_MATCH_RIGHT;
1128         break;
1129     case 2:
1130         i_input_slave_priority = SLAVE_PRIORITY_MATCH_LEFT;
1131         break;
1132     case 3:
1133         i_input_slave_priority = SLAVE_PRIORITY_MATCH_ALL;
1134         break;
1135     default:
1136     case 4:
1137         i_input_slave_priority = SLAVE_PRIORITY_USER;
1138         break;
1139     }
1140
1141     input_item_slave_t *p_slave = input_item_slave_New( psz_uri,
1142                                                       i_input_slave_type,
1143                                                       i_input_slave_priority );
1144     if( p_slave == NULL )
1145         return -1;
1146     return input_item_AddSlave( p_input_item, p_slave ) == VLC_SUCCESS ? 0 : -1;
1147 }
1148
1149 void libvlc_media_slaves_clear( libvlc_media_t *p_md )
1150 {
1151     assert( p_md );
1152     input_item_t *p_input_item = p_md->p_input_item;
1153
1154     vlc_mutex_lock( &p_input_item->lock );
1155     for( int i = 0; i < p_input_item->i_slaves; i++ )
1156         input_item_slave_Delete( p_input_item->pp_slaves[i] );
1157     TAB_CLEAN( p_input_item->i_slaves, p_input_item->pp_slaves );
1158     vlc_mutex_unlock( &p_input_item->lock );
1159 }
1160
1161 unsigned int libvlc_media_slaves_get( libvlc_media_t *p_md,
1162                                       libvlc_media_slave_t ***ppp_slaves )
1163 {
1164     assert( p_md && ppp_slaves );
1165     input_item_t *p_input_item = p_md->p_input_item;
1166
1167     vlc_mutex_lock( &p_input_item->lock );
1168
1169     int i_count = p_input_item->i_slaves;
1170     if( i_count <= 0 )
1171         return vlc_mutex_unlock( &p_input_item->lock ), 0;
1172
1173     libvlc_media_slave_t **pp_slaves = calloc( i_count, sizeof(*pp_slaves) );
1174     if( pp_slaves == NULL )
1175         return vlc_mutex_unlock( &p_input_item->lock ), 0;
1176
1177     for( int i = 0; i < i_count; ++i )
1178     {
1179         input_item_slave_t *p_item_slave = p_input_item->pp_slaves[i];
1180         assert( p_item_slave->i_priority >= SLAVE_PRIORITY_MATCH_NONE );
1181
1182         /* also allocate psz_uri buffer at the end of the struct */
1183         libvlc_media_slave_t *p_slave = malloc( sizeof(*p_slave) +
1184                                                 strlen( p_item_slave->psz_uri )
1185                                                 + 1 );
1186         if( p_slave == NULL )
1187         {
1188             libvlc_media_slaves_release(pp_slaves, i);
1189             return vlc_mutex_unlock( &p_input_item->lock ), 0;
1190         }
1191         p_slave->psz_uri = (char *) ((uint8_t *)p_slave) + sizeof(*p_slave);
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     if( i_count > 0 )
1238     {
1239         assert( pp_slaves );
1240         for( unsigned int i = 0; i < i_count; ++i )
1241             free( pp_slaves[i] );
1242         free( pp_slaves );
1243     }
1244 }