mux: mp4: fix mpeg1 object id
[vlc.git] / lib / media.c
blob90d9007eadc87f9cd2bad699f1806702752d34cd
1 /*****************************************************************************
2 * media.c: Libvlc API media descripor management
3 *****************************************************************************
4 * Copyright (C) 2007 VLC authors and VideoLAN
6 * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <assert.h>
28 #include <errno.h>
30 #include <vlc/libvlc.h>
31 #include <vlc/libvlc_picture.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_legacy.h> /* For the preparser */
40 #include <vlc_url.h>
41 #include <vlc_thumbnailer.h>
43 #include "../src/libvlc.h"
45 #include "libvlc_internal.h"
46 #include "media_internal.h"
47 #include "media_list_internal.h"
48 #include "picture_internal.h"
50 static const vlc_meta_type_t libvlc_to_vlc_meta[] =
52 [libvlc_meta_Title] = vlc_meta_Title,
53 [libvlc_meta_Artist] = vlc_meta_Artist,
54 [libvlc_meta_Genre] = vlc_meta_Genre,
55 [libvlc_meta_Copyright] = vlc_meta_Copyright,
56 [libvlc_meta_Album] = vlc_meta_Album,
57 [libvlc_meta_TrackNumber] = vlc_meta_TrackNumber,
58 [libvlc_meta_Description] = vlc_meta_Description,
59 [libvlc_meta_Rating] = vlc_meta_Rating,
60 [libvlc_meta_Date] = vlc_meta_Date,
61 [libvlc_meta_Setting] = vlc_meta_Setting,
62 [libvlc_meta_URL] = vlc_meta_URL,
63 [libvlc_meta_Language] = vlc_meta_Language,
64 [libvlc_meta_NowPlaying] = vlc_meta_NowPlaying,
65 [libvlc_meta_Publisher] = vlc_meta_Publisher,
66 [libvlc_meta_EncodedBy] = vlc_meta_EncodedBy,
67 [libvlc_meta_ArtworkURL] = vlc_meta_ArtworkURL,
68 [libvlc_meta_TrackID] = vlc_meta_TrackID,
69 [libvlc_meta_TrackTotal] = vlc_meta_TrackTotal,
70 [libvlc_meta_Director] = vlc_meta_Director,
71 [libvlc_meta_Season] = vlc_meta_Season,
72 [libvlc_meta_Episode] = vlc_meta_Episode,
73 [libvlc_meta_ShowName] = vlc_meta_ShowName,
74 [libvlc_meta_Actors] = vlc_meta_Actors,
75 [libvlc_meta_AlbumArtist] = vlc_meta_AlbumArtist,
76 [libvlc_meta_DiscNumber] = vlc_meta_DiscNumber,
77 [libvlc_meta_DiscTotal] = vlc_meta_DiscTotal
80 static const libvlc_meta_t vlc_to_libvlc_meta[] =
82 [vlc_meta_Title] = libvlc_meta_Title,
83 [vlc_meta_Artist] = libvlc_meta_Artist,
84 [vlc_meta_Genre] = libvlc_meta_Genre,
85 [vlc_meta_Copyright] = libvlc_meta_Copyright,
86 [vlc_meta_Album] = libvlc_meta_Album,
87 [vlc_meta_TrackNumber] = libvlc_meta_TrackNumber,
88 [vlc_meta_Description] = libvlc_meta_Description,
89 [vlc_meta_Rating] = libvlc_meta_Rating,
90 [vlc_meta_Date] = libvlc_meta_Date,
91 [vlc_meta_Setting] = libvlc_meta_Setting,
92 [vlc_meta_URL] = libvlc_meta_URL,
93 [vlc_meta_Language] = libvlc_meta_Language,
94 [vlc_meta_NowPlaying] = libvlc_meta_NowPlaying,
95 [vlc_meta_ESNowPlaying] = libvlc_meta_NowPlaying,
96 [vlc_meta_Publisher] = libvlc_meta_Publisher,
97 [vlc_meta_EncodedBy] = libvlc_meta_EncodedBy,
98 [vlc_meta_ArtworkURL] = libvlc_meta_ArtworkURL,
99 [vlc_meta_TrackID] = libvlc_meta_TrackID,
100 [vlc_meta_TrackTotal] = libvlc_meta_TrackTotal,
101 [vlc_meta_Director] = libvlc_meta_Director,
102 [vlc_meta_Season] = libvlc_meta_Season,
103 [vlc_meta_Episode] = libvlc_meta_Episode,
104 [vlc_meta_ShowName] = libvlc_meta_ShowName,
105 [vlc_meta_Actors] = libvlc_meta_Actors,
106 [vlc_meta_AlbumArtist] = libvlc_meta_AlbumArtist,
107 [vlc_meta_DiscNumber] = libvlc_meta_DiscNumber,
108 [vlc_meta_DiscTotal] = libvlc_meta_DiscTotal
111 static_assert(
112 ORIENT_TOP_LEFT == (int) libvlc_video_orient_top_left &&
113 ORIENT_TOP_RIGHT == (int) libvlc_video_orient_top_right &&
114 ORIENT_BOTTOM_LEFT == (int) libvlc_video_orient_bottom_left &&
115 ORIENT_BOTTOM_RIGHT == (int) libvlc_video_orient_bottom_right &&
116 ORIENT_LEFT_TOP == (int) libvlc_video_orient_left_top &&
117 ORIENT_LEFT_BOTTOM == (int) libvlc_video_orient_left_bottom &&
118 ORIENT_RIGHT_TOP == (int) libvlc_video_orient_right_top &&
119 ORIENT_RIGHT_BOTTOM == (int) libvlc_video_orient_right_bottom,
120 "Mismatch between libvlc_video_orient_t and video_orientation_t" );
122 static_assert(
123 PROJECTION_MODE_RECTANGULAR == (int) libvlc_video_projection_rectangular &&
124 PROJECTION_MODE_EQUIRECTANGULAR == (int) libvlc_video_projection_equirectangular &&
125 PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD == (int) libvlc_video_projection_cubemap_layout_standard,
126 "Mismatch between libvlc_video_projection_t and video_projection_mode_t" );
128 static_assert(
129 MULTIVIEW_2D == (int) libvlc_video_multiview_2d &&
130 MULTIVIEW_STEREO_SBS == (int) libvlc_video_multiview_stereo_sbs &&
131 MULTIVIEW_STEREO_TB == (int) libvlc_video_multiview_stereo_tb &&
132 MULTIVIEW_STEREO_ROW == (int) libvlc_video_multiview_stereo_row &&
133 MULTIVIEW_STEREO_COL == (int) libvlc_video_multiview_stereo_col &&
134 MULTIVIEW_STEREO_FRAME == (int) libvlc_video_multiview_stereo_frame &&
135 MULTIVIEW_STEREO_CHECKERBOARD == (int) libvlc_video_multiview_stereo_checkerboard,
136 "Mismatch between libvlc_video_multiview_t and video_multiview_mode_t");
138 static libvlc_media_list_t *media_get_subitems( libvlc_media_t * p_md,
139 bool b_create )
141 libvlc_media_list_t *p_subitems = NULL;
143 vlc_mutex_lock( &p_md->subitems_lock );
144 if( p_md->p_subitems == NULL && b_create )
146 p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
147 if( p_md->p_subitems != NULL )
149 p_md->p_subitems->b_read_only = true;
150 p_md->p_subitems->p_internal_md = p_md;
153 p_subitems = p_md->p_subitems;
154 vlc_mutex_unlock( &p_md->subitems_lock );
155 return p_subitems;
158 static libvlc_media_t *input_item_add_subitem( libvlc_media_t *p_md,
159 input_item_t *item )
161 libvlc_media_t * p_md_child;
162 libvlc_media_list_t *p_subitems;
163 libvlc_event_t event;
165 p_md_child = libvlc_media_new_from_input_item( p_md->p_libvlc_instance,
166 item );
168 /* Add this to our media list */
169 p_subitems = media_get_subitems( p_md, true );
170 if( p_subitems != NULL )
172 libvlc_media_list_lock( p_subitems );
173 libvlc_media_list_internal_add_media( p_subitems, p_md_child );
174 libvlc_media_list_unlock( p_subitems );
177 /* Construct the event */
178 event.type = libvlc_MediaSubItemAdded;
179 event.u.media_subitem_added.new_child = p_md_child;
181 /* Send the event */
182 libvlc_event_send( &p_md->event_manager, &event );
183 return p_md_child;
186 static void input_item_add_subnode( libvlc_media_t *md,
187 input_item_node_t *node )
189 for( int i = 0; i < node->i_children; i++ )
191 input_item_node_t *child = node->pp_children[i];
192 libvlc_media_t *md_child = input_item_add_subitem( md, child->p_item );
194 if( md_child != NULL )
196 input_item_add_subnode( md_child, child );
197 libvlc_media_release( md_child );
202 /**************************************************************************
203 * input_item_subitemtree_added (Private) (vlc event Callback)
204 **************************************************************************/
205 static void input_item_subtree_added(input_item_t *item,
206 input_item_node_t *node,
207 void *user_data)
209 VLC_UNUSED(item);
210 libvlc_media_t * p_md = user_data;
211 libvlc_media_add_subtree(p_md, node);
214 void libvlc_media_add_subtree(libvlc_media_t *p_md, input_item_node_t *node)
216 /* FIXME FIXME FIXME
217 * Recursive function calls seem much simpler for this. But playlists are
218 * untrusted and can be arbitrarily deep (e.g. with XSPF). So recursion can
219 * potentially lead to plain old stack overflow. */
220 input_item_add_subnode( p_md, node );
222 /* Construct the event */
223 libvlc_event_t event;
224 event.type = libvlc_MediaSubItemTreeAdded;
225 event.u.media_subitemtree_added.item = p_md;
227 /* Send the event */
228 libvlc_event_send( &p_md->event_manager, &event );
231 /**************************************************************************
232 * input_item_meta_changed (Private) (vlc event Callback)
233 **************************************************************************/
234 static void input_item_meta_changed( const vlc_event_t *p_event,
235 void * user_data )
237 libvlc_media_t * p_md = user_data;
238 libvlc_event_t event;
240 /* Construct the event */
241 event.type = libvlc_MediaMetaChanged;
242 event.u.media_meta_changed.meta_type =
243 vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];
245 /* Send the event */
246 libvlc_event_send( &p_md->event_manager, &event );
249 /**************************************************************************
250 * input_item_duration_changed (Private) (vlc event Callback)
251 **************************************************************************/
252 static void input_item_duration_changed( const vlc_event_t *p_event,
253 void * user_data )
255 libvlc_media_t * p_md = user_data;
256 libvlc_event_t event;
258 /* Construct the event */
259 event.type = libvlc_MediaDurationChanged;
260 event.u.media_duration_changed.new_duration =
261 from_mtime(p_event->u.input_item_duration_changed.new_duration);
263 /* Send the event */
264 libvlc_event_send( &p_md->event_manager, &event );
267 static void send_parsed_changed( libvlc_media_t *p_md,
268 libvlc_media_parsed_status_t new_status )
270 libvlc_event_t event;
272 vlc_mutex_lock( &p_md->parsed_lock );
273 if( p_md->parsed_status == new_status )
275 vlc_mutex_unlock( &p_md->parsed_lock );
276 return;
279 /* Legacy: notify libvlc_media_parse */
280 if( !p_md->is_parsed )
282 p_md->is_parsed = true;
283 vlc_cond_broadcast( &p_md->parsed_cond );
286 p_md->parsed_status = new_status;
287 if( p_md->parsed_status == libvlc_media_parsed_status_skipped )
288 p_md->has_asked_preparse = false;
290 vlc_mutex_unlock( &p_md->parsed_lock );
292 if( new_status == libvlc_media_parsed_status_done )
294 libvlc_media_list_t *p_subitems = media_get_subitems( p_md, false );
295 if( p_subitems != NULL )
297 /* notify the media list */
298 libvlc_media_list_lock( p_subitems );
299 libvlc_media_list_internal_end_reached( p_subitems );
300 libvlc_media_list_unlock( p_subitems );
304 /* Construct the event */
305 event.type = libvlc_MediaParsedChanged;
306 event.u.media_parsed_changed.new_status = new_status;
308 /* Send the event */
309 libvlc_event_send( &p_md->event_manager, &event );
312 /**************************************************************************
313 * input_item_preparse_ended (Private) (vlc event Callback)
314 **************************************************************************/
315 static void input_item_preparse_ended(input_item_t *item,
316 enum input_item_preparse_status status,
317 void *user_data)
319 VLC_UNUSED(item);
320 libvlc_media_t * p_md = user_data;
321 libvlc_media_parsed_status_t new_status;
323 switch( status )
325 case ITEM_PREPARSE_SKIPPED:
326 new_status = libvlc_media_parsed_status_skipped;
327 break;
328 case ITEM_PREPARSE_FAILED:
329 new_status = libvlc_media_parsed_status_failed;
330 break;
331 case ITEM_PREPARSE_TIMEOUT:
332 new_status = libvlc_media_parsed_status_timeout;
333 break;
334 case ITEM_PREPARSE_DONE:
335 new_status = libvlc_media_parsed_status_done;
336 break;
337 default:
338 return;
340 send_parsed_changed( p_md, new_status );
343 /**************************************************************************
344 * Install event handler (Private)
345 **************************************************************************/
346 static void install_input_item_observer( libvlc_media_t *p_md )
348 vlc_event_attach( &p_md->p_input_item->event_manager,
349 vlc_InputItemMetaChanged,
350 input_item_meta_changed,
351 p_md );
352 vlc_event_attach( &p_md->p_input_item->event_manager,
353 vlc_InputItemDurationChanged,
354 input_item_duration_changed,
355 p_md );
358 /**************************************************************************
359 * Uninstall event handler (Private)
360 **************************************************************************/
361 static void uninstall_input_item_observer( libvlc_media_t *p_md )
363 vlc_event_detach( &p_md->p_input_item->event_manager,
364 vlc_InputItemMetaChanged,
365 input_item_meta_changed,
366 p_md );
367 vlc_event_detach( &p_md->p_input_item->event_manager,
368 vlc_InputItemDurationChanged,
369 input_item_duration_changed,
370 p_md );
373 /**************************************************************************
374 * Create a new media descriptor object from an input_item
375 * (libvlc internal)
376 * That's the generic constructor
377 **************************************************************************/
378 libvlc_media_t * libvlc_media_new_from_input_item(
379 libvlc_instance_t *p_instance,
380 input_item_t *p_input_item )
382 libvlc_media_t * p_md;
384 if (!p_input_item)
386 libvlc_printerr( "No input item given" );
387 return NULL;
390 p_md = calloc( 1, sizeof(libvlc_media_t) );
391 if( !p_md )
393 libvlc_printerr( "Not enough memory" );
394 return NULL;
397 p_md->p_libvlc_instance = p_instance;
398 p_md->p_input_item = p_input_item;
399 p_md->i_refcount = 1;
401 vlc_cond_init(&p_md->parsed_cond);
402 vlc_mutex_init(&p_md->parsed_lock);
403 vlc_mutex_init(&p_md->subitems_lock);
405 p_md->state = libvlc_NothingSpecial;
407 /* A media descriptor can be a playlist. When you open a playlist
408 * It can give a bunch of item to read. */
409 p_md->p_subitems = NULL;
411 libvlc_event_manager_init( &p_md->event_manager, p_md );
413 input_item_Hold( p_md->p_input_item );
415 install_input_item_observer( p_md );
417 libvlc_retain( p_instance );
418 return p_md;
421 /**************************************************************************
422 * Create a new media descriptor object
423 **************************************************************************/
424 libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
425 const char * psz_mrl )
427 input_item_t * p_input_item;
428 libvlc_media_t * p_md;
430 p_input_item = input_item_New( psz_mrl, NULL );
432 if (!p_input_item)
434 libvlc_printerr( "Not enough memory" );
435 return NULL;
438 p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
440 /* The p_input_item is retained in libvlc_media_new_from_input_item */
441 input_item_Release( p_input_item );
443 return p_md;
446 libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
447 const char *path )
449 char *mrl = vlc_path2uri( path, NULL );
450 if( unlikely(mrl == NULL) )
452 libvlc_printerr( "%s", vlc_strerror_c(errno) );
453 return NULL;
456 libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl );
457 free( mrl );
458 return m;
461 libvlc_media_t *libvlc_media_new_fd( libvlc_instance_t *p_instance, int fd )
463 char mrl[16];
464 snprintf( mrl, sizeof(mrl), "fd://%d", fd );
466 return libvlc_media_new_location( p_instance, mrl );
469 libvlc_media_t *libvlc_media_new_callbacks(libvlc_instance_t *p_instance,
470 libvlc_media_open_cb open_cb,
471 libvlc_media_read_cb read_cb,
472 libvlc_media_seek_cb seek_cb,
473 libvlc_media_close_cb close_cb,
474 void *opaque)
476 libvlc_media_t *m = libvlc_media_new_location(p_instance, "imem://");
477 if (unlikely(m == NULL))
478 return NULL;
480 assert(read_cb != NULL);
481 input_item_AddOpaque(m->p_input_item, "imem-data", opaque);
482 input_item_AddOpaque(m->p_input_item, "imem-open", open_cb);
483 input_item_AddOpaque(m->p_input_item, "imem-read", read_cb);
484 input_item_AddOpaque(m->p_input_item, "imem-seek", seek_cb);
485 input_item_AddOpaque(m->p_input_item, "imem-close", close_cb);
486 return m;
489 /**************************************************************************
490 * Create a new media descriptor object
491 **************************************************************************/
492 libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
493 const char * psz_name )
495 input_item_t * p_input_item;
496 libvlc_media_t * p_md;
497 libvlc_media_list_t * p_subitems;
499 p_input_item = input_item_New( INPUT_ITEM_URI_NOP, psz_name );
501 if (!p_input_item)
503 libvlc_printerr( "Not enough memory" );
504 return NULL;
507 p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
508 input_item_Release( p_input_item );
510 p_subitems = media_get_subitems( p_md, true );
511 if( p_subitems == NULL) {
512 libvlc_media_release( p_md );
513 return NULL;
516 return p_md;
519 /**************************************************************************
520 * Add an option to the media descriptor,
521 * that will be used to determine how the media_player will read the
522 * media. This allow to use VLC advanced reading/streaming
523 * options in a per-media basis
525 * The options are detailled in vlc --long-help, for instance "--sout-all"
526 **************************************************************************/
527 void libvlc_media_add_option( libvlc_media_t * p_md,
528 const char * psz_option )
530 libvlc_media_add_option_flag( p_md, psz_option,
531 VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
534 /**************************************************************************
535 * Same as libvlc_media_add_option but with configurable flags.
536 **************************************************************************/
537 void libvlc_media_add_option_flag( libvlc_media_t * p_md,
538 const char * ppsz_option,
539 unsigned i_flags )
541 input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
544 /**************************************************************************
545 * Delete a media descriptor object
546 **************************************************************************/
547 void libvlc_media_release( libvlc_media_t *p_md )
549 if (!p_md)
550 return;
552 p_md->i_refcount--;
554 if( p_md->i_refcount > 0 )
555 return;
557 uninstall_input_item_observer( p_md );
559 /* Cancel asynchronous parsing (if any) */
560 libvlc_MetadataCancel( p_md->p_libvlc_instance->p_libvlc_int, p_md );
562 if( p_md->p_subitems )
563 libvlc_media_list_release( p_md->p_subitems );
565 input_item_Release( p_md->p_input_item );
567 vlc_cond_destroy( &p_md->parsed_cond );
568 vlc_mutex_destroy( &p_md->parsed_lock );
569 vlc_mutex_destroy( &p_md->subitems_lock );
571 /* Construct the event */
572 libvlc_event_t event;
573 event.type = libvlc_MediaFreed;
574 event.u.media_freed.md = p_md;
576 /* Send the event */
577 libvlc_event_send( &p_md->event_manager, &event );
579 libvlc_event_manager_destroy( &p_md->event_manager );
580 libvlc_release( p_md->p_libvlc_instance );
581 free( p_md );
584 /**************************************************************************
585 * Retain a media descriptor object
586 **************************************************************************/
587 void libvlc_media_retain( libvlc_media_t *p_md )
589 assert (p_md);
590 p_md->i_refcount++;
593 /**************************************************************************
594 * Duplicate a media descriptor object
595 **************************************************************************/
596 libvlc_media_t *
597 libvlc_media_duplicate( libvlc_media_t *p_md_orig )
599 return libvlc_media_new_from_input_item(
600 p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
603 /**************************************************************************
604 * Get mrl from a media descriptor object
605 **************************************************************************/
606 char *
607 libvlc_media_get_mrl( libvlc_media_t * p_md )
609 assert( p_md );
610 return input_item_GetURI( p_md->p_input_item );
613 /**************************************************************************
614 * Getter for meta information
615 **************************************************************************/
617 char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
619 char *psz_meta = NULL;
621 if( e_meta == libvlc_meta_NowPlaying )
623 psz_meta = input_item_GetNowPlayingFb( p_md->p_input_item );
625 else
627 psz_meta = input_item_GetMeta( p_md->p_input_item,
628 libvlc_to_vlc_meta[e_meta] );
629 /* Should be integrated in core */
630 if( psz_meta == NULL && e_meta == libvlc_meta_Title
631 && p_md->p_input_item->psz_name != NULL )
632 psz_meta = strdup( p_md->p_input_item->psz_name );
634 return psz_meta;
637 /**************************************************************************
638 * Setter for meta information
639 **************************************************************************/
641 void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value )
643 assert( p_md );
644 input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value );
647 int libvlc_media_save_meta( libvlc_media_t *p_md )
649 assert( p_md );
650 vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
651 return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
654 /**************************************************************************
655 * Getter for state information
656 * Can be error, playing, buffering, NothingSpecial.
657 **************************************************************************/
659 libvlc_state_t
660 libvlc_media_get_state( libvlc_media_t *p_md )
662 assert( p_md );
663 return p_md->state;
666 /**************************************************************************
667 * Setter for state information (LibVLC Internal)
668 **************************************************************************/
670 void
671 libvlc_media_set_state( libvlc_media_t *p_md,
672 libvlc_state_t state )
674 libvlc_event_t event;
676 p_md->state = state;
678 /* Construct the event */
679 event.type = libvlc_MediaStateChanged;
680 event.u.media_state_changed.new_state = state;
682 /* Send the event */
683 libvlc_event_send( &p_md->event_manager, &event );
686 /**************************************************************************
687 * subitems
688 **************************************************************************/
689 libvlc_media_list_t *
690 libvlc_media_subitems( libvlc_media_t * p_md )
692 libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true );
693 if( p_subitems )
694 libvlc_media_list_retain( p_subitems );
695 return p_subitems;
698 /**************************************************************************
699 * Getter for statistics information
700 **************************************************************************/
701 int libvlc_media_get_stats( libvlc_media_t *p_md,
702 libvlc_media_stats_t *p_stats )
704 input_item_t *item = p_md->p_input_item;
706 if( !p_md->p_input_item )
707 return false;
709 vlc_mutex_lock( &item->lock );
711 input_stats_t *p_itm_stats = p_md->p_input_item->p_stats;
712 if( p_itm_stats == NULL )
714 vlc_mutex_unlock( &item->lock );
715 return false;
718 p_stats->i_read_bytes = p_itm_stats->i_read_bytes;
719 p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate;
721 p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes;
722 p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate;
723 p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted;
724 p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity;
726 p_stats->i_decoded_video = p_itm_stats->i_decoded_video;
727 p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio;
729 p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures;
730 p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures;
732 p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers;
733 p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers;
735 p_stats->i_sent_packets = 0;
736 p_stats->i_sent_bytes = 0;
737 p_stats->f_send_bitrate = 0.;
739 vlc_mutex_unlock( &item->lock );
740 return true;
743 /**************************************************************************
744 * event_manager
745 **************************************************************************/
746 libvlc_event_manager_t *
747 libvlc_media_event_manager( libvlc_media_t * p_md )
749 assert( p_md );
751 return &p_md->event_manager;
754 /**************************************************************************
755 * Get duration of media object (in ms)
756 **************************************************************************/
757 int64_t
758 libvlc_media_get_duration( libvlc_media_t * p_md )
760 assert( p_md );
762 if( !p_md->p_input_item )
764 libvlc_printerr( "No input item" );
765 return -1;
768 if (!input_item_IsPreparsed( p_md->p_input_item ))
769 return -1;
771 return from_mtime(input_item_GetDuration( p_md->p_input_item ));
774 static const input_preparser_callbacks_t input_preparser_callbacks = {
775 .on_preparse_ended = input_item_preparse_ended,
776 .on_subtree_added = input_item_subtree_added,
779 static int media_parse(libvlc_media_t *media, bool b_async,
780 libvlc_media_parse_flag_t parse_flag, int timeout)
782 bool needed;
784 vlc_mutex_lock(&media->parsed_lock);
785 needed = !media->has_asked_preparse;
786 media->has_asked_preparse = true;
787 if (needed)
788 media->is_parsed = false;
789 vlc_mutex_unlock(&media->parsed_lock);
791 if (needed)
793 libvlc_int_t *libvlc = media->p_libvlc_instance->p_libvlc_int;
794 input_item_t *item = media->p_input_item;
795 input_item_meta_request_option_t parse_scope = META_REQUEST_OPTION_SCOPE_LOCAL;
796 int ret;
798 /* Ignore libvlc_media_fetch_local flag since local art will be fetched
799 * by libvlc_MetadataRequest */
800 if (parse_flag & libvlc_media_fetch_network)
802 ret = libvlc_ArtRequest(libvlc, item,
803 META_REQUEST_OPTION_SCOPE_NETWORK,
804 NULL, NULL);
805 if (ret != VLC_SUCCESS)
806 return ret;
809 if (parse_flag & libvlc_media_parse_network)
810 parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
811 if (parse_flag & libvlc_media_do_interact)
812 parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
813 ret = libvlc_MetadataRequest(libvlc, item, parse_scope, &input_preparser_callbacks, media, timeout, media);
814 if (ret != VLC_SUCCESS)
815 return ret;
817 else
818 return VLC_EGENERIC;
820 if (!b_async)
822 vlc_mutex_lock(&media->parsed_lock);
823 while (!media->is_parsed)
824 vlc_cond_wait(&media->parsed_cond, &media->parsed_lock);
825 vlc_mutex_unlock(&media->parsed_lock);
827 return VLC_SUCCESS;
830 /**************************************************************************
831 * Parse the media and wait.
832 **************************************************************************/
833 void
834 libvlc_media_parse(libvlc_media_t *media)
836 media_parse( media, false, libvlc_media_fetch_local, -1 );
839 /**************************************************************************
840 * Parse the media but do not wait.
841 **************************************************************************/
842 void
843 libvlc_media_parse_async(libvlc_media_t *media)
845 media_parse( media, true, libvlc_media_fetch_local, -1 );
848 /**************************************************************************
849 * Parse the media asynchronously with options.
850 **************************************************************************/
852 libvlc_media_parse_with_options( libvlc_media_t *media,
853 libvlc_media_parse_flag_t parse_flag,
854 int timeout )
856 return media_parse( media, true, parse_flag, timeout ) == VLC_SUCCESS ? 0 : -1;
859 void
860 libvlc_media_parse_stop( libvlc_media_t *media )
862 libvlc_MetadataCancel( media->p_libvlc_instance->p_libvlc_int, media );
865 /**************************************************************************
866 * Get parsed status for media object.
867 **************************************************************************/
869 libvlc_media_is_parsed(libvlc_media_t *media)
871 bool parsed;
873 vlc_mutex_lock(&media->parsed_lock);
874 parsed = media->is_parsed;
875 vlc_mutex_unlock(&media->parsed_lock);
876 return parsed;
879 libvlc_media_parsed_status_t
880 libvlc_media_get_parsed_status(libvlc_media_t *media)
882 libvlc_media_parsed_status_t status;
884 vlc_mutex_lock(&media->parsed_lock);
885 status = media->parsed_status;
886 vlc_mutex_unlock(&media->parsed_lock);
887 return status;
890 /**************************************************************************
891 * Sets media descriptor's user_data. user_data is specialized data
892 * accessed by the host application, VLC.framework uses it as a pointer to
893 * an native object that references a libvlc_media_t pointer
894 **************************************************************************/
895 void
896 libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
898 assert( p_md );
899 p_md->p_user_data = p_new_user_data;
902 /**************************************************************************
903 * Get media descriptor's user_data. user_data is specialized data
904 * accessed by the host application, VLC.framework uses it as a pointer to
905 * an native object that references a libvlc_media_t pointer
906 **************************************************************************/
907 void *
908 libvlc_media_get_user_data( libvlc_media_t * p_md )
910 assert( p_md );
911 return p_md->p_user_data;
914 unsigned
915 libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es )
917 assert( p_md );
919 input_item_t *p_input_item = p_md->p_input_item;
920 vlc_mutex_lock( &p_input_item->lock );
922 const int i_es = p_input_item->i_es;
923 *pp_es = (i_es > 0) ? calloc( i_es, sizeof(**pp_es) ) : NULL;
925 if( !*pp_es ) /* no ES, or OOM */
927 vlc_mutex_unlock( &p_input_item->lock );
928 return 0;
931 /* Fill array */
932 for( int i = 0; i < i_es; i++ )
934 libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) );
935 if ( p_mes )
937 p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio),
938 sizeof(*p_mes->video)),
939 sizeof(*p_mes->subtitle)) );
941 if ( !p_mes || !p_mes->audio )
943 libvlc_media_tracks_release( *pp_es, i_es );
944 *pp_es = NULL;
945 free( p_mes );
946 vlc_mutex_unlock( &p_input_item->lock );
947 return 0;
949 (*pp_es)[i] = p_mes;
951 const es_format_t *p_es = p_input_item->es[i];
953 p_mes->i_codec = p_es->i_codec;
954 p_mes->i_original_fourcc = p_es->i_original_fourcc;
955 p_mes->i_id = p_es->i_id;
957 p_mes->i_profile = p_es->i_profile;
958 p_mes->i_level = p_es->i_level;
960 p_mes->i_bitrate = p_es->i_bitrate;
961 p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL;
962 p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL;
964 switch(p_es->i_cat)
966 case UNKNOWN_ES:
967 default:
968 p_mes->i_type = libvlc_track_unknown;
969 break;
970 case VIDEO_ES:
971 p_mes->i_type = libvlc_track_video;
972 p_mes->video->i_height = p_es->video.i_visible_height;
973 p_mes->video->i_width = p_es->video.i_visible_width;
974 p_mes->video->i_sar_num = p_es->video.i_sar_num;
975 p_mes->video->i_sar_den = p_es->video.i_sar_den;
976 p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate;
977 p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base;
979 assert( p_es->video.orientation >= ORIENT_TOP_LEFT &&
980 p_es->video.orientation <= ORIENT_RIGHT_BOTTOM );
981 p_mes->video->i_orientation = (int) p_es->video.orientation;
983 assert( ( p_es->video.projection_mode >= PROJECTION_MODE_RECTANGULAR &&
984 p_es->video.projection_mode <= PROJECTION_MODE_EQUIRECTANGULAR ) ||
985 ( p_es->video.projection_mode == PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD ) );
986 p_mes->video->i_projection = (int) p_es->video.projection_mode;
988 p_mes->video->pose.f_yaw = p_es->video.pose.yaw;
989 p_mes->video->pose.f_pitch = p_es->video.pose.pitch;
990 p_mes->video->pose.f_roll = p_es->video.pose.roll;
991 p_mes->video->pose.f_field_of_view = p_es->video.pose.fov;
993 assert( p_es->video.multiview_mode >= MULTIVIEW_2D &&
994 p_es->video.multiview_mode <= MULTIVIEW_STEREO_CHECKERBOARD );
995 p_mes->video->i_multiview = (int) p_es->video.multiview_mode;
996 break;
997 case AUDIO_ES:
998 p_mes->i_type = libvlc_track_audio;
999 p_mes->audio->i_channels = p_es->audio.i_channels;
1000 p_mes->audio->i_rate = p_es->audio.i_rate;
1001 break;
1002 case SPU_ES:
1003 p_mes->i_type = libvlc_track_text;
1004 p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ?
1005 strdup(p_es->subs.psz_encoding) : NULL;
1006 break;
1010 vlc_mutex_unlock( &p_input_item->lock );
1011 return i_es;
1014 /**************************************************************************
1015 * Get codec description from media elementary stream
1016 **************************************************************************/
1017 const char *
1018 libvlc_media_get_codec_description( libvlc_track_type_t i_type,
1019 uint32_t i_codec )
1021 switch( i_type )
1023 case libvlc_track_audio:
1024 return vlc_fourcc_GetDescription( AUDIO_ES, i_codec );
1025 case libvlc_track_video:
1026 return vlc_fourcc_GetDescription( VIDEO_ES, i_codec );
1027 case libvlc_track_text:
1028 return vlc_fourcc_GetDescription( SPU_ES, i_codec );
1029 case libvlc_track_unknown:
1030 default:
1031 return vlc_fourcc_GetDescription( UNKNOWN_ES, i_codec );
1035 /**************************************************************************
1036 * Release media descriptor's elementary streams description array
1037 **************************************************************************/
1038 void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
1040 for( unsigned i = 0; i < i_count; ++i )
1042 if ( !p_tracks[i] )
1043 continue;
1044 free( p_tracks[i]->psz_language );
1045 free( p_tracks[i]->psz_description );
1046 switch( p_tracks[i]->i_type )
1048 case libvlc_track_audio:
1049 break;
1050 case libvlc_track_video:
1051 break;
1052 case libvlc_track_text:
1053 free( p_tracks[i]->subtitle->psz_encoding );
1054 break;
1055 case libvlc_track_unknown:
1056 default:
1057 break;
1059 free( p_tracks[i]->audio );
1060 free( p_tracks[i] );
1062 free( p_tracks );
1065 /**************************************************************************
1066 * Get the media type of the media descriptor object
1067 **************************************************************************/
1068 libvlc_media_type_t libvlc_media_get_type( libvlc_media_t *p_md )
1070 assert( p_md );
1072 enum input_item_type_e i_type;
1073 input_item_t *p_input_item = p_md->p_input_item;
1075 vlc_mutex_lock( &p_input_item->lock );
1076 i_type = p_md->p_input_item->i_type;
1077 vlc_mutex_unlock( &p_input_item->lock );
1079 switch( i_type )
1081 case ITEM_TYPE_FILE:
1082 return libvlc_media_type_file;
1083 case ITEM_TYPE_NODE:
1084 case ITEM_TYPE_DIRECTORY:
1085 return libvlc_media_type_directory;
1086 case ITEM_TYPE_DISC:
1087 return libvlc_media_type_disc;
1088 case ITEM_TYPE_STREAM:
1089 return libvlc_media_type_stream;
1090 case ITEM_TYPE_PLAYLIST:
1091 return libvlc_media_type_playlist;
1092 default:
1093 return libvlc_media_type_unknown;
1097 struct libvlc_media_thumbnail_request_t
1099 libvlc_media_t *md;
1100 unsigned int width;
1101 unsigned int height;
1102 libvlc_picture_type_t type;
1103 vlc_thumbnailer_request_t* req;
1106 static void media_on_thumbnail_ready( void* data, picture_t* thumbnail )
1108 libvlc_media_thumbnail_request_t *req = data;
1109 libvlc_media_t *p_media = req->md;
1110 libvlc_event_t event;
1111 event.type = libvlc_MediaThumbnailGenerated;
1112 libvlc_picture_t* pic = NULL;
1113 if ( thumbnail != NULL )
1114 pic = libvlc_picture_new( VLC_OBJECT(p_media->p_libvlc_instance->p_libvlc_int),
1115 thumbnail, req->type, req->width, req->height );
1116 event.u.media_thumbnail_generated.p_thumbnail = pic;
1117 libvlc_event_send( &p_media->event_manager, &event );
1118 if ( pic != NULL )
1119 libvlc_picture_release( pic );
1120 libvlc_media_release( p_media );
1121 free( req );
1124 libvlc_media_thumbnail_request_t*
1125 libvlc_media_thumbnail_request_by_time( libvlc_media_t *md, libvlc_time_t time,
1126 libvlc_thumbnailer_seek_speed_t speed,
1127 unsigned int width, unsigned int height,
1128 libvlc_picture_type_t picture_type,
1129 libvlc_time_t timeout )
1131 assert( md );
1132 libvlc_priv_t *p_priv = libvlc_priv(md->p_libvlc_instance->p_libvlc_int);
1133 if( unlikely( p_priv->p_thumbnailer == NULL ) )
1134 return NULL;
1135 libvlc_media_thumbnail_request_t *req = malloc( sizeof( *req ) );
1136 if ( unlikely( req == NULL ) )
1137 return NULL;
1139 req->md = md;
1140 req->width = width;
1141 req->height = height;
1142 req->type = picture_type;
1143 libvlc_media_retain( md );
1144 req->req = vlc_thumbnailer_RequestByTime( p_priv->p_thumbnailer,
1145 VLC_TICK_FROM_MS( time ),
1146 speed == libvlc_media_thumbnail_seek_fast ?
1147 VLC_THUMBNAILER_SEEK_FAST : VLC_THUMBNAILER_SEEK_PRECISE,
1148 md->p_input_item,
1149 timeout > 0 ? VLC_TICK_FROM_MS( timeout ) : VLC_TICK_INVALID,
1150 media_on_thumbnail_ready, req );
1151 if ( req->req == NULL )
1153 free( req );
1154 libvlc_media_release( md );
1155 return NULL;
1157 return req;
1160 libvlc_media_thumbnail_request_t*
1161 libvlc_media_thumbnail_request_by_pos( libvlc_media_t *md, float pos,
1162 libvlc_thumbnailer_seek_speed_t speed,
1163 unsigned int width, unsigned int height,
1164 libvlc_picture_type_t picture_type,
1165 libvlc_time_t timeout )
1167 assert( md );
1168 libvlc_priv_t *priv = libvlc_priv(md->p_libvlc_instance->p_libvlc_int);
1169 if( unlikely( priv->p_thumbnailer == NULL ) )
1170 return NULL;
1171 libvlc_media_thumbnail_request_t *req = malloc( sizeof( *req ) );
1172 if ( unlikely( req == NULL ) )
1173 return NULL;
1175 req->md = md;
1176 req->width = width;
1177 req->height = height;
1178 req->type = picture_type;
1179 libvlc_media_retain( md );
1180 req->req = vlc_thumbnailer_RequestByPos( priv->p_thumbnailer, pos,
1181 speed == libvlc_media_thumbnail_seek_fast ?
1182 VLC_THUMBNAILER_SEEK_FAST : VLC_THUMBNAILER_SEEK_PRECISE,
1183 md->p_input_item,
1184 timeout > 0 ? VLC_TICK_FROM_MS( timeout ) : VLC_TICK_INVALID,
1185 media_on_thumbnail_ready, req );
1186 if ( req->req == NULL )
1188 free( req );
1189 libvlc_media_release( md );
1190 return NULL;
1192 return req;
1195 void libvlc_media_thumbnail_cancel( libvlc_media_thumbnail_request_t *req )
1197 libvlc_priv_t *p_priv = libvlc_priv(req->md->p_libvlc_instance->p_libvlc_int);
1198 assert( p_priv->p_thumbnailer != NULL );
1199 vlc_thumbnailer_Cancel( p_priv->p_thumbnailer, req->req );
1200 libvlc_media_release( req->md );
1201 free( req );
1204 int libvlc_media_slaves_add( libvlc_media_t *p_md,
1205 libvlc_media_slave_type_t i_type,
1206 unsigned int i_priority,
1207 const char *psz_uri )
1209 assert( p_md && psz_uri );
1210 input_item_t *p_input_item = p_md->p_input_item;
1212 enum slave_type i_input_slave_type;
1213 switch( i_type )
1215 case libvlc_media_slave_type_subtitle:
1216 i_input_slave_type = SLAVE_TYPE_SPU;
1217 break;
1218 case libvlc_media_slave_type_audio:
1219 i_input_slave_type = SLAVE_TYPE_AUDIO;
1220 break;
1221 default:
1222 vlc_assert_unreachable();
1223 return -1;
1226 enum slave_priority i_input_slave_priority;
1227 switch( i_priority )
1229 case 0:
1230 i_input_slave_priority = SLAVE_PRIORITY_MATCH_NONE;
1231 break;
1232 case 1:
1233 i_input_slave_priority = SLAVE_PRIORITY_MATCH_RIGHT;
1234 break;
1235 case 2:
1236 i_input_slave_priority = SLAVE_PRIORITY_MATCH_LEFT;
1237 break;
1238 case 3:
1239 i_input_slave_priority = SLAVE_PRIORITY_MATCH_ALL;
1240 break;
1241 default:
1242 case 4:
1243 i_input_slave_priority = SLAVE_PRIORITY_USER;
1244 break;
1247 input_item_slave_t *p_slave = input_item_slave_New( psz_uri,
1248 i_input_slave_type,
1249 i_input_slave_priority );
1250 if( p_slave == NULL )
1251 return -1;
1252 return input_item_AddSlave( p_input_item, p_slave ) == VLC_SUCCESS ? 0 : -1;
1255 void libvlc_media_slaves_clear( libvlc_media_t *p_md )
1257 assert( p_md );
1258 input_item_t *p_input_item = p_md->p_input_item;
1260 vlc_mutex_lock( &p_input_item->lock );
1261 for( int i = 0; i < p_input_item->i_slaves; i++ )
1262 input_item_slave_Delete( p_input_item->pp_slaves[i] );
1263 TAB_CLEAN( p_input_item->i_slaves, p_input_item->pp_slaves );
1264 vlc_mutex_unlock( &p_input_item->lock );
1267 unsigned int libvlc_media_slaves_get( libvlc_media_t *p_md,
1268 libvlc_media_slave_t ***ppp_slaves )
1270 assert( p_md && ppp_slaves );
1271 input_item_t *p_input_item = p_md->p_input_item;
1272 *ppp_slaves = NULL;
1274 vlc_mutex_lock( &p_input_item->lock );
1276 int i_count = p_input_item->i_slaves;
1277 if( i_count <= 0 )
1278 return vlc_mutex_unlock( &p_input_item->lock ), 0;
1280 libvlc_media_slave_t **pp_slaves = calloc( i_count, sizeof(*pp_slaves) );
1281 if( pp_slaves == NULL )
1282 return vlc_mutex_unlock( &p_input_item->lock ), 0;
1284 for( int i = 0; i < i_count; ++i )
1286 input_item_slave_t *p_item_slave = p_input_item->pp_slaves[i];
1287 assert( p_item_slave->i_priority >= SLAVE_PRIORITY_MATCH_NONE );
1289 /* also allocate psz_uri buffer at the end of the struct */
1290 libvlc_media_slave_t *p_slave = malloc( sizeof(*p_slave) +
1291 strlen( p_item_slave->psz_uri )
1292 + 1 );
1293 if( p_slave == NULL )
1295 libvlc_media_slaves_release(pp_slaves, i);
1296 return vlc_mutex_unlock( &p_input_item->lock ), 0;
1298 p_slave->psz_uri = (char *) ((uint8_t *)p_slave) + sizeof(*p_slave);
1299 strcpy( p_slave->psz_uri, p_item_slave->psz_uri );
1301 switch( p_item_slave->i_type )
1303 case SLAVE_TYPE_SPU:
1304 p_slave->i_type = libvlc_media_slave_type_subtitle;
1305 break;
1306 case SLAVE_TYPE_AUDIO:
1307 p_slave->i_type = libvlc_media_slave_type_audio;
1308 break;
1309 default:
1310 vlc_assert_unreachable();
1313 switch( p_item_slave->i_priority )
1315 case SLAVE_PRIORITY_MATCH_NONE:
1316 p_slave->i_priority = 0;
1317 break;
1318 case SLAVE_PRIORITY_MATCH_RIGHT:
1319 p_slave->i_priority = 1;
1320 break;
1321 case SLAVE_PRIORITY_MATCH_LEFT:
1322 p_slave->i_priority = 2;
1323 break;
1324 case SLAVE_PRIORITY_MATCH_ALL:
1325 p_slave->i_priority = 3;
1326 break;
1327 case SLAVE_PRIORITY_USER:
1328 p_slave->i_priority = 4;
1329 break;
1330 default:
1331 vlc_assert_unreachable();
1333 pp_slaves[i] = p_slave;
1335 vlc_mutex_unlock( &p_input_item->lock );
1337 *ppp_slaves = pp_slaves;
1338 return i_count;
1341 void libvlc_media_slaves_release( libvlc_media_slave_t **pp_slaves,
1342 unsigned int i_count )
1344 if( i_count > 0 )
1346 assert( pp_slaves );
1347 for( unsigned int i = 0; i < i_count; ++i )
1348 free( pp_slaves[i] );
1350 free( pp_slaves );