SORTFN( SORT_DURATION, first, second ) { mtime_t time1 = input_item_GetDuration( first->p_input ); mtime_t time2 = input_item_GetDuration( second->p_input ); int i_ret = time1 > time2 ? 1 : ( time1 == time2 ? 0 : -1 ); return i_ret; }
/***************************************************************************** * ReadMetaData : Read meta data when parsed by vlc *****************************************************************************/ static void ReadMetaData(intf_thread_t *p_this, input_thread_t *p_input) { intf_sys_t *p_sys = p_this->p_sys; assert(p_input != NULL); input_item_t *p_item = input_GetItem(p_input); if (p_item == NULL) return; #define ALLOC_ITEM_META(a, b) do { \ char *psz_meta = input_item_Get##b(p_item); \ if (psz_meta && *psz_meta) \ a = encode_URI_component(psz_meta); \ free(psz_meta); \ } while (0) vlc_mutex_lock(&p_sys->lock); p_sys->b_meta_read = true; ALLOC_ITEM_META(p_sys->p_current_song.psz_a, Artist); if (!p_sys->p_current_song.psz_a) { msg_Dbg(p_this, "No artist.."); DeleteSong(&p_sys->p_current_song); goto end; } ALLOC_ITEM_META(p_sys->p_current_song.psz_t, Title); if (!p_sys->p_current_song.psz_t) { msg_Dbg(p_this, "No track name.."); DeleteSong(&p_sys->p_current_song); goto end; } /* Now we have read the mandatory meta data, so we can submit that info */ p_sys->b_submit = true; ALLOC_ITEM_META(p_sys->p_current_song.psz_b, Album); if (!p_sys->p_current_song.psz_b) p_sys->p_current_song.psz_b = calloc(1, 1); ALLOC_ITEM_META(p_sys->p_current_song.psz_m, TrackID); if (!p_sys->p_current_song.psz_m) p_sys->p_current_song.psz_m = calloc(1, 1); p_sys->p_current_song.i_l = input_item_GetDuration(p_item) / 1000000; ALLOC_ITEM_META(p_sys->p_current_song.psz_n, TrackNum); if (!p_sys->p_current_song.psz_n) p_sys->p_current_song.psz_n = calloc(1, 1); #undef ALLOC_ITEM_META msg_Dbg(p_this, "Meta data registered"); end: vlc_mutex_unlock(&p_sys->lock); }
/* ****************************************************************************/ static void ReadMetaData(intf_thread_t *p_this) { input_thread_t *p_input; input_item_t *p_item; intf_sys_t *p_sys = p_this->p_sys; p_input = playlist_CurrentInput(pl_Get(p_this)); if (!p_input) return; p_item = input_GetItem(p_input); if (!p_item) { vlc_object_release(p_input); return; } #define ALLOC_ITEM_META(a, b) do { \ char *psz_meta = input_item_Get##b(p_item); \ if (psz_meta && *psz_meta) \ a = encode_URI_component(psz_meta); \ free(psz_meta); \ } while (0) vlc_mutex_lock(&p_sys->lock); p_sys->b_meta_read = true; ALLOC_ITEM_META(p_sys->p_current_item.psz_n, Name); if (!p_sys->p_current_item.psz_n) { msg_Dbg(p_this, "No name.."); DeleteItem(&p_sys->p_current_item); goto end; } ALLOC_ITEM_META(p_sys->p_current_item.psz_u, URI); if (!p_sys->p_current_item.psz_u) { msg_Dbg(p_this, "No URI.."); DeleteItem(&p_sys->p_current_item); goto end; } /* Now we have read the mandatory meta data, so we can submit that info */ p_sys->b_submit = true; /* Duration in seconds */ p_sys->p_current_item.i_l = input_item_GetDuration(p_item) / 1000000; #undef ALLOC_ITEM_META end: vlc_mutex_unlock(&p_sys->lock); vlc_object_release(p_input); }
int GetInputMeta( input_item_t* p_input, DBusMessageIter *args ) { DBusMessageIter dict, dict_entry, variant; /** The duration of the track can be expressed in second, milli-seconds and µ-seconds */ dbus_int64_t i_mtime = input_item_GetDuration( p_input ); dbus_uint32_t i_time = i_mtime / 1000000; dbus_int64_t i_length = i_mtime / 1000; const char* ppsz_meta_items[] = { /* Official MPRIS metas */ "location", "title", "artist", "album", "tracknumber", "time", "mtime", "genre", "rating", "date", "arturl", "audio-bitrate", "audio-samplerate", "video-bitrate", /* VLC specifics metas */ "audio-codec", "copyright", "description", "encodedby", "language", "length", "nowplaying", "publisher", "setting", "status", "trackid", "url", "video-codec" }; dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict ); ADD_VLC_META_STRING( 0, URI ); ADD_VLC_META_STRING( 1, Title ); ADD_VLC_META_STRING( 2, Artist ); ADD_VLC_META_STRING( 3, Album ); ADD_VLC_META_STRING( 4, TrackNum ); ADD_META( 5, DBUS_TYPE_UINT32, i_time ); ADD_META( 6, DBUS_TYPE_UINT32, i_mtime ); ADD_VLC_META_STRING( 7, Genre ); ADD_VLC_META_STRING( 8, Rating ); ADD_VLC_META_STRING( 9, Date ); ADD_VLC_META_STRING( 10, ArtURL ); ADD_VLC_META_STRING( 15, Copyright ); ADD_VLC_META_STRING( 16, Description ); ADD_VLC_META_STRING( 17, EncodedBy ); ADD_VLC_META_STRING( 18, Language ); ADD_META( 19, DBUS_TYPE_INT64, i_length ); ADD_VLC_META_STRING( 20, NowPlaying ); ADD_VLC_META_STRING( 21, Publisher ); ADD_VLC_META_STRING( 22, Setting ); ADD_VLC_META_STRING( 24, TrackID ); ADD_VLC_META_STRING( 25, URL ); vlc_mutex_lock( &p_input->lock ); if( p_input->p_meta ) { int i_status = vlc_meta_GetStatus( p_input->p_meta ); ADD_META( 23, DBUS_TYPE_INT32, i_status ); } vlc_mutex_unlock( &p_input->lock ); dbus_message_iter_close_container( args, &dict ); return VLC_SUCCESS; }
/***************************************************************************** * ReadMetaData : Read meta data when parsed by vlc *****************************************************************************/ static void ReadMetaData(intf_thread_t *p_this) { intf_sys_t *p_sys = p_this->p_sys; vlc_player_t *player = vlc_playlist_GetPlayer(p_sys->playlist); input_item_t *item = vlc_player_GetCurrentMedia(player); if (item == NULL) return; #define ALLOC_ITEM_META(a, b) do { \ char *psz_meta = input_item_Get##b(item); \ if (psz_meta && *psz_meta) \ a = vlc_uri_encode(psz_meta); \ free(psz_meta); \ } while (0) vlc_mutex_lock(&p_sys->lock); p_sys->b_meta_read = true; ALLOC_ITEM_META(p_sys->p_current_song.psz_a, Artist); if (!p_sys->p_current_song.psz_a) { msg_Dbg(p_this, "No artist.."); DeleteSong(&p_sys->p_current_song); goto end; } ALLOC_ITEM_META(p_sys->p_current_song.psz_t, Title); if (!p_sys->p_current_song.psz_t) { msg_Dbg(p_this, "No track name.."); DeleteSong(&p_sys->p_current_song); goto end; } /* Now we have read the mandatory meta data, so we can submit that info */ p_sys->b_submit_nowp = true; ALLOC_ITEM_META(p_sys->p_current_song.psz_b, Album); ALLOC_ITEM_META(p_sys->p_current_song.psz_m, TrackID); ALLOC_ITEM_META(p_sys->p_current_song.psz_n, TrackNum); p_sys->p_current_song.i_l = SEC_FROM_VLC_TICK(input_item_GetDuration(item)); #undef ALLOC_ITEM_META msg_Dbg(p_this, "Meta data registered"); vlc_cond_signal(&p_sys->wait); end: vlc_mutex_unlock(&p_sys->lock); }
/** * Get the duration of all items in a node. */ mtime_t playlist_GetNodeDuration( playlist_item_t* node ) { /* For the assert */ playlist_t *p_playlist = node->p_playlist; PL_ASSERT_LOCKED; mtime_t mt_duration = 0; if( node->i_children != -1 ) for( int i = 0; i < node->i_children; i++ ) mt_duration += input_item_GetDuration( node->pp_children[i]->p_input ); return mt_duration; }
static int GetInputMeta( input_item_t* p_input, DBusMessageIter *args ) { DBusMessageIter dict, dict_entry, variant; /* We need the track length to be expressed in milli-seconds * instead of µ-seconds */ dbus_int64_t i_length = ( input_item_GetDuration( p_input ) / 1000 ); const char* ppsz_meta_items[] = { "title", "artist", "genre", "copyright", "album", "tracknum", "description", "rating", "date", "setting", "url", "language", "nowplaying", "publisher", "encodedby", "arturl", "trackid", "status", "location", "length", "video-codec", "audio-codec", "video-bitrate", "audio-bitrate", "audio-samplerate" }; dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict ); ADD_VLC_META_STRING( 0, Title ); ADD_VLC_META_STRING( 1, Artist ); ADD_VLC_META_STRING( 2, Genre ); ADD_VLC_META_STRING( 3, Copyright ); ADD_VLC_META_STRING( 4, Album ); ADD_VLC_META_STRING( 5, TrackNum ); ADD_VLC_META_STRING( 6, Description ); ADD_VLC_META_STRING( 7, Rating ); ADD_VLC_META_STRING( 8, Date ); ADD_VLC_META_STRING( 9, Setting ); ADD_VLC_META_STRING( 10, URL ); ADD_VLC_META_STRING( 11, Language ); ADD_VLC_META_STRING( 12, NowPlaying ); ADD_VLC_META_STRING( 13, Publisher ); ADD_VLC_META_STRING( 14, EncodedBy ); ADD_VLC_META_STRING( 15, ArtURL ); ADD_VLC_META_STRING( 16, TrackID ); vlc_mutex_lock( &p_input->lock ); if( p_input->p_meta ) ADD_META( 17, DBUS_TYPE_INT32, p_input->p_meta->i_status ); vlc_mutex_unlock( &p_input->lock ); ADD_VLC_META_STRING( 18, URI ); ADD_META( 19, DBUS_TYPE_INT64, i_length ); dbus_message_iter_close_container( args, &dict ); return VLC_SUCCESS; }
/************************************************************************** * Get duration of media object (in ms) **************************************************************************/ int64_t libvlc_media_get_duration( libvlc_media_t * p_md ) { assert( p_md ); if( !p_md->p_input_item ) { libvlc_printerr( "No input item" ); return -1; } if (!input_item_IsPreparsed( p_md->p_input_item )) return -1; return from_mtime(input_item_GetDuration( p_md->p_input_item )); }
/** * Recursiveyy follow the playlist * @param p_playlist: the playlist * @param p_export: the export structure * @param p_root: the current node */ static void DoChildren( playlist_t *p_playlist, playlist_export_t *p_export, playlist_item_t *p_root ) { /* Go through the playlist and add items */ for( int i = 0; i < p_root->i_children ; i++) { playlist_item_t *p_current = p_root->pp_children[i]; assert( p_current ); if( p_current->i_flags & PLAYLIST_SAVE_FLAG ) continue; if( p_current->i_children >= 0 ) { DoChildren( p_playlist, p_export, p_current ); continue; } char* psz_name = NULL; char *psz_tmp = input_item_GetName( p_current->p_input ); if( psz_tmp ) psz_name = convert_xml_special_chars( psz_tmp ); free( psz_tmp ); if( psz_name ) { char* psz_artist = NULL; psz_tmp = input_item_GetArtist( p_current->p_input ); if( psz_tmp ) psz_artist = convert_xml_special_chars( psz_tmp ); free( psz_tmp ); mtime_t i_duration = input_item_GetDuration( p_current->p_input ); int min = ( i_duration / 1000000 ) / 60; int sec = ( i_duration / 1000000 ) - min * 60; // Print the artist if we have one if( psz_artist && *psz_artist ) fprintf( p_export->p_file, " <li>%s - %s (%02d:%02d)</li>\n", psz_artist, psz_name, min, sec ); else fprintf( p_export->p_file, " <li>%s (%2d:%2d)</li>\n", psz_name, min, sec ); free( psz_artist ); } free( psz_name ); } }
/** * Recursively follow the playlist * @param p_export: the export structure * @param p_root: the current node */ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root ) { /* Go through the playlist and add items */ for( int i = 0; i < p_root->i_children ; i++) { playlist_item_t *p_current = p_root->pp_children[i]; assert( p_current ); if( p_current->i_children >= 0 ) { DoChildren( p_export, p_current ); continue; } char* psz_name = NULL; char *psz_tmp = input_item_GetName( p_current->p_input ); if( psz_tmp ) psz_name = vlc_xml_encode( psz_tmp ); free( psz_tmp ); if( psz_name ) { char* psz_artist = NULL; psz_tmp = input_item_GetArtist( p_current->p_input ); if( psz_tmp ) psz_artist = vlc_xml_encode( psz_tmp ); free( psz_tmp ); vlc_tick_t i_duration = input_item_GetDuration( p_current->p_input ); int min = SEC_FROM_VLC_TICK( i_duration ) / 60; int sec = SEC_FROM_VLC_TICK( i_duration ) - min * 60; // Print the artist if we have one if( psz_artist && *psz_artist ) fprintf( p_export->p_file, " <li>%s - %s (%02d:%02d)</li>\n", psz_artist, psz_name, min, sec ); else fprintf( p_export->p_file, " <li>%s (%2d:%2d)</li>\n", psz_name, min, sec ); free( psz_artist ); } free( psz_name ); } }
/** * Get the duration of all items in a node. */ mtime_t playlist_GetNodeDuration( playlist_item_t* node ) { /* For the assert */ playlist_t *p_playlist = node->p_playlist; PL_ASSERT_LOCKED; mtime_t mt_duration = 0; if( node->i_children != -1 ) for( int i = 0; i < node->i_children; i++ ) { input_item_t* p_input = node->pp_children[i]->p_input; if ( p_input->i_type == ITEM_TYPE_NODE ) mt_duration += playlist_GetNodeDuration( node->pp_children[i] ); else mt_duration += input_item_GetDuration( p_input ); } return mt_duration; }
/***************************************************************************** * Run: xosd thread ***************************************************************************** * This part of the interface runs in a separate thread *****************************************************************************/ static void Run( intf_thread_t *p_intf ) { playlist_t *p_playlist; playlist_item_t *p_item = NULL; char *psz_display = NULL; int cancel = vlc_savecancel(); while( true ) { // Wait for a signal vlc_restorecancel( cancel ); vlc_mutex_lock( &p_intf->p_sys->lock ); mutex_cleanup_push( &p_intf->p_sys->lock ); while( !p_intf->p_sys->b_need_update ) vlc_cond_wait( &p_intf->p_sys->cond, &p_intf->p_sys->lock ); p_intf->p_sys->b_need_update = false; vlc_cleanup_run(); // Compute the signal cancel = vlc_savecancel(); p_playlist = pl_Hold( p_intf ); PL_LOCK; // If the playlist is empty don't do anything if( playlist_IsEmpty( p_playlist ) ) { PL_UNLOCK; pl_Release( p_intf ); continue; } free( psz_display ); int i_status = playlist_Status( p_playlist ); if( i_status == PLAYLIST_STOPPED ) { psz_display = strdup(_("Stop")); } else if( i_status == PLAYLIST_PAUSED ) { psz_display = strdup(_("Pause")); } else { p_item = playlist_CurrentPlayingItem( p_playlist ); if( !p_item ) { psz_display = NULL; PL_UNLOCK; pl_Release( p_intf ); continue; } input_item_t *p_input = p_item->p_input; mtime_t i_duration = input_item_GetDuration( p_input ); if( i_duration != -1 ) { char psz_durationstr[MSTRTIME_MAX_SIZE]; secstotimestr( psz_durationstr, i_duration / 1000000 ); if( asprintf( &psz_display, "%s (%s)", p_input->psz_name, psz_durationstr ) == -1 ) psz_display = NULL; } else psz_display = strdup( p_input->psz_name ); } PL_UNLOCK; pl_Release( p_intf ); /* Display */ xosd_display( p_intf->p_sys->p_osd, 0, /* first line */ XOSD_string, psz_display ); } }
/***************************************************************************** * Media handling *****************************************************************************/ static vod_media_t *MediaNew( vod_t *p_vod, const char *psz_name, input_item_t *p_item ) { vod_media_t *p_media = calloc( 1, sizeof(vod_media_t) ); if( !p_media ) return NULL; p_media->p_vod = p_vod; p_media->rtsp = NULL; TAB_INIT( p_media->i_es, p_media->es ); p_media->psz_mux = NULL; p_media->i_length = input_item_GetDuration( p_item ); vlc_mutex_lock( &p_item->lock ); msg_Dbg( p_vod, "media '%s' has %i declared ES", psz_name, p_item->i_es ); for( int i = 0; i < p_item->i_es; i++ ) { es_format_t *p_fmt = p_item->es[i]; switch( p_fmt->i_codec ) { case VLC_FOURCC( 'm', 'p', '2', 't' ): p_media->psz_mux = "ts"; break; case VLC_FOURCC( 'm', 'p', '2', 'p' ): p_media->psz_mux = "ps"; break; } assert(p_media->psz_mux == NULL || p_item->i_es == 1); media_es_t *p_es = calloc( 1, sizeof(media_es_t) ); if( !p_es ) continue; p_es->es_id = p_fmt->i_id; p_es->rtsp_id = NULL; if (rtp_get_fmt(VLC_OBJECT(p_vod), p_fmt, p_media->psz_mux, &p_es->rtp_fmt) != VLC_SUCCESS) { free(p_es); continue; } TAB_APPEND( (media_es_t **), p_media->i_es, p_media->es, p_es ); // sunqueen modify msg_Dbg(p_vod, " - added ES %u %s (%4.4s)", p_es->rtp_fmt.payload_type, p_es->rtp_fmt.ptname, (char *)&p_fmt->i_codec); } vlc_mutex_unlock( &p_item->lock ); if (p_media->i_es == 0) { msg_Err(p_vod, "no ES was added to the media, aborting"); goto error; } msg_Dbg(p_vod, "adding media '%s'", psz_name); CommandPush( p_vod, RTSP_CMD_TYPE_ADD, p_media, psz_name ); return p_media; error: MediaDel(p_vod, p_media); return NULL; }
int GetInputMeta( input_item_t* p_input, DBusMessageIter *args ) { DBusMessageIter dict, dict_entry, variant; /** The duration of the track can be expressed in second, milli-seconds and µ-seconds */ dbus_int64_t i_mtime = input_item_GetDuration( p_input ); dbus_uint32_t i_time = i_mtime / 1000000; dbus_int64_t i_length = i_mtime / 1000; char *psz_trackid; if( -1 == asprintf( &psz_trackid, MPRIS_TRACKID_FORMAT, p_input->i_id ) ) return VLC_ENOMEM; const char* ppsz_meta_items[] = { "mpris:trackid", "xesam:url", "xesam:title", "xesam:artist", "xesam:album", "xesam:tracknumber", "vlc:time", "mpris:length", "xesam:genre", "xesam:userRating", "xesam:contentCreated", "mpris:artUrl", "mb:trackId", "vlc:audio-bitrate", "vlc:audio-samplerate", "vlc:video-bitrate", "vlc:audio-codec", "vlc:copyright", "xesam:comment", "vlc:encodedby", "language", "vlc:length", "vlc:nowplaying", "vlc:publisher", "vlc:setting", "status", "vlc:url", "vlc:video-codec" }; dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict ); ADD_META( 0, DBUS_TYPE_OBJECT_PATH, psz_trackid ); ADD_VLC_META_STRING( 1, URI ); ADD_VLC_META_STRING( 2, Title ); ADD_VLC_META_STRING( 3, Artist ); ADD_VLC_META_STRING( 4, Album ); ADD_VLC_META_STRING( 5, TrackNum ); ADD_META( 6, DBUS_TYPE_UINT32, i_time ); ADD_META( 7, DBUS_TYPE_INT64, i_mtime ); ADD_VLC_META_STRING( 8, Genre ); ADD_VLC_META_STRING( 9, Rating ); ADD_VLC_META_STRING( 10, Date ); ADD_VLC_META_STRING( 11, ArtURL ); ADD_VLC_META_STRING( 12, TrackID ); ADD_VLC_META_STRING( 17, Copyright ); ADD_VLC_META_STRING( 18, Description ); ADD_VLC_META_STRING( 19, EncodedBy ); ADD_VLC_META_STRING( 20, Language ); ADD_META( 21, DBUS_TYPE_INT64, i_length ); ADD_VLC_META_STRING( 22, NowPlaying ); ADD_VLC_META_STRING( 23, Publisher ); ADD_VLC_META_STRING( 24, Setting ); ADD_VLC_META_STRING( 25, URL ); free( psz_trackid ); vlc_mutex_lock( &p_input->lock ); if( p_input->p_meta ) { int i_status = vlc_meta_GetStatus( p_input->p_meta ); ADD_META( 23, DBUS_TYPE_INT32, i_status ); } vlc_mutex_unlock( &p_input->lock ); dbus_message_iter_close_container( args, &dict ); return VLC_SUCCESS; }
static LRESULT HandleCadMessage(intf_thread_t* p_intf, HWND hwnd, WPARAM wParam, LPARAM lParam) { intf_sys_t* const p_sys = p_intf->p_sys; switch (lParam) { case IPC_PLAY: { playlist_Play(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_PLAYPAUSE: { playlist_t* p_playlist = pl_Get(p_intf->p_libvlc); const bool playing = playlist_Status(p_playlist) == PLAYLIST_RUNNING; playlist_Control(p_playlist, playing ? PLAYLIST_PAUSE : PLAYLIST_PLAY, pl_Unlocked); return 1; } case IPC_PAUSE: { playlist_Pause(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_STOP: { playlist_Stop(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_NEXT: { playlist_Next(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_PREVIOUS: { playlist_Prev(pl_Get(p_intf->p_libvlc)); return 1; } case IPC_SET_VOLUME: { playlist_VolumeSet(pl_Get(p_intf->p_libvlc), (int)wParam / 100.0f); return 1; } case IPC_GET_VOLUME: { // VLC can return a volume larger than 100% so we need to cap it to 100 here. const float volume = playlist_VolumeGet(pl_Get(p_intf->p_libvlc)) * 100.0f; return (LRESULT)min(volume, 100.0f); } case IPC_GET_DURATION: { unsigned int duration = 0; if (p_sys->p_input) { input_item_t* const p_item = input_GetItem(p_sys->p_input); duration = (unsigned int)(input_item_GetDuration(p_item) / 1000000); } return duration; } case IPC_GET_POSITION: { int pos = 0; if (p_sys->p_input) { pos = (int)(var_GetTime(p_sys->p_input, "time") / CLOCK_FREQ); } return pos; } case IPC_SET_POSITION: { if (p_sys->p_input) { var_SetTime(p_sys->p_input, "time", (int64_t)wParam * CLOCK_FREQ); } return 0; } case IPC_GET_SHUFFLE: { return (int)var_GetBool(pl_Get(p_intf->p_libvlc), "random"); } case IPC_SET_SHUFFLE: { return (int)var_SetBool(pl_Get(p_intf->p_libvlc), "random", (bool)wParam); } case IPC_GET_REPEAT: { return (int)var_GetBool(pl_Get(p_intf->p_libvlc), "repeat"); } case IPC_SET_REPEAT: { return (int)var_SetBool(pl_Get(p_intf->p_libvlc), "repeat", (bool)wParam); } case IPC_SET_RATING: { // VLC does not support ratings so send back 0. PostMessage(p_sys->cad_window, WM_USER, 0, IPC_RATING_CHANGED_NOTIFICATION); return 0; } case IPC_SET_CALLBACK_HWND: { p_sys->cad_window = (HWND)wParam; return 1; } case IPC_SHOW_WINDOW: { // TODO. return 0; } case IPC_GET_STATE: { const int status = playlist_Status(pl_Get(p_intf->p_libvlc)); return status == PLAYLIST_RUNNING ? 1 : status == PLAYLIST_PAUSED ? 2 : 0; } case IPC_SHUTDOWN_NOTIFICATION: { p_sys->cad_window = NULL; return 1; } case IPC_CLOSE: { libvlc_Quit(p_intf->p_libvlc); return 1; } case IPC_GET_CURRENT_TRACK: { if (!p_sys->p_input) return 0; input_item_t* p_item = input_GetItem(p_sys->p_input); char buffer[DATA_MAX_LENGTH]; int buffer_len = 0; // If the i sstarts with file://, we assume that it is a local file and detailed // metadata is available. Otherwise, we assume it to be a network stream (i.e. radio) // with limited info (only a title). char* const file = decode_URI(input_item_GetURI(p_item)); if (strncmp(file, "file://", 7) == 0) { char* const title = input_item_GetTitleFbName(p_item); char* const artist = input_item_GetArtist(p_item); char* const album = input_item_GetAlbum(p_item); char* const cover = decode_URI(input_item_GetArtworkURL(p_item)); const unsigned int duration = input_item_GetDuration(p_item) / 1000000U; buffer_len = _snprintf( buffer, ARRAYSIZE(buffer), "%s\t%s\t%s\t\t\t\t\t%u\t%s\t\t%s\t\t\t\t\t\t\t", title ? title : "", artist ? artist : "", album ? album : "", duration, file ? &file[8] : "", cover ? &cover[8] : ""); // Skip the "file://" part. free(title); free(artist); free(album); free(cover); } else if (char* now_playing = input_item_GetNowPlaying(p_item)) { char* artist = NULL; char* title = now_playing; char* pos = strstr(now_playing, " - "); if (pos) { pos[0] = '\0'; artist = title; title = pos + 3; // Skip the " - " } buffer_len = _snprintf( buffer, ARRAYSIZE(buffer), "%s\t%s\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", title ? title : "", artist ? artist : ""); free(now_playing); } free(file); if (buffer_len) { wchar_t buffer_w[DATA_MAX_LENGTH]; const int buffer_w_len = MultiByteToWideChar( CP_UTF8, 0, buffer, buffer_len + 1, buffer_w, ARRAYSIZE(buffer_w)); COPYDATASTRUCT cds; cds.dwData = IPC_CURRENT_TRACK_NOTIFICATION; cds.lpData = &buffer_w; cds.cbData = buffer_w_len * sizeof(buffer_w[0]); SendMessage( p_sys->cad_window, WM_COPYDATA, IPC_CURRENT_TRACK_NOTIFICATION, (LPARAM)&cds); } return 1; } } return 0; }
/************************************************************************* * Playlist stuff *************************************************************************/ void PlaylistListNode( intf_thread_t *p_intf, playlist_t *p_pl, playlist_item_t *p_node, char *name, mvar_t *s, int i_depth ) { if( !p_node || !p_node->p_input ) return; if( p_node->i_children == -1 ) { char value[512]; char *psz; playlist_item_t * p_item = playlist_CurrentPlayingItem( p_pl ); if( !p_item || !p_item->p_input ) return; mvar_t *itm = mvar_New( name, "set" ); if( p_item->p_input == p_node->p_input ) mvar_AppendNewVar( itm, "current", "1" ); else mvar_AppendNewVar( itm, "current", "0" ); sprintf( value, "%d", p_node->i_id ); mvar_AppendNewVar( itm, "index", value ); psz = input_item_GetName( p_node->p_input ); mvar_AppendNewVar( itm, "name", psz ); free( psz ); psz = input_item_GetURI( p_node->p_input ); mvar_AppendNewVar( itm, "uri", psz ); free( psz ); mvar_AppendNewVar( itm, "type", "Item" ); sprintf( value, "%d", i_depth ); mvar_AppendNewVar( itm, "depth", value ); if( p_node->i_flags & PLAYLIST_RO_FLAG ) mvar_AppendNewVar( itm, "ro", "ro" ); else mvar_AppendNewVar( itm, "ro", "rw" ); sprintf( value, "%"PRId64, input_item_GetDuration( p_node->p_input ) ); mvar_AppendNewVar( itm, "duration", value ); //Adding extra meta-information to each playlist item psz = input_item_GetTitle( p_node->p_input ); mvar_AppendNewVar( itm, "title", psz ); free( psz ); psz = input_item_GetArtist( p_node->p_input ); mvar_AppendNewVar( itm, "artist", psz ); free( psz ); psz = input_item_GetGenre( p_node->p_input ); mvar_AppendNewVar( itm, "genre", psz ); free( psz ); psz = input_item_GetCopyright( p_node->p_input ); mvar_AppendNewVar( itm, "copyright", psz ); free( psz ); psz = input_item_GetAlbum( p_node->p_input ); mvar_AppendNewVar( itm, "album", psz ); free( psz ); psz = input_item_GetTrackNum( p_node->p_input ); mvar_AppendNewVar( itm, "track", psz ); free( psz ); psz = input_item_GetDescription( p_node->p_input ); mvar_AppendNewVar( itm, "description", psz ); free( psz ); psz = input_item_GetRating( p_node->p_input ); mvar_AppendNewVar( itm, "rating", psz ); free( psz ); psz = input_item_GetDate( p_node->p_input ); mvar_AppendNewVar( itm, "date", psz ); free( psz ); psz = input_item_GetURL( p_node->p_input ); mvar_AppendNewVar( itm, "url", psz ); free( psz ); psz = input_item_GetLanguage( p_node->p_input ); mvar_AppendNewVar( itm, "language", psz ); free( psz ); psz = input_item_GetNowPlaying( p_node->p_input ); mvar_AppendNewVar( itm, "now_playing", psz ); free( psz ); psz = input_item_GetPublisher( p_node->p_input ); mvar_AppendNewVar( itm, "publisher", psz ); free( psz ); psz = input_item_GetEncodedBy( p_node->p_input ); mvar_AppendNewVar( itm, "encoded_by", psz ); free( psz ); psz = input_item_GetArtURL( p_node->p_input ); mvar_AppendNewVar( itm, "art_url", psz ); free( psz ); psz = input_item_GetTrackID( p_node->p_input ); mvar_AppendNewVar( itm, "track_id", psz ); free( psz ); mvar_AppendVar( s, itm ); } else { char value[512]; int i_child; mvar_t *itm = mvar_New( name, "set" ); mvar_AppendNewVar( itm, "name", p_node->p_input->psz_name ); mvar_AppendNewVar( itm, "uri", p_node->p_input->psz_name ); mvar_AppendNewVar( itm, "type", "Node" ); sprintf( value, "%d", p_node->i_id ); mvar_AppendNewVar( itm, "index", value ); sprintf( value, "%d", p_node->i_children); mvar_AppendNewVar( itm, "i_children", value ); sprintf( value, "%d", i_depth ); mvar_AppendNewVar( itm, "depth", value ); if( p_node->i_flags & PLAYLIST_RO_FLAG ) mvar_AppendNewVar( itm, "ro", "ro" ); else mvar_AppendNewVar( itm, "ro", "rw" ); mvar_AppendVar( s, itm ); for( i_child = 0 ; i_child < p_node->i_children ; i_child++ ) PlaylistListNode( p_intf, p_pl, p_node->pp_children[i_child], name, s, i_depth + 1); } }
/***************************************************************************** * Export_M3U: main export function *****************************************************************************/ static void DoChildren( playlist_export_t *p_export, playlist_item_t *p_root, int (*pf_fprintf) (FILE *, const char *, ...) ) { /* Write header */ fputs( "#EXTM3U\n", p_export->p_file ); /* Go through the playlist and add items */ for( int i = 0; i< p_root->i_children ; i++) { playlist_item_t *p_current = p_root->pp_children[i]; assert( p_current ); if( p_current->i_flags & PLAYLIST_SAVE_FLAG ) continue; if( p_current->i_children >= 0 ) { DoChildren( p_export, p_current, pf_fprintf ); continue; } /* General info */ char *psz_uri = input_item_GetURI( p_current->p_input ); assert( psz_uri ); char *psz_name = input_item_GetName( p_current->p_input ); if( psz_name && strcmp( psz_uri, psz_name ) ) { char *psz_artist = input_item_GetArtist( p_current->p_input ); if( psz_artist == NULL ) psz_artist = strdup( "" ); mtime_t i_duration = input_item_GetDuration( p_current->p_input ); if( psz_artist && *psz_artist ) { /* write EXTINF with artist */ pf_fprintf( p_export->p_file, "#EXTINF:%"PRIu64",%s - %s\n", i_duration / CLOCK_FREQ, psz_artist, psz_name); } else { /* write EXTINF without artist */ pf_fprintf( p_export->p_file, "#EXTINF:%"PRIu64",%s\n", i_duration / CLOCK_FREQ, psz_name); } free( psz_artist ); } free( psz_name ); /* VLC specific options */ vlc_mutex_lock( &p_current->p_input->lock ); for( int j = 0; j < p_current->p_input->i_options; j++ ) { pf_fprintf( p_export->p_file, "#EXTVLCOPT:%s\n", p_current->p_input->ppsz_options[j][0] == ':' ? p_current->p_input->ppsz_options[j] + 1 : p_current->p_input->ppsz_options[j] ); } vlc_mutex_unlock( &p_current->p_input->lock ); /* Stupid third party players don't understand file: URIs. */ char *psz_path = make_path( psz_uri ); if( psz_path != NULL ) { free( psz_uri ); psz_uri = psz_path; } fprintf( p_export->p_file, "%s\n", psz_uri ); free( psz_uri ); } }
/** * \brief exports one item to file or traverse if item is a node * \param p_item playlist item to export * \param p_file file to write xml-converted item to * \param p_i_count counter for track identifiers */ static void xspf_export_item( playlist_item_t *p_item, FILE *p_file, int *p_i_count ) { if( !p_item ) return; /* if we get a node here, we must traverse it */ if( p_item->i_children > 0 ) { for( int i = 0; i < p_item->i_children; i++ ) xspf_export_item( p_item->pp_children[i], p_file, p_i_count ); return; } /* don't write empty nodes */ if( p_item->i_children == 0 ) return; input_item_t *p_input = p_item->p_input; char *psz; mtime_t i_duration; /* leaves can be written directly */ fputs( "\t\t<track>\n", p_file ); /* -> the location */ char *psz_uri = input_xml( p_input, input_item_GetURI ); if( psz_uri && *psz_uri ) fprintf( p_file, "\t\t\t<location>%s</location>\n", psz_uri ); /* -> the name/title (only if different from uri)*/ psz = input_xml( p_input, input_item_GetTitle ); if( psz && strcmp( psz_uri, psz ) ) fprintf( p_file, "\t\t\t<title>%s</title>\n", psz ); free( psz ); free( psz_uri ); if( p_item->p_input->p_meta == NULL ) { goto xspfexportitem_end; } /* -> the artist/creator */ psz = input_xml( p_input, input_item_GetArtist ); if( psz && *psz ) fprintf( p_file, "\t\t\t<creator>%s</creator>\n", psz ); free( psz ); /* -> the album */ psz = input_xml( p_input, input_item_GetAlbum ); if( psz && *psz ) fprintf( p_file, "\t\t\t<album>%s</album>\n", psz ); free( psz ); /* -> the track number */ psz = input_xml( p_input, input_item_GetTrackNum ); if( psz ) { int i_tracknum = atoi( psz ); free( psz ); if( i_tracknum > 0 ) fprintf( p_file, "\t\t\t<trackNum>%i</trackNum>\n", i_tracknum ); } /* -> the description */ psz = input_xml( p_input, input_item_GetDescription ); if( psz && *psz ) fprintf( p_file, "\t\t\t<annotation>%s</annotation>\n", psz ); free( psz ); psz = input_xml( p_input, input_item_GetURL ); if( psz && *psz ) fprintf( p_file, "\t\t\t<info>%s</info>\n", psz ); free( psz ); psz = input_xml( p_input, input_item_GetArtURL ); if( psz && *psz ) fprintf( p_file, "\t\t\t<image>%s</image>\n", psz ); free( psz ); xspfexportitem_end: /* -> the duration */ i_duration = input_item_GetDuration( p_item->p_input ); if( i_duration > 0 ) fprintf( p_file, "\t\t\t<duration>%"PRIu64"</duration>\n", i_duration / 1000 ); /* export the intenal id and the input's options (bookmarks, ...) * in <extension> */ fputs( "\t\t\t<extension application=\"" "http://www.videolan.org/vlc/playlist/0\">\n", p_file ); /* print the id and increase the counter */ fprintf( p_file, "\t\t\t\t<vlc:id>%i</vlc:id>\n", *p_i_count ); ( *p_i_count )++; for( int i = 0; i < p_item->p_input->i_options; i++ ) { char* psz_src = p_item->p_input->ppsz_options[i]; char* psz_ret = NULL; if ( psz_src[0] == ':' ) psz_src++; psz_ret = vlc_xml_encode( psz_src ); if ( psz_ret == NULL ) continue; fprintf( p_file, "\t\t\t\t<vlc:option>%s</vlc:option>\n", psz_ret ); free( psz_ret ); } fputs( "\t\t\t</extension>\n", p_file ); fputs( "\t\t</track>\n", p_file ); }
/***************************************************************************** * ReadMetaData : Read meta data when parsed by vlc *****************************************************************************/ static int ReadMetaData( intf_thread_t *p_this ) { input_thread_t *p_input; input_item_t *p_item; intf_sys_t *p_sys = p_this->p_sys; p_input = playlist_CurrentInput( pl_Get( p_this ) ); if( !p_input ) return( VLC_SUCCESS ); p_item = input_GetItem( p_input ); if( !p_item ) return VLC_SUCCESS; char *psz_meta; #define ALLOC_ITEM_META( a, b ) \ psz_meta = input_item_Get##b( p_item ); \ if( psz_meta && *psz_meta ) \ { \ a = encode_URI_component( psz_meta ); \ if( !a ) \ { \ vlc_mutex_unlock( &p_sys->lock ); \ vlc_object_release( p_input ); \ free( psz_meta ); \ return VLC_ENOMEM; \ } \ } vlc_mutex_lock( &p_sys->lock ); p_sys->b_meta_read = true; ALLOC_ITEM_META( p_sys->p_current_song.psz_a, Artist ) else { vlc_mutex_unlock( &p_sys->lock ); msg_Dbg( p_this, "No artist.." ); vlc_object_release( p_input ); free( psz_meta ); return VLC_EGENERIC; } free( psz_meta ); ALLOC_ITEM_META( p_sys->p_current_song.psz_t, Title ) else { vlc_mutex_unlock( &p_sys->lock ); msg_Dbg( p_this, "No track name.." ); vlc_object_release( p_input ); free( p_sys->p_current_song.psz_a ); free( psz_meta ); return VLC_EGENERIC; } free( psz_meta ); /* Now we have read the mandatory meta data, so we can submit that info */ p_sys->b_submit = true; ALLOC_ITEM_META( p_sys->p_current_song.psz_b, Album ) else p_sys->p_current_song.psz_b = calloc( 1, 1 ); free( psz_meta ); ALLOC_ITEM_META( p_sys->p_current_song.psz_m, TrackID ) else p_sys->p_current_song.psz_m = calloc( 1, 1 ); free( psz_meta ); p_sys->p_current_song.i_l = input_item_GetDuration( p_item ) / 1000000; ALLOC_ITEM_META( p_sys->p_current_song.psz_n, TrackNum ) else p_sys->p_current_song.psz_n = calloc( 1, 1 ); free( psz_meta ); #undef ALLOC_ITEM_META msg_Dbg( p_this, "Meta data registered" ); vlc_mutex_unlock( &p_sys->lock ); vlc_object_release( p_input ); return VLC_SUCCESS; }
static int vlclua_input_item_duration( lua_State *L ) { mtime_t duration = input_item_GetDuration( vlclua_input_item_get_internal( L ) ); lua_pushnumber( L, ((double)duration)/1000000. ); return 1; }