]> git.sesse.net Git - vlc/blob - lib/media.c
input: Add support for DiscNumber meta
[vlc] / 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
47 static const vlc_meta_type_t libvlc_to_vlc_meta[] =
48 {
49     [libvlc_meta_Title]        = vlc_meta_Title,
50     [libvlc_meta_Artist]       = vlc_meta_Artist,
51     [libvlc_meta_Genre]        = vlc_meta_Genre,
52     [libvlc_meta_Copyright]    = vlc_meta_Copyright,
53     [libvlc_meta_Album]        = vlc_meta_Album,
54     [libvlc_meta_TrackNumber]  = vlc_meta_TrackNumber,
55     [libvlc_meta_Description]  = vlc_meta_Description,
56     [libvlc_meta_Rating]       = vlc_meta_Rating,
57     [libvlc_meta_Date]         = vlc_meta_Date,
58     [libvlc_meta_Setting]      = vlc_meta_Setting,
59     [libvlc_meta_URL]          = vlc_meta_URL,
60     [libvlc_meta_Language]     = vlc_meta_Language,
61     [libvlc_meta_NowPlaying]   = vlc_meta_NowPlaying,
62     [libvlc_meta_Publisher]    = vlc_meta_Publisher,
63     [libvlc_meta_EncodedBy]    = vlc_meta_EncodedBy,
64     [libvlc_meta_ArtworkURL]   = vlc_meta_ArtworkURL,
65     [libvlc_meta_TrackID]      = vlc_meta_TrackID,
66     [libvlc_meta_TrackTotal]   = vlc_meta_TrackTotal,
67     [libvlc_meta_Director]     = vlc_meta_Director,
68     [libvlc_meta_Season]       = vlc_meta_Season,
69     [libvlc_meta_Episode]      = vlc_meta_Episode,
70     [libvlc_meta_ShowName]     = vlc_meta_ShowName,
71     [libvlc_meta_Actors]       = vlc_meta_Actors,
72     [libvlc_meta_AlbumArtist]  = vlc_meta_AlbumArtist,
73     [libvlc_meta_DiscNumber]   = vlc_meta_DiscNumber
74 };
75
76 static const libvlc_meta_t vlc_to_libvlc_meta[] =
77 {
78     [vlc_meta_Title]        = libvlc_meta_Title,
79     [vlc_meta_Artist]       = libvlc_meta_Artist,
80     [vlc_meta_Genre]        = libvlc_meta_Genre,
81     [vlc_meta_Copyright]    = libvlc_meta_Copyright,
82     [vlc_meta_Album]        = libvlc_meta_Album,
83     [vlc_meta_TrackNumber]  = libvlc_meta_TrackNumber,
84     [vlc_meta_Description]  = libvlc_meta_Description,
85     [vlc_meta_Rating]       = libvlc_meta_Rating,
86     [vlc_meta_Date]         = libvlc_meta_Date,
87     [vlc_meta_Setting]      = libvlc_meta_Setting,
88     [vlc_meta_URL]          = libvlc_meta_URL,
89     [vlc_meta_Language]     = libvlc_meta_Language,
90     [vlc_meta_NowPlaying]   = libvlc_meta_NowPlaying,
91     [vlc_meta_Publisher]    = libvlc_meta_Publisher,
92     [vlc_meta_EncodedBy]    = libvlc_meta_EncodedBy,
93     [vlc_meta_ArtworkURL]   = libvlc_meta_ArtworkURL,
94     [vlc_meta_TrackID]      = libvlc_meta_TrackID,
95     [vlc_meta_TrackTotal]   = libvlc_meta_TrackTotal,
96     [vlc_meta_Director]     = libvlc_meta_Director,
97     [vlc_meta_Season]       = libvlc_meta_Season,
98     [vlc_meta_Episode]      = libvlc_meta_Episode,
99     [vlc_meta_ShowName]     = libvlc_meta_ShowName,
100     [vlc_meta_Actors]       = libvlc_meta_Actors,
101     [vlc_meta_AlbumArtist]  = libvlc_meta_AlbumArtist,
102     [vlc_meta_DiscNumber]   = libvlc_meta_DiscNumber
103 };
104
105 /**************************************************************************
106  * input_item_subitem_added (Private) (vlc event Callback)
107  **************************************************************************/
108 static void input_item_subitem_added( const vlc_event_t *p_event,
109                                        void * user_data )
110 {
111     libvlc_media_t * p_md = user_data;
112     libvlc_media_t * p_md_child;
113     libvlc_event_t event;
114
115     p_md_child = libvlc_media_new_from_input_item(
116                 p_md->p_libvlc_instance,
117                 p_event->u.input_item_subitem_added.p_new_child );
118
119     /* Add this to our media list */
120     if( p_md->p_subitems == NULL )
121     {
122         p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
123         if( unlikely(p_md->p_subitems == NULL) )
124             abort();
125         libvlc_media_list_set_media( p_md->p_subitems, p_md );
126     }
127     libvlc_media_list_add_media( p_md->p_subitems, p_md_child );
128
129     /* Construct the event */
130     event.type = libvlc_MediaSubItemAdded;
131     event.u.media_subitem_added.new_child = p_md_child;
132
133     /* Send the event */
134     libvlc_event_send( p_md->p_event_manager, &event );
135     libvlc_media_release( p_md_child );
136 }
137
138 /**************************************************************************
139  * input_item_subitemtree_added (Private) (vlc event Callback)
140  **************************************************************************/
141 static void input_item_subitemtree_added( const vlc_event_t * p_event,
142                                           void * user_data )
143 {
144     VLC_UNUSED( p_event );
145     libvlc_media_t * p_md = user_data;
146     libvlc_event_t event;
147
148     /* Construct the event */
149     event.type = libvlc_MediaSubItemTreeAdded;
150     event.u.media_subitemtree_added.item = p_md;
151
152     /* Send the event */
153     libvlc_event_send( p_md->p_event_manager, &event );
154 }
155
156 /**************************************************************************
157  * input_item_meta_changed (Private) (vlc event Callback)
158  **************************************************************************/
159 static void input_item_meta_changed( const vlc_event_t *p_event,
160                                      void * user_data )
161 {
162     libvlc_media_t * p_md = user_data;
163     libvlc_event_t event;
164
165     /* Construct the event */
166     event.type = libvlc_MediaMetaChanged;
167     event.u.media_meta_changed.meta_type =
168         vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];
169
170     /* Send the event */
171     libvlc_event_send( p_md->p_event_manager, &event );
172 }
173
174 /**************************************************************************
175  * input_item_duration_changed (Private) (vlc event Callback)
176  **************************************************************************/
177 static void input_item_duration_changed( const vlc_event_t *p_event,
178                                          void * user_data )
179 {
180     libvlc_media_t * p_md = user_data;
181     libvlc_event_t event;
182
183     /* Construct the event */
184     event.type = libvlc_MediaDurationChanged;
185     event.u.media_duration_changed.new_duration =
186         from_mtime(p_event->u.input_item_duration_changed.new_duration);
187
188     /* Send the event */
189     libvlc_event_send( p_md->p_event_manager, &event );
190 }
191
192 /**************************************************************************
193  * input_item_preparsed_changed (Private) (vlc event Callback)
194  **************************************************************************/
195 static void input_item_preparsed_changed(const vlc_event_t *p_event,
196                                          void * user_data)
197 {
198     libvlc_media_t *media = user_data;
199     libvlc_event_t event;
200
201     /* Eventually notify libvlc_media_parse() */
202     vlc_mutex_lock(&media->parsed_lock);
203     media->is_parsed = true;
204     vlc_cond_broadcast(&media->parsed_cond);
205     vlc_mutex_unlock(&media->parsed_lock);
206
207
208     /* Construct the event */
209     event.type = libvlc_MediaParsedChanged;
210     event.u.media_parsed_changed.new_status =
211         p_event->u.input_item_preparsed_changed.new_status;
212
213     /* Send the event */
214     libvlc_event_send(media->p_event_manager, &event);
215 }
216
217 /**************************************************************************
218  * Install event handler (Private)
219  **************************************************************************/
220 static void install_input_item_observer( libvlc_media_t *p_md )
221 {
222     vlc_event_attach( &p_md->p_input_item->event_manager,
223                       vlc_InputItemSubItemAdded,
224                       input_item_subitem_added,
225                       p_md );
226     vlc_event_attach( &p_md->p_input_item->event_manager,
227                       vlc_InputItemMetaChanged,
228                       input_item_meta_changed,
229                       p_md );
230     vlc_event_attach( &p_md->p_input_item->event_manager,
231                       vlc_InputItemDurationChanged,
232                       input_item_duration_changed,
233                       p_md );
234     vlc_event_attach( &p_md->p_input_item->event_manager,
235                       vlc_InputItemPreparsedChanged,
236                       input_item_preparsed_changed,
237                       p_md );
238     vlc_event_attach( &p_md->p_input_item->event_manager,
239                       vlc_InputItemSubItemTreeAdded,
240                       input_item_subitemtree_added,
241                       p_md );
242 }
243
244 /**************************************************************************
245  * Uninstall event handler (Private)
246  **************************************************************************/
247 static void uninstall_input_item_observer( libvlc_media_t *p_md )
248 {
249     vlc_event_detach( &p_md->p_input_item->event_manager,
250                       vlc_InputItemSubItemAdded,
251                       input_item_subitem_added,
252                       p_md );
253     vlc_event_detach( &p_md->p_input_item->event_manager,
254                       vlc_InputItemMetaChanged,
255                       input_item_meta_changed,
256                       p_md );
257     vlc_event_detach( &p_md->p_input_item->event_manager,
258                       vlc_InputItemDurationChanged,
259                       input_item_duration_changed,
260                       p_md );
261     vlc_event_detach( &p_md->p_input_item->event_manager,
262                       vlc_InputItemPreparsedChanged,
263                       input_item_preparsed_changed,
264                       p_md );
265     vlc_event_detach( &p_md->p_input_item->event_manager,
266                       vlc_InputItemSubItemTreeAdded,
267                       input_item_subitemtree_added,
268                       p_md );
269 }
270
271 /**************************************************************************
272  * Create a new media descriptor object from an input_item
273  * (libvlc internal)
274  * That's the generic constructor
275  **************************************************************************/
276 libvlc_media_t * libvlc_media_new_from_input_item(
277                                    libvlc_instance_t *p_instance,
278                                    input_item_t *p_input_item )
279 {
280     libvlc_media_t * p_md;
281
282     if (!p_input_item)
283     {
284         libvlc_printerr( "No input item given" );
285         return NULL;
286     }
287
288     p_md = calloc( 1, sizeof(libvlc_media_t) );
289     if( !p_md )
290     {
291         libvlc_printerr( "Not enough memory" );
292         return NULL;
293     }
294
295     p_md->p_libvlc_instance = p_instance;
296     p_md->p_input_item      = p_input_item;
297     p_md->i_refcount        = 1;
298
299     vlc_cond_init(&p_md->parsed_cond);
300     vlc_mutex_init(&p_md->parsed_lock);
301
302     p_md->state = libvlc_NothingSpecial;
303
304     /* A media descriptor can be a playlist. When you open a playlist
305      * It can give a bunch of item to read. */
306     p_md->p_subitems        = NULL;
307
308     p_md->p_event_manager = libvlc_event_manager_new( p_md, p_instance );
309     if( unlikely(p_md->p_event_manager == NULL) )
310     {
311         free(p_md);
312         return NULL;
313     }
314
315     libvlc_event_manager_t *em = p_md->p_event_manager;
316     libvlc_event_manager_register_event_type(em, libvlc_MediaMetaChanged);
317     libvlc_event_manager_register_event_type(em, libvlc_MediaSubItemAdded);
318     libvlc_event_manager_register_event_type(em, libvlc_MediaFreed);
319     libvlc_event_manager_register_event_type(em, libvlc_MediaDurationChanged);
320     libvlc_event_manager_register_event_type(em, libvlc_MediaStateChanged);
321     libvlc_event_manager_register_event_type(em, libvlc_MediaParsedChanged);
322     libvlc_event_manager_register_event_type(em, libvlc_MediaSubItemTreeAdded);
323
324     vlc_gc_incref( p_md->p_input_item );
325
326     install_input_item_observer( p_md );
327
328     return p_md;
329 }
330
331 /**************************************************************************
332  * Create a new media descriptor object
333  **************************************************************************/
334 libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
335                                            const char * psz_mrl )
336 {
337     input_item_t * p_input_item;
338     libvlc_media_t * p_md;
339
340     p_input_item = input_item_New( psz_mrl, NULL );
341
342     if (!p_input_item)
343     {
344         libvlc_printerr( "Not enough memory" );
345         return NULL;
346     }
347
348     p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
349
350     /* The p_input_item is retained in libvlc_media_new_from_input_item */
351     vlc_gc_decref( p_input_item );
352
353     return p_md;
354 }
355
356 libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
357                                        const char *path )
358 {
359     char *mrl = vlc_path2uri( path, NULL );
360     if( unlikely(mrl == NULL) )
361     {
362         libvlc_printerr( "%s", vlc_strerror_c(errno) );
363         return NULL;
364     }
365
366     libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl );
367     free( mrl );
368     return m;
369 }
370
371 libvlc_media_t *libvlc_media_new_fd( libvlc_instance_t *p_instance, int fd )
372 {
373     char mrl[16];
374     snprintf( mrl, sizeof(mrl), "fd://%d", fd );
375
376     return libvlc_media_new_location( p_instance, mrl );
377 }
378
379 /**************************************************************************
380  * Create a new media descriptor object
381  **************************************************************************/
382 libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
383                                            const char * psz_name )
384 {
385     input_item_t * p_input_item;
386     libvlc_media_t * p_md;
387
388     p_input_item = input_item_New( "vlc://nop", psz_name );
389
390     if (!p_input_item)
391     {
392         libvlc_printerr( "Not enough memory" );
393         return NULL;
394     }
395
396     p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
397
398     p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
399
400     return p_md;
401 }
402
403 /**************************************************************************
404  * Add an option to the media descriptor,
405  * that will be used to determine how the media_player will read the
406  * media. This allow to use VLC advanced reading/streaming
407  * options in a per-media basis
408  *
409  * The options are detailled in vlc --long-help, for instance "--sout-all"
410  **************************************************************************/
411 void libvlc_media_add_option( libvlc_media_t * p_md,
412                               const char * psz_option )
413 {
414     libvlc_media_add_option_flag( p_md, psz_option,
415                           VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
416 }
417
418 /**************************************************************************
419  * Same as libvlc_media_add_option but with configurable flags.
420  **************************************************************************/
421 void libvlc_media_add_option_flag( libvlc_media_t * p_md,
422                                    const char * ppsz_option,
423                                    unsigned i_flags )
424 {
425     input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
426 }
427
428 /**************************************************************************
429  * Delete a media descriptor object
430  **************************************************************************/
431 void libvlc_media_release( libvlc_media_t *p_md )
432 {
433     if (!p_md)
434         return;
435
436     p_md->i_refcount--;
437
438     if( p_md->i_refcount > 0 )
439         return;
440
441     if( p_md->p_subitems )
442         libvlc_media_list_release( p_md->p_subitems );
443
444     uninstall_input_item_observer( p_md );
445     vlc_gc_decref( p_md->p_input_item );
446
447     vlc_cond_destroy( &p_md->parsed_cond );
448     vlc_mutex_destroy( &p_md->parsed_lock );
449
450     /* Construct the event */
451     libvlc_event_t event;
452     event.type = libvlc_MediaFreed;
453     event.u.media_freed.md = p_md;
454
455     /* Send the event */
456     libvlc_event_send( p_md->p_event_manager, &event );
457
458     libvlc_event_manager_release( p_md->p_event_manager );
459
460     free( p_md );
461 }
462
463 /**************************************************************************
464  * Retain a media descriptor object
465  **************************************************************************/
466 void libvlc_media_retain( libvlc_media_t *p_md )
467 {
468     assert (p_md);
469     p_md->i_refcount++;
470 }
471
472 /**************************************************************************
473  * Duplicate a media descriptor object
474  **************************************************************************/
475 libvlc_media_t *
476 libvlc_media_duplicate( libvlc_media_t *p_md_orig )
477 {
478     return libvlc_media_new_from_input_item(
479         p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
480 }
481
482 /**************************************************************************
483  * Get mrl from a media descriptor object
484  **************************************************************************/
485 char *
486 libvlc_media_get_mrl( libvlc_media_t * p_md )
487 {
488     assert( p_md );
489     return input_item_GetURI( p_md->p_input_item );
490 }
491
492 /**************************************************************************
493  * Getter for meta information
494  **************************************************************************/
495
496 char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
497 {
498     char *psz_meta = input_item_GetMeta( p_md->p_input_item,
499                                          libvlc_to_vlc_meta[e_meta] );
500     /* Should be integrated in core */
501     if( psz_meta == NULL && e_meta == libvlc_meta_Title
502      && p_md->p_input_item->psz_name != NULL )
503         psz_meta = strdup( p_md->p_input_item->psz_name );
504
505     return psz_meta;
506 }
507
508 /**************************************************************************
509  * Setter for meta information
510  **************************************************************************/
511
512 void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value )
513 {
514     assert( p_md );
515     input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value );
516 }
517
518 int libvlc_media_save_meta( libvlc_media_t *p_md )
519 {
520     assert( p_md );
521     vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
522     return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
523 }
524
525 /**************************************************************************
526  * Getter for state information
527  * Can be error, playing, buffering, NothingSpecial.
528  **************************************************************************/
529
530 libvlc_state_t
531 libvlc_media_get_state( libvlc_media_t *p_md )
532 {
533     assert( p_md );
534     return p_md->state;
535 }
536
537 /**************************************************************************
538  * Setter for state information (LibVLC Internal)
539  **************************************************************************/
540
541 void
542 libvlc_media_set_state( libvlc_media_t *p_md,
543                                    libvlc_state_t state )
544 {
545     libvlc_event_t event;
546
547     p_md->state = state;
548
549     /* Construct the event */
550     event.type = libvlc_MediaStateChanged;
551     event.u.media_state_changed.new_state = state;
552
553     /* Send the event */
554     libvlc_event_send( p_md->p_event_manager, &event );
555 }
556
557 /**************************************************************************
558  * subitems
559  **************************************************************************/
560 libvlc_media_list_t *
561 libvlc_media_subitems( libvlc_media_t * p_md )
562 {
563     if( p_md->p_subitems )
564         libvlc_media_list_retain( p_md->p_subitems );
565     return p_md->p_subitems;
566 }
567
568 /**************************************************************************
569  * Getter for statistics information
570  **************************************************************************/
571 int libvlc_media_get_stats( libvlc_media_t *p_md,
572                             libvlc_media_stats_t *p_stats )
573 {
574     if( !p_md->p_input_item )
575         return false;
576
577     input_stats_t *p_itm_stats = p_md->p_input_item->p_stats;
578     vlc_mutex_lock( &p_itm_stats->lock );
579     p_stats->i_read_bytes = p_itm_stats->i_read_bytes;
580     p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate;
581
582     p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes;
583     p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate;
584     p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted;
585     p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity;
586
587     p_stats->i_decoded_video = p_itm_stats->i_decoded_video;
588     p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio;
589
590     p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures;
591     p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures;
592
593     p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers;
594     p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers;
595
596     p_stats->i_sent_packets = p_itm_stats->i_sent_packets;
597     p_stats->i_sent_bytes = p_itm_stats->i_sent_bytes;
598     p_stats->f_send_bitrate = p_itm_stats->f_send_bitrate;
599     vlc_mutex_unlock( &p_itm_stats->lock );
600     return true;
601 }
602
603 /**************************************************************************
604  * event_manager
605  **************************************************************************/
606 libvlc_event_manager_t *
607 libvlc_media_event_manager( libvlc_media_t * p_md )
608 {
609     assert( p_md );
610
611     return p_md->p_event_manager;
612 }
613
614 /**************************************************************************
615  * Get duration of media object (in ms)
616  **************************************************************************/
617 int64_t
618 libvlc_media_get_duration( libvlc_media_t * p_md )
619 {
620     assert( p_md );
621
622     if( !p_md->p_input_item )
623     {
624         libvlc_printerr( "No input item" );
625         return -1;
626     }
627
628     if (!input_item_IsPreparsed( p_md->p_input_item ))
629         return -1;
630
631     return from_mtime(input_item_GetDuration( p_md->p_input_item ));
632 }
633
634 static int media_parse(libvlc_media_t *media)
635 {
636     libvlc_int_t *libvlc = media->p_libvlc_instance->p_libvlc_int;
637     input_item_t *item = media->p_input_item;
638
639     /* TODO: Fetch art on need basis. But how not to break compatibility? */
640     libvlc_ArtRequest(libvlc, item, META_REQUEST_OPTION_NONE);
641     return libvlc_MetaRequest(libvlc, item, META_REQUEST_OPTION_NONE);
642 }
643
644 /**************************************************************************
645  * Parse the media and wait.
646  **************************************************************************/
647 void
648 libvlc_media_parse(libvlc_media_t *media)
649 {
650     vlc_mutex_lock(&media->parsed_lock);
651     if (!media->has_asked_preparse)
652     {
653         media->has_asked_preparse = true;
654         vlc_mutex_unlock(&media->parsed_lock);
655
656         if (media_parse(media))
657             /* Parse failed: do not wait! */
658             return;
659         vlc_mutex_lock(&media->parsed_lock);
660     }
661
662     while (!media->is_parsed)
663         vlc_cond_wait(&media->parsed_cond, &media->parsed_lock);
664     vlc_mutex_unlock(&media->parsed_lock);
665 }
666
667 /**************************************************************************
668  * Parse the media but do not wait.
669  **************************************************************************/
670 void
671 libvlc_media_parse_async(libvlc_media_t *media)
672 {
673     bool needed;
674
675     vlc_mutex_lock(&media->parsed_lock);
676     needed = !media->has_asked_preparse;
677     media->has_asked_preparse = true;
678     vlc_mutex_unlock(&media->parsed_lock);
679
680     if (needed)
681         media_parse(media);
682 }
683
684 /**************************************************************************
685  * Get parsed status for media object.
686  **************************************************************************/
687 int
688 libvlc_media_is_parsed(libvlc_media_t *media)
689 {
690     bool parsed;
691
692     vlc_mutex_lock(&media->parsed_lock);
693     parsed = media->is_parsed;
694     vlc_mutex_unlock(&media->parsed_lock);
695     return parsed;
696 }
697
698 /**************************************************************************
699  * Sets media descriptor's user_data. user_data is specialized data
700  * accessed by the host application, VLC.framework uses it as a pointer to
701  * an native object that references a libvlc_media_t pointer
702  **************************************************************************/
703 void
704 libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
705 {
706     assert( p_md );
707     p_md->p_user_data = p_new_user_data;
708 }
709
710 /**************************************************************************
711  * Get media descriptor's user_data. user_data is specialized data
712  * accessed by the host application, VLC.framework uses it as a pointer to
713  * an native object that references a libvlc_media_t pointer
714  **************************************************************************/
715 void *
716 libvlc_media_get_user_data( libvlc_media_t * p_md )
717 {
718     assert( p_md );
719     return p_md->p_user_data;
720 }
721
722 /**************************************************************************
723  * Get media descriptor's elementary streams description
724  **************************************************************************/
725 int
726 libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
727 {
728     assert( p_md );
729
730     input_item_t *p_input_item = p_md->p_input_item;
731     vlc_mutex_lock( &p_input_item->lock );
732
733     const int i_es = p_input_item->i_es;
734     *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL;
735
736     if( !*pp_es ) /* no ES, or OOM */
737     {
738         vlc_mutex_unlock( &p_input_item->lock );
739         return 0;
740     }
741
742     /* Fill array */
743     for( int i = 0; i < i_es; i++ )
744     {
745         libvlc_media_track_info_t *p_mes = *pp_es+i;
746         const es_format_t *p_es = p_input_item->es[i];
747
748         p_mes->i_codec = p_es->i_codec;
749         p_mes->i_id = p_es->i_id;
750
751         p_mes->i_profile = p_es->i_profile;
752         p_mes->i_level = p_es->i_level;
753
754         switch(p_es->i_cat)
755         {
756         case UNKNOWN_ES:
757         default:
758             p_mes->i_type = libvlc_track_unknown;
759             break;
760         case VIDEO_ES:
761             p_mes->i_type = libvlc_track_video;
762             p_mes->u.video.i_height = p_es->video.i_height;
763             p_mes->u.video.i_width = p_es->video.i_width;
764             break;
765         case AUDIO_ES:
766             p_mes->i_type = libvlc_track_audio;
767             p_mes->u.audio.i_channels = p_es->audio.i_channels;
768             p_mes->u.audio.i_rate = p_es->audio.i_rate;
769             break;
770         case SPU_ES:
771             p_mes->i_type = libvlc_track_text;
772             break;
773         }
774     }
775
776     vlc_mutex_unlock( &p_input_item->lock );
777     return i_es;
778 }
779
780 unsigned
781 libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es )
782 {
783     assert( p_md );
784
785     input_item_t *p_input_item = p_md->p_input_item;
786     vlc_mutex_lock( &p_input_item->lock );
787
788     const int i_es = p_input_item->i_es;
789     *pp_es = (i_es > 0) ? calloc( i_es, sizeof(**pp_es) ) : NULL;
790
791     if( !*pp_es ) /* no ES, or OOM */
792     {
793         vlc_mutex_unlock( &p_input_item->lock );
794         return 0;
795     }
796
797     /* Fill array */
798     for( int i = 0; i < i_es; i++ )
799     {
800         libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) );
801         if ( p_mes )
802         {
803             p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio),
804                                                sizeof(*p_mes->video)),
805                                                sizeof(*p_mes->subtitle)) );
806         }
807         if ( !p_mes || !p_mes->audio )
808         {
809             libvlc_media_tracks_release( *pp_es, i_es );
810             *pp_es = NULL;
811             free( p_mes );
812             vlc_mutex_unlock( &p_input_item->lock );
813             return 0;
814         }
815         (*pp_es)[i] = p_mes;
816
817         const es_format_t *p_es = p_input_item->es[i];
818
819         p_mes->i_codec = p_es->i_codec;
820         p_mes->i_original_fourcc = p_es->i_original_fourcc;
821         p_mes->i_id = p_es->i_id;
822
823         p_mes->i_profile = p_es->i_profile;
824         p_mes->i_level = p_es->i_level;
825
826         p_mes->i_bitrate = p_es->i_bitrate;
827         p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL;
828         p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL;
829
830         switch(p_es->i_cat)
831         {
832         case UNKNOWN_ES:
833         default:
834             p_mes->i_type = libvlc_track_unknown;
835             break;
836         case VIDEO_ES:
837             p_mes->i_type = libvlc_track_video;
838             p_mes->video->i_height = p_es->video.i_height;
839             p_mes->video->i_width = p_es->video.i_width;
840             p_mes->video->i_sar_num = p_es->video.i_sar_num;
841             p_mes->video->i_sar_den = p_es->video.i_sar_den;
842             p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate;
843             p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base;
844             break;
845         case AUDIO_ES:
846             p_mes->i_type = libvlc_track_audio;
847             p_mes->audio->i_channels = p_es->audio.i_channels;
848             p_mes->audio->i_rate = p_es->audio.i_rate;
849             break;
850         case SPU_ES:
851             p_mes->i_type = libvlc_track_text;
852             p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ?
853                                             strdup(p_es->subs.psz_encoding) : NULL;
854             break;
855         }
856     }
857
858     vlc_mutex_unlock( &p_input_item->lock );
859     return i_es;
860 }
861
862
863 /**************************************************************************
864  * Release media descriptor's elementary streams description array
865  **************************************************************************/
866 void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
867 {
868     for( unsigned i = 0; i < i_count; ++i )
869     {
870         if ( !p_tracks[i] )
871             continue;
872         free( p_tracks[i]->psz_language );
873         free( p_tracks[i]->psz_description );
874         switch( p_tracks[i]->i_type )
875         {
876         case libvlc_track_audio:
877             break;
878         case libvlc_track_video:
879             break;
880         case libvlc_track_text:
881             free( p_tracks[i]->subtitle->psz_encoding );
882             break;
883         case libvlc_track_unknown:
884         default:
885             break;
886         }
887         free( p_tracks[i]->audio );
888         free( p_tracks[i] );
889     }
890     free( p_tracks );
891 }