X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fcontrol%2Fmedia.c;h=3f39841bd785178383c386cbd6a5f11e6156e822;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=566ce11b24b1a2aac6e4a45531946b00b78378c9;hpb=ad77d955a5dc051976d94d6e08ee0f717ec3a938;p=vlc diff --git a/src/control/media.c b/src/control/media.c index 566ce11b24..3f39841bd7 100644 --- a/src/control/media.c +++ b/src/control/media.c @@ -25,6 +25,8 @@ # include "config.h" #endif +#include + #include #include #include // For the subitems, here for convenience @@ -34,6 +36,7 @@ #include #include #include /* For the preparser */ +#include #include "libvlc.h" @@ -94,17 +97,17 @@ static void input_item_subitem_added( const vlc_event_t *p_event, p_md_child = libvlc_media_new_from_input_item( p_md->p_libvlc_instance, - p_event->u.input_item_subitem_added.p_new_child, NULL ); + p_event->u.input_item_subitem_added.p_new_child ); /* Add this to our media list */ if( !p_md->p_subitems ) { - p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance, NULL ); - libvlc_media_list_set_media( p_md->p_subitems, p_md, NULL ); + p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance ); + libvlc_media_list_set_media( p_md->p_subitems, p_md ); } if( p_md->p_subitems ) { - libvlc_media_list_add_media( p_md->p_subitems, p_md_child, NULL ); + libvlc_media_list_add_media( p_md->p_subitems, p_md_child ); } /* Construct the event */ @@ -145,8 +148,8 @@ static void input_item_duration_changed( const vlc_event_t *p_event, /* Construct the event */ event.type = libvlc_MediaDurationChanged; - event.u.media_duration_changed.new_duration = - p_event->u.input_item_duration_changed.new_duration; + event.u.media_duration_changed.new_duration = + from_mtime(p_event->u.input_item_duration_changed.new_duration); /* Send the event */ libvlc_event_send( p_md->p_event_manager, &event ); @@ -155,19 +158,26 @@ static void input_item_duration_changed( const vlc_event_t *p_event, /************************************************************************** * input_item_preparsed_changed (Private) (vlc event Callback) **************************************************************************/ -static void input_item_preparsed_changed( const vlc_event_t *p_event, - void * user_data ) +static void input_item_preparsed_changed(const vlc_event_t *p_event, + void * user_data) { - libvlc_media_t * p_md = user_data; + libvlc_media_t *media = user_data; libvlc_event_t event; + /* Eventually notify libvlc_media_parse() */ + vlc_mutex_lock(&media->parsed_lock); + media->is_parsed = true; + vlc_cond_broadcast(&media->parsed_cond); + vlc_mutex_unlock(&media->parsed_lock); + + /* Construct the event */ - event.type = libvlc_MediaPreparsedChanged; - event.u.media_preparsed_changed.new_status = + event.type = libvlc_MediaParsedChanged; + event.u.media_parsed_changed.new_status = p_event->u.input_item_preparsed_changed.new_status; /* Send the event */ - libvlc_event_send( p_md->p_event_manager, &event ); + libvlc_event_send(media->p_event_manager, &event); } /************************************************************************** @@ -222,12 +232,12 @@ static void uninstall_input_item_observer( libvlc_media_t *p_md ) static void preparse_if_needed( libvlc_media_t *p_md ) { /* XXX: need some locking here */ - if (!p_md->b_preparsed) + if (!p_md->has_asked_preparse) { playlist_PreparseEnqueue( libvlc_priv (p_md->p_libvlc_instance->p_libvlc_int)->p_playlist, - p_md->p_input_item, pl_Unlocked ); - p_md->b_preparsed = true; + p_md->p_input_item ); + p_md->has_asked_preparse = true; } } @@ -238,29 +248,29 @@ static void preparse_if_needed( libvlc_media_t *p_md ) **************************************************************************/ libvlc_media_t * libvlc_media_new_from_input_item( libvlc_instance_t *p_instance, - input_item_t *p_input_item, - libvlc_exception_t *p_e ) + input_item_t *p_input_item ) { libvlc_media_t * p_md; if (!p_input_item) { - libvlc_exception_raise( p_e, "No input item given" ); + libvlc_printerr( "No input item given" ); return NULL; } - p_md = malloc( sizeof(libvlc_media_t) ); + p_md = calloc( 1, sizeof(libvlc_media_t) ); if( !p_md ) { - libvlc_exception_raise( p_e, "Not enough memory" ); + libvlc_printerr( "Not enough memory" ); return NULL; } p_md->p_libvlc_instance = p_instance; p_md->p_input_item = p_input_item; - p_md->b_preparsed = false; p_md->i_refcount = 1; - p_md->p_user_data = NULL; + + vlc_cond_init(&p_md->parsed_cond); + vlc_mutex_init(&p_md->parsed_lock); p_md->state = libvlc_NothingSpecial; @@ -268,17 +278,20 @@ libvlc_media_t * libvlc_media_new_from_input_item( * It can give a bunch of item to read. */ p_md->p_subitems = NULL; - p_md->p_event_manager = libvlc_event_manager_new( p_md, p_instance, p_e ); - libvlc_event_manager_register_event_type( p_md->p_event_manager, - libvlc_MediaMetaChanged, p_e ); - libvlc_event_manager_register_event_type( p_md->p_event_manager, - libvlc_MediaSubItemAdded, p_e ); - libvlc_event_manager_register_event_type( p_md->p_event_manager, - libvlc_MediaFreed, p_e ); - libvlc_event_manager_register_event_type( p_md->p_event_manager, - libvlc_MediaDurationChanged, p_e ); - libvlc_event_manager_register_event_type( p_md->p_event_manager, - libvlc_MediaStateChanged, p_e ); + p_md->p_event_manager = libvlc_event_manager_new( p_md, p_instance ); + if( unlikely(p_md->p_event_manager == NULL) ) + { + free(p_md); + return NULL; + } + + libvlc_event_manager_t *em = p_md->p_event_manager; + libvlc_event_manager_register_event_type(em, libvlc_MediaMetaChanged); + libvlc_event_manager_register_event_type(em, libvlc_MediaSubItemAdded); + libvlc_event_manager_register_event_type(em, libvlc_MediaFreed); + libvlc_event_manager_register_event_type(em, libvlc_MediaDurationChanged); + libvlc_event_manager_register_event_type(em, libvlc_MediaStateChanged); + libvlc_event_manager_register_event_type(em, libvlc_MediaParsedChanged); vlc_gc_incref( p_md->p_input_item ); @@ -290,10 +303,8 @@ libvlc_media_t * libvlc_media_new_from_input_item( /************************************************************************** * Create a new media descriptor object **************************************************************************/ -libvlc_media_t * libvlc_media_new( - libvlc_instance_t *p_instance, - const char * psz_mrl, - libvlc_exception_t *p_e ) +libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance, + const char * psz_mrl ) { input_item_t * p_input_item; libvlc_media_t * p_md; @@ -302,12 +313,11 @@ libvlc_media_t * libvlc_media_new( if (!p_input_item) { - libvlc_exception_raise( p_e, "Can't create md's input_item" ); + libvlc_printerr( "Not enough memory" ); return NULL; } - p_md = libvlc_media_new_from_input_item( p_instance, - p_input_item, p_e ); + p_md = libvlc_media_new_from_input_item( p_instance, p_input_item ); /* The p_input_item is retained in libvlc_media_new_from_input_item */ vlc_gc_decref( p_input_item ); @@ -315,13 +325,26 @@ libvlc_media_t * libvlc_media_new( return p_md; } +libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance, + const char *path ) +{ + char *mrl = make_URI( path, "file" ); + if( unlikely(mrl == NULL) ) + { + libvlc_printerr( "Not enough memory" ); + return NULL; + } + + libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl ); + free( mrl ); + return m; +} + /************************************************************************** * Create a new media descriptor object **************************************************************************/ -libvlc_media_t * libvlc_media_new_as_node( - libvlc_instance_t *p_instance, - const char * psz_name, - libvlc_exception_t *p_e ) +libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance, + const char * psz_name ) { input_item_t * p_input_item; libvlc_media_t * p_md; @@ -330,14 +353,13 @@ libvlc_media_t * libvlc_media_new_as_node( if (!p_input_item) { - libvlc_exception_raise( p_e, "Can't create md's input_item" ); + libvlc_printerr( "Not enough memory" ); return NULL; } - p_md = libvlc_media_new_from_input_item( p_instance, - p_input_item, p_e ); + p_md = libvlc_media_new_from_input_item( p_instance, p_input_item ); - p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance, NULL ); + p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance ); return p_md; } @@ -350,30 +372,23 @@ libvlc_media_t * libvlc_media_new_as_node( * * The options are detailled in vlc --long-help, for instance "--sout-all" **************************************************************************/ -void libvlc_media_add_option( - libvlc_media_t * p_md, - const char * ppsz_option, - libvlc_exception_t *p_e ) +void libvlc_media_add_option( libvlc_media_t * p_md, + const char * psz_option ) { - VLC_UNUSED(p_e); - input_item_AddOption( p_md->p_input_item, ppsz_option, + libvlc_media_add_option_flag( p_md, psz_option, VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED ); } /************************************************************************** - * Same as libvlc_media_add_option but with untrusted source. + * Same as libvlc_media_add_option but with configurable flags. **************************************************************************/ -void libvlc_media_add_option_untrusted( - libvlc_media_t * p_md, +void libvlc_media_add_option_flag( libvlc_media_t * p_md, const char * ppsz_option, - libvlc_exception_t *p_e ) + unsigned i_flags ) { - VLC_UNUSED(p_e); - input_item_AddOption( p_md->p_input_item, ppsz_option, - VLC_INPUT_OPTION_UNIQUE ); + input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags ); } - /************************************************************************** * Delete a media descriptor object **************************************************************************/ @@ -393,6 +408,9 @@ void libvlc_media_release( libvlc_media_t *p_md ) uninstall_input_item_observer( p_md ); vlc_gc_decref( p_md->p_input_item ); + vlc_cond_destroy( &p_md->parsed_cond ); + vlc_mutex_destroy( &p_md->parsed_lock ); + /* Construct the event */ libvlc_event_t event; event.type = libvlc_MediaFreed; @@ -411,9 +429,7 @@ void libvlc_media_release( libvlc_media_t *p_md ) **************************************************************************/ void libvlc_media_retain( libvlc_media_t *p_md ) { - if (!p_md) - return; - + assert (p_md); p_md->i_refcount++; } @@ -424,17 +440,16 @@ libvlc_media_t * libvlc_media_duplicate( libvlc_media_t *p_md_orig ) { return libvlc_media_new_from_input_item( - p_md_orig->p_libvlc_instance, p_md_orig->p_input_item, NULL ); + p_md_orig->p_libvlc_instance, p_md_orig->p_input_item ); } /************************************************************************** * Get mrl from a media descriptor object **************************************************************************/ char * -libvlc_media_get_mrl( libvlc_media_t * p_md, - libvlc_exception_t * p_e ) +libvlc_media_get_mrl( libvlc_media_t * p_md ) { - VLC_UNUSED(p_e); + assert( p_md ); return input_item_GetURI( p_md->p_input_item ); } @@ -442,13 +457,11 @@ libvlc_media_get_mrl( libvlc_media_t * p_md, * Getter for meta information **************************************************************************/ -char * libvlc_media_get_meta( libvlc_media_t *p_md, - libvlc_meta_t e_meta, - libvlc_exception_t *p_e ) +char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta ) { char * psz_meta; - VLC_UNUSED(p_e); + assert( p_md ); /* XXX: locking */ preparse_if_needed( p_md ); @@ -456,11 +469,12 @@ char * libvlc_media_get_meta( libvlc_media_t *p_md, psz_meta = input_item_GetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta] ); - if( e_meta == libvlc_meta_ArtworkURL && !psz_meta ) + if( e_meta == libvlc_meta_ArtworkURL && !psz_meta && !p_md->has_asked_art ) { + p_md->has_asked_art = true; playlist_AskForArtEnqueue( libvlc_priv(p_md->p_libvlc_instance->p_libvlc_int)->p_playlist, - p_md->p_input_item, pl_Unlocked ); + p_md->p_input_item ); } /* Should be integrated in core */ @@ -473,16 +487,33 @@ char * libvlc_media_get_meta( libvlc_media_t *p_md, return psz_meta; } +/************************************************************************** + * Setter for meta information + **************************************************************************/ + +void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value ) +{ + assert( p_md ); + input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value ); +} + +int libvlc_media_save_meta( libvlc_media_t *p_md ) +{ + assert( p_md ); + vlc_object_t *p_obj = VLC_OBJECT(libvlc_priv( + p_md->p_libvlc_instance->p_libvlc_int)->p_playlist); + return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS; +} + /************************************************************************** * Getter for state information * Can be error, playing, buffering, NothingSpecial. **************************************************************************/ libvlc_state_t -libvlc_media_get_state( libvlc_media_t *p_md, - libvlc_exception_t *p_e ) +libvlc_media_get_state( libvlc_media_t *p_md ) { - VLC_UNUSED(p_e); + assert( p_md ); return p_md->state; } @@ -492,11 +523,9 @@ libvlc_media_get_state( libvlc_media_t *p_md, void libvlc_media_set_state( libvlc_media_t *p_md, - libvlc_state_t state, - libvlc_exception_t *p_e ) + libvlc_state_t state ) { libvlc_event_t event; - VLC_UNUSED(p_e); p_md->state = state; @@ -512,99 +541,196 @@ libvlc_media_set_state( libvlc_media_t *p_md, * subitems **************************************************************************/ libvlc_media_list_t * -libvlc_media_subitems( libvlc_media_t * p_md, - libvlc_exception_t * p_e ) +libvlc_media_subitems( libvlc_media_t * p_md ) { - VLC_UNUSED(p_e); - if( p_md->p_subitems ) libvlc_media_list_retain( p_md->p_subitems ); return p_md->p_subitems; } +/************************************************************************** + * Getter for statistics information + **************************************************************************/ +int libvlc_media_get_stats( libvlc_media_t *p_md, + libvlc_media_stats_t *p_stats ) +{ + if( !p_md->p_input_item ) + return false; + + input_stats_t *p_itm_stats = p_md->p_input_item->p_stats; + vlc_mutex_lock( &p_itm_stats->lock ); + p_stats->i_read_bytes = p_itm_stats->i_read_bytes; + p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate; + + p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes; + p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate; + p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted; + p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity; + + p_stats->i_decoded_video = p_itm_stats->i_decoded_video; + p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio; + + p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures; + p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures; + + p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers; + p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers; + + p_stats->i_sent_packets = p_itm_stats->i_sent_packets; + p_stats->i_sent_bytes = p_itm_stats->i_sent_bytes; + p_stats->f_send_bitrate = p_itm_stats->f_send_bitrate; + vlc_mutex_unlock( &p_itm_stats->lock ); + return true; +} + /************************************************************************** * event_manager **************************************************************************/ libvlc_event_manager_t * -libvlc_media_event_manager( libvlc_media_t * p_md, - libvlc_exception_t * p_e ) +libvlc_media_event_manager( libvlc_media_t * p_md ) { - VLC_UNUSED(p_e); + assert( p_md ); return p_md->p_event_manager; } /************************************************************************** - * Get duration of media object. + * Get duration of media object (in ms) **************************************************************************/ int64_t -libvlc_media_get_duration( libvlc_media_t * p_md, - libvlc_exception_t * p_e ) +libvlc_media_get_duration( libvlc_media_t * p_md ) { - VLC_UNUSED(p_e); + assert( p_md ); - if( !p_md || !p_md->p_input_item) + if( !p_md->p_input_item ) { - libvlc_exception_raise( p_e, "No input item" ); + libvlc_printerr( "No input item" ); return -1; } - return input_item_GetDuration( p_md->p_input_item ); + preparse_if_needed( p_md ); + + if (!input_item_IsPreparsed( p_md->p_input_item )) + return -1; + + return from_mtime(input_item_GetDuration( p_md->p_input_item )); +} + +/************************************************************************** + * Parse the media. + **************************************************************************/ +void +libvlc_media_parse(libvlc_media_t *media) +{ + preparse_if_needed(media); + + vlc_mutex_lock(&media->parsed_lock); + while (!media->is_parsed) + vlc_cond_wait(&media->parsed_cond, &media->parsed_lock); + vlc_mutex_unlock(&media->parsed_lock); +} + +/************************************************************************** + * Parse the media. + **************************************************************************/ +void +libvlc_media_parse_async(libvlc_media_t *media) +{ + preparse_if_needed(media); } /************************************************************************** - * Get preparsed status for media object. + * Get parsed status for media object. **************************************************************************/ int -libvlc_media_is_preparsed( libvlc_media_t * p_md, - libvlc_exception_t * p_e ) +libvlc_media_is_parsed( libvlc_media_t * p_md ) { - VLC_UNUSED(p_e); + assert( p_md ); - if( !p_md || !p_md->p_input_item) - { - libvlc_exception_raise( p_e, "No input item" ); + if( !p_md->p_input_item ) return false; - } return input_item_IsPreparsed( p_md->p_input_item ); } /************************************************************************** - * Sets media descriptor's user_data. user_data is specialized data - * accessed by the host application, VLC.framework uses it as a pointer to + * Sets media descriptor's user_data. user_data is specialized data + * accessed by the host application, VLC.framework uses it as a pointer to * an native object that references a libvlc_media_t pointer **************************************************************************/ -void -libvlc_media_set_user_data( libvlc_media_t * p_md, - void * p_new_user_data, - libvlc_exception_t * p_e ) +void +libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data ) { - VLC_UNUSED(p_e); - - if( p_md ) - { - p_md->p_user_data = p_new_user_data; - } + assert( p_md ); + p_md->p_user_data = p_new_user_data; } /************************************************************************** - * Get media descriptor's user_data. user_data is specialized data - * accessed by the host application, VLC.framework uses it as a pointer to + * Get media descriptor's user_data. user_data is specialized data + * accessed by the host application, VLC.framework uses it as a pointer to * an native object that references a libvlc_media_t pointer **************************************************************************/ void * -libvlc_media_get_user_data( libvlc_media_t * p_md, - libvlc_exception_t * p_e ) +libvlc_media_get_user_data( libvlc_media_t * p_md ) +{ + assert( p_md ); + return p_md->p_user_data; +} + +/************************************************************************** + * Get media descriptor's elementary streams description + **************************************************************************/ +int +libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es ) { - VLC_UNUSED(p_e); + assert( p_md ); - if( p_md ) + input_item_t *p_input_item = p_md->p_input_item; + vlc_mutex_lock( &p_input_item->lock ); + + const int i_es = p_input_item->i_es; + *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL; + + if( !pp_es ) /* no ES, or OOM */ { - return p_md->p_user_data; + vlc_mutex_unlock( &p_input_item->lock ); + return 0; } - else + + /* Fill array */ + for( int i = 0; i < i_es; i++ ) { - return NULL; + libvlc_media_track_info_t *p_mes = *pp_es+i; + const es_format_t *p_es = p_input_item->es[i]; + + p_mes->i_codec = p_es->i_codec; + p_mes->i_id = p_es->i_id; + + p_mes->i_profile = p_es->i_profile; + p_mes->i_level = p_es->i_level; + + switch(p_es->i_cat) + { + case UNKNOWN_ES: + default: + p_mes->i_type = libvlc_track_unknown; + break; + case VIDEO_ES: + p_mes->i_type = libvlc_track_video; + p_mes->u.video.i_height = p_es->video.i_height; + p_mes->u.video.i_width = p_es->video.i_width; + break; + case AUDIO_ES: + p_mes->i_type = libvlc_track_audio; + p_mes->u.audio.i_channels = p_es->audio.i_channels; + p_mes->u.audio.i_rate = p_es->audio.i_rate; + break; + case SPU_ES: + p_mes->i_type = libvlc_track_text; + break; + } } + + vlc_mutex_unlock( &p_input_item->lock ); + return i_es; }