/** * Moves an item * * This function must be entered with the playlist lock * * \param p_playlist the playlist * \param p_item the item to move * \param p_node the new parent of the item * \param i_newpos the new position under this new parent * \return VLC_SUCCESS or an error */ int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item, playlist_item_t *p_node, int i_newpos ) { PL_ASSERT_LOCKED; if( p_node->i_children == -1 ) return VLC_EGENERIC; playlist_item_t *p_detach = p_item->p_parent; int i_index = ItemIndex( p_item ); REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, i_index ); if( p_detach == p_node && i_index < i_newpos ) i_newpos--; INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item ); p_item->p_parent = p_node; pl_priv( p_playlist )->b_reset_currently_playing = true; vlc_cond_signal( &pl_priv( p_playlist )->signal ); return VLC_SUCCESS; }
void input_item_MergeInfos( input_item_t *p_item, info_category_t *p_cat ) { vlc_mutex_lock( &p_item->lock ); info_category_t *p_old = InputItemFindCat( p_item, NULL, p_cat->psz_name ); if( p_old ) { for( int i = 0; i < p_cat->i_infos; i++ ) info_category_ReplaceInfo( p_old, p_cat->pp_infos[i] ); TAB_CLEAN( p_cat->i_infos, p_cat->pp_infos ); info_category_Delete( p_cat ); } else { INSERT_ELEM( p_item->pp_categories, p_item->i_categories, p_item->i_categories, p_cat ); } vlc_mutex_unlock( &p_item->lock ); vlc_event_t event; event.type = vlc_InputItemInfoChanged; vlc_event_send( &p_item->event_manager, &event ); }
void playlist_preparser_Push( playlist_preparser_t *p_preparser, input_item_t *p_item, input_item_meta_request_option_t i_options ) { preparser_entry_t *p_entry = malloc( sizeof(preparser_entry_t) ); if ( !p_entry ) return; p_entry->p_item = p_item; p_entry->i_options = i_options; vlc_gc_incref( p_entry->p_item ); vlc_mutex_lock( &p_preparser->lock ); INSERT_ELEM( p_preparser->pp_waiting, p_preparser->i_waiting, p_preparser->i_waiting, p_entry ); if( !p_preparser->b_live ) { if( vlc_clone_detach( NULL, Thread, p_preparser, VLC_THREAD_PRIORITY_LOW ) ) msg_Warn( p_preparser->object, "cannot spawn pre-parser thread" ); else p_preparser->b_live = true; } vlc_mutex_unlock( &p_preparser->lock ); }
/** * Register a callback in a variable * * We store a function pointer that will be called upon variable * modification. * * \param p_this The object that holds the variable * \param psz_name The name of the variable * \param pf_callback The function pointer * \param p_data A generic pointer that will be passed as the last * argument to the callback function. * * \warning The callback function is run in the thread that calls var_Set on * the variable. Use proper locking. This thread may not have much * time to spare, so keep callback functions short. */ int var_AddCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { variable_t *p_var; callback_entry_t entry; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); entry.pf_callback = pf_callback; entry.p_data = p_data; vlc_mutex_lock( &p_priv->var_lock ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { #ifndef NDEBUG msg_Warn( p_this, "Failed to add a callback to the non-existing " "variable '%s'", psz_name ); #endif vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } WaitUnused( p_this, p_var ); INSERT_ELEM( p_var->p_entries, p_var->i_entries, p_var->i_entries, entry ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS; }
/** RTSP requests handler * @param id selected track for non-aggregate URLs, * NULL for aggregate URLs */ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, httpd_client_t *cl, httpd_message_t *answer, const httpd_message_t *query ) { sout_stream_t *p_stream = rtsp->owner; char psz_sesbuf[17]; const char *psz_session = NULL, *psz; char control[sizeof("rtsp://[]:12345") + NI_MAXNUMERICHOST + strlen( rtsp->psz_path )]; time_t now; time (&now); if( answer == NULL || query == NULL || cl == NULL ) return VLC_SUCCESS; else { /* Build self-referential control URL */ char ip[NI_MAXNUMERICHOST], *ptr; httpd_ServerIP( cl, ip ); ptr = strchr( ip, '%' ); if( ptr != NULL ) *ptr = '\0'; if( strchr( ip, ':' ) != NULL ) sprintf( control, "rtsp://[%s]:%u%s", ip, rtsp->port, rtsp->psz_path ); else sprintf( control, "rtsp://%s:%u%s", ip, rtsp->port, rtsp->psz_path ); } /* */ answer->i_proto = HTTPD_PROTO_RTSP; answer->i_version= 0; answer->i_type = HTTPD_MSG_ANSWER; answer->i_body = 0; answer->p_body = NULL; httpd_MsgAdd( answer, "Server", "%s", PACKAGE_STRING ); /* Date: is always allowed, and sometimes mandatory with RTSP/2.0. */ struct tm ut; if (gmtime_r (&now, &ut) != NULL) { /* RFC1123 format, GMT is mandatory */ static const char wdays[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char mons[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; httpd_MsgAdd (answer, "Date", "%s, %02u %s %04u %02u:%02u:%02u GMT", wdays[ut.tm_wday], ut.tm_mday, mons[ut.tm_mon], 1900 + ut.tm_year, ut.tm_hour, ut.tm_min, ut.tm_sec); } if( query->i_proto != HTTPD_PROTO_RTSP ) { answer->i_status = 505; } else if( httpd_MsgGet( query, "Require" ) != NULL ) { answer->i_status = 551; httpd_MsgAdd( answer, "Unsupported", "%s", httpd_MsgGet( query, "Require" ) ); } else switch( query->i_type ) { case HTTPD_MSG_DESCRIBE: { /* Aggregate-only */ if( id != NULL ) { answer->i_status = 460; break; } answer->i_status = 200; httpd_MsgAdd( answer, "Content-Type", "%s", "application/sdp" ); httpd_MsgAdd( answer, "Content-Base", "%s", control ); answer->p_body = (uint8_t *)SDPGenerate( rtsp->owner, control ); if( answer->p_body != NULL ) answer->i_body = strlen( (char *)answer->p_body ); else answer->i_status = 500; break; } case HTTPD_MSG_SETUP: /* Non-aggregate-only */ if( id == NULL ) { answer->i_status = 459; break; } psz_session = httpd_MsgGet( query, "Session" ); answer->i_status = 461; for( const char *tpt = httpd_MsgGet( query, "Transport" ); tpt != NULL; tpt = transport_next( tpt ) ) { bool b_multicast = true, b_unsupp = false; unsigned loport = 5004, hiport = 5005; /* from RFC3551 */ /* Check transport protocol. */ /* Currently, we only support RTP/AVP over UDP */ if( strncmp( tpt, "RTP/AVP", 7 ) ) continue; tpt += 7; if( strncmp( tpt, "/UDP", 4 ) == 0 ) tpt += 4; if( strchr( ";,", *tpt ) == NULL ) continue; /* Parse transport options */ for( const char *opt = parameter_next( tpt ); opt != NULL; opt = parameter_next( opt ) ) { if( strncmp( opt, "multicast", 9 ) == 0) b_multicast = true; else if( strncmp( opt, "unicast", 7 ) == 0 ) b_multicast = false; else if( sscanf( opt, "client_port=%u-%u", &loport, &hiport ) == 2 ) ; else if( strncmp( opt, "mode=", 5 ) == 0 ) { if( strncasecmp( opt + 5, "play", 4 ) && strncasecmp( opt + 5, "\"PLAY\"", 6 ) ) { /* Not playing?! */ b_unsupp = true; break; } } else if( strncmp( opt,"destination=", 12 ) == 0 ) { answer->i_status = 403; b_unsupp = true; } else { /* * Every other option is unsupported: * * "source" and "append" are invalid (server-only); * "ssrc" also (as clarified per RFC2326bis). * * For multicast, "port", "layers", "ttl" are set by the * stream output configuration. * * For unicast, we want to decide "server_port" values. * * "interleaved" is not implemented. */ b_unsupp = true; break; } } if( b_unsupp ) continue; if( b_multicast ) { const char *dst = id->dst; if( dst == NULL ) continue; if( psz_session == NULL ) { /* Create a dummy session ID */ snprintf( psz_sesbuf, sizeof( psz_sesbuf ), "%d", rand() ); psz_session = psz_sesbuf; } answer->i_status = 200; httpd_MsgAdd( answer, "Transport", "RTP/AVP/UDP;destination=%s;port=%u-%u;" "ttl=%d;mode=play", dst, id->loport, id->hiport, ( id->ttl > 0 ) ? id->ttl : 1 ); } else { char ip[NI_MAXNUMERICHOST], src[NI_MAXNUMERICHOST]; rtsp_session_t *ses = NULL; rtsp_strack_t track = { id->sout_id, -1, false }; int sport; if( httpd_ClientIP( cl, ip ) == NULL ) { answer->i_status = 500; continue; } track.fd = net_ConnectDgram( p_stream, ip, loport, -1, IPPROTO_UDP ); if( track.fd == -1 ) { msg_Err( p_stream, "cannot create RTP socket for %s port %u", ip, loport ); answer->i_status = 500; continue; } net_GetSockAddress( track.fd, src, &sport ); vlc_mutex_lock( &rtsp->lock ); if( psz_session == NULL ) { ses = RtspClientNew( rtsp ); snprintf( psz_sesbuf, sizeof( psz_sesbuf ), "%"PRIx64, ses->id ); psz_session = psz_sesbuf; } else { /* FIXME: we probably need to remove an access out, * if there is already one for the same ID */ ses = RtspClientGet( rtsp, psz_session ); if( ses == NULL ) { answer->i_status = 454; vlc_mutex_unlock( &rtsp->lock ); continue; } } INSERT_ELEM( ses->trackv, ses->trackc, ses->trackc, track ); vlc_mutex_unlock( &rtsp->lock ); httpd_ServerIP( cl, ip ); if( strcmp( src, ip ) ) { /* Specify source IP if it is different from the RTSP * control connection server address */ char *ptr = strchr( src, '%' ); if( ptr != NULL ) *ptr = '\0'; /* remove scope ID */ httpd_MsgAdd( answer, "Transport", "RTP/AVP/UDP;unicast;source=%s;" "client_port=%u-%u;server_port=%u-%u;" "ssrc=%08X;mode=play", src, loport, loport + 1, sport, sport + 1, id->ssrc ); } else { httpd_MsgAdd( answer, "Transport", "RTP/AVP/UDP;unicast;" "client_port=%u-%u;server_port=%u-%u;" "ssrc=%08X;mode=play", loport, loport + 1, sport, sport + 1, id->ssrc ); } answer->i_status = 200; } break; } break; case HTTPD_MSG_PLAY: { rtsp_session_t *ses; answer->i_status = 200; psz_session = httpd_MsgGet( query, "Session" ); const char *range = httpd_MsgGet (query, "Range"); if (range && strncmp (range, "npt=", 4)) { answer->i_status = 501; break; } vlc_mutex_lock( &rtsp->lock ); ses = RtspClientGet( rtsp, psz_session ); if( ses != NULL ) { /* FIXME: we really need to limit the number of tracks... */ char info[ses->trackc * ( strlen( control ) + sizeof("url=/trackID=123;seq=65535, ") ) + 1]; size_t infolen = 0; for( int i = 0; i < ses->trackc; i++ ) { rtsp_strack_t *tr = ses->trackv + i; if( ( id == NULL ) || ( tr->id == id->sout_id ) ) { if( !tr->playing ) { tr->playing = true; rtp_add_sink( tr->id, tr->fd, false ); } infolen += sprintf( info + infolen, "url=%s/trackID=%u;seq=%u, ", control, rtp_get_num( tr->id ), rtp_get_seq( tr->id ) ); } } if( infolen > 0 ) { info[infolen - 2] = '\0'; /* remove trailing ", " */ httpd_MsgAdd( answer, "RTP-Info", "%s", info ); } } vlc_mutex_unlock( &rtsp->lock ); if( httpd_MsgGet( query, "Scale" ) != NULL ) httpd_MsgAdd( answer, "Scale", "1." ); break; } case HTTPD_MSG_PAUSE: answer->i_status = 405; httpd_MsgAdd( answer, "Allow", "%s, TEARDOWN, PLAY, GET_PARAMETER", ( id != NULL ) ? "SETUP" : "DESCRIBE" ); break; case HTTPD_MSG_GETPARAMETER: if( query->i_body > 0 ) { answer->i_status = 451; break; } psz_session = httpd_MsgGet( query, "Session" ); answer->i_status = 200; break; case HTTPD_MSG_TEARDOWN: { rtsp_session_t *ses; answer->i_status = 200; psz_session = httpd_MsgGet( query, "Session" ); vlc_mutex_lock( &rtsp->lock ); ses = RtspClientGet( rtsp, psz_session ); if( ses != NULL ) { if( id == NULL ) /* Delete the entire session */ RtspClientDel( rtsp, ses ); else /* Delete one track from the session */ for( int i = 0; i < ses->trackc; i++ ) { if( ses->trackv[i].id == id->sout_id ) { rtp_del_sink( id->sout_id, ses->trackv[i].fd ); REMOVE_ELEM( ses->trackv, ses->trackc, i ); } } } vlc_mutex_unlock( &rtsp->lock ); break; } default: return VLC_EGENERIC; } if( psz_session ) httpd_MsgAdd( answer, "Session", "%s"/*;timeout=5*/, psz_session ); httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); httpd_MsgAdd( answer, "Cache-Control", "no-cache" ); psz = httpd_MsgGet( query, "Cseq" ); if( psz != NULL ) httpd_MsgAdd( answer, "Cseq", "%s", psz ); psz = httpd_MsgGet( query, "Timestamp" ); if( psz != NULL ) httpd_MsgAdd( answer, "Timestamp", "%s", psz ); return VLC_SUCCESS; }
/** * Add a playlist item into a playlist * * \param p_playlist the playlist to insert into * \param p_item the playlist item to insert * \param i_mode the mode used when adding * \param i_pos the possition in the playlist where to add. If this is * PLAYLIST_END the item will be added at the end of the playlist * regardless of it's size * \return The id of the playlist item */ int playlist_AddItem( playlist_t *p_playlist, playlist_item_t *p_item, int i_mode, int i_pos) { vlc_value_t val; vlc_mutex_lock( &p_playlist->object_lock ); /* * CHECK_INSERT : checks if the item is already enqued before * enqueing it */ if ( i_mode & PLAYLIST_CHECK_INSERT ) { int j; if ( p_playlist->pp_items ) { for ( j = 0; j < p_playlist->i_size; j++ ) { if ( !strcmp( p_playlist->pp_items[j]->input.psz_uri, p_item->input.psz_uri ) ) { if ( p_item->input.psz_name ) { free( p_item->input.psz_name ); } if ( p_item->input.psz_uri ) { free ( p_item->input.psz_uri ); } free( p_item ); vlc_mutex_unlock( &p_playlist->object_lock ); return -1; } } } i_mode &= ~PLAYLIST_CHECK_INSERT; i_mode |= PLAYLIST_APPEND; } msg_Dbg( p_playlist, "adding playlist item `%s' ( %s )", p_item->input.psz_name, p_item->input.psz_uri ); p_item->i_id = ++p_playlist->i_last_id; /* Do a few boundary checks and allocate space for the item */ if( i_pos == PLAYLIST_END ) { if( i_mode & PLAYLIST_INSERT ) { i_mode &= ~PLAYLIST_INSERT; i_mode |= PLAYLIST_APPEND; } i_pos = p_playlist->i_size - 1; } if( !(i_mode & PLAYLIST_REPLACE) || i_pos < 0 || i_pos >= p_playlist->i_size ) { /* Additional boundary checks */ if( i_mode & PLAYLIST_APPEND ) { i_pos++; } if( i_pos < 0 ) { i_pos = 0; } else if( i_pos > p_playlist->i_size ) { i_pos = p_playlist->i_size; } INSERT_ELEM( p_playlist->pp_items, p_playlist->i_size, i_pos, p_item ); p_playlist->i_enabled ++; if( p_playlist->i_index >= i_pos ) { p_playlist->i_index++; } } else { /* i_mode == PLAYLIST_REPLACE and 0 <= i_pos < p_playlist->i_size */ if( p_playlist->pp_items[i_pos]->input.psz_name ) { free( p_playlist->pp_items[i_pos]->input.psz_name ); } if( p_playlist->pp_items[i_pos]->input.psz_uri ) { free( p_playlist->pp_items[i_pos]->input.psz_uri ); } /* XXX: what if the item is still in use? */ free( p_playlist->pp_items[i_pos] ); p_playlist->pp_items[i_pos] = p_item; } if( i_mode & PLAYLIST_GO ) { p_playlist->i_index = i_pos; if( p_playlist->p_input ) { input_StopThread( p_playlist->p_input ); } p_playlist->i_status = PLAYLIST_RUNNING; } vlc_mutex_unlock( &p_playlist->object_lock ); val.b_bool = VLC_TRUE; var_Set( p_playlist, "intf-change", val ); return p_item->i_id; }
/** * Add a playlist item into a playlist * * \param p_playlist the playlist to insert into * \param p_item the playlist item to insert * \param i_mode the mode used when adding * \param i_pos the possition in the playlist where to add. If this is * PLAYLIST_END the item will be added at the end of the playlist * regardless of it's size * \return The id of the playlist item */ int playlist_AddItem( playlist_t *p_playlist, playlist_item_t *p_item, int i_mode, int i_pos) { vlc_value_t val; vlc_bool_t b_end = VLC_FALSE; playlist_view_t *p_view = NULL; playlist_add_t *p_add = (playlist_add_t *)malloc(sizeof( playlist_add_t)); vlc_mutex_lock( &p_playlist->object_lock ); /* * CHECK_INSERT : checks if the item is already enqued before * enqueing it */ /* That should not change */ if ( i_mode & PLAYLIST_CHECK_INSERT ) { int j; if ( p_playlist->pp_items ) { for ( j = 0; j < p_playlist->i_size; j++ ) { if ( !strcmp( p_playlist->pp_items[j]->input.psz_uri, p_item->input.psz_uri ) ) { playlist_ItemDelete( p_item ); vlc_mutex_unlock( &p_playlist->object_lock ); return -1; } } } i_mode &= ~PLAYLIST_CHECK_INSERT; i_mode |= PLAYLIST_APPEND; } msg_Dbg( p_playlist, "adding playlist item `%s' ( %s )", p_item->input.psz_name, p_item->input.psz_uri ); p_item->input.i_id = ++p_playlist->i_last_id; /* Do a few boundary checks and allocate space for the item */ if( i_pos == PLAYLIST_END ) { b_end = VLC_TRUE; if( i_mode & PLAYLIST_INSERT ) { i_mode &= ~PLAYLIST_INSERT; i_mode |= PLAYLIST_APPEND; } i_pos = p_playlist->i_size - 1; } if( !(i_mode & PLAYLIST_REPLACE) || i_pos < 0 || i_pos >= p_playlist->i_size ) { /* Additional boundary checks */ if( i_mode & PLAYLIST_APPEND ) { i_pos++; } if( i_pos < 0 ) { i_pos = 0; } else if( i_pos > p_playlist->i_size ) { i_pos = p_playlist->i_size; } INSERT_ELEM( p_playlist->pp_items, p_playlist->i_size, i_pos, p_item ); INSERT_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size, p_playlist->i_all_size, p_item ); p_playlist->i_enabled ++; /* We update the ALL view directly */ playlist_ViewUpdate( p_playlist, VIEW_ALL ); /* Add the item to the General category */ if( b_end == VLC_TRUE ) { playlist_NodeAppend( p_playlist, VIEW_CATEGORY, p_item, p_playlist->p_general ); p_add->i_item = p_item->input.i_id; p_add->i_node = p_playlist->p_general->input.i_id; p_add->i_view = VIEW_CATEGORY; val.p_address = p_add; var_Set( p_playlist, "item-append", val ); } else { playlist_NodeInsert( p_playlist, VIEW_CATEGORY, p_item, p_playlist->p_general, i_pos ); } p_view = playlist_ViewFind( p_playlist, VIEW_ALL ); playlist_ItemAddParent( p_item, VIEW_ALL, p_view->p_root ); /* FIXME : Update sorted views */ if( p_playlist->i_index >= i_pos ) { p_playlist->i_index++; } } else { msg_Err( p_playlist, "Insert mode not implemented" ); } if( (i_mode & PLAYLIST_GO ) && p_view ) { p_playlist->request.b_request = VLC_TRUE; /* FIXME ... */ p_playlist->request.i_view = VIEW_CATEGORY; p_playlist->request.p_node = p_view->p_root; p_playlist->request.p_item = p_item; if( p_playlist->p_input ) { input_StopThread( p_playlist->p_input ); } p_playlist->status.i_status = PLAYLIST_RUNNING; } if( i_mode & PLAYLIST_PREPARSE && var_CreateGetBool( p_playlist, "auto-preparse" ) ) { playlist_PreparseEnqueue( p_playlist, &p_item->input ); } vlc_mutex_unlock( &p_playlist->object_lock ); if( b_end == VLC_FALSE ) { val.b_bool = VLC_TRUE; var_Set( p_playlist, "intf-change", val ); } free( p_add ); return p_item->input.i_id; }
/** * Add a playlist item to a given node (in the category view ) * * \param p_playlist the playlist to insert into * \param p_item the playlist item to insert * \param i_view the view for which to add or TODO: ALL_VIEWS * \param p_parent the parent node * \param i_mode the mode used when adding * \param i_pos the possition in the node where to add. If this is * PLAYLIST_END the item will be added at the end of the node ** \return The id of the playlist item */ int playlist_NodeAddItem( playlist_t *p_playlist, playlist_item_t *p_item, int i_view,playlist_item_t *p_parent, int i_mode, int i_pos) { vlc_value_t val; int i_position; playlist_view_t *p_view; playlist_add_t *p_add = (playlist_add_t *)malloc(sizeof( playlist_add_t)); vlc_mutex_lock( &p_playlist->object_lock ); if ( i_pos == PLAYLIST_END ) i_pos = -1; /* Sanity checks */ if( !p_parent || p_parent->i_children == -1 ) { msg_Err( p_playlist, "invalid node" ); } /* * CHECK_INSERT : checks if the item is already enqued before * enqueing it */ if ( i_mode & PLAYLIST_CHECK_INSERT ) { int j; if ( p_playlist->pp_items ) { for ( j = 0; j < p_playlist->i_size; j++ ) { if ( !strcmp( p_playlist->pp_items[j]->input.psz_uri, p_item->input.psz_uri ) ) { playlist_ItemDelete( p_item ); vlc_mutex_unlock( &p_playlist->object_lock ); free( p_add ); return -1; } } } i_mode &= ~PLAYLIST_CHECK_INSERT; i_mode |= PLAYLIST_APPEND; } msg_Dbg( p_playlist, "adding playlist item `%s' ( %s )", p_item->input.psz_name, p_item->input.psz_uri ); p_item->input.i_id = ++p_playlist->i_last_id; /* First, add the item at the right position in the item bank */ /* WHY THAT ? */ //i_position = p_playlist->i_index == -1 ? 0 : p_playlist->i_index; i_position = p_playlist->i_size ; INSERT_ELEM( p_playlist->pp_items, p_playlist->i_size, i_position, p_item ); INSERT_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size, p_playlist->i_all_size, p_item ); p_playlist->i_enabled ++; /* TODO: Handle modes */ playlist_NodeInsert( p_playlist, i_view, p_item, p_parent, i_pos ); p_add->i_item = p_item->input.i_id; p_add->i_node = p_parent->input.i_id; p_add->i_view = i_view; val.p_address = p_add; var_Set( p_playlist, "item-append", val ); /* We update the ALL view directly */ p_view = playlist_ViewFind( p_playlist, VIEW_ALL ); playlist_ItemAddParent( p_item, VIEW_ALL, p_view->p_root ); playlist_ViewUpdate( p_playlist, VIEW_ALL ); /* TODO : Update sorted views*/ if( i_mode & PLAYLIST_GO ) { p_playlist->request.b_request = VLC_TRUE; p_playlist->request.i_view = VIEW_CATEGORY; p_playlist->request.p_node = p_parent; p_playlist->request.p_item = p_item; if( p_playlist->p_input ) { input_StopThread( p_playlist->p_input ); } p_playlist->status.i_status = PLAYLIST_RUNNING; } if( i_mode & PLAYLIST_PREPARSE && var_CreateGetBool( p_playlist, "auto-preparse" ) ) { playlist_PreparseEnqueue( p_playlist, &p_item->input ); } vlc_mutex_unlock( &p_playlist->object_lock ); val.b_bool = VLC_TRUE; // var_Set( p_playlist, "intf-change", val ); // free( p_add ); return p_item->input.i_id; }
static int Demux( demux_t *p_demux ) { char *psz_line; char *psz_name = NULL; char *psz_artist = NULL; int i_parsed_duration = 0; mtime_t i_duration = -1; const char**ppsz_options = NULL; char * (*pf_dup) (const char *) = p_demux->p_sys->pf_dup; int i_options = 0; bool b_cleanup = false; input_item_t *p_input; input_item_t *p_current_input = GetCurrentItem(p_demux); psz_line = stream_ReadLine( p_demux->s ); while( psz_line ) { char *psz_parse = psz_line; /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++; if( *psz_parse == '#' ) { /* Parse extra info */ /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' || *psz_parse == '#' ) psz_parse++; if( !*psz_parse ) goto error; if( !strncasecmp( psz_parse, "EXTINF:", sizeof("EXTINF:") -1 ) ) { /* Extended info */ psz_parse += sizeof("EXTINF:") - 1; parseEXTINF( psz_parse, &psz_artist, &psz_name, &i_parsed_duration ); if( i_parsed_duration >= 0 ) i_duration = i_parsed_duration * INT64_C(1000000); if( psz_name ) psz_name = pf_dup( psz_name ); if( psz_artist ) psz_artist = pf_dup( psz_artist ); } else if( !strncasecmp( psz_parse, "EXTVLCOPT:", sizeof("EXTVLCOPT:") -1 ) ) { /* VLC Option */ char *psz_option; psz_parse += sizeof("EXTVLCOPT:") -1; if( !*psz_parse ) goto error; psz_option = pf_dup( psz_parse ); if( psz_option ) INSERT_ELEM( ppsz_options, i_options, i_options, psz_option ); } } else if( !strncasecmp( psz_parse, "RTSPtext", sizeof("RTSPtext") -1 ) ) { ;/* special case to handle QuickTime RTSPtext redirect files */ } else if( *psz_parse ) { char *psz_mrl; psz_parse = pf_dup( psz_parse ); if( !psz_name && psz_parse ) /* Use filename as name for relative entries */ psz_name = strdup( psz_parse ); psz_mrl = ProcessMRL( psz_parse, p_demux->p_sys->psz_prefix ); b_cleanup = true; if( !psz_mrl ) goto error; p_input = input_item_NewExt( p_demux, psz_mrl, psz_name, i_options, ppsz_options, 0, i_duration ); LocaleFree( psz_parse ); free( psz_mrl ); if ( psz_artist && *psz_artist ) input_item_SetArtist( p_input, psz_artist ); if( psz_name ) input_item_SetTitle( p_input, psz_name ); input_item_AddSubItem( p_current_input, p_input ); vlc_gc_decref( p_input ); } error: /* Fetch another line */ free( psz_line ); psz_line = stream_ReadLine( p_demux->s ); if( !psz_line ) b_cleanup = true; if( b_cleanup ) { /* Cleanup state */ while( i_options-- ) free( (char*)ppsz_options[i_options] ); free( ppsz_options ); ppsz_options = NULL; i_options = 0; free( psz_name ); psz_name = NULL; free( psz_artist ); psz_artist = NULL; i_parsed_duration = 0; i_duration = -1; b_cleanup = false; } } vlc_gc_decref(p_current_input); var_Destroy( p_demux, "m3u-extvlcopt" ); return 0; /* Needed for correct operation of go back */ }
/** * Initialize a vlc object * * This function allocates memory for a vlc object and initializes it. If * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and * so on, vlc_object_create will use its value for the object size. */ void * __vlc_object_create( vlc_object_t *p_this, int i_type ) { vlc_object_t * p_new; char * psz_type; size_t i_size; switch( i_type ) { case VLC_OBJECT_ROOT: i_size = sizeof(libvlc_t); psz_type = "root"; break; case VLC_OBJECT_VLC: i_size = sizeof(vlc_t); psz_type = "vlc"; break; case VLC_OBJECT_MODULE: i_size = sizeof(module_t); psz_type = "module"; break; case VLC_OBJECT_INTF: i_size = sizeof(intf_thread_t); psz_type = "interface"; break; case VLC_OBJECT_DIALOGS: i_size = sizeof(intf_thread_t); psz_type = "dialogs provider"; break; case VLC_OBJECT_PLAYLIST: i_size = sizeof(playlist_t); psz_type = "playlist"; break; case VLC_OBJECT_INPUT: i_size = sizeof(input_thread_t); psz_type = "input"; break; case VLC_OBJECT_DEMUX: i_size = sizeof(demux_t); psz_type = "demux"; break; case VLC_OBJECT_STREAM: i_size = sizeof(stream_t); psz_type = "stream"; break; case VLC_OBJECT_ACCESS: i_size = sizeof(access_t); psz_type = "access"; break; case VLC_OBJECT_DECODER: i_size = sizeof(decoder_t); psz_type = "decoder"; break; case VLC_OBJECT_PACKETIZER: i_size = sizeof(decoder_t); psz_type = "packetizer"; break; case VLC_OBJECT_ENCODER: i_size = sizeof(encoder_t); psz_type = "encoder"; break; case VLC_OBJECT_FILTER: i_size = sizeof(filter_t); psz_type = "filter"; break; case VLC_OBJECT_VOUT: i_size = sizeof(vout_thread_t); psz_type = "video output"; break; case VLC_OBJECT_SPU: i_size = sizeof(spu_t); psz_type = "subpicture unit"; break; case VLC_OBJECT_AOUT: i_size = sizeof(aout_instance_t); psz_type = "audio output"; break; case VLC_OBJECT_SOUT: i_size = sizeof(sout_instance_t); psz_type = "stream output"; break; case VLC_OBJECT_HTTPD: i_size = sizeof( httpd_t ); psz_type = "http daemon"; break; case VLC_OBJECT_VLM: i_size = sizeof( vlm_t ); psz_type = "vlm dameon"; break; case VLC_OBJECT_VOD: i_size = sizeof( vod_t ); psz_type = "vod server"; break; case VLC_OBJECT_TLS: i_size = sizeof( tls_t ); psz_type = "tls"; break; case VLC_OBJECT_OPENGL: i_size = sizeof( vout_thread_t ); psz_type = "opengl provider"; break; case VLC_OBJECT_ANNOUNCE: i_size = sizeof( announce_handler_t ); psz_type = "announce handler"; break; default: i_size = i_type > 0 ? i_type > (int)sizeof(vlc_object_t) ? i_type : (int)sizeof(vlc_object_t) : (int)sizeof(vlc_object_t); i_type = VLC_OBJECT_GENERIC; psz_type = "generic"; break; } if( i_type == VLC_OBJECT_ROOT ) { p_new = p_this; } else { p_new = malloc( i_size ); if( !p_new ) return NULL; memset( p_new, 0, i_size ); } p_new->i_object_type = i_type; p_new->psz_object_type = psz_type; p_new->psz_object_name = NULL; p_new->b_die = VLC_FALSE; p_new->b_error = VLC_FALSE; p_new->b_dead = VLC_FALSE; p_new->b_attached = VLC_FALSE; p_new->b_force = VLC_FALSE; p_new->i_vars = 0; p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) ); if( !p_new->p_vars ) { free( p_new ); return NULL; } if( i_type == VLC_OBJECT_ROOT ) { /* If i_type is root, then p_new is actually p_libvlc */ p_new->p_libvlc = (libvlc_t*)p_new; p_new->p_vlc = NULL; p_new->p_libvlc->i_counter = 0; p_new->i_object_id = 0; p_new->p_libvlc->i_objects = 1; p_new->p_libvlc->pp_objects = malloc( sizeof(vlc_object_t *) ); p_new->p_libvlc->pp_objects[0] = p_new; p_new->b_attached = VLC_TRUE; } else { p_new->p_libvlc = p_this->p_libvlc; p_new->p_vlc = ( i_type == VLC_OBJECT_VLC ) ? (vlc_t*)p_new : p_this->p_vlc; vlc_mutex_lock( &structure_lock ); p_new->p_libvlc->i_counter++; p_new->i_object_id = p_new->p_libvlc->i_counter; /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's * useless to try and recover anything if pp_objects gets smashed. */ INSERT_ELEM( p_new->p_libvlc->pp_objects, p_new->p_libvlc->i_objects, p_new->p_libvlc->i_objects, p_new ); vlc_mutex_unlock( &structure_lock ); } p_new->i_refcount = 0; p_new->p_parent = NULL; p_new->pp_children = NULL; p_new->i_children = 0; p_new->p_private = NULL; /* Initialize mutexes and condvars */ vlc_mutex_init( p_new, &p_new->object_lock ); vlc_cond_init( p_new, &p_new->object_wait ); vlc_mutex_init( p_new, &p_new->var_lock ); if( i_type == VLC_OBJECT_ROOT ) { vlc_mutex_init( p_new, &structure_lock ); var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_new, "list", DumpCommand, NULL ); var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_new, "tree", DumpCommand, NULL ); } return p_new; }
/** * Detect subtitle files. * * When called this function will split up the psz_name string into a * directory, filename and extension. It then opens the directory * in which the file resides and tries to find possible matches of * subtitles files. * * \ingroup Demux * \param p_this the calling \ref input_thread_t * \param psz_path a list of subdirectories (separated by a ',') to look in. * \param psz_name_org the complete filename to base the search on. * \param pp_slaves an initialized input item slave list to append detected subtitles to * \param p_slaves pointer to the size of the slave list * \return VLC_SUCCESS if ok */ int subtitles_Detect( input_thread_t *p_this, char *psz_path, const char *psz_name_org, input_item_slave_t ***ppp_slaves, int *p_slaves ) { int i_fuzzy = var_GetInteger( p_this, "sub-autodetect-fuzzy" ); if ( i_fuzzy == 0 ) return VLC_EGENERIC; int j, i_fname_len; input_item_slave_t **pp_slaves = *ppp_slaves; int i_slaves = *p_slaves; char *f_fname_noext = NULL, *f_fname_trim = NULL; char **subdirs; /* list of subdirectories to look in */ if( !psz_name_org ) return VLC_EGENERIC; char *psz_fname = vlc_uri2path( psz_name_org ); if( !psz_fname ) return VLC_EGENERIC; /* extract filename & dirname from psz_fname */ char *f_dir = strdup( psz_fname ); if( f_dir == 0 ) { free( psz_fname ); return VLC_ENOMEM; } const char *f_fname = strrchr( psz_fname, DIR_SEP_CHAR ); if( !f_fname ) { free( f_dir ); free( psz_fname ); return VLC_EGENERIC; } f_fname++; /* Skip the '/' */ f_dir[f_fname - psz_fname] = 0; /* keep dir separator in f_dir */ i_fname_len = strlen( f_fname ); f_fname_noext = malloc(i_fname_len + 1); f_fname_trim = malloc(i_fname_len + 1 ); if( !f_fname_noext || !f_fname_trim ) { free( f_dir ); free( f_fname_noext ); free( f_fname_trim ); free( psz_fname ); return VLC_ENOMEM; } strcpy_strip_ext( f_fname_noext, f_fname ); strcpy_trim( f_fname_trim, f_fname_noext ); subdirs = paths_to_list( f_dir, psz_path ); for( j = -1; (j == -1) || ( j >= 0 && subdirs != NULL && subdirs[j] != NULL ); j++ ) { const char *psz_dir = (j < 0) ? f_dir : subdirs[j]; if( psz_dir == NULL || ( j >= 0 && !strcmp( psz_dir, f_dir ) ) ) continue; /* parse psz_src dir */ DIR *dir = vlc_opendir( psz_dir ); if( dir == NULL ) continue; msg_Dbg( p_this, "looking for a subtitle file in %s", psz_dir ); const char *psz_name; while( (psz_name = vlc_readdir( dir )) ) { if( psz_name[0] == '.' || !subtitles_Filter( psz_name ) ) continue; char tmp_fname_noext[strlen( psz_name ) + 1]; char tmp_fname_trim[strlen( psz_name ) + 1]; char tmp_fname_ext[strlen( psz_name ) + 1]; const char *tmp; int i_prio = 0; /* retrieve various parts of the filename */ strcpy_strip_ext( tmp_fname_noext, psz_name ); strcpy_get_ext( tmp_fname_ext, psz_name ); strcpy_trim( tmp_fname_trim, tmp_fname_noext ); if( !strcmp( tmp_fname_trim, f_fname_trim ) ) { /* matches the movie name exactly */ i_prio = SLAVE_PRIORITY_MATCH_ALL; } else if( (tmp = strstr( tmp_fname_trim, f_fname_trim )) ) { /* contains the movie name */ tmp += strlen( f_fname_trim ); if( whiteonly( tmp ) ) { /* chars in front of the movie name */ i_prio = SLAVE_PRIORITY_MATCH_RIGHT; } else { /* chars after (and possibly in front of) * the movie name */ i_prio = SLAVE_PRIORITY_MATCH_LEFT; } } else if( j == -1 ) { /* doesn't contain the movie name, prefer files in f_dir over subdirs */ i_prio = SLAVE_PRIORITY_MATCH_NONE; } if( i_prio >= i_fuzzy ) { struct stat st; char *path; size_t i_len = strlen( psz_dir ); const char *psz_format; if ( i_len == 0 ) continue; if( psz_dir[i_len - 1] == DIR_SEP_CHAR ) psz_format = "%s%s"; else psz_format = "%s"DIR_SEP"%s"; if( asprintf( &path, psz_format, psz_dir, psz_name ) < 0 ) continue; if( strcmp( path, psz_fname ) && vlc_stat( path, &st ) == 0 && S_ISREG( st.st_mode ) ) { msg_Dbg( p_this, "autodetected subtitle: %s with priority %d", path, i_prio ); char *psz_uri = vlc_path2uri( path, NULL ); input_item_slave_t *p_sub = psz_uri != NULL ? input_item_slave_New( psz_uri, SLAVE_TYPE_SPU, i_prio ) : NULL; if( p_sub ) { p_sub->b_forced = true; INSERT_ELEM( pp_slaves, i_slaves, i_slaves, p_sub ); } free( psz_uri ); } free( path ); } } closedir( dir ); } if( subdirs ) { for( j = 0; subdirs[j]; j++ ) free( subdirs[j] ); free( subdirs ); } free( f_dir ); free( f_fname_trim ); free( f_fname_noext ); free( psz_fname ); for( int i = 0; i < i_slaves; i++ ) { input_item_slave_t *p_sub = pp_slaves[i]; bool b_reject = false; char *psz_ext = strrchr( p_sub->psz_uri, '.' ); if( !psz_ext ) continue; psz_ext++; if( !strcasecmp( psz_ext, "sub" ) ) { for( int j = 0; j < i_slaves; j++ ) { input_item_slave_t *p_sub_inner = pp_slaves[j]; /* A slave can be null if it's already rejected */ if( p_sub_inner == NULL ) continue; /* check that the filenames without extension match */ if( strncasecmp( p_sub->psz_uri, p_sub_inner->psz_uri, strlen( p_sub->psz_uri ) - 3 ) ) continue; char *psz_ext_inner = strrchr( p_sub_inner->psz_uri, '.' ); if( !psz_ext_inner ) continue; psz_ext_inner++; /* check that we have an idx file */ if( !strcasecmp( psz_ext_inner, "idx" ) ) { b_reject = true; break; } } } else if( !strcasecmp( psz_ext, "cdg" ) ) { if( p_sub->i_priority < SLAVE_PRIORITY_MATCH_ALL ) b_reject = true; } if( b_reject ) { pp_slaves[i] = NULL; input_item_slave_Delete( p_sub ); } } /* Sort alphabetically */ if( i_slaves > 0 ) qsort( pp_slaves, i_slaves, sizeof (input_item_slave_t*), slave_strcmp ); *ppp_slaves = pp_slaves; /* in case of realloc */ *p_slaves = i_slaves; return VLC_SUCCESS; }
static int ParseLine( char *psz_line, char **ppsz_name, char ***pppsz_options, int *pi_options ) { char *psz_name = 0, *psz_parse = psz_line; int i_count = 0, i_program = 0, i_frequency = 0; vlc_bool_t b_valid = VLC_FALSE; if( pppsz_options ) *pppsz_options = 0; if( pi_options ) *pi_options = 0; if( ppsz_name ) *ppsz_name = 0; /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++; /* Ignore comments */ if( *psz_parse == '#' ) return VLC_FALSE; while( psz_parse ) { char *psz_option = 0; char *psz_end = strchr( psz_parse, ':' ); if( psz_end ) { *psz_end = 0; psz_end++; } if( i_count == 0 ) { /* Channel name */ psz_name = psz_parse; } else if( i_count == 1 ) { /* Frequency */ char *psz_end; long i_value; i_value = strtol( psz_parse, &psz_end, 10 ); if( psz_end == psz_parse || i_value == LONG_MAX || i_value == LONG_MIN ) break; i_frequency = i_value; } else { int i; /* Check option name with our list */ for( i = 0; dvb_options[i].psz_name; i++ ) { if( !strcmp( psz_parse, dvb_options[i].psz_name ) ) { psz_option = dvb_options[i].psz_option; /* If we recognize one of the strings, then we are sure * the data is really valid (ie. a channels file). */ b_valid = VLC_TRUE; break; } } if( !psz_option ) { /* Option not recognized, test if it is a number */ char *psz_end; long i_value; i_value = strtol( psz_parse, &psz_end, 10 ); if( psz_end != psz_parse && i_value != LONG_MAX && i_value != LONG_MIN ) { i_program = i_value; } } } if( psz_option && pppsz_options && pi_options ) { psz_option = strdup( psz_option ); INSERT_ELEM( *pppsz_options, (*pi_options), (*pi_options), psz_option ); } psz_parse = psz_end; i_count++; } if( !b_valid && pppsz_options && pi_options ) { /* This isn't a valid channels file, cleanup everything */ while( (*pi_options)-- ) free( (*pppsz_options)[*pi_options] ); if( *pppsz_options ) free( *pppsz_options ); *pppsz_options = 0; *pi_options = 0; } if( i_program && pppsz_options && pi_options ) { char *psz_option; asprintf( &psz_option, "program=%i", i_program ); INSERT_ELEM( *pppsz_options, (*pi_options), (*pi_options), psz_option ); } if( i_frequency && pppsz_options && pi_options ) { char *psz_option; asprintf( &psz_option, "dvb-frequency=%i", i_frequency ); INSERT_ELEM( *pppsz_options, (*pi_options), (*pi_options), psz_option ); } if( ppsz_name && psz_name ) *ppsz_name = strdup( psz_name ); return b_valid; }
/** * Initialize a vlc variable * * We hash the given string and insert it into the sorted list. The insertion * may require slow memory copies, but think about what we gain in the log(n) * lookup phase when setting/getting the variable value! * * \param p_this The object in which to create the variable * \param psz_name The name of the variable * \param i_type The variables type. Must be one of \ref var_type combined with * zero or more \ref var_flags */ int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type ) { assert( p_this ); variable_t *p_var = calloc( 1, sizeof( *p_var ) ); if( p_var == NULL ) return VLC_ENOMEM; p_var->psz_name = strdup( psz_name ); p_var->psz_text = NULL; p_var->i_type = i_type & ~VLC_VAR_DOINHERIT; p_var->i_usage = 1; p_var->i_default = -1; p_var->choices.i_count = 0; p_var->choices.p_values = NULL; p_var->choices_text.i_count = 0; p_var->choices_text.p_values = NULL; p_var->b_incallback = false; p_var->i_entries = 0; p_var->p_entries = NULL; /* Always initialize the variable, even if it is a list variable; this * will lead to errors if the variable is not initialized, but it will * not cause crashes in the variable handling. */ switch( i_type & VLC_VAR_CLASS ) { case VLC_VAR_BOOL: p_var->ops = &bool_ops; p_var->val.b_bool = false; break; case VLC_VAR_INTEGER: p_var->ops = &int_ops; p_var->val.i_int = 0; break; case VLC_VAR_STRING: p_var->ops = &string_ops; p_var->val.psz_string = NULL; break; case VLC_VAR_FLOAT: p_var->ops = &float_ops; p_var->val.f_float = 0.0; break; case VLC_VAR_TIME: p_var->ops = &time_ops; p_var->val.i_time = 0; break; case VLC_VAR_COORDS: p_var->ops = &coords_ops; p_var->val.coords.x = p_var->val.coords.y = 0; break; case VLC_VAR_ADDRESS: p_var->ops = &addr_ops; p_var->val.p_address = NULL; break; default: p_var->ops = &void_ops; #ifndef NDEBUG if( (i_type & VLC_VAR_CLASS) != VLC_VAR_VOID ) msg_Err( p_this, "Creating the variable '%s' without a type", psz_name ); #endif } if( i_type & VLC_VAR_DOINHERIT ) { if( var_Inherit( p_this, psz_name, i_type, &p_var->val ) ) msg_Err( p_this, "cannot inherit value for %s", psz_name ); else if( i_type & VLC_VAR_HASCHOICE ) { /* We must add the inherited value to our choice list */ p_var->i_default = 0; INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count, 0, p_var->val ); INSERT_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, 0, p_var->val ); p_var->ops->pf_dup( &p_var->choices.p_values[0] ); p_var->choices_text.p_values[0].psz_string = NULL; } } vlc_object_internals_t *p_priv = vlc_internals( p_this ); variable_t **pp_var, *p_oldvar; int ret = VLC_SUCCESS; vlc_mutex_lock( &p_priv->var_lock ); pp_var = tsearch( p_var, &p_priv->var_root, varcmp ); if( unlikely(pp_var == NULL) ) ret = VLC_ENOMEM; else if( (p_oldvar = *pp_var) == p_var ) p_var = NULL; else if( unlikely((i_type ^ p_oldvar->i_type) & VLC_VAR_CLASS) ) { /* If the types differ, variable creation failed. */ msg_Err( p_this, "Variable '%s' (0x%04x) already exist " "but with a different type (0x%04x)", psz_name, p_oldvar->i_type, i_type ); ret = VLC_EBADVAR; } else { p_oldvar->i_usage++; p_oldvar->i_type |= i_type & (VLC_VAR_ISCOMMAND|VLC_VAR_HASCHOICE); } vlc_mutex_unlock( &p_priv->var_lock ); /* If we did not need to create a new variable, free everything... */ if( p_var != NULL ) Destroy( p_var ); return ret; }
/* Add a SAP announce */ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, session_descriptor_t *p_session, announce_method_t *p_method ) { int i; char *psz_type = "application/sdp"; int i_header_size; char *psz_head; vlc_bool_t b_found = VLC_FALSE; sap_session_t *p_sap_session; mtime_t i_hash; vlc_mutex_lock( &p_sap->object_lock ); /* If needed, build the SDP */ if( !p_session->psz_sdp ) { if ( SDPGenerate( p_sap, p_session ) != VLC_SUCCESS ) { vlc_mutex_unlock( &p_sap->object_lock ); return VLC_EGENERIC; } } if( !p_method->psz_address ) { if( p_method->i_ip_version == 6 ) { char sz_scope; if( p_method->psz_ipv6_scope != NULL ) { sz_scope = *p_method->psz_ipv6_scope; } else { sz_scope = DEFAULT_IPV6_SCOPE; } p_method->psz_address = (char*)malloc( 30*sizeof(char )); sprintf( p_method->psz_address, "%s%c%s", SAP_IPV6_ADDR_1, sz_scope, SAP_IPV6_ADDR_2 ); } else { /* IPv4 */ p_method->psz_address = (char*)malloc( 15*sizeof(char) ); snprintf(p_method->psz_address, 15, SAP_IPV4_ADDR ); } } msg_Dbg( p_sap, "using SAP address: %s",p_method->psz_address); /* XXX: Check for dupes */ p_sap_session = (sap_session_t*)malloc(sizeof(sap_session_t)); p_sap_session->psz_sdp = strdup( p_session->psz_sdp ); p_sap_session->i_last = 0; /* Add the address to the buffer */ for( i = 0; i< p_sap->i_addresses; i++) { if( !strcmp( p_method->psz_address, p_sap->pp_addresses[i]->psz_address ) ) { p_sap_session->p_address = p_sap->pp_addresses[i]; b_found = VLC_TRUE; break; } } if( b_found == VLC_FALSE ) { sap_address_t *p_address = (sap_address_t *) malloc( sizeof(sap_address_t) ); if( !p_address ) { msg_Err( p_sap, "out of memory" ); return VLC_ENOMEM; } p_address->psz_address = strdup( p_method->psz_address ); p_address->i_ip_version = p_method->i_ip_version; p_address->i_port = 9875; p_address->i_wfd = net_OpenUDP( p_sap, "", 0, p_address->psz_address, p_address->i_port ); if( p_sap->b_control == VLC_TRUE ) { p_address->i_rfd = net_OpenUDP( p_sap, p_method->psz_address, p_address->i_port, "", 0 ); p_address->i_buff = 0; p_address->b_enabled = VLC_TRUE; p_address->b_ready = VLC_FALSE; p_address->i_limit = 10000; /* 10000 bps */ p_address->t1 = 0; } else { p_address->b_enabled = VLC_TRUE; p_address->b_ready = VLC_TRUE; p_address->i_interval = config_GetInt( p_sap,"sap-interval"); } if( p_address->i_wfd == -1 || (p_address->i_rfd == -1 && p_sap->b_control ) ) { msg_Warn( p_sap, "disabling address" ); p_address->b_enabled = VLC_FALSE; } INSERT_ELEM( p_sap->pp_addresses, p_sap->i_addresses, p_sap->i_addresses, p_address ); p_sap_session->p_address = p_address; } /* Build the SAP Headers */ i_header_size = ( p_method->i_ip_version == 6 ? 20 : 8 ) + strlen( psz_type ) + 1; psz_head = (char *) malloc( i_header_size * sizeof( char ) ); if( ! psz_head ) { msg_Err( p_sap, "out of memory" ); return VLC_ENOMEM; } psz_head[0] = 0x20; /* Means SAPv1, IPv4, not encrypted, not compressed */ psz_head[1] = 0x00; /* No authentification length */ i_hash = mdate(); psz_head[2] = (i_hash & 0xFF00) >> 8; /* Msg id hash */ psz_head[3] = (i_hash & 0xFF); /* Msg id hash 2 */ if( p_method->i_ip_version == 6 ) { /* in_addr_t ip_server = inet_addr( ip ); */ psz_head[0] |= 0x10; /* Set IPv6 */ psz_head[4] = 0x01; /* Source IP FIXME: we should get the real address */ psz_head[5] = 0x02; /* idem */ psz_head[6] = 0x03; /* idem */ psz_head[7] = 0x04; /* idem */ psz_head[8] = 0x01; /* Source IP FIXME: we should get the real address */ psz_head[9] = 0x02; /* idem */ psz_head[10] = 0x03; /* idem */ psz_head[11] = 0x04; /* idem */ psz_head[12] = 0x01; /* Source IP FIXME: we should get the real address */ psz_head[13] = 0x02; /* idem */ psz_head[14] = 0x03; /* idem */ psz_head[15] = 0x04; /* idem */ psz_head[16] = 0x01; /* Source IP FIXME: we should get the real address */ psz_head[17] = 0x02; /* idem */ psz_head[18] = 0x03; /* idem */ psz_head[19] = 0x04; /* idem */ strncpy( psz_head + 20, psz_type, 15 ); } else { /* in_addr_t ip_server = inet_addr( ip) */ /* Source IP FIXME: we should get the real address */ psz_head[4] = 0x01; /* ip_server */ psz_head[5] = 0x02; /* ip_server>>8 */ psz_head[6] = 0x03; /* ip_server>>16 */ psz_head[7] = 0x04; /* ip_server>>24 */ strncpy( psz_head + 8, psz_type, 15 ); } psz_head[ i_header_size-1 ] = '\0'; p_sap_session->i_length = i_header_size + strlen( p_sap_session->psz_sdp); p_sap_session->psz_data = (char *)malloc( sizeof(char)* p_sap_session->i_length ); /* Build the final message */ memcpy( p_sap_session->psz_data, psz_head, i_header_size ); memcpy( p_sap_session->psz_data+i_header_size, p_sap_session->psz_sdp, strlen( p_sap_session->psz_sdp) ); free( psz_head ); /* Enqueue the announce */ INSERT_ELEM( p_sap->pp_sessions, p_sap->i_sessions, p_sap->i_sessions, p_sap_session ); msg_Dbg( p_sap,"Addresses: %i Sessions: %i", p_sap->i_addresses,p_sap->i_sessions); /* Remember the SAP session for later deletion */ p_session->p_sap = p_sap_session; vlc_mutex_unlock( &p_sap->object_lock ); return VLC_SUCCESS; }
/** Parse a stringified option * This function parse a string option and create the associated object * variable * The option must be of the form "[no[-]]foo[=bar]" where foo is the * option name and bar is the value of the option. * \param p_obj the object in which the variable must be created * \param psz_option the option to parse * \return nothing */ void __var_OptionParse( vlc_object_t *p_obj, const char *psz_option ) { char *psz_name, *psz_value = strchr( psz_option, '=' ); int i_name_len, i_type; vlc_bool_t b_isno = VLC_FALSE; vlc_value_t val; if( psz_value ) i_name_len = psz_value - psz_option; else i_name_len = strlen( psz_option ); /* It's too much of an hassle to remove the ':' when we parse * the cmd line :) */ if( i_name_len && *psz_option == ':' ) { psz_option++; i_name_len--; } if( i_name_len == 0 ) return; psz_name = strndup( psz_option, i_name_len ); if( psz_value ) psz_value++; /* FIXME: :programs should be handled generically */ if( !strcmp( psz_name, "programs" ) ) i_type = VLC_VAR_LIST; else i_type = config_GetType( p_obj, psz_name ); if( !i_type && !psz_value ) { /* check for "no-foo" or "nofoo" */ if( !strncmp( psz_name, "no-", 3 ) ) { memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 ); } else if( !strncmp( psz_name, "no", 2 ) ) { memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 ); } else goto cleanup; /* Option doesn't exist */ b_isno = VLC_TRUE; i_type = config_GetType( p_obj, psz_name ); if( !i_type ) goto cleanup; /* Option doesn't exist */ } else if( !i_type ) goto cleanup; /* Option doesn't exist */ if( ( i_type != VLC_VAR_BOOL ) && ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */ /* Create the variable in the input object. * Children of the input object will be able to retreive this value * thanks to the inheritance property of the object variables. */ var_Create( p_obj, psz_name, i_type ); switch( i_type ) { case VLC_VAR_BOOL: val.b_bool = !b_isno; break; case VLC_VAR_INTEGER: val.i_int = strtol( psz_value, NULL, 0 ); break; case VLC_VAR_FLOAT: val.f_float = atof( psz_value ); break; case VLC_VAR_STRING: case VLC_VAR_MODULE: case VLC_VAR_FILE: case VLC_VAR_DIRECTORY: val.psz_string = psz_value; break; case VLC_VAR_LIST: { char *psz_orig, *psz_var; vlc_list_t *p_list = malloc(sizeof(vlc_list_t)); val.p_list = p_list; p_list->i_count = 0; psz_var = psz_orig = strdup(psz_value); while( psz_var && *psz_var ) { char *psz_item = psz_var; vlc_value_t val2; while( *psz_var && *psz_var != ',' ) psz_var++; if( *psz_var == ',' ) { *psz_var = '\0'; psz_var++; } val2.i_int = strtol( psz_item, NULL, 0 ); INSERT_ELEM( p_list->p_values, p_list->i_count, p_list->i_count, val2 ); /* p_list->i_count is incremented twice by INSERT_ELEM */ p_list->i_count--; INSERT_ELEM( p_list->pi_types, p_list->i_count, p_list->i_count, VLC_VAR_INTEGER ); } if( psz_orig ) free( psz_orig ); break; } default: goto cleanup; break; } var_Set( p_obj, psz_name, val ); cleanup: if( psz_name ) free( psz_name ); return; }
/** * Perform an action on a variable * * \param p_this The object that holds the variable * \param psz_name The name of the variable * \param i_action The action to perform. Must be one of \ref var_action * \param p_val First action parameter * \param p_val2 Second action parameter */ int __var_Change( vlc_object_t *p_this, const char *psz_name, int i_action, vlc_value_t *p_val, vlc_value_t *p_val2 ) { int i_var, i; variable_t *p_var; vlc_value_t oldval; vlc_mutex_lock( &p_this->var_lock ); i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_this->var_lock ); return VLC_ENOVAR; } p_var = &p_this->p_vars[i_var]; switch( i_action ) { case VLC_VAR_SETMIN: if( p_var->i_type & VLC_VAR_HASMIN ) { p_var->pf_free( &p_var->min ); } p_var->i_type |= VLC_VAR_HASMIN; p_var->min = *p_val; p_var->pf_dup( &p_var->min ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_SETMAX: if( p_var->i_type & VLC_VAR_HASMAX ) { p_var->pf_free( &p_var->max ); } p_var->i_type |= VLC_VAR_HASMAX; p_var->max = *p_val; p_var->pf_dup( &p_var->max ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_SETSTEP: if( p_var->i_type & VLC_VAR_HASSTEP ) { p_var->pf_free( &p_var->step ); } p_var->i_type |= VLC_VAR_HASSTEP; p_var->step = *p_val; p_var->pf_dup( &p_var->step ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_ADDCHOICE: /* FIXME: the list is sorted, dude. Use something cleverer. */ for( i = p_var->choices.i_count ; i-- ; ) { if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) < 0 ) { break; } } /* The new place is i+1 */ i++; if( p_var->i_default >= i ) { p_var->i_default++; } INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count, i, *p_val ); INSERT_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, i, *p_val ); p_var->pf_dup( &p_var->choices.p_values[i] ); p_var->choices_text.p_values[i].psz_string = ( p_val2 && p_val2->psz_string ) ? strdup( p_val2->psz_string ) : NULL; CheckValue( p_var, &p_var->val ); break; case VLC_VAR_DELCHOICE: /* FIXME: the list is sorted, dude. Use something cleverer. */ for( i = 0 ; i < p_var->choices.i_count ; i++ ) { if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) { break; } } if( i == p_var->choices.i_count ) { /* Not found */ vlc_mutex_unlock( &p_this->var_lock ); return VLC_EGENERIC; } if( p_var->i_default > i ) { p_var->i_default--; } else if( p_var->i_default == i ) { p_var->i_default = -1; } p_var->pf_free( &p_var->choices.p_values[i] ); if( p_var->choices_text.p_values[i].psz_string ) free( p_var->choices_text.p_values[i].psz_string ); REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i ); REMOVE_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, i ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_CHOICESCOUNT: p_val->i_int = p_var->choices.i_count; break; case VLC_VAR_CLEARCHOICES: for( i = 0 ; i < p_var->choices.i_count ; i++ ) { p_var->pf_free( &p_var->choices.p_values[i] ); } for( i = 0 ; i < p_var->choices_text.i_count ; i++ ) { if( p_var->choices_text.p_values[i].psz_string ) free( p_var->choices_text.p_values[i].psz_string ); } if( p_var->choices.i_count ) free( p_var->choices.p_values ); if( p_var->choices_text.i_count ) free( p_var->choices_text.p_values ); p_var->choices.i_count = 0; p_var->choices.p_values = NULL; p_var->choices_text.i_count = 0; p_var->choices_text.p_values = NULL; p_var->i_default = -1; break; case VLC_VAR_SETDEFAULT: /* FIXME: the list is sorted, dude. Use something cleverer. */ for( i = 0 ; i < p_var->choices.i_count ; i++ ) { if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) { break; } } if( i == p_var->choices.i_count ) { /* Not found */ break; } p_var->i_default = i; CheckValue( p_var, &p_var->val ); break; case VLC_VAR_SETVALUE: /* Duplicate data if needed */ p_var->pf_dup( p_val ); /* Backup needed stuff */ oldval = p_var->val; /* Check boundaries and list */ CheckValue( p_var, p_val ); /* Set the variable */ p_var->val = *p_val; /* Free data if needed */ p_var->pf_free( &oldval ); break; case VLC_VAR_GETCHOICES: case VLC_VAR_GETLIST: p_val->p_list = malloc( sizeof(vlc_list_t) ); if( p_val2 ) p_val2->p_list = malloc( sizeof(vlc_list_t) ); if( p_var->choices.i_count ) { p_val->p_list->p_values = malloc( p_var->choices.i_count * sizeof(vlc_value_t) ); p_val->p_list->pi_types = malloc( p_var->choices.i_count * sizeof(int) ); if( p_val2 ) { p_val2->p_list->p_values = malloc( p_var->choices.i_count * sizeof(vlc_value_t) ); p_val2->p_list->pi_types = malloc( p_var->choices.i_count * sizeof(int) ); } } p_val->p_list->i_count = p_var->choices.i_count; if( p_val2 ) p_val2->p_list->i_count = p_var->choices.i_count; for( i = 0 ; i < p_var->choices.i_count ; i++ ) { p_val->p_list->p_values[i] = p_var->choices.p_values[i]; p_val->p_list->pi_types[i] = p_var->i_type; p_var->pf_dup( &p_val->p_list->p_values[i] ); if( p_val2 ) { p_val2->p_list->p_values[i].psz_string = p_var->choices_text.p_values[i].psz_string ? strdup(p_var->choices_text.p_values[i].psz_string) : NULL; p_val2->p_list->pi_types[i] = VLC_VAR_STRING; } } break; case VLC_VAR_FREELIST: FreeList( p_val ); if( p_val2 && p_val2->p_list ) { for( i = 0; i < p_val2->p_list->i_count; i++ ) if( p_val2->p_list->p_values[i].psz_string ) free( p_val2->p_list->p_values[i].psz_string ); if( p_val2->p_list->i_count ) { free( p_val2->p_list->p_values ); free( p_val2->p_list->pi_types ); } free( p_val2->p_list ); } break; case VLC_VAR_SETTEXT: if( p_var->psz_text ) free( p_var->psz_text ); if( p_val && p_val->psz_string ) p_var->psz_text = strdup( p_val->psz_string ); break; case VLC_VAR_GETTEXT: p_val->psz_string = NULL; if( p_var->psz_text ) { p_val->psz_string = strdup( p_var->psz_text ); } break; case VLC_VAR_INHERITVALUE: { vlc_value_t val; if( InheritValue( p_this, psz_name, &val, p_var->i_type ) == VLC_SUCCESS ) { /* Duplicate already done */ /* Backup needed stuff */ oldval = p_var->val; /* Check boundaries and list */ CheckValue( p_var, &val ); /* Set the variable */ p_var->val = val; /* Free data if needed */ p_var->pf_free( &oldval ); } if( p_val ) { *p_val = p_var->val; p_var->pf_dup( p_val ); } } break; case VLC_VAR_TRIGGER_CALLBACKS: { /* Deal with callbacks. Tell we're in a callback, release the lock, * call stored functions, retake the lock. */ if( p_var->i_entries ) { int i_var; int i_entries = p_var->i_entries; callback_entry_t *p_entries = p_var->p_entries; p_var->b_incallback = VLC_TRUE; vlc_mutex_unlock( &p_this->var_lock ); /* The real calls */ for( ; i_entries-- ; ) { p_entries[i_entries].pf_callback( p_this, psz_name, p_var->val, p_var->val, p_entries[i_entries].p_data ); } vlc_mutex_lock( &p_this->var_lock ); i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); if( i_var < 0 ) { msg_Err( p_this, "variable %s has disappeared", psz_name ); vlc_mutex_unlock( &p_this->var_lock ); return VLC_ENOVAR; } p_var = &p_this->p_vars[i_var]; p_var->b_incallback = VLC_FALSE; } } break; default: break; } vlc_mutex_unlock( &p_this->var_lock ); return VLC_SUCCESS; }
/** * Initialize a vlc variable * * We hash the given string and insert it into the sorted list. The insertion * may require slow memory copies, but think about what we gain in the log(n) * lookup phase when setting/getting the variable value! * * \param p_this The object in which to create the variable * \param psz_name The name of the variable * \param i_type The variables type. Must be one of \ref var_type combined with * zero or more \ref var_flags */ int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type ) { int i_new; variable_t *p_var; static vlc_list_t dummy_null_list = {0, NULL, NULL}; vlc_mutex_lock( &p_this->var_lock ); /* FIXME: if the variable already exists, we don't duplicate it. But we * duplicate the lookups. It's not that serious, but if anyone finds some * time to rework Insert() so that only one lookup has to be done, feel * free to do so. */ i_new = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); if( i_new >= 0 ) { /* If the types differ, variable creation failed. */ if( (i_type & ~VLC_VAR_DOINHERIT) != p_this->p_vars[i_new].i_type ) { vlc_mutex_unlock( &p_this->var_lock ); return VLC_EBADVAR; } p_this->p_vars[i_new].i_usage++; vlc_mutex_unlock( &p_this->var_lock ); return VLC_SUCCESS; } i_new = Insert( p_this->p_vars, p_this->i_vars, psz_name ); if( (p_this->i_vars & 15) == 15 ) { p_this->p_vars = realloc( p_this->p_vars, (p_this->i_vars+17) * sizeof(variable_t) ); } memmove( p_this->p_vars + i_new + 1, p_this->p_vars + i_new, (p_this->i_vars - i_new) * sizeof(variable_t) ); p_this->i_vars++; p_var = &p_this->p_vars[i_new]; memset( p_var, 0, sizeof(*p_var) ); p_var->i_hash = HashString( psz_name ); p_var->psz_name = strdup( psz_name ); p_var->psz_text = NULL; p_var->i_type = i_type & ~VLC_VAR_DOINHERIT; memset( &p_var->val, 0, sizeof(vlc_value_t) ); p_var->pf_dup = DupDummy; p_var->pf_free = FreeDummy; p_var->i_usage = 1; p_var->i_default = -1; p_var->choices.i_count = 0; p_var->choices.p_values = NULL; p_var->choices_text.i_count = 0; p_var->choices_text.p_values = NULL; p_var->b_incallback = VLC_FALSE; p_var->i_entries = 0; p_var->p_entries = NULL; /* Always initialize the variable, even if it is a list variable; this * will lead to errors if the variable is not initialized, but it will * not cause crashes in the variable handling. */ switch( i_type & VLC_VAR_TYPE ) { case VLC_VAR_BOOL: p_var->pf_cmp = CmpBool; p_var->val.b_bool = VLC_FALSE; break; case VLC_VAR_INTEGER: case VLC_VAR_HOTKEY: p_var->pf_cmp = CmpInt; p_var->val.i_int = 0; break; case VLC_VAR_STRING: case VLC_VAR_MODULE: case VLC_VAR_FILE: case VLC_VAR_DIRECTORY: case VLC_VAR_VARIABLE: p_var->pf_cmp = CmpString; p_var->pf_dup = DupString; p_var->pf_free = FreeString; p_var->val.psz_string = ""; break; case VLC_VAR_FLOAT: p_var->pf_cmp = CmpFloat; p_var->val.f_float = 0.0; break; case VLC_VAR_TIME: p_var->pf_cmp = CmpTime; p_var->val.i_time = 0; break; case VLC_VAR_ADDRESS: p_var->pf_cmp = CmpAddress; p_var->val.p_address = NULL; break; case VLC_VAR_MUTEX: p_var->pf_cmp = CmpAddress; p_var->pf_free = FreeMutex; p_var->val.p_address = malloc( sizeof(vlc_mutex_t) ); vlc_mutex_init( p_this, (vlc_mutex_t*)p_var->val.p_address ); break; case VLC_VAR_LIST: p_var->pf_cmp = CmpAddress; p_var->pf_dup = DupList; p_var->pf_free = FreeList; p_var->val.p_list = &dummy_null_list; break; } /* Duplicate the default data we stored. */ p_var->pf_dup( &p_var->val ); if( i_type & VLC_VAR_DOINHERIT ) { vlc_value_t val; if( InheritValue( p_this, psz_name, &val, p_var->i_type ) == VLC_SUCCESS ) { /* Free data if needed */ p_var->pf_free( &p_var->val ); /* Set the variable */ p_var->val = val; if( i_type & VLC_VAR_HASCHOICE ) { /* We must add the inherited value to our choice list */ p_var->i_default = 0; INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count, 0, val ); INSERT_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, 0, val ); p_var->pf_dup( &p_var->choices.p_values[0] ); p_var->choices_text.p_values[0].psz_string = NULL; } } } vlc_mutex_unlock( &p_this->var_lock ); return VLC_SUCCESS; }
/***************************************************************************** * InheritValue: try to inherit the value of this variable from the same one * in our closest parent. *****************************************************************************/ static int InheritValue( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val, int i_type ) { int i_var; variable_t *p_var; /* No need to take the structure lock, * we are only looking for our parents */ if( !p_this->p_parent ) { switch( i_type & VLC_VAR_TYPE ) { case VLC_VAR_FILE: case VLC_VAR_DIRECTORY: case VLC_VAR_STRING: case VLC_VAR_MODULE: p_val->psz_string = config_GetPsz( p_this, psz_name ); if( !p_val->psz_string ) p_val->psz_string = strdup(""); break; case VLC_VAR_FLOAT: p_val->f_float = config_GetFloat( p_this, psz_name ); break; case VLC_VAR_INTEGER: case VLC_VAR_HOTKEY: p_val->i_int = config_GetInt( p_this, psz_name ); break; case VLC_VAR_BOOL: p_val->b_bool = config_GetInt( p_this, psz_name ); break; case VLC_VAR_LIST: { char *psz_orig, *psz_var; vlc_list_t *p_list = malloc(sizeof(vlc_list_t)); p_val->p_list = p_list; p_list->i_count = 0; psz_var = psz_orig = config_GetPsz( p_this, psz_name ); while( psz_var && *psz_var ) { char *psz_item = psz_var; vlc_value_t val; while( *psz_var && *psz_var != ',' ) psz_var++; if( *psz_var == ',' ) { *psz_var = '\0'; psz_var++; } val.i_int = strtol( psz_item, NULL, 0 ); INSERT_ELEM( p_list->p_values, p_list->i_count, p_list->i_count, val ); /* p_list->i_count is incremented twice by INSERT_ELEM */ p_list->i_count--; INSERT_ELEM( p_list->pi_types, p_list->i_count, p_list->i_count, VLC_VAR_INTEGER ); } if( psz_orig ) free( psz_orig ); break; } default: return VLC_ENOOBJ; break; } return VLC_SUCCESS; } /* Look for the variable */ vlc_mutex_lock( &p_this->p_parent->var_lock ); i_var = Lookup( p_this->p_parent->p_vars, p_this->p_parent->i_vars, psz_name ); if( i_var >= 0 ) { /* We found it! */ p_var = &p_this->p_parent->p_vars[i_var]; /* Really get the variable */ *p_val = p_var->val; /* Duplicate value if needed */ p_var->pf_dup( p_val ); vlc_mutex_unlock( &p_this->p_parent->var_lock ); return VLC_SUCCESS; } vlc_mutex_unlock( &p_this->p_parent->var_lock ); /* We're still not there */ return InheritValue( p_this->p_parent, psz_name, p_val, i_type ); }
static int Demux( demux_t *p_demux ) { playlist_t *p_playlist; char *psz_line; int i_position; char *psz_name = NULL; mtime_t i_duration = -1; char **ppsz_options = NULL; int i_options = 0; vlc_bool_t b_cleanup = VLC_FALSE; p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST, FIND_PARENT ); if( !p_playlist ) { msg_Err( p_demux, "can't find playlist" ); return -1; } vlc_mutex_lock( &p_playlist->object_lock ); p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE; i_position = p_playlist->i_index + 1; vlc_mutex_unlock( &p_playlist->object_lock ); psz_line = stream_ReadLine( p_demux->s ); while( psz_line ) { char *psz_parse = psz_line; /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++; if( *psz_parse == '#' ) { /* Parse extra info */ /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' || *psz_parse == '#' ) psz_parse++; if( !*psz_parse ) goto error; if( !strncasecmp( psz_parse, "EXTINF:", sizeof("EXTINF:") -1 ) ) { /* Extended info */ char *psz_duration; psz_parse += sizeof("EXTINF:") - 1; while( *psz_parse == '\t' || *psz_parse == ' ' ) psz_parse++; psz_duration = psz_parse; psz_parse = strchr( psz_parse, ',' ); if( psz_parse ) { *psz_parse = '\0'; psz_parse++; psz_name = strdup( psz_parse ); i_duration = atoi( psz_duration ); if( i_duration != -1 ) i_duration *= 1000000; } } else if( !strncasecmp( psz_parse, "EXTVLCOPT:", sizeof("EXTVLCOPT:") -1 ) ) { /* VLC Option */ char *psz_option; psz_parse += sizeof("EXTVLCOPT:") -1; if( !*psz_parse ) goto error; psz_option = strdup( psz_parse ); if( psz_option ) INSERT_ELEM( ppsz_options, i_options, i_options, psz_option ); } } else if( *psz_parse ) { char *psz_mrl = ProcessMRL( psz_parse, p_demux->p_sys->psz_prefix ); b_cleanup = VLC_TRUE; if( !psz_mrl ) goto error; playlist_AddExt( p_playlist, psz_mrl, psz_name, PLAYLIST_INSERT, i_position, i_duration, (const char **)ppsz_options, i_options ); i_position++; free( psz_mrl ); } error: /* Fetch another line */ free( psz_line ); psz_line = stream_ReadLine( p_demux->s ); if( !psz_line ) b_cleanup = VLC_TRUE; if( b_cleanup ) { /* Cleanup state */ while( i_options-- ) free( ppsz_options[i_options] ); if( ppsz_options ) free( ppsz_options ); ppsz_options = NULL; i_options = 0; if( psz_name ) free( psz_name ); psz_name = NULL; i_duration = -1; b_cleanup = VLC_FALSE; } } vlc_object_release( p_playlist ); return VLC_SUCCESS; }
static void ParseUrls( services_discovery_t *p_sd, char *psz_urls ) { services_discovery_sys_t *p_sys = p_sd->p_sys; int i_new_items = 0; input_item_t **pp_new_items = NULL; int i_new_urls = 0; char **ppsz_new_urls = NULL; int i, j; for( ;; ) { if( !psz_urls ) break; char *psz_tok = strchr( psz_urls, '|' ); if( psz_tok ) *psz_tok = '\0'; for( i = 0; i < p_sys->i_urls; i++ ) if( !strcmp( psz_urls, p_sys->ppsz_urls[i] ) ) break; if( i == p_sys->i_urls ) { INSERT_ELEM( ppsz_new_urls, i_new_urls, i_new_urls, strdup( psz_urls ) ); input_item_t *p_input; p_input = input_item_New( p_sd, psz_urls, psz_urls ); input_item_AddOption( p_input, "demux=podcast", VLC_INPUT_OPTION_TRUSTED ); INSERT_ELEM( pp_new_items, i_new_items, i_new_items, p_input ); services_discovery_AddItem( p_sd, p_input, NULL /* no cat */ ); INSERT_ELEM( p_sys->pp_input, p_sys->i_input, p_sys->i_input, input_CreateAndStart( p_sd, p_input, NULL ) ); } else { INSERT_ELEM( ppsz_new_urls, i_new_urls, i_new_urls, strdup( p_sys->ppsz_urls[i]) ); INSERT_ELEM( pp_new_items, i_new_items, i_new_items, p_sys->pp_items[i] ); } if( psz_tok ) psz_urls = psz_tok+1; else break; } /* delete removed items and signal the removal */ for( i = 0; i<p_sys->i_items; ++i ) { for( j = 0; j < i_new_items; ++j ) if( pp_new_items[j] == p_sys->pp_items[i] ) break; if( j == i_new_items ) { services_discovery_RemoveItem( p_sd, p_sys->pp_items[i] ); vlc_gc_decref( p_sys->pp_items[i] ); } } free( p_sys->pp_items ); for( int i = 0; i < p_sys->i_urls; i++ ) free( p_sys->ppsz_urls[i] ); free( p_sys->ppsz_urls ); p_sys->ppsz_urls = ppsz_new_urls; p_sys->i_urls = i_new_urls; p_sys->pp_items = pp_new_items; p_sys->i_items = i_new_items; }
/** * Initialize a vlc variable * * We hash the given string and insert it into the sorted list. The insertion * may require slow memory copies, but think about what we gain in the log(n) * lookup phase when setting/getting the variable value! * * \param p_this The object in which to create the variable * \param psz_name The name of the variable * \param i_type The variables type. Must be one of \ref var_type combined with * zero or more \ref var_flags */ int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type ) { assert( p_this ); variable_t *p_var = calloc( 1, sizeof( *p_var ) ); if( p_var == NULL ) return VLC_ENOMEM; p_var->psz_name = strdup( psz_name ); p_var->psz_text = NULL; p_var->i_type = i_type & ~VLC_VAR_DOINHERIT; p_var->i_usage = 1; p_var->i_default = -1; p_var->choices.i_count = 0; p_var->choices.p_values = NULL; p_var->choices_text.i_count = 0; p_var->choices_text.p_values = NULL; p_var->b_incallback = false; p_var->value_callbacks = (callback_table_t){ 0 }; /* Always initialize the variable, even if it is a list variable; this * will lead to errors if the variable is not initialized, but it will * not cause crashes in the variable handling. */ switch( i_type & VLC_VAR_CLASS ) { case VLC_VAR_BOOL: p_var->ops = &bool_ops; p_var->val.b_bool = false; break; case VLC_VAR_INTEGER: p_var->ops = &int_ops; p_var->val.i_int = 0; break; case VLC_VAR_STRING: p_var->ops = &string_ops; p_var->val.psz_string = NULL; break; case VLC_VAR_FLOAT: p_var->ops = &float_ops; p_var->val.f_float = 0.0; break; case VLC_VAR_COORDS: p_var->ops = &coords_ops; p_var->val.coords.x = p_var->val.coords.y = 0; break; case VLC_VAR_ADDRESS: p_var->ops = &addr_ops; p_var->val.p_address = NULL; break; case VLC_VAR_VOID: p_var->ops = &void_ops; break; default: vlc_assert_unreachable (); } if( (i_type & VLC_VAR_DOINHERIT) && var_Inherit( p_this, psz_name, i_type, &p_var->val ) == 0 ) { if( i_type & VLC_VAR_HASCHOICE ) { /* We must add the inherited value to our choice list */ p_var->i_default = 0; INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count, 0, p_var->val ); INSERT_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, 0, p_var->val ); p_var->ops->pf_dup( &p_var->choices.p_values[0] ); p_var->choices_text.p_values[0].psz_string = NULL; } } vlc_object_internals_t *p_priv = vlc_internals( p_this ); variable_t **pp_var, *p_oldvar; int ret = VLC_SUCCESS; vlc_mutex_lock( &p_priv->var_lock ); pp_var = tsearch( p_var, &p_priv->var_root, varcmp ); if( unlikely(pp_var == NULL) ) ret = VLC_ENOMEM; else if( (p_oldvar = *pp_var) == p_var ) /* Variable create */ p_var = NULL; /* Variable created */ else /* Variable already exists */ { assert (((i_type ^ p_oldvar->i_type) & VLC_VAR_CLASS) == 0); p_oldvar->i_usage++; p_oldvar->i_type |= i_type & (VLC_VAR_ISCOMMAND|VLC_VAR_HASCHOICE); } vlc_mutex_unlock( &p_priv->var_lock ); /* If we did not need to create a new variable, free everything... */ if( p_var != NULL ) Destroy( p_var ); return ret; }
/** * Main demux callback function * @param p_demux: this demux object */ static int Demux( demux_t *p_demux ) { char *psz_line; char *psz_artist = NULL, *psz_album = NULL, *psz_genre = NULL, *psz_year = NULL; char *psz_author = NULL, *psz_title = NULL, *psz_copyright = NULL, *psz_cdnum = NULL, *psz_comments = NULL; mtime_t i_duration = -1; const char **ppsz_options = NULL; int i_options = 0, i_start = 0, i_stop = 0; bool b_cleanup = false; input_item_t *p_input; input_item_t *p_current_input = GetCurrentItem(p_demux); input_item_node_t *p_subitems = input_item_node_Create( p_current_input ); psz_line = vlc_stream_ReadLine( p_demux->s ); while( psz_line ) { char *psz_parse = psz_line; /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++; if( *psz_parse == '#' ) { /* Ignore comments */ } else if( *psz_parse ) { char *psz_mrl, *psz_option_next, *psz_option; char *psz_param, *psz_value; /* Get the MRL from the file. Note that this might contain parameters of form ?param1=value1¶m2=value2 in a RAM file */ psz_mrl = ProcessMRL( psz_parse, p_demux->p_sys->psz_prefix ); b_cleanup = true; if ( !psz_mrl ) goto error; /* We have the MRL, now we have to check for options and parse them from MRL */ psz_option = strchr( psz_mrl, '?' ); /* Look for start of options */ if( psz_option ) { /* Remove options from MRL because VLC can't get the file otherwise */ *psz_option = '\0'; psz_option++; psz_option_next = psz_option; while( 1 ) /* Process each option */ { /* Look for end of first option which maybe a & or \0 */ psz_option = psz_option_next; psz_option_next = strchr( psz_option, '&' ); if( psz_option_next ) { *psz_option_next = '\0'; psz_option_next++; } else psz_option_next = strchr( psz_option, '\0' ); /* Quit if options are over */ if( psz_option_next == psz_option ) break; /* Parse out param and value */ psz_param = psz_option; psz_value = strchr( psz_option, '=' ); if( psz_value == NULL ) break; *psz_value = '\0'; psz_value++; /* Take action based on parameter value in the below if else structure */ /* TODO: Remove any quotes surrounding values if required */ if( !strcmp( psz_param, "clipinfo" ) ) { ParseClipInfo( psz_value, &psz_artist, &psz_title, &psz_album, &psz_genre, &psz_year, &psz_cdnum, &psz_comments ); /* clipinfo has various sub parameters, which is parsed by this function */ } else if( !strcmp( psz_param, "author" ) ) { psz_author = vlc_uri_decode_duplicate(psz_value); EnsureUTF8( psz_author ); } else if( !strcmp( psz_param, "start" ) && strncmp( psz_mrl, "rtsp", 4 ) /* Our rtsp-real or our real demuxer is wrong */ ) { i_start = ParseTime( psz_value, strlen( psz_value ) ); char *temp; if( i_start ) { if( asprintf( &temp, ":start-time=%d", i_start ) != -1 ) INSERT_ELEM( ppsz_options, i_options, i_options, temp ); } } else if( !strcmp( psz_param, "end" ) ) { i_stop = ParseTime( psz_value, strlen( psz_value ) ); char *temp; if( i_stop ) { if( asprintf( &temp, ":stop-time=%d", i_stop ) != -1 ) INSERT_ELEM( ppsz_options, i_options, i_options, temp ); } } else if( !strcmp( psz_param, "title" ) ) { free( psz_title ); psz_title = vlc_uri_decode_duplicate(psz_value); EnsureUTF8( psz_title ); } else if( !strcmp( psz_param, "copyright" ) ) { psz_copyright = vlc_uri_decode_duplicate(psz_value); EnsureUTF8( psz_copyright ); } else { /* TODO: insert option anyway? Currently ignores*/ /* INSERT_ELEM( ppsz_options, i_options, i_options, psz_option ); */ } } } /* Create the input item and pump in all the options into playlist item */ p_input = input_item_NewExt( psz_mrl, psz_title, i_duration, ITEM_TYPE_UNKNOWN, ITEM_NET_UNKNOWN ); if( !p_input ) { free( psz_mrl ); goto error; } input_item_AddOptions( p_input, i_options, ppsz_options, 0 ); if( !EMPTY_STR( psz_artist ) ) input_item_SetArtist( p_input, psz_artist ); if( !EMPTY_STR( psz_author ) ) input_item_SetPublisher( p_input, psz_author ); if( !EMPTY_STR( psz_title ) ) input_item_SetTitle( p_input, psz_title ); if( !EMPTY_STR( psz_copyright ) ) input_item_SetCopyright( p_input, psz_copyright ); if( !EMPTY_STR( psz_album ) ) input_item_SetAlbum( p_input, psz_album ); if( !EMPTY_STR( psz_genre ) ) input_item_SetGenre( p_input, psz_genre ); if( !EMPTY_STR( psz_year ) ) input_item_SetDate( p_input, psz_year ); if( !EMPTY_STR( psz_cdnum ) ) input_item_SetTrackNum( p_input, psz_cdnum ); if( !EMPTY_STR( psz_comments ) ) input_item_SetDescription( p_input, psz_comments ); input_item_node_AppendItem( p_subitems, p_input ); vlc_gc_decref( p_input ); free( psz_mrl ); } error: /* Fetch another line */ free( psz_line ); psz_line = vlc_stream_ReadLine( p_demux->s ); if( !psz_line ) b_cleanup = true; if( b_cleanup ) { /* Cleanup state */ while( i_options-- ) free( (char*)ppsz_options[i_options] ); FREENULL( ppsz_options ); FREENULL( psz_artist ); FREENULL( psz_title ); FREENULL( psz_author ); FREENULL( psz_copyright ); FREENULL( psz_album ); FREENULL( psz_genre ); FREENULL( psz_year ); FREENULL( psz_cdnum ); FREENULL( psz_comments ); i_options = 0; i_duration = -1; i_start = 0; i_stop = 0; b_cleanup = false; } } input_item_node_PostAndDelete( p_subitems ); vlc_gc_decref(p_current_input); var_Destroy( p_demux, "m3u-extvlcopt" ); return 0; /* Needed for correct operation of go back */ }
/** * Perform an action on a variable * * \param p_this The object that holds the variable * \param psz_name The name of the variable * \param i_action The action to perform. Must be one of \ref var_action * \param p_val First action parameter * \param p_val2 Second action parameter */ int var_Change( vlc_object_t *p_this, const char *psz_name, int i_action, vlc_value_t *p_val, vlc_value_t *p_val2 ) { int ret = VLC_SUCCESS; variable_t *p_var; vlc_value_t oldval; vlc_value_t newval; assert( p_this ); vlc_object_internals_t *p_priv = vlc_internals( p_this ); p_var = Lookup( p_this, psz_name ); if( p_var == NULL ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } switch( i_action ) { case VLC_VAR_SETMIN: if( p_var->i_type & VLC_VAR_HASMIN ) { p_var->ops->pf_free( &p_var->min ); } p_var->i_type |= VLC_VAR_HASMIN; p_var->min = *p_val; p_var->ops->pf_dup( &p_var->min ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_GETMIN: if( p_var->i_type & VLC_VAR_HASMIN ) *p_val = p_var->min; else ret = VLC_EGENERIC; break; case VLC_VAR_SETMAX: if( p_var->i_type & VLC_VAR_HASMAX ) { p_var->ops->pf_free( &p_var->max ); } p_var->i_type |= VLC_VAR_HASMAX; p_var->max = *p_val; p_var->ops->pf_dup( &p_var->max ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_GETMAX: if( p_var->i_type & VLC_VAR_HASMAX ) *p_val = p_var->max; else ret = VLC_EGENERIC; break; case VLC_VAR_SETSTEP: if( p_var->i_type & VLC_VAR_HASSTEP ) { p_var->ops->pf_free( &p_var->step ); } p_var->i_type |= VLC_VAR_HASSTEP; p_var->step = *p_val; p_var->ops->pf_dup( &p_var->step ); CheckValue( p_var, &p_var->val ); break; case VLC_VAR_GETSTEP: if( p_var->i_type & VLC_VAR_HASSTEP ) *p_val = p_var->step; else ret = VLC_EGENERIC; break; case VLC_VAR_ADDCHOICE: { int i = p_var->choices.i_count; INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count, i, *p_val ); INSERT_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, i, *p_val ); p_var->ops->pf_dup( &p_var->choices.p_values[i] ); p_var->choices_text.p_values[i].psz_string = ( p_val2 && p_val2->psz_string ) ? strdup( p_val2->psz_string ) : NULL; CheckValue( p_var, &p_var->val ); TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_ADDCHOICE, p_val); break; } case VLC_VAR_DELCHOICE: { int i; for( i = 0 ; i < p_var->choices.i_count ; i++ ) if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) break; if( i == p_var->choices.i_count ) { /* Not found */ vlc_mutex_unlock( &p_priv->var_lock ); return VLC_EGENERIC; } if( p_var->i_default > i ) p_var->i_default--; else if( p_var->i_default == i ) p_var->i_default = -1; p_var->ops->pf_free( &p_var->choices.p_values[i] ); free( p_var->choices_text.p_values[i].psz_string ); REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i ); REMOVE_ELEM( p_var->choices_text.p_values, p_var->choices_text.i_count, i ); CheckValue( p_var, &p_var->val ); TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_DELCHOICE, p_val); break; } case VLC_VAR_CHOICESCOUNT: p_val->i_int = p_var->choices.i_count; break; case VLC_VAR_CLEARCHOICES: for( int i = 0 ; i < p_var->choices.i_count ; i++ ) p_var->ops->pf_free( &p_var->choices.p_values[i] ); for( int i = 0 ; i < p_var->choices_text.i_count ; i++ ) free( p_var->choices_text.p_values[i].psz_string ); if( p_var->choices.i_count ) free( p_var->choices.p_values ); if( p_var->choices_text.i_count ) free( p_var->choices_text.p_values ); p_var->choices.i_count = 0; p_var->choices.p_values = NULL; p_var->choices_text.i_count = 0; p_var->choices_text.p_values = NULL; p_var->i_default = -1; TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_CLEARCHOICES, NULL); break; case VLC_VAR_SETDEFAULT: { int i; /* FIXME: the list is sorted, dude. Use something cleverer. */ for( i = 0 ; i < p_var->choices.i_count ; i++ ) if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) break; if( i == p_var->choices.i_count ) /* Not found */ break; p_var->i_default = i; CheckValue( p_var, &p_var->val ); break; } case VLC_VAR_SETVALUE: /* Duplicate data if needed */ newval = *p_val; p_var->ops->pf_dup( &newval ); /* Backup needed stuff */ oldval = p_var->val; /* Check boundaries and list */ CheckValue( p_var, &newval ); /* Set the variable */ p_var->val = newval; /* Free data if needed */ p_var->ops->pf_free( &oldval ); break; case VLC_VAR_GETCHOICES: p_val->p_list = xmalloc( sizeof(vlc_list_t) ); p_val->p_list->p_values = xmalloc( p_var->choices.i_count * sizeof(vlc_value_t) ); p_val->p_list->i_type = p_var->i_type; p_val->p_list->i_count = p_var->choices.i_count; if( p_val2 ) { p_val2->p_list = xmalloc( sizeof(vlc_list_t) ); p_val2->p_list->p_values = xmalloc( p_var->choices.i_count * sizeof(vlc_value_t) ); p_val2->p_list->i_type = VLC_VAR_STRING; p_val2->p_list->i_count = p_var->choices.i_count; } for( int i = 0 ; i < p_var->choices.i_count ; i++ ) { p_val->p_list->p_values[i] = p_var->choices.p_values[i]; p_var->ops->pf_dup( &p_val->p_list->p_values[i] ); if( p_val2 ) { p_val2->p_list->p_values[i].psz_string = p_var->choices_text.p_values[i].psz_string ? strdup(p_var->choices_text.p_values[i].psz_string) : NULL; } } break; case VLC_VAR_SETTEXT: free( p_var->psz_text ); if( p_val && p_val->psz_string ) p_var->psz_text = strdup( p_val->psz_string ); else p_var->psz_text = NULL; break; case VLC_VAR_GETTEXT: p_val->psz_string = p_var->psz_text ? strdup( p_var->psz_text ) : NULL; break; default: break; } vlc_mutex_unlock( &p_priv->var_lock ); return ret; }
static int Demux( demux_t *p_demux ) { char *psz_line; char *psz_name = NULL; char *psz_artist = NULL; char *psz_album_art = NULL; int i_parsed_duration = 0; mtime_t i_duration = -1; const char**ppsz_options = NULL; char * (*pf_dup) (const char *) = p_demux->p_sys->pf_dup; int i_options = 0; bool b_cleanup = false; input_item_t *p_input; input_item_t *p_current_input = GetCurrentItem(p_demux); input_item_node_t *p_subitems = input_item_node_Create( p_current_input ); psz_line = vlc_stream_ReadLine( p_demux->s ); while( psz_line ) { char *psz_parse = psz_line; /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++; if( *psz_parse == '#' ) { /* Parse extra info */ /* Skip leading tabs and spaces */ while( *psz_parse == ' ' || *psz_parse == '\t' || *psz_parse == '\n' || *psz_parse == '\r' || *psz_parse == '#' ) psz_parse++; if( !*psz_parse ) goto error; if( !strncasecmp( psz_parse, "EXTINF:", sizeof("EXTINF:") -1 ) ) { /* Extended info */ psz_parse += sizeof("EXTINF:") - 1; FREENULL( psz_name ); FREENULL( psz_artist ); parseEXTINF( psz_parse, &psz_artist, &psz_name, &i_parsed_duration ); if( i_parsed_duration >= 0 ) i_duration = i_parsed_duration * INT64_C(1000000); if( psz_name ) psz_name = pf_dup( psz_name ); if( psz_artist ) psz_artist = pf_dup( psz_artist ); } else if( !strncasecmp( psz_parse, "EXTVLCOPT:", sizeof("EXTVLCOPT:") -1 ) ) { /* VLC Option */ char *psz_option; psz_parse += sizeof("EXTVLCOPT:") -1; if( !*psz_parse ) goto error; psz_option = pf_dup( psz_parse ); if( psz_option ) INSERT_ELEM( ppsz_options, i_options, i_options, psz_option ); } /* Special case for jamendo which provide the albumart */ else if( !strncasecmp( psz_parse, "EXTALBUMARTURL:", sizeof( "EXTALBUMARTURL:" ) -1 ) ) { psz_parse += sizeof( "EXTALBUMARTURL:" ) - 1; free( psz_album_art ); psz_album_art = pf_dup( psz_parse ); } } else if( !strncasecmp( psz_parse, "RTSPtext", sizeof("RTSPtext") -1 ) ) { ;/* special case to handle QuickTime RTSPtext redirect files */ } else if( *psz_parse ) { char *psz_mrl; psz_parse = pf_dup( psz_parse ); if( !psz_name && psz_parse ) /* Use filename as name for relative entries */ psz_name = strdup( psz_parse ); psz_mrl = ProcessMRL( psz_parse, p_demux->p_sys->psz_prefix ); b_cleanup = true; if( !psz_mrl ) { free( psz_parse ); goto error; } p_input = input_item_NewExt( psz_mrl, psz_name, i_duration, ITEM_TYPE_UNKNOWN, ITEM_NET_UNKNOWN ); free( psz_parse ); free( psz_mrl ); if( !p_input ) goto error; input_item_AddOptions( p_input, i_options, ppsz_options, 0 ); input_item_CopyOptions( p_input, p_current_input ); if( !EMPTY_STR(psz_artist) ) input_item_SetArtist( p_input, psz_artist ); if( psz_name ) input_item_SetTitle( p_input, psz_name ); if( !EMPTY_STR(psz_album_art) ) input_item_SetArtURL( p_input, psz_album_art ); input_item_node_AppendItem( p_subitems, p_input ); vlc_gc_decref( p_input ); } error: /* Fetch another line */ free( psz_line ); psz_line = vlc_stream_ReadLine( p_demux->s ); if( !psz_line ) b_cleanup = true; if( b_cleanup ) { /* Cleanup state */ while( i_options-- ) free( (char*)ppsz_options[i_options] ); FREENULL( ppsz_options ); i_options = 0; FREENULL( psz_name ); FREENULL( psz_artist ); FREENULL( psz_album_art ); i_parsed_duration = 0; i_duration = -1; b_cleanup = false; } } input_item_node_PostAndDelete( p_subitems ); vlc_gc_decref(p_current_input); var_Destroy( p_demux, "m3u-extvlcopt" ); return 0; /* Needed for correct operation of go back */ }
static void ParseRequest( services_discovery_t *p_sd ) { services_discovery_sys_t *p_sys = p_sd->p_sys; char *psz_request = p_sys->psz_request; int i; char *psz_tok = strchr( psz_request, ':' ); if( !psz_tok ) return; *psz_tok = '\0'; if ( ! p_sys->b_savedurls_loaded ) { char *psz_urls = var_GetNonEmptyString( p_sd->p_parent, "podcast-urls" ); ParseUrls( p_sd, psz_urls ); free( psz_urls ); } if( !strcmp( psz_request, "ADD" ) ) { psz_request = psz_tok + 1; for( i = 0; i<p_sys->i_urls; i++ ) if( !strcmp(p_sys->ppsz_urls[i],psz_request) ) break; if( i == p_sys->i_urls ) { INSERT_ELEM( p_sys->ppsz_urls, p_sys->i_urls, p_sys->i_urls, strdup( psz_request ) ); input_item_t *p_input; p_input = input_item_New( psz_request, psz_request ); input_item_AddOption( p_input, "demux=podcast", VLC_INPUT_OPTION_TRUSTED ); INSERT_ELEM( p_sys->pp_items, p_sys->i_items, p_sys->i_items, p_input ); services_discovery_AddItem( p_sd, p_input, NULL /* no cat */ ); INSERT_ELEM( p_sys->pp_input, p_sys->i_input, p_sys->i_input, input_CreateAndStart( p_sd, p_input, NULL ) ); SaveUrls( p_sd ); } } else if ( !strcmp( psz_request, "RM" ) ) { psz_request = psz_tok + 1; for( i = 0; i<p_sys->i_urls; i++ ) if( !strcmp(p_sys->ppsz_urls[i],psz_request) ) break; if( i != p_sys->i_urls ) { services_discovery_RemoveItem( p_sd, p_sys->pp_items[i] ); vlc_gc_decref( p_sys->pp_items[i] ); REMOVE_ELEM( p_sys->ppsz_urls, p_sys->i_urls, i ); REMOVE_ELEM( p_sys->pp_items, p_sys->i_items, i ); } SaveUrls( p_sd ); } free( p_sys->psz_request ); p_sys->psz_request = NULL; }