X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=lib%2Fmedia.c;h=1d01c11c425a60a050c891bc9321cffe9d4ed63a;hb=f3cc5c9f0f1512eb0a69ec4a080bebc609b3645c;hp=afafdff963e04a22d1c221d0ec3df13847cc3398;hpb=33dfab3c2119f7121288c091a7b82cac40a8a5f9;p=vlc diff --git a/lib/media.c b/lib/media.c index afafdff963..1d01c11c42 100644 --- a/lib/media.c +++ b/lib/media.c @@ -26,6 +26,7 @@ #endif #include +#include #include #include @@ -42,6 +43,7 @@ #include "libvlc_internal.h" #include "media_internal.h" +#include "media_list_internal.h" static const vlc_meta_type_t libvlc_to_vlc_meta[] = { @@ -61,7 +63,15 @@ static const vlc_meta_type_t libvlc_to_vlc_meta[] = [libvlc_meta_Publisher] = vlc_meta_Publisher, [libvlc_meta_EncodedBy] = vlc_meta_EncodedBy, [libvlc_meta_ArtworkURL] = vlc_meta_ArtworkURL, - [libvlc_meta_TrackID] = vlc_meta_TrackID + [libvlc_meta_TrackID] = vlc_meta_TrackID, + [libvlc_meta_TrackTotal] = vlc_meta_TrackTotal, + [libvlc_meta_Director] = vlc_meta_Director, + [libvlc_meta_Season] = vlc_meta_Season, + [libvlc_meta_Episode] = vlc_meta_Episode, + [libvlc_meta_ShowName] = vlc_meta_ShowName, + [libvlc_meta_Actors] = vlc_meta_Actors, + [libvlc_meta_AlbumArtist] = vlc_meta_AlbumArtist, + [libvlc_meta_DiscNumber] = vlc_meta_DiscNumber }; static const libvlc_meta_t vlc_to_libvlc_meta[] = @@ -79,12 +89,41 @@ static const libvlc_meta_t vlc_to_libvlc_meta[] = [vlc_meta_URL] = libvlc_meta_URL, [vlc_meta_Language] = libvlc_meta_Language, [vlc_meta_NowPlaying] = libvlc_meta_NowPlaying, + [vlc_meta_ESNowPlaying] = libvlc_meta_NowPlaying, [vlc_meta_Publisher] = libvlc_meta_Publisher, [vlc_meta_EncodedBy] = libvlc_meta_EncodedBy, [vlc_meta_ArtworkURL] = libvlc_meta_ArtworkURL, - [vlc_meta_TrackID] = libvlc_meta_TrackID + [vlc_meta_TrackID] = libvlc_meta_TrackID, + [vlc_meta_TrackTotal] = libvlc_meta_TrackTotal, + [vlc_meta_Director] = libvlc_meta_Director, + [vlc_meta_Season] = libvlc_meta_Season, + [vlc_meta_Episode] = libvlc_meta_Episode, + [vlc_meta_ShowName] = libvlc_meta_ShowName, + [vlc_meta_Actors] = libvlc_meta_Actors, + [vlc_meta_AlbumArtist] = libvlc_meta_AlbumArtist, + [vlc_meta_DiscNumber] = libvlc_meta_DiscNumber }; +static libvlc_media_list_t *media_get_subitems( libvlc_media_t * p_md, + bool b_create ) +{ + libvlc_media_list_t *p_subitems = NULL; + + vlc_mutex_lock( &p_md->subitems_lock ); + if( p_md->p_subitems == NULL && b_create ) + { + p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance ); + if( p_md->p_subitems != NULL ) + { + p_md->p_subitems->b_read_only = true; + p_md->p_subitems->p_internal_md = p_md; + } + } + p_subitems = p_md->p_subitems; + vlc_mutex_unlock( &p_md->subitems_lock ); + return p_subitems; +} + /************************************************************************** * input_item_subitem_added (Private) (vlc event Callback) **************************************************************************/ @@ -93,6 +132,7 @@ static void input_item_subitem_added( const vlc_event_t *p_event, { libvlc_media_t * p_md = user_data; libvlc_media_t * p_md_child; + libvlc_media_list_t *p_subitems; libvlc_event_t event; p_md_child = libvlc_media_new_from_input_item( @@ -100,14 +140,12 @@ static void input_item_subitem_added( const vlc_event_t *p_event, 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 ); - libvlc_media_list_set_media( p_md->p_subitems, p_md ); - } - if( p_md->p_subitems ) + p_subitems = media_get_subitems( p_md, true ); + if( p_subitems != NULL ) { - libvlc_media_list_add_media( p_md->p_subitems, p_md_child ); + libvlc_media_list_lock( p_subitems ); + libvlc_media_list_internal_add_media( p_subitems, p_md_child ); + libvlc_media_list_unlock( p_subitems ); } /* Construct the event */ @@ -119,6 +157,24 @@ static void input_item_subitem_added( const vlc_event_t *p_event, libvlc_media_release( p_md_child ); } +/************************************************************************** + * input_item_subitemtree_added (Private) (vlc event Callback) + **************************************************************************/ +static void input_item_subitemtree_added( const vlc_event_t * p_event, + void * user_data ) +{ + VLC_UNUSED( p_event ); + libvlc_media_t * p_md = user_data; + libvlc_event_t event; + + /* Construct the event */ + event.type = libvlc_MediaSubItemTreeAdded; + event.u.media_subitemtree_added.item = p_md; + + /* Send the event */ + libvlc_event_send( p_md->p_event_manager, &event ); +} + /************************************************************************** * input_item_meta_changed (Private) (vlc event Callback) **************************************************************************/ @@ -180,6 +236,25 @@ static void input_item_preparsed_changed(const vlc_event_t *p_event, libvlc_event_send(media->p_event_manager, &event); } +/************************************************************************** + * input_item_preparse_ended (Private) (vlc event Callback) + **************************************************************************/ +static void input_item_preparse_ended( const vlc_event_t * p_event, + void * user_data ) +{ + VLC_UNUSED( p_event ); + libvlc_media_t * p_md = user_data; + libvlc_media_list_t *p_subitems = media_get_subitems( p_md, false ); + + if( p_subitems != NULL ) + { + /* notify the media list */ + libvlc_media_list_lock( p_subitems ); + libvlc_media_list_internal_end_reached( p_subitems ); + libvlc_media_list_unlock( p_subitems ); + } +} + /************************************************************************** * Install event handler (Private) **************************************************************************/ @@ -201,6 +276,14 @@ static void install_input_item_observer( libvlc_media_t *p_md ) vlc_InputItemPreparsedChanged, input_item_preparsed_changed, p_md ); + vlc_event_attach( &p_md->p_input_item->event_manager, + vlc_InputItemSubItemTreeAdded, + input_item_subitemtree_added, + p_md ); + vlc_event_attach( &p_md->p_input_item->event_manager, + vlc_InputItemPreparseEnded, + input_item_preparse_ended, + p_md ); } /************************************************************************** @@ -224,6 +307,14 @@ static void uninstall_input_item_observer( libvlc_media_t *p_md ) vlc_InputItemPreparsedChanged, input_item_preparsed_changed, p_md ); + vlc_event_detach( &p_md->p_input_item->event_manager, + vlc_InputItemSubItemTreeAdded, + input_item_subitemtree_added, + p_md ); + vlc_event_detach( &p_md->p_input_item->event_manager, + vlc_InputItemPreparseEnded, + input_item_preparse_ended, + p_md ); } /************************************************************************** @@ -256,6 +347,7 @@ libvlc_media_t * libvlc_media_new_from_input_item( vlc_cond_init(&p_md->parsed_cond); vlc_mutex_init(&p_md->parsed_lock); + vlc_mutex_init(&p_md->subitems_lock); p_md->state = libvlc_NothingSpecial; @@ -277,6 +369,7 @@ libvlc_media_t * libvlc_media_new_from_input_item( 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); + libvlc_event_manager_register_event_type(em, libvlc_MediaSubItemTreeAdded); vlc_gc_incref( p_md->p_input_item ); @@ -313,10 +406,10 @@ libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance, libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance, const char *path ) { - char *mrl = vlc_path2uri( path, "file" ); + char *mrl = vlc_path2uri( path, NULL ); if( unlikely(mrl == NULL) ) { - libvlc_printerr( "Not enough memory" ); + libvlc_printerr( "%s", vlc_strerror_c(errno) ); return NULL; } @@ -341,6 +434,7 @@ libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance, { input_item_t * p_input_item; libvlc_media_t * p_md; + libvlc_media_list_t * p_subitems; p_input_item = input_item_New( "vlc://nop", psz_name ); @@ -352,7 +446,11 @@ libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance, 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 ); + p_subitems = media_get_subitems( p_md, true ); + if( p_subitems == NULL) { + libvlc_media_release( p_md ); + return NULL; + } return p_md; } @@ -403,6 +501,7 @@ void libvlc_media_release( libvlc_media_t *p_md ) vlc_cond_destroy( &p_md->parsed_cond ); vlc_mutex_destroy( &p_md->parsed_lock ); + vlc_mutex_destroy( &p_md->subitems_lock ); /* Construct the event */ libvlc_event_t event; @@ -452,13 +551,21 @@ libvlc_media_get_mrl( libvlc_media_t * p_md ) char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta ) { - char *psz_meta = input_item_GetMeta( p_md->p_input_item, - libvlc_to_vlc_meta[e_meta] ); - /* Should be integrated in core */ - if( psz_meta == NULL && e_meta == libvlc_meta_Title - && p_md->p_input_item->psz_name != NULL ) - psz_meta = strdup( p_md->p_input_item->psz_name ); + char *psz_meta = NULL; + if( e_meta == libvlc_meta_NowPlaying ) + { + psz_meta = input_item_GetNowPlayingFb( p_md->p_input_item ); + } + else + { + psz_meta = input_item_GetMeta( p_md->p_input_item, + libvlc_to_vlc_meta[e_meta] ); + /* Should be integrated in core */ + if( psz_meta == NULL && e_meta == libvlc_meta_Title + && p_md->p_input_item->psz_name != NULL ) + psz_meta = strdup( p_md->p_input_item->psz_name ); + } return psz_meta; } @@ -475,8 +582,7 @@ void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const ch 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); + vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int); return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS; } @@ -518,9 +624,10 @@ libvlc_media_set_state( libvlc_media_t *p_md, libvlc_media_list_t * libvlc_media_subitems( libvlc_media_t * p_md ) { - if( p_md->p_subitems ) - libvlc_media_list_retain( p_md->p_subitems ); - return p_md->p_subitems; + libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true ); + if( p_subitems ) + libvlc_media_list_retain( p_subitems ); + return p_subitems; } /************************************************************************** @@ -589,15 +696,51 @@ libvlc_media_get_duration( libvlc_media_t * p_md ) return from_mtime(input_item_GetDuration( p_md->p_input_item )); } -static int media_parse(libvlc_media_t *media) +static int media_parse(libvlc_media_t *media, bool b_async, + libvlc_media_parse_flag_t parse_flag) { - /* TODO: fetcher and parser independent of playlist */ - playlist_t *playlist = - libvlc_priv (media->p_libvlc_instance->p_libvlc_int)->p_playlist; + bool needed; + + vlc_mutex_lock(&media->parsed_lock); + needed = !media->has_asked_preparse; + media->has_asked_preparse = true; + vlc_mutex_unlock(&media->parsed_lock); + + if (needed) + { + libvlc_int_t *libvlc = media->p_libvlc_instance->p_libvlc_int; + input_item_t *item = media->p_input_item; + input_item_meta_request_option_t art_scope = META_REQUEST_OPTION_NONE; + input_item_meta_request_option_t parse_scope = META_REQUEST_OPTION_SCOPE_LOCAL; + int ret; + + if (parse_flag & libvlc_media_fetch_local) + art_scope |= META_REQUEST_OPTION_SCOPE_LOCAL; + if (parse_flag & libvlc_media_fetch_network) + art_scope |= META_REQUEST_OPTION_SCOPE_NETWORK; + if (art_scope != META_REQUEST_OPTION_NONE) { + ret = libvlc_ArtRequest(libvlc, item, art_scope); + if (ret != VLC_SUCCESS) + return ret; + } - /* TODO: Fetch art on need basis. But how not to break compatibility? */ - playlist_AskForArtEnqueue(playlist, media->p_input_item ); - return playlist_PreparseEnqueue(playlist, media->p_input_item); + if (parse_flag & libvlc_media_parse_network) + parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK; + ret = libvlc_MetaRequest(libvlc, item, parse_scope); + if (ret != VLC_SUCCESS) + return ret; + } + else + return VLC_EGENERIC; + + if (!b_async) + { + 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); + } + return VLC_SUCCESS; } /************************************************************************** @@ -606,21 +749,7 @@ static int media_parse(libvlc_media_t *media) void libvlc_media_parse(libvlc_media_t *media) { - vlc_mutex_lock(&media->parsed_lock); - if (!media->has_asked_preparse) - { - media->has_asked_preparse = true; - vlc_mutex_unlock(&media->parsed_lock); - - if (media_parse(media)) - /* Parse failed: do not wait! */ - return; - 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); + media_parse( media, false, libvlc_media_fetch_local ); } /************************************************************************** @@ -629,15 +758,17 @@ libvlc_media_parse(libvlc_media_t *media) void libvlc_media_parse_async(libvlc_media_t *media) { - bool needed; - - vlc_mutex_lock(&media->parsed_lock); - needed = !media->has_asked_preparse; - media->has_asked_preparse = true; - vlc_mutex_unlock(&media->parsed_lock); + media_parse( media, true, libvlc_media_fetch_local ); +} - if (needed) - media_parse(media); +/************************************************************************** + * Parse the media asynchronously with options. + **************************************************************************/ +int +libvlc_media_parse_with_options( libvlc_media_t *media, + libvlc_media_parse_flag_t parse_flag ) +{ + return media_parse( media, true, parse_flag ) == VLC_SUCCESS ? 0 : -1; } /************************************************************************** @@ -735,3 +866,168 @@ libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** vlc_mutex_unlock( &p_input_item->lock ); return i_es; } + +unsigned +libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es ) +{ + assert( 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) ? calloc( i_es, sizeof(**pp_es) ) : NULL; + + if( !*pp_es ) /* no ES, or OOM */ + { + vlc_mutex_unlock( &p_input_item->lock ); + return 0; + } + + /* Fill array */ + for( int i = 0; i < i_es; i++ ) + { + libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) ); + if ( p_mes ) + { + p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio), + sizeof(*p_mes->video)), + sizeof(*p_mes->subtitle)) ); + } + if ( !p_mes || !p_mes->audio ) + { + libvlc_media_tracks_release( *pp_es, i_es ); + *pp_es = NULL; + free( p_mes ); + vlc_mutex_unlock( &p_input_item->lock ); + return 0; + } + (*pp_es)[i] = p_mes; + + const es_format_t *p_es = p_input_item->es[i]; + + p_mes->i_codec = p_es->i_codec; + p_mes->i_original_fourcc = p_es->i_original_fourcc; + p_mes->i_id = p_es->i_id; + + p_mes->i_profile = p_es->i_profile; + p_mes->i_level = p_es->i_level; + + p_mes->i_bitrate = p_es->i_bitrate; + p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL; + p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL; + + 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->video->i_height = p_es->video.i_height; + p_mes->video->i_width = p_es->video.i_width; + p_mes->video->i_sar_num = p_es->video.i_sar_num; + p_mes->video->i_sar_den = p_es->video.i_sar_den; + p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate; + p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base; + break; + case AUDIO_ES: + p_mes->i_type = libvlc_track_audio; + p_mes->audio->i_channels = p_es->audio.i_channels; + p_mes->audio->i_rate = p_es->audio.i_rate; + break; + case SPU_ES: + p_mes->i_type = libvlc_track_text; + p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ? + strdup(p_es->subs.psz_encoding) : NULL; + break; + } + } + + vlc_mutex_unlock( &p_input_item->lock ); + return i_es; +} + +/************************************************************************** + * Get codec description from media elementary stream + **************************************************************************/ +const char * +libvlc_media_get_codec_description( libvlc_track_type_t i_type, + uint32_t i_codec ) +{ + switch( i_type ) + { + case libvlc_track_audio: + return vlc_fourcc_GetDescription( AUDIO_ES, i_codec ); + case libvlc_track_video: + return vlc_fourcc_GetDescription( VIDEO_ES, i_codec ); + case libvlc_track_text: + return vlc_fourcc_GetDescription( SPU_ES, i_codec ); + case libvlc_track_unknown: + default: + return vlc_fourcc_GetDescription( UNKNOWN_ES, i_codec ); + } +} + +/************************************************************************** + * Release media descriptor's elementary streams description array + **************************************************************************/ +void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count ) +{ + for( unsigned i = 0; i < i_count; ++i ) + { + if ( !p_tracks[i] ) + continue; + free( p_tracks[i]->psz_language ); + free( p_tracks[i]->psz_description ); + switch( p_tracks[i]->i_type ) + { + case libvlc_track_audio: + break; + case libvlc_track_video: + break; + case libvlc_track_text: + free( p_tracks[i]->subtitle->psz_encoding ); + break; + case libvlc_track_unknown: + default: + break; + } + free( p_tracks[i]->audio ); + free( p_tracks[i] ); + } + free( p_tracks ); +} + +/************************************************************************** + * Get the media type of the media descriptor object + **************************************************************************/ +libvlc_media_type_t libvlc_media_get_type( libvlc_media_t *p_md ) +{ + assert( p_md ); + + int i_type; + input_item_t *p_input_item = p_md->p_input_item; + + vlc_mutex_lock( &p_input_item->lock ); + i_type = p_md->p_input_item->i_type; + vlc_mutex_unlock( &p_input_item->lock ); + + switch( i_type ) + { + case ITEM_TYPE_FILE: + return libvlc_media_type_file; + case ITEM_TYPE_NODE: + case ITEM_TYPE_DIRECTORY: + return libvlc_media_type_directory; + case ITEM_TYPE_DISC: + return libvlc_media_type_disc; + case ITEM_TYPE_STREAM: + return libvlc_media_type_stream; + case ITEM_TYPE_PLAYLIST: + return libvlc_media_type_playlist; + default: + return libvlc_media_type_unknown; + } +}