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