modules: remove empty curly braces initialization
[vlc.git] / lib / media.c
blob2b32f9d337a918462f620d7fb76f58882e41274a
1 /*****************************************************************************
2 * media.c: Libvlc API media descripor management
3 *****************************************************************************
4 * Copyright (C) 2007 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
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.
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.
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 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <assert.h>
29 #include <errno.h>
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>
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>
42 #include "../src/libvlc.h"
44 #include "libvlc_internal.h"
45 #include "media_internal.h"
46 #include "media_list_internal.h"
48 static const vlc_meta_type_t libvlc_to_vlc_meta[] =
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
78 static const libvlc_meta_t vlc_to_libvlc_meta[] =
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
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" );
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" );
126 static_assert(
127 MULTIVIEW_2D == (int) libvlc_video_multiview_2d &&
128 MULTIVIEW_STEREO_SBS == (int) libvlc_video_multiview_stereo_sbs &&
129 MULTIVIEW_STEREO_TB == (int) libvlc_video_multiview_stereo_tb &&
130 MULTIVIEW_STEREO_ROW == (int) libvlc_video_multiview_stereo_row &&
131 MULTIVIEW_STEREO_COL == (int) libvlc_video_multiview_stereo_col &&
132 MULTIVIEW_STEREO_FRAME == (int) libvlc_video_multiview_stereo_frame &&
133 MULTIVIEW_STEREO_CHECKERBOARD == (int) libvlc_video_multiview_stereo_checkerboard,
134 "Mismatch between libvlc_video_multiview_t and video_multiview_mode_t");
136 static libvlc_media_list_t *media_get_subitems( libvlc_media_t * p_md,
137 bool b_create )
139 libvlc_media_list_t *p_subitems = NULL;
141 vlc_mutex_lock( &p_md->subitems_lock );
142 if( p_md->p_subitems == NULL && b_create )
144 p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
145 if( p_md->p_subitems != NULL )
147 p_md->p_subitems->b_read_only = true;
148 p_md->p_subitems->p_internal_md = p_md;
151 p_subitems = p_md->p_subitems;
152 vlc_mutex_unlock( &p_md->subitems_lock );
153 return p_subitems;
156 static libvlc_media_t *input_item_add_subitem( libvlc_media_t *p_md,
157 input_item_t *item )
159 libvlc_media_t * p_md_child;
160 libvlc_media_list_t *p_subitems;
161 libvlc_event_t event;
163 p_md_child = libvlc_media_new_from_input_item( p_md->p_libvlc_instance,
164 item );
166 /* Add this to our media list */
167 p_subitems = media_get_subitems( p_md, true );
168 if( p_subitems != NULL )
170 libvlc_media_list_lock( p_subitems );
171 libvlc_media_list_internal_add_media( p_subitems, p_md_child );
172 libvlc_media_list_unlock( p_subitems );
175 /* Construct the event */
176 event.type = libvlc_MediaSubItemAdded;
177 event.u.media_subitem_added.new_child = p_md_child;
179 /* Send the event */
180 libvlc_event_send( &p_md->event_manager, &event );
181 return p_md_child;
184 static void input_item_add_subnode( libvlc_media_t *md,
185 input_item_node_t *node )
187 for( int i = 0; i < node->i_children; i++ )
189 input_item_node_t *child = node->pp_children[i];
190 libvlc_media_t *md_child = input_item_add_subitem( md, child->p_item );
192 if( md_child != NULL )
194 input_item_add_subnode( md_child, child );
195 libvlc_media_release( md_child );
200 /**************************************************************************
201 * input_item_subitemtree_added (Private) (vlc event Callback)
202 **************************************************************************/
203 static void input_item_subitemtree_added( const vlc_event_t * p_event,
204 void * user_data )
206 libvlc_media_t * p_md = user_data;
207 libvlc_event_t event;
208 input_item_node_t *node = p_event->u.input_item_subitem_tree_added.p_root;
210 /* FIXME FIXME FIXME
211 * Recursive function calls seem much simpler for this. But playlists are
212 * untrusted and can be arbitrarily deep (e.g. with XSPF). So recursion can
213 * potentially lead to plain old stack overflow. */
214 input_item_add_subnode( p_md, node );
216 /* Construct the event */
217 event.type = libvlc_MediaSubItemTreeAdded;
218 event.u.media_subitemtree_added.item = p_md;
220 /* Send the event */
221 libvlc_event_send( &p_md->event_manager, &event );
224 /**************************************************************************
225 * input_item_meta_changed (Private) (vlc event Callback)
226 **************************************************************************/
227 static void input_item_meta_changed( const vlc_event_t *p_event,
228 void * user_data )
230 libvlc_media_t * p_md = user_data;
231 libvlc_event_t event;
233 /* Construct the event */
234 event.type = libvlc_MediaMetaChanged;
235 event.u.media_meta_changed.meta_type =
236 vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];
238 /* Send the event */
239 libvlc_event_send( &p_md->event_manager, &event );
242 /**************************************************************************
243 * input_item_duration_changed (Private) (vlc event Callback)
244 **************************************************************************/
245 static void input_item_duration_changed( const vlc_event_t *p_event,
246 void * user_data )
248 libvlc_media_t * p_md = user_data;
249 libvlc_event_t event;
251 /* Construct the event */
252 event.type = libvlc_MediaDurationChanged;
253 event.u.media_duration_changed.new_duration =
254 from_mtime(p_event->u.input_item_duration_changed.new_duration);
256 /* Send the event */
257 libvlc_event_send( &p_md->event_manager, &event );
260 static void send_parsed_changed( libvlc_media_t *p_md,
261 libvlc_media_parsed_status_t new_status )
263 libvlc_event_t event;
265 vlc_mutex_lock( &p_md->parsed_lock );
266 if( p_md->parsed_status == new_status )
268 vlc_mutex_unlock( &p_md->parsed_lock );
269 return;
272 /* Legacy: notify libvlc_media_parse */
273 if( !p_md->is_parsed )
275 p_md->is_parsed = true;
276 vlc_cond_broadcast( &p_md->parsed_cond );
279 p_md->parsed_status = new_status;
280 if( p_md->parsed_status == libvlc_media_parsed_status_skipped )
281 p_md->has_asked_preparse = false;
283 vlc_mutex_unlock( &p_md->parsed_lock );
285 if( new_status == libvlc_media_parsed_status_done )
287 libvlc_media_list_t *p_subitems = media_get_subitems( p_md, false );
288 if( p_subitems != NULL )
290 /* notify the media list */
291 libvlc_media_list_lock( p_subitems );
292 libvlc_media_list_internal_end_reached( p_subitems );
293 libvlc_media_list_unlock( p_subitems );
297 /* Construct the event */
298 event.type = libvlc_MediaParsedChanged;
299 event.u.media_parsed_changed.new_status = new_status;
301 /* Send the event */
302 libvlc_event_send( &p_md->event_manager, &event );
305 /**************************************************************************
306 * input_item_preparse_ended (Private) (vlc event Callback)
307 **************************************************************************/
308 static void input_item_preparse_ended( const vlc_event_t * p_event,
309 void * user_data )
311 libvlc_media_t * p_md = user_data;
312 libvlc_media_parsed_status_t new_status;
314 switch( p_event->u.input_item_preparse_ended.new_status )
316 case ITEM_PREPARSE_SKIPPED:
317 new_status = libvlc_media_parsed_status_skipped;
318 break;
319 case ITEM_PREPARSE_FAILED:
320 new_status = libvlc_media_parsed_status_failed;
321 break;
322 case ITEM_PREPARSE_TIMEOUT:
323 new_status = libvlc_media_parsed_status_timeout;
324 break;
325 case ITEM_PREPARSE_DONE:
326 new_status = libvlc_media_parsed_status_done;
327 break;
328 default:
329 return;
331 send_parsed_changed( p_md, new_status );
334 /**************************************************************************
335 * Install event handler (Private)
336 **************************************************************************/
337 static void install_input_item_observer( libvlc_media_t *p_md )
339 vlc_event_attach( &p_md->p_input_item->event_manager,
340 vlc_InputItemMetaChanged,
341 input_item_meta_changed,
342 p_md );
343 vlc_event_attach( &p_md->p_input_item->event_manager,
344 vlc_InputItemDurationChanged,
345 input_item_duration_changed,
346 p_md );
347 vlc_event_attach( &p_md->p_input_item->event_manager,
348 vlc_InputItemSubItemTreeAdded,
349 input_item_subitemtree_added,
350 p_md );
351 vlc_event_attach( &p_md->p_input_item->event_manager,
352 vlc_InputItemPreparseEnded,
353 input_item_preparse_ended,
354 p_md );
357 /**************************************************************************
358 * Uninstall event handler (Private)
359 **************************************************************************/
360 static void uninstall_input_item_observer( libvlc_media_t *p_md )
362 vlc_event_detach( &p_md->p_input_item->event_manager,
363 vlc_InputItemMetaChanged,
364 input_item_meta_changed,
365 p_md );
366 vlc_event_detach( &p_md->p_input_item->event_manager,
367 vlc_InputItemDurationChanged,
368 input_item_duration_changed,
369 p_md );
370 vlc_event_detach( &p_md->p_input_item->event_manager,
371 vlc_InputItemSubItemTreeAdded,
372 input_item_subitemtree_added,
373 p_md );
374 vlc_event_detach( &p_md->p_input_item->event_manager,
375 vlc_InputItemPreparseEnded,
376 input_item_preparse_ended,
377 p_md );
380 /**************************************************************************
381 * Create a new media descriptor object from an input_item
382 * (libvlc internal)
383 * That's the generic constructor
384 **************************************************************************/
385 libvlc_media_t * libvlc_media_new_from_input_item(
386 libvlc_instance_t *p_instance,
387 input_item_t *p_input_item )
389 libvlc_media_t * p_md;
391 if (!p_input_item)
393 libvlc_printerr( "No input item given" );
394 return NULL;
397 p_md = calloc( 1, sizeof(libvlc_media_t) );
398 if( !p_md )
400 libvlc_printerr( "Not enough memory" );
401 return NULL;
404 p_md->p_libvlc_instance = p_instance;
405 p_md->p_input_item = p_input_item;
406 p_md->i_refcount = 1;
408 vlc_cond_init(&p_md->parsed_cond);
409 vlc_mutex_init(&p_md->parsed_lock);
410 vlc_mutex_init(&p_md->subitems_lock);
412 p_md->state = libvlc_NothingSpecial;
414 /* A media descriptor can be a playlist. When you open a playlist
415 * It can give a bunch of item to read. */
416 p_md->p_subitems = NULL;
418 libvlc_event_manager_init( &p_md->event_manager, p_md );
420 input_item_Hold( p_md->p_input_item );
422 install_input_item_observer( p_md );
424 libvlc_retain( p_instance );
425 return p_md;
428 /**************************************************************************
429 * Create a new media descriptor object
430 **************************************************************************/
431 libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
432 const char * psz_mrl )
434 input_item_t * p_input_item;
435 libvlc_media_t * p_md;
437 p_input_item = input_item_New( psz_mrl, NULL );
439 if (!p_input_item)
441 libvlc_printerr( "Not enough memory" );
442 return NULL;
445 p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
447 /* The p_input_item is retained in libvlc_media_new_from_input_item */
448 input_item_Release( p_input_item );
450 return p_md;
453 libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
454 const char *path )
456 char *mrl = vlc_path2uri( path, NULL );
457 if( unlikely(mrl == NULL) )
459 libvlc_printerr( "%s", vlc_strerror_c(errno) );
460 return NULL;
463 libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl );
464 free( mrl );
465 return m;
468 libvlc_media_t *libvlc_media_new_fd( libvlc_instance_t *p_instance, int fd )
470 char mrl[16];
471 snprintf( mrl, sizeof(mrl), "fd://%d", fd );
473 return libvlc_media_new_location( p_instance, mrl );
476 libvlc_media_t *libvlc_media_new_callbacks(libvlc_instance_t *p_instance,
477 libvlc_media_open_cb open_cb,
478 libvlc_media_read_cb read_cb,
479 libvlc_media_seek_cb seek_cb,
480 libvlc_media_close_cb close_cb,
481 void *opaque)
483 libvlc_media_t *m = libvlc_media_new_location(p_instance, "imem://");
484 if (unlikely(m == NULL))
485 return NULL;
487 assert(read_cb != NULL);
488 input_item_AddOpaque(m->p_input_item, "imem-data", opaque);
489 input_item_AddOpaque(m->p_input_item, "imem-open", open_cb);
490 input_item_AddOpaque(m->p_input_item, "imem-read", read_cb);
491 input_item_AddOpaque(m->p_input_item, "imem-seek", seek_cb);
492 input_item_AddOpaque(m->p_input_item, "imem-close", close_cb);
493 return m;
496 /**************************************************************************
497 * Create a new media descriptor object
498 **************************************************************************/
499 libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
500 const char * psz_name )
502 input_item_t * p_input_item;
503 libvlc_media_t * p_md;
504 libvlc_media_list_t * p_subitems;
506 p_input_item = input_item_New( "vlc://nop", psz_name );
508 if (!p_input_item)
510 libvlc_printerr( "Not enough memory" );
511 return NULL;
514 p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
515 input_item_Release( p_input_item );
517 p_subitems = media_get_subitems( p_md, true );
518 if( p_subitems == NULL) {
519 libvlc_media_release( p_md );
520 return NULL;
523 return p_md;
526 /**************************************************************************
527 * Add an option to the media descriptor,
528 * that will be used to determine how the media_player will read the
529 * media. This allow to use VLC advanced reading/streaming
530 * options in a per-media basis
532 * The options are detailled in vlc --long-help, for instance "--sout-all"
533 **************************************************************************/
534 void libvlc_media_add_option( libvlc_media_t * p_md,
535 const char * psz_option )
537 libvlc_media_add_option_flag( p_md, psz_option,
538 VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
541 /**************************************************************************
542 * Same as libvlc_media_add_option but with configurable flags.
543 **************************************************************************/
544 void libvlc_media_add_option_flag( libvlc_media_t * p_md,
545 const char * ppsz_option,
546 unsigned i_flags )
548 input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
551 /**************************************************************************
552 * Delete a media descriptor object
553 **************************************************************************/
554 void libvlc_media_release( libvlc_media_t *p_md )
556 if (!p_md)
557 return;
559 p_md->i_refcount--;
561 if( p_md->i_refcount > 0 )
562 return;
564 uninstall_input_item_observer( p_md );
566 /* Cancel asynchronous parsing (if any) */
567 libvlc_MetadataCancel( p_md->p_libvlc_instance->p_libvlc_int, p_md );
569 if( p_md->p_subitems )
570 libvlc_media_list_release( p_md->p_subitems );
572 input_item_Release( p_md->p_input_item );
574 vlc_cond_destroy( &p_md->parsed_cond );
575 vlc_mutex_destroy( &p_md->parsed_lock );
576 vlc_mutex_destroy( &p_md->subitems_lock );
578 /* Construct the event */
579 libvlc_event_t event;
580 event.type = libvlc_MediaFreed;
581 event.u.media_freed.md = p_md;
583 /* Send the event */
584 libvlc_event_send( &p_md->event_manager, &event );
586 libvlc_event_manager_destroy( &p_md->event_manager );
587 libvlc_release( p_md->p_libvlc_instance );
588 free( p_md );
591 /**************************************************************************
592 * Retain a media descriptor object
593 **************************************************************************/
594 void libvlc_media_retain( libvlc_media_t *p_md )
596 assert (p_md);
597 p_md->i_refcount++;
600 /**************************************************************************
601 * Duplicate a media descriptor object
602 **************************************************************************/
603 libvlc_media_t *
604 libvlc_media_duplicate( libvlc_media_t *p_md_orig )
606 return libvlc_media_new_from_input_item(
607 p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
610 /**************************************************************************
611 * Get mrl from a media descriptor object
612 **************************************************************************/
613 char *
614 libvlc_media_get_mrl( libvlc_media_t * p_md )
616 assert( p_md );
617 return input_item_GetURI( p_md->p_input_item );
620 /**************************************************************************
621 * Getter for meta information
622 **************************************************************************/
624 char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
626 char *psz_meta = NULL;
628 if( e_meta == libvlc_meta_NowPlaying )
630 psz_meta = input_item_GetNowPlayingFb( p_md->p_input_item );
632 else
634 psz_meta = input_item_GetMeta( p_md->p_input_item,
635 libvlc_to_vlc_meta[e_meta] );
636 /* Should be integrated in core */
637 if( psz_meta == NULL && e_meta == libvlc_meta_Title
638 && p_md->p_input_item->psz_name != NULL )
639 psz_meta = strdup( p_md->p_input_item->psz_name );
641 return psz_meta;
644 /**************************************************************************
645 * Setter for meta information
646 **************************************************************************/
648 void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value )
650 assert( p_md );
651 input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value );
654 int libvlc_media_save_meta( libvlc_media_t *p_md )
656 assert( p_md );
657 vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
658 return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
661 /**************************************************************************
662 * Getter for state information
663 * Can be error, playing, buffering, NothingSpecial.
664 **************************************************************************/
666 libvlc_state_t
667 libvlc_media_get_state( libvlc_media_t *p_md )
669 assert( p_md );
670 return p_md->state;
673 /**************************************************************************
674 * Setter for state information (LibVLC Internal)
675 **************************************************************************/
677 void
678 libvlc_media_set_state( libvlc_media_t *p_md,
679 libvlc_state_t state )
681 libvlc_event_t event;
683 p_md->state = state;
685 /* Construct the event */
686 event.type = libvlc_MediaStateChanged;
687 event.u.media_state_changed.new_state = state;
689 /* Send the event */
690 libvlc_event_send( &p_md->event_manager, &event );
693 /**************************************************************************
694 * subitems
695 **************************************************************************/
696 libvlc_media_list_t *
697 libvlc_media_subitems( libvlc_media_t * p_md )
699 libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true );
700 if( p_subitems )
701 libvlc_media_list_retain( p_subitems );
702 return p_subitems;
705 /**************************************************************************
706 * Getter for statistics information
707 **************************************************************************/
708 int libvlc_media_get_stats( libvlc_media_t *p_md,
709 libvlc_media_stats_t *p_stats )
711 input_item_t *item = p_md->p_input_item;
713 if( !p_md->p_input_item )
714 return false;
716 vlc_mutex_lock( &item->lock );
718 input_stats_t *p_itm_stats = p_md->p_input_item->p_stats;
719 if( p_itm_stats == NULL )
721 vlc_mutex_unlock( &item->lock );
722 return false;
725 p_stats->i_read_bytes = p_itm_stats->i_read_bytes;
726 p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate;
728 p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes;
729 p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate;
730 p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted;
731 p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity;
733 p_stats->i_decoded_video = p_itm_stats->i_decoded_video;
734 p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio;
736 p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures;
737 p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures;
739 p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers;
740 p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers;
742 p_stats->i_sent_packets = 0;
743 p_stats->i_sent_bytes = 0;
744 p_stats->f_send_bitrate = 0.;
746 vlc_mutex_unlock( &item->lock );
747 return true;
750 /**************************************************************************
751 * event_manager
752 **************************************************************************/
753 libvlc_event_manager_t *
754 libvlc_media_event_manager( libvlc_media_t * p_md )
756 assert( p_md );
758 return &p_md->event_manager;
761 /**************************************************************************
762 * Get duration of media object (in ms)
763 **************************************************************************/
764 int64_t
765 libvlc_media_get_duration( libvlc_media_t * p_md )
767 assert( p_md );
769 if( !p_md->p_input_item )
771 libvlc_printerr( "No input item" );
772 return -1;
775 if (!input_item_IsPreparsed( p_md->p_input_item ))
776 return -1;
778 return from_mtime(input_item_GetDuration( p_md->p_input_item ));
781 static int media_parse(libvlc_media_t *media, bool b_async,
782 libvlc_media_parse_flag_t parse_flag, int timeout)
784 bool needed;
786 vlc_mutex_lock(&media->parsed_lock);
787 needed = !media->has_asked_preparse;
788 media->has_asked_preparse = true;
789 if (needed)
790 media->is_parsed = false;
791 vlc_mutex_unlock(&media->parsed_lock);
793 if (needed)
795 libvlc_int_t *libvlc = media->p_libvlc_instance->p_libvlc_int;
796 input_item_t *item = media->p_input_item;
797 input_item_meta_request_option_t parse_scope = META_REQUEST_OPTION_SCOPE_LOCAL;
798 int ret;
800 /* Ignore libvlc_media_fetch_local flag since local art will be fetched
801 * by libvlc_MetadataRequest */
802 if (parse_flag & libvlc_media_fetch_network)
804 ret = libvlc_ArtRequest(libvlc, item,
805 META_REQUEST_OPTION_SCOPE_NETWORK);
806 if (ret != VLC_SUCCESS)
807 return ret;
810 if (parse_flag & libvlc_media_parse_network)
811 parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
812 if (parse_flag & libvlc_media_do_interact)
813 parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
814 ret = libvlc_MetadataRequest(libvlc, item, parse_scope, timeout, media);
815 if (ret != VLC_SUCCESS)
816 return ret;
818 else
819 return VLC_EGENERIC;
821 if (!b_async)
823 vlc_mutex_lock(&media->parsed_lock);
824 while (!media->is_parsed)
825 vlc_cond_wait(&media->parsed_cond, &media->parsed_lock);
826 vlc_mutex_unlock(&media->parsed_lock);
828 return VLC_SUCCESS;
831 /**************************************************************************
832 * Parse the media and wait.
833 **************************************************************************/
834 void
835 libvlc_media_parse(libvlc_media_t *media)
837 media_parse( media, false, libvlc_media_fetch_local, -1 );
840 /**************************************************************************
841 * Parse the media but do not wait.
842 **************************************************************************/
843 void
844 libvlc_media_parse_async(libvlc_media_t *media)
846 media_parse( media, true, libvlc_media_fetch_local, -1 );
849 /**************************************************************************
850 * Parse the media asynchronously with options.
851 **************************************************************************/
853 libvlc_media_parse_with_options( libvlc_media_t *media,
854 libvlc_media_parse_flag_t parse_flag,
855 int timeout )
857 return media_parse( media, true, parse_flag, timeout ) == VLC_SUCCESS ? 0 : -1;
860 void
861 libvlc_media_parse_stop( libvlc_media_t *media )
863 libvlc_MetadataCancel( media->p_libvlc_instance->p_libvlc_int, media );
866 /**************************************************************************
867 * Get parsed status for media object.
868 **************************************************************************/
870 libvlc_media_is_parsed(libvlc_media_t *media)
872 bool parsed;
874 vlc_mutex_lock(&media->parsed_lock);
875 parsed = media->is_parsed;
876 vlc_mutex_unlock(&media->parsed_lock);
877 return parsed;
880 libvlc_media_parsed_status_t
881 libvlc_media_get_parsed_status(libvlc_media_t *media)
883 libvlc_media_parsed_status_t status;
885 vlc_mutex_lock(&media->parsed_lock);
886 status = media->parsed_status;
887 vlc_mutex_unlock(&media->parsed_lock);
888 return status;
891 /**************************************************************************
892 * Sets media descriptor's user_data. user_data is specialized data
893 * accessed by the host application, VLC.framework uses it as a pointer to
894 * an native object that references a libvlc_media_t pointer
895 **************************************************************************/
896 void
897 libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
899 assert( p_md );
900 p_md->p_user_data = p_new_user_data;
903 /**************************************************************************
904 * Get media descriptor's user_data. user_data is specialized data
905 * accessed by the host application, VLC.framework uses it as a pointer to
906 * an native object that references a libvlc_media_t pointer
907 **************************************************************************/
908 void *
909 libvlc_media_get_user_data( libvlc_media_t * p_md )
911 assert( p_md );
912 return p_md->p_user_data;
915 /**************************************************************************
916 * Get media descriptor's elementary streams description
917 **************************************************************************/
919 libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
921 assert( p_md );
923 input_item_t *p_input_item = p_md->p_input_item;
924 vlc_mutex_lock( &p_input_item->lock );
926 const int i_es = p_input_item->i_es;
927 *pp_es = (i_es > 0) ? vlc_alloc( i_es, sizeof(libvlc_media_track_info_t) ) : NULL;
929 if( !*pp_es ) /* no ES, or OOM */
931 vlc_mutex_unlock( &p_input_item->lock );
932 return 0;
935 /* Fill array */
936 for( int i = 0; i < i_es; i++ )
938 libvlc_media_track_info_t *p_mes = *pp_es+i;
939 const es_format_t *p_es = p_input_item->es[i];
941 p_mes->i_codec = p_es->i_codec;
942 p_mes->i_id = p_es->i_id;
944 p_mes->i_profile = p_es->i_profile;
945 p_mes->i_level = p_es->i_level;
947 switch(p_es->i_cat)
949 case UNKNOWN_ES:
950 default:
951 p_mes->i_type = libvlc_track_unknown;
952 break;
953 case VIDEO_ES:
954 p_mes->i_type = libvlc_track_video;
955 p_mes->u.video.i_height = p_es->video.i_visible_height;
956 p_mes->u.video.i_width = p_es->video.i_visible_width;
957 break;
958 case AUDIO_ES:
959 p_mes->i_type = libvlc_track_audio;
960 p_mes->u.audio.i_channels = p_es->audio.i_channels;
961 p_mes->u.audio.i_rate = p_es->audio.i_rate;
962 break;
963 case SPU_ES:
964 p_mes->i_type = libvlc_track_text;
965 break;
969 vlc_mutex_unlock( &p_input_item->lock );
970 return i_es;
973 unsigned
974 libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es )
976 assert( p_md );
978 input_item_t *p_input_item = p_md->p_input_item;
979 vlc_mutex_lock( &p_input_item->lock );
981 const int i_es = p_input_item->i_es;
982 *pp_es = (i_es > 0) ? calloc( i_es, sizeof(**pp_es) ) : NULL;
984 if( !*pp_es ) /* no ES, or OOM */
986 vlc_mutex_unlock( &p_input_item->lock );
987 return 0;
990 /* Fill array */
991 for( int i = 0; i < i_es; i++ )
993 libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) );
994 if ( p_mes )
996 p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio),
997 sizeof(*p_mes->video)),
998 sizeof(*p_mes->subtitle)) );
1000 if ( !p_mes || !p_mes->audio )
1002 libvlc_media_tracks_release( *pp_es, i_es );
1003 *pp_es = NULL;
1004 free( p_mes );
1005 vlc_mutex_unlock( &p_input_item->lock );
1006 return 0;
1008 (*pp_es)[i] = p_mes;
1010 const es_format_t *p_es = p_input_item->es[i];
1012 p_mes->i_codec = p_es->i_codec;
1013 p_mes->i_original_fourcc = p_es->i_original_fourcc;
1014 p_mes->i_id = p_es->i_id;
1016 p_mes->i_profile = p_es->i_profile;
1017 p_mes->i_level = p_es->i_level;
1019 p_mes->i_bitrate = p_es->i_bitrate;
1020 p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL;
1021 p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL;
1023 switch(p_es->i_cat)
1025 case UNKNOWN_ES:
1026 default:
1027 p_mes->i_type = libvlc_track_unknown;
1028 break;
1029 case VIDEO_ES:
1030 p_mes->i_type = libvlc_track_video;
1031 p_mes->video->i_height = p_es->video.i_visible_height;
1032 p_mes->video->i_width = p_es->video.i_visible_width;
1033 p_mes->video->i_sar_num = p_es->video.i_sar_num;
1034 p_mes->video->i_sar_den = p_es->video.i_sar_den;
1035 p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate;
1036 p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base;
1038 assert( p_es->video.orientation >= ORIENT_TOP_LEFT &&
1039 p_es->video.orientation <= ORIENT_RIGHT_BOTTOM );
1040 p_mes->video->i_orientation = (int) p_es->video.orientation;
1042 assert( ( p_es->video.projection_mode >= PROJECTION_MODE_RECTANGULAR &&
1043 p_es->video.projection_mode <= PROJECTION_MODE_EQUIRECTANGULAR ) ||
1044 ( p_es->video.projection_mode == PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD ) );
1045 p_mes->video->i_projection = (int) p_es->video.projection_mode;
1047 p_mes->video->pose.f_yaw = p_es->video.pose.yaw;
1048 p_mes->video->pose.f_pitch = p_es->video.pose.pitch;
1049 p_mes->video->pose.f_roll = p_es->video.pose.roll;
1050 p_mes->video->pose.f_field_of_view = p_es->video.pose.fov;
1052 assert( p_es->video.multiview_mode >= MULTIVIEW_2D &&
1053 p_es->video.multiview_mode <= MULTIVIEW_STEREO_CHECKERBOARD );
1054 p_mes->video->i_multiview = (int) p_es->video.multiview_mode;
1055 break;
1056 case AUDIO_ES:
1057 p_mes->i_type = libvlc_track_audio;
1058 p_mes->audio->i_channels = p_es->audio.i_channels;
1059 p_mes->audio->i_rate = p_es->audio.i_rate;
1060 break;
1061 case SPU_ES:
1062 p_mes->i_type = libvlc_track_text;
1063 p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ?
1064 strdup(p_es->subs.psz_encoding) : NULL;
1065 break;
1069 vlc_mutex_unlock( &p_input_item->lock );
1070 return i_es;
1073 /**************************************************************************
1074 * Get codec description from media elementary stream
1075 **************************************************************************/
1076 const char *
1077 libvlc_media_get_codec_description( libvlc_track_type_t i_type,
1078 uint32_t i_codec )
1080 switch( i_type )
1082 case libvlc_track_audio:
1083 return vlc_fourcc_GetDescription( AUDIO_ES, i_codec );
1084 case libvlc_track_video:
1085 return vlc_fourcc_GetDescription( VIDEO_ES, i_codec );
1086 case libvlc_track_text:
1087 return vlc_fourcc_GetDescription( SPU_ES, i_codec );
1088 case libvlc_track_unknown:
1089 default:
1090 return vlc_fourcc_GetDescription( UNKNOWN_ES, i_codec );
1094 /**************************************************************************
1095 * Release media descriptor's elementary streams description array
1096 **************************************************************************/
1097 void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
1099 for( unsigned i = 0; i < i_count; ++i )
1101 if ( !p_tracks[i] )
1102 continue;
1103 free( p_tracks[i]->psz_language );
1104 free( p_tracks[i]->psz_description );
1105 switch( p_tracks[i]->i_type )
1107 case libvlc_track_audio:
1108 break;
1109 case libvlc_track_video:
1110 break;
1111 case libvlc_track_text:
1112 free( p_tracks[i]->subtitle->psz_encoding );
1113 break;
1114 case libvlc_track_unknown:
1115 default:
1116 break;
1118 free( p_tracks[i]->audio );
1119 free( p_tracks[i] );
1121 free( p_tracks );
1124 /**************************************************************************
1125 * Get the media type of the media descriptor object
1126 **************************************************************************/
1127 libvlc_media_type_t libvlc_media_get_type( libvlc_media_t *p_md )
1129 assert( p_md );
1131 int i_type;
1132 input_item_t *p_input_item = p_md->p_input_item;
1134 vlc_mutex_lock( &p_input_item->lock );
1135 i_type = p_md->p_input_item->i_type;
1136 vlc_mutex_unlock( &p_input_item->lock );
1138 switch( i_type )
1140 case ITEM_TYPE_FILE:
1141 return libvlc_media_type_file;
1142 case ITEM_TYPE_NODE:
1143 case ITEM_TYPE_DIRECTORY:
1144 return libvlc_media_type_directory;
1145 case ITEM_TYPE_DISC:
1146 return libvlc_media_type_disc;
1147 case ITEM_TYPE_STREAM:
1148 return libvlc_media_type_stream;
1149 case ITEM_TYPE_PLAYLIST:
1150 return libvlc_media_type_playlist;
1151 default:
1152 return libvlc_media_type_unknown;
1156 int libvlc_media_slaves_add( libvlc_media_t *p_md,
1157 libvlc_media_slave_type_t i_type,
1158 unsigned int i_priority,
1159 const char *psz_uri )
1161 assert( p_md && psz_uri );
1162 input_item_t *p_input_item = p_md->p_input_item;
1164 enum slave_type i_input_slave_type;
1165 switch( i_type )
1167 case libvlc_media_slave_type_subtitle:
1168 i_input_slave_type = SLAVE_TYPE_SPU;
1169 break;
1170 case libvlc_media_slave_type_audio:
1171 i_input_slave_type = SLAVE_TYPE_AUDIO;
1172 break;
1173 default:
1174 vlc_assert_unreachable();
1175 return -1;
1178 enum slave_priority i_input_slave_priority;
1179 switch( i_priority )
1181 case 0:
1182 i_input_slave_priority = SLAVE_PRIORITY_MATCH_NONE;
1183 break;
1184 case 1:
1185 i_input_slave_priority = SLAVE_PRIORITY_MATCH_RIGHT;
1186 break;
1187 case 2:
1188 i_input_slave_priority = SLAVE_PRIORITY_MATCH_LEFT;
1189 break;
1190 case 3:
1191 i_input_slave_priority = SLAVE_PRIORITY_MATCH_ALL;
1192 break;
1193 default:
1194 case 4:
1195 i_input_slave_priority = SLAVE_PRIORITY_USER;
1196 break;
1199 input_item_slave_t *p_slave = input_item_slave_New( psz_uri,
1200 i_input_slave_type,
1201 i_input_slave_priority );
1202 if( p_slave == NULL )
1203 return -1;
1204 return input_item_AddSlave( p_input_item, p_slave ) == VLC_SUCCESS ? 0 : -1;
1207 void libvlc_media_slaves_clear( libvlc_media_t *p_md )
1209 assert( p_md );
1210 input_item_t *p_input_item = p_md->p_input_item;
1212 vlc_mutex_lock( &p_input_item->lock );
1213 for( int i = 0; i < p_input_item->i_slaves; i++ )
1214 input_item_slave_Delete( p_input_item->pp_slaves[i] );
1215 TAB_CLEAN( p_input_item->i_slaves, p_input_item->pp_slaves );
1216 vlc_mutex_unlock( &p_input_item->lock );
1219 unsigned int libvlc_media_slaves_get( libvlc_media_t *p_md,
1220 libvlc_media_slave_t ***ppp_slaves )
1222 assert( p_md && ppp_slaves );
1223 input_item_t *p_input_item = p_md->p_input_item;
1224 *ppp_slaves = NULL;
1226 vlc_mutex_lock( &p_input_item->lock );
1228 int i_count = p_input_item->i_slaves;
1229 if( i_count <= 0 )
1230 return vlc_mutex_unlock( &p_input_item->lock ), 0;
1232 libvlc_media_slave_t **pp_slaves = calloc( i_count, sizeof(*pp_slaves) );
1233 if( pp_slaves == NULL )
1234 return vlc_mutex_unlock( &p_input_item->lock ), 0;
1236 for( int i = 0; i < i_count; ++i )
1238 input_item_slave_t *p_item_slave = p_input_item->pp_slaves[i];
1239 assert( p_item_slave->i_priority >= SLAVE_PRIORITY_MATCH_NONE );
1241 /* also allocate psz_uri buffer at the end of the struct */
1242 libvlc_media_slave_t *p_slave = malloc( sizeof(*p_slave) +
1243 strlen( p_item_slave->psz_uri )
1244 + 1 );
1245 if( p_slave == NULL )
1247 libvlc_media_slaves_release(pp_slaves, i);
1248 return vlc_mutex_unlock( &p_input_item->lock ), 0;
1250 p_slave->psz_uri = (char *) ((uint8_t *)p_slave) + sizeof(*p_slave);
1251 strcpy( p_slave->psz_uri, p_item_slave->psz_uri );
1253 switch( p_item_slave->i_type )
1255 case SLAVE_TYPE_SPU:
1256 p_slave->i_type = libvlc_media_slave_type_subtitle;
1257 break;
1258 case SLAVE_TYPE_AUDIO:
1259 p_slave->i_type = libvlc_media_slave_type_audio;
1260 break;
1261 default:
1262 vlc_assert_unreachable();
1265 switch( p_item_slave->i_priority )
1267 case SLAVE_PRIORITY_MATCH_NONE:
1268 p_slave->i_priority = 0;
1269 break;
1270 case SLAVE_PRIORITY_MATCH_RIGHT:
1271 p_slave->i_priority = 1;
1272 break;
1273 case SLAVE_PRIORITY_MATCH_LEFT:
1274 p_slave->i_priority = 2;
1275 break;
1276 case SLAVE_PRIORITY_MATCH_ALL:
1277 p_slave->i_priority = 3;
1278 break;
1279 case SLAVE_PRIORITY_USER:
1280 p_slave->i_priority = 4;
1281 break;
1282 default:
1283 vlc_assert_unreachable();
1285 pp_slaves[i] = p_slave;
1287 vlc_mutex_unlock( &p_input_item->lock );
1289 *ppp_slaves = pp_slaves;
1290 return i_count;
1293 void libvlc_media_slaves_release( libvlc_media_slave_t **pp_slaves,
1294 unsigned int i_count )
1296 if( i_count > 0 )
1298 assert( pp_slaves );
1299 for( unsigned int i = 0; i < i_count; ++i )
1300 free( pp_slaves[i] );
1302 free( pp_slaves );