#endif
#include <assert.h>
+#include <errno.h>
#include <vlc/libvlc.h>
#include <vlc/libvlc_media.h>
#include "libvlc_internal.h"
#include "media_internal.h"
+#include "media_list_internal.h"
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[] =
[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)
**************************************************************************/
{
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(
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 */
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)
**************************************************************************/
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)
**************************************************************************/
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 );
}
/**************************************************************************
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 );
}
/**************************************************************************
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;
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 );
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;
}
{
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 );
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;
}
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;
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;
}
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;
}
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;
}
/**************************************************************************
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;
}
/**************************************************************************
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 );
}
/**************************************************************************
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;
}
/**************************************************************************
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;
+ }
+}