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; }
static int Open( vlc_object_t *p_this ) { stream_t *s = (stream_t*)p_this; stream_sys_t *p_sys; if( !isSmoothStreaming( s ) ) return VLC_EGENERIC; msg_Info( p_this, "Smooth Streaming (%s)", s->psz_path ); s->p_sys = p_sys = calloc( 1, sizeof(*p_sys ) ); if( unlikely( p_sys == NULL ) ) return VLC_ENOMEM; char *uri = NULL; if( unlikely( asprintf( &uri, "%s://%s", s->psz_access, s->psz_path ) < 0 ) ) { free( p_sys ); return VLC_ENOMEM; } /* remove the last part of the url */ char *pos = strrchr( uri, '/'); *pos = '\0'; p_sys->base_url = uri; /* XXX I don't know wether or not we should allow caching */ p_sys->b_cache = false; p_sys->sms_streams = vlc_array_new(); p_sys->selected_st = vlc_array_new(); p_sys->download.chunks = vlc_array_new(); p_sys->init_chunks = vlc_array_new(); if( unlikely( !p_sys->sms_streams || !p_sys->download.chunks || !p_sys->selected_st || !p_sys->init_chunks ) ) { free( p_sys ); return VLC_ENOMEM; } /* Parse SMS ismc content. */ if( parse_Manifest( s ) != VLC_SUCCESS ) { free( p_sys ); return VLC_EGENERIC; } if( !p_sys->vod_duration ) p_sys->b_live = true; p_sys->i_tracks = vlc_array_count( p_sys->sms_streams ); /* Choose first video / audio / subtitle stream available */ sms_stream_t *tmp = NULL, *selected = NULL; for( unsigned i = 0; i < p_sys->i_tracks; i++ ) { tmp = vlc_array_item_at_index( p_sys->sms_streams, i ); selected = SMS_GET_SELECTED_ST( tmp->type ); if( !selected ) vlc_array_append( p_sys->selected_st, tmp ); } /* Choose lowest quality for the first chunks */ quality_level_t *wanted, *qlvl; sms_stream_t *sms = NULL; for( unsigned i = 0; i < p_sys->i_tracks; i++ ) { wanted = qlvl = NULL; sms = vlc_array_item_at_index( p_sys->sms_streams, i ); wanted = vlc_array_item_at_index( sms->qlevels, 0 ); for( unsigned i=1; i < sms->qlevel_nb; i++ ) { qlvl = vlc_array_item_at_index( sms->qlevels, i ); if( qlvl->Bitrate < wanted->Bitrate ) wanted = qlvl; } sms->download_qlvl = wanted->id; } vlc_mutex_init( &p_sys->download.lock_wait ); vlc_cond_init( &p_sys->download.wait ); /* */ s->pf_read = Read; s->pf_peek = Peek; s->pf_control = Control; if( vlc_clone( &p_sys->thread, sms_Thread, s, VLC_THREAD_PRIORITY_INPUT ) ) { free( p_sys ); vlc_mutex_destroy( &p_sys->download.lock_wait ); vlc_cond_destroy( &p_sys->download.wait ); return VLC_EGENERIC; } return VLC_SUCCESS; }
static int sms_Read( stream_t *s, uint8_t *p_read, int i_read ) { stream_sys_t *p_sys = s->p_sys; int copied = 0; chunk_t *chunk = NULL; do { chunk = get_chunk( s, true ); if( !chunk ) return copied; if( chunk->read_pos >= (int)chunk->size ) { if( chunk->type == VIDEO_ES || ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && chunk->type == AUDIO_ES ) ) { vlc_mutex_lock( &p_sys->download.lock_wait ); p_sys->playback.toffset += chunk->duration; vlc_mutex_unlock( &p_sys->download.lock_wait ); vlc_cond_signal( &p_sys->download.wait); } if( !p_sys->b_cache || p_sys->b_live ) { FREENULL( chunk->data ); chunk->read_pos = 0; } chunk->read_pos = 0; p_sys->playback.index += 1; msg_Dbg( s, "Incrementing playback index" ); continue; } if( chunk->read_pos == 0 ) { const char *verb = p_read == NULL ? "skipping" : "reading"; msg_Dbg( s, "%s chunk %u (%u bytes), type %i", verb, chunk->sequence, i_read, chunk->type ); /* check integrity */ uint32_t type; uint8_t *slice = chunk->data; SMS_GET4BYTES( type ); SMS_GETFOURCC( type ); assert( type == ATOM_moof || type == ATOM_uuid ); } int len = -1; uint8_t *src = chunk->data + chunk->read_pos; if( i_read <= chunk->size - chunk->read_pos ) len = i_read; else len = chunk->size - chunk->read_pos; if( len > 0 ) { if( p_read ) /* otherwise caller skips data */ memcpy( p_read + copied, src, len ); chunk->read_pos += len; copied += len; i_read -= len; } } while ( i_read > 0 ); return copied; }
static unsigned int sms_Read( stream_t *s, uint8_t *p_read, unsigned int i_read ) { stream_sys_t *p_sys = s->p_sys; unsigned int copied = 0; chunk_t *chunk = NULL; do { bool b_isinitchunk = false; chunk = get_chunk( s, true, &b_isinitchunk ); /* chunk here won't be processed further */ // msg_Dbg( s, "chunk %"PRIu64" init %d", (uint64_t) chunk, b_isinitchunk ); if( !chunk ) return copied; if( chunk->read_pos >= chunk->size ) { if( chunk->type == VIDEO_ES || ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && chunk->type == AUDIO_ES ) ) { p_sys->playback.toffset += chunk->duration; vlc_cond_signal( &p_sys->download.wait ); } if ( b_isinitchunk ) { assert( chunk->read_pos == chunk->size ); vlc_mutex_lock( &p_sys->playback.lock ); p_sys->playback.init.p_startchunk = NULL; p_sys->playback.init.p_datachunk = NULL; chunk_Free( chunk ); vlc_mutex_unlock( &p_sys->playback.lock ); } else { vlc_mutex_lock( &p_sys->lock ); if( gotoNextChunk( p_sys ) == NULL ) { vlc_mutex_unlock( &p_sys->lock ); return 0; } vlc_mutex_unlock( &p_sys->lock ); } continue; } if( chunk->read_pos == 0 ) { const char *verb = p_read == NULL ? "skipping" : "reading"; msg_Dbg( s, "%s chunk time %"PRIu64" (%u bytes), type %i", verb, chunk->start_time, i_read, chunk->type ); } uint64_t len = 0; uint8_t *src = chunk->data + chunk->read_pos; if( i_read <= chunk->size - chunk->read_pos ) len = i_read; else len = chunk->size - chunk->read_pos; if( len > 0 ) { if( p_read ) /* otherwise caller skips data */ memcpy( p_read + copied, src, len ); chunk->read_pos += len; copied += len; i_read -= len; p_sys->playback.boffset += len; } } while ( i_read > 0 ); return copied; }