Esempio n. 1
0
/**
 * Destroy playlist.
 * This is not thread-safe. Any reference to the playlist is assumed gone.
 * (In particular, all interface and services threads must have been joined).
 *
 * \param p_playlist the playlist object
 */
void playlist_Destroy( playlist_t *p_playlist )
{
    playlist_private_t *p_sys = pl_priv(p_playlist);

    /* Remove all services discovery */
    playlist_ServicesDiscoveryKillAll( p_playlist );

    msg_Dbg( p_playlist, "destroying" );

    playlist_Deactivate( p_playlist );
    if( p_sys->p_preparser )
        playlist_preparser_Delete( p_sys->p_preparser );

    /* Release input resources */
    assert( p_sys->p_input == NULL );
    input_resource_Release( p_sys->p_input_resource );

    if( p_playlist->p_media_library != NULL )
        playlist_MLDump( p_playlist );

    PL_LOCK;
    /* Release the current node */
    set_current_status_node( p_playlist, NULL );
    /* Release the current item */
    set_current_status_item( p_playlist, NULL );
    PL_UNLOCK;

    vlc_cond_destroy( &p_sys->signal );
    vlc_mutex_destroy( &p_sys->lock );

    /* Remove all remaining items */
    FOREACH_ARRAY( playlist_item_t *p_del, p_playlist->all_items )
        free( p_del->pp_children );
        vlc_gc_decref( p_del->p_input );
        free( p_del );
    FOREACH_END();
    ARRAY_RESET( p_playlist->all_items );
    FOREACH_ARRAY( playlist_item_t *p_del, p_sys->items_to_delete )
        free( p_del->pp_children );
        vlc_gc_decref( p_del->p_input );
        free( p_del );
    FOREACH_END();
    ARRAY_RESET( p_sys->items_to_delete );

    ARRAY_RESET( p_playlist->items );
    ARRAY_RESET( p_playlist->current );

    vlc_http_cookie_jar_t *cookies = var_GetAddress( p_playlist, "http-cookies" );
    if ( cookies )
    {
        var_Destroy( p_playlist, "http-cookies" );
        vlc_http_cookies_destroy( cookies );
    }

    vlc_object_release( p_playlist );
}
Esempio n. 2
0
static int Remove( addons_storage_t *p_storage, addon_entry_t *p_entry )
{
    vlc_mutex_lock( &p_entry->lock );
    FOREACH_ARRAY( addon_file_t *p_file, p_entry->files )
    switch( p_file->e_filetype )
    {
        case ADDON_EXTENSION:
        case ADDON_PLAYLIST_PARSER:
        case ADDON_SERVICE_DISCOVERY:
        case ADDON_INTERFACE:
        case ADDON_META:
        case ADDON_SKIN2:
        {
            char *psz_dest;

            char *psz_translated_filename = strdup( p_file->psz_filename );
            if ( !psz_translated_filename )
                return VLC_ENOMEM;
            char *tmp = psz_translated_filename;
            while (*tmp++) if ( *tmp == '/' ) *tmp = DIR_SEP_CHAR;

            char *psz_dir = getAddonInstallDir( p_file->e_filetype );
            if ( !psz_dir || asprintf( &psz_dest, "%s"DIR_SEP"%s", psz_dir,
                                       psz_translated_filename ) < 1 )
            {
                free( psz_dir );
                free( psz_translated_filename );
                return VLC_EGENERIC;
            }
            free( psz_dir );
            free( psz_translated_filename );

            vlc_unlink( psz_dest );
            msg_Dbg( p_storage, "removing %s", psz_dest );

            free( psz_dest );
            break;
        }
            /* Ignore all other unhandled files */
        case ADDON_UNKNOWN:
        case ADDON_PLUGIN:
        case ADDON_OTHER:
        default:
            break;
    }
    FOREACH_END()

    /* Remove file info on success */
    FOREACH_ARRAY( addon_file_t *p_file, p_entry->files )
    free( p_file->psz_filename );
    free( p_file->psz_download_uri );
    free( p_file );
    FOREACH_END()
    ARRAY_RESET( p_entry->files );

    vlc_mutex_unlock( &p_entry->lock );
    return VLC_SUCCESS;
}
Esempio n. 3
0
sms_stream_t * sms_get_stream_by_cat( stream_sys_t *p_sys, int i_cat )
{
    assert( p_sys->sms_selected.i_size >= 0 && p_sys->sms_selected.i_size <= 3 );
    FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
    if( sms->type == i_cat )
        return sms;
    FOREACH_END();
    return NULL;
}
Esempio n. 4
0
bool no_more_chunks( stream_sys_t *p_sys )
{
    FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
    if ( sms->p_playback )
    {
        return false;
    }
    FOREACH_END();
    return true;
}
Esempio n. 5
0
void ql_Free( quality_level_t *qlevel )
{
    free( qlevel->CodecPrivateData );
    FOREACH_ARRAY( custom_attrs_t *p_attrs, qlevel->custom_attrs )
        free( p_attrs->psz_key );
        free( p_attrs->psz_value );
    FOREACH_END()
    ARRAY_RESET(qlevel->custom_attrs);
    free( qlevel );
    qlevel = NULL;
}
Esempio n. 6
0
static sms_stream_t *next_playback_stream( stream_sys_t *p_sys )
{
    sms_stream_t *p_candidate = NULL;
    FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
    if ( !sms->p_playback )
        continue;
    if ( p_candidate == NULL ||
         sms->p_playback->start_time < p_candidate->p_playback->start_time )
        p_candidate = sms;
    FOREACH_END();
    return p_candidate;
}
Esempio n. 7
0
static void SysCleanup( stream_sys_t *p_sys )
{
    if ( p_sys->sms.i_size )
    {
        FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms );
            sms_Free( sms );
        FOREACH_END();
        ARRAY_RESET( p_sys->sms );
    }
    ARRAY_RESET( p_sys->sms_selected );
    if ( p_sys->playback.init.p_datachunk )
        chunk_Free( p_sys->playback.init.p_datachunk );
    free( p_sys->download.base_url );
}
Esempio n. 8
0
void resetChunksState( stream_sys_t *p_sys )
{
    FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
    vlc_mutex_lock( &sms->chunks_lock );
    chunk_t *p_chunk = sms->p_playback;
    while( p_chunk )
    {
        FREENULL( p_chunk->data );
        p_chunk->offset = CHUNK_OFFSET_UNSET;
        p_chunk->size = 0;
        p_chunk->read_pos = 0;
        if ( p_chunk == sms->p_nextdownload )
            break;
        p_chunk = p_chunk->p_next;
    }
    sms->p_playback = NULL;
    sms->p_nextdownload = NULL;
    vlc_mutex_unlock( &sms->chunks_lock );
    FOREACH_END();
}
Esempio n. 9
0
void sms_Free( sms_stream_t *sms )
{
    if ( !sms )
        return;
    FOREACH_ARRAY( quality_level_t *qlevel, sms->qlevels );
    if( qlevel )
        ql_Free( qlevel );
    FOREACH_END();
    ARRAY_RESET( sms->qlevels );

    vlc_mutex_lock( &sms->chunks_lock );
    while( sms->p_chunks )
    {
        chunk_t *p_chunk = sms->p_chunks;
        sms->p_chunks = sms->p_chunks->p_next;
        chunk_Free( p_chunk );
    }
    vlc_mutex_unlock( &sms->chunks_lock );

    vlc_mutex_destroy( &sms->chunks_lock );
    free( sms->name );
    free( sms->url_template );
    free( sms );
}
Esempio n. 10
0
static int WriteCatalog( addons_storage_t *p_storage,
                         addon_entry_t **pp_entries, int i_entries )
{
    addon_entry_t *p_entry;
    char *psz_file;
    char *psz_file_tmp;
    char *psz_tempstring;
    char *psz_userdir = config_GetUserDir( VLC_DATA_DIR );
    if ( !psz_userdir ) return VLC_ENOMEM;

    if ( asprintf( &psz_file, "%s%s", psz_userdir, ADDONS_CATALOG ) < 1 )
    {
        free( psz_userdir );
        return VLC_ENOMEM;
    }
    free( psz_userdir );

    if ( asprintf( &psz_file_tmp, "%s.tmp%"PRIu32, psz_file, (uint32_t)getpid() ) < 1 )
    {
        free( psz_file );
        return VLC_ENOMEM;
    }

    char *psz_path = strdup( psz_file );
    if ( !psz_path )
    {
        free( psz_file );
        free( psz_file_tmp );
        return VLC_ENOMEM;
    }

    char *psz_buf = strrchr( psz_path, DIR_SEP_CHAR );
    if( psz_buf )
    {
        *++psz_buf = '\0';
        /* ensure directory exists */
        if( !EMPTY_STR( psz_path ) ) recursive_mkdir( VLC_OBJECT(p_storage), psz_path );
    }
    free( psz_path );

    FILE *p_catalog = vlc_fopen( psz_file_tmp, "wt" );
    if ( !p_catalog )
    {
        free( psz_file );
        free( psz_file_tmp );
        return VLC_EGENERIC;
    }

    /* write XML header */
    fprintf( p_catalog, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
    fprintf( p_catalog, "<videolan xmlns=\"http://videolan.org/ns/vlc/addons/1.0\">\n" );
    fprintf( p_catalog, "\t<addons>\n" );

    for ( int i=0; i<i_entries; i++ )
    {
        p_entry = pp_entries[i];
        vlc_mutex_lock( &p_entry->lock );
        psz_tempstring = NULL;

        if ( ( p_entry->e_state != ADDON_INSTALLED ) ||
             !( p_entry->e_flags & ADDON_MANAGEABLE ) )
        {
            vlc_mutex_unlock( &p_entry->lock );
            continue;
        }

        if ( p_entry->psz_source_module )
            psz_tempstring = vlc_xml_encode( p_entry->psz_source_module );

        char *psz_uuid = addons_uuid_to_psz( ( const addon_uuid_t * ) & p_entry->uuid );
        fprintf( p_catalog, "\t\t<addon source=\"%s\" type=\"%s\" id=\"%s\" "
                                 "downloads=\"%ld\" score=\"%d\"",
                 ( psz_tempstring ) ? psz_tempstring : "",
                 getTypePsz( p_entry->e_type ),
                 psz_uuid,
                 p_entry->i_downloads,
                 p_entry->i_score );
        free( psz_uuid );
        free( psz_tempstring );

        WRITE_WITH_ENTITIES( " version=\"%s\"", p_entry->psz_version )
        fprintf( p_catalog, ">\n" );

        WRITE_WITH_ENTITIES( "\t\t\t<name>%s</name>\n", p_entry->psz_name )
        WRITE_WITH_ENTITIES( "\t\t\t<summary>%s</summary>\n", p_entry->psz_summary )

        if ( p_entry->psz_description )
        {
            psz_tempstring = p_entry->psz_description;
            /* FIXME: do real escaping */
            while( ( psz_tempstring = strstr( psz_tempstring, "]]>" ) ) )
                *psz_tempstring = ' ';
            fprintf( p_catalog, "\t\t\t<description><![CDATA[%s]]></description>\n", p_entry->psz_description );
        }

        WRITE_WITH_ENTITIES( "\t\t\t<image>%s</image>\n", p_entry->psz_image_data )
        WRITE_WITH_ENTITIES( "\t\t\t<archive>%s</archive>\n", p_entry->psz_archive_uri )

        fprintf( p_catalog, "\t\t\t<authorship>\n" );
        WRITE_WITH_ENTITIES( "\t\t\t\t<creator>%s</creator>\n", p_entry->psz_author )
        WRITE_WITH_ENTITIES( "\t\t\t\t<sourceurl>%s</sourceurl>\n", p_entry->psz_source_uri )
        fprintf( p_catalog, "\t\t\t</authorship>\n" );

        FOREACH_ARRAY( addon_file_t *p_file, p_entry->files )
            psz_tempstring = vlc_xml_encode( p_file->psz_filename );
            fprintf( p_catalog, "\t\t\t<resource type=\"%s\">%s</resource>\n",
                     getTypePsz( p_file->e_filetype ), psz_tempstring );
            free( psz_tempstring );
        FOREACH_END();

        fprintf( p_catalog, "\t\t</addon>\n" );

        vlc_mutex_unlock( &p_entry->lock );
    }

    fprintf( p_catalog, "\t</addons>\n" );
    fprintf( p_catalog, "</videolan>\n" );
    fclose( p_catalog );

    int i_ret = vlc_rename( psz_file_tmp, psz_file );
    free( psz_file );
    free( psz_file_tmp );

    if( i_ret == -1 )
    {
        msg_Err( p_storage, "could not rename temp catalog: %s",
                 vlc_strerror_c(errno) );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
Esempio n. 11
0
/* Normaly a stream_filter is not able to provide *time* seeking, since a
 * stream_filter operates on a byte stream. Thus, in order to circumvent this
 * limitation, I treat a STREAM_SET_POSITION request which value "pos" is less
 * than FAKE_STREAM_SIZE as a *time* seek request, and more precisely a request
 * to jump at time position: pos / FAKE_STREAM_SIZE * total_video_duration.
 * For exemple, it pos == 500, it would be interpreted as a request to jump at
 * the middle of the video.
 * If pos > 1000, it would be treated as a normal byte seek request. That means
 * the demux is not able to request a byte seek with 0 <= pos <= 1000
 * (unless it is in the current chunk), but that doesn't matter in practice.
 * Of course this a bit hack-ish, but if Smooth Streaming doesn't die, its
 * implementation will be moved to a access_demux module, and this hack won't
 * be needed anymore (among others). */
static int chunk_Seek( stream_t *s, const uint64_t pos )
{
    stream_sys_t *p_sys = s->p_sys;

    if( pos == p_sys->playback.boffset )
        return VLC_SUCCESS;

    chunk_t *chunk = get_chunk( s, false, NULL );
    if( chunk == NULL )
        return VLC_EGENERIC;

    assert( chunk->offset != CHUNK_OFFSET_UNSET );
    uint64_t i_chunkspos = CHUNK_OFFSET_0 + pos;

    bool inside_chunk = i_chunkspos >= chunk->offset &&
                        i_chunkspos < (chunk->offset + chunk->size);

    if( inside_chunk )
    {
        chunk->read_pos = i_chunkspos - chunk->offset;
        p_sys->playback.boffset = pos;
        return VLC_SUCCESS;
    }
    else
    {
        if( p_sys->b_live )
        {
            msg_Err( s, "Cannot seek to %"PRIu64" outside the current chunk for a live stream at %"PRIu64, pos, p_sys->playback.boffset );
            return VLC_EGENERIC;
        }

        msg_Info( s, "Seeking outside the current chunk (%"PRIu64"->%"PRIu64") to %"PRIu64, chunk->offset, chunk->offset+chunk->size, pos );
        assert( pos <= FAKE_STREAM_SIZE );

        vlc_mutex_lock( &p_sys->lock );
        resetChunksState( p_sys );
        p_sys->playback.next_chunk_offset = 0;
        p_sys->playback.boffset = 0;
        p_sys->time_pos = p_sys->vod_duration * pos / FAKE_STREAM_SIZE;

        /* set queues heads */
        FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
        vlc_mutex_lock( &sms->chunks_lock );
        chunk_t *p_chunk = sms->p_chunks;
        while ( p_chunk )
        {
            if ( p_chunk->start_time > p_sys->time_pos )
                break;
            if ( p_chunk->start_time <= p_sys->time_pos &&
                 p_chunk->start_time + p_chunk->duration >= p_sys->time_pos )
            {
                sms->p_playback = p_chunk;
                sms->p_nextdownload = p_chunk;
                break;
            }
            p_chunk = p_chunk->p_next;
        }
        vlc_mutex_unlock( &sms->chunks_lock );
        FOREACH_END();
        /* !set queues heads */

        vlc_cond_signal( &p_sys->download.wait);
        vlc_mutex_unlock( &p_sys->lock );

        return VLC_SUCCESS;
    }
}
Esempio n. 12
0
static int Open( vlc_object_t *p_this )
{
    stream_t *s = (stream_t*)p_this;
    stream_sys_t *p_sys;

    if( !isSmoothStreaming( s ) || s->psz_url == NULL )
        return VLC_EGENERIC;

    msg_Info( p_this, "Smooth Streaming (%s)", s->psz_url );

    s->p_sys = p_sys = calloc( 1, sizeof(*p_sys ) );
    if( unlikely( p_sys == NULL ) )
        return VLC_ENOMEM;

    char *uri = strdup( s->psz_url );
    if( unlikely( uri == NULL ) )
    {
        free( p_sys );
        return VLC_ENOMEM;
    }

    /* remove the last part of the url */
    char *pos = strrchr( uri, '/');
    *pos = '\0';
    p_sys->download.base_url = uri;

    ARRAY_INIT( p_sys->sms );
    ARRAY_INIT( p_sys->sms_selected );

    /* Parse SMS ismc content. */
    if( parse_Manifest( s ) != VLC_SUCCESS )
    {
        SysCleanup( p_sys );
        free( p_sys );
        return VLC_EGENERIC;
    }

    if( !p_sys->vod_duration )
       p_sys->b_live = true;

    /* Choose first video / audio / subtitle stream available */
    sms_stream_t *selected = NULL;
    FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms );
    selected = SMS_GET_SELECTED_ST( sms->type );
    if( !selected )
        ARRAY_APPEND( p_sys->sms_selected, sms );
    FOREACH_END();

    /* Choose lowest quality for the first chunks */
    FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms );
    quality_level_t *wanted = NULL;
    if ( sms->qlevels.i_size )
    {
        wanted = sms->qlevels.p_elems[0];
        for( int i=1; i < sms->qlevels.i_size; i++ )
        {
            if( sms->qlevels.p_elems[i]->Bitrate < wanted->Bitrate )
                wanted = sms->qlevels.p_elems[i];
        }
        sms->current_qlvl = wanted;
    }
    FOREACH_END();

    /* Init our playback queue */
    p_sys->p_current_stream = next_playback_stream( p_sys );
    if ( !p_sys->p_current_stream )
    {
        SysCleanup( p_sys );
        free( p_sys );
        return VLC_EGENERIC;
    }
    p_sys->playback.next_chunk_offset = CHUNK_OFFSET_UNSET;
    p_sys->i_probe_length = SMS_PROBE_LENGTH;

    vlc_mutex_init( &p_sys->lock );
    vlc_cond_init( &p_sys->download.wait );
    vlc_cond_init( &p_sys->playback.wait );
    vlc_mutex_init( &p_sys->playback.lock );

    /* */
    s->pf_read = Read;
    s->pf_control = Control;

    if( vlc_clone( &p_sys->download.thread, sms_Thread, s, VLC_THREAD_PRIORITY_INPUT ) )
    {
        SysCleanup( p_sys );
        vlc_mutex_destroy( &p_sys->lock );
        vlc_cond_destroy( &p_sys->download.wait );
        vlc_mutex_destroy( &p_sys->playback.lock );
        vlc_cond_destroy( &p_sys->playback.wait );
        free( p_sys );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}