📄 stream.c
字号:
msg_Dbg( s, "p_buffer %p-%p", p_sys->immediate.p_buffer, p_sys->immediate.p_buffer + STREAM_CACHE_SIZE ); if( p_sys->immediate.p_buffer == NULL ) { msg_Err( s, "Out of memory when allocating stream cache (%d bytes)", STREAM_CACHE_SIZE ); goto error; } } else /* ( p_sys->method == Stream ) */ { int i; msg_Dbg( s, "Using AStream*Stream" ); s->pf_read = AStreamReadStream; s->pf_peek = AStreamPeekStream; /* Allocate/Setup our tracks */ p_sys->stream.i_offset = 0; p_sys->stream.i_tk = 0; p_sys->stream.p_buffer = malloc( STREAM_CACHE_SIZE ); if( p_sys->stream.p_buffer == NULL ) { msg_Err( s, "Out of memory when allocating stream cache (%d bytes)", STREAM_CACHE_SIZE ); goto error; } p_sys->stream.i_used = 0; access_Control( p_access, ACCESS_GET_MTU, &p_sys->stream.i_read_size ); if( p_sys->stream.i_read_size <= 0 ) p_sys->stream.i_read_size = STREAM_READ_ATONCE; else if( p_sys->stream.i_read_size <= 256 ) p_sys->stream.i_read_size = 256; for( i = 0; i < STREAM_CACHE_TRACK; i++ ) { p_sys->stream.tk[i].i_date = 0; p_sys->stream.tk[i].i_start = p_sys->i_pos; p_sys->stream.tk[i].i_end = p_sys->i_pos; p_sys->stream.tk[i].p_buffer= &p_sys->stream.p_buffer[i * STREAM_CACHE_TRACK_SIZE]; } /* Do the prebuffering */ AStreamPrebufferStream( s ); if( p_sys->stream.tk[p_sys->stream.i_tk].i_end <= 0 ) { msg_Err( s, "cannot pre fill buffer" ); goto error; } } return s;error: if( p_sys->method == Block ) { /* Nothing yet */ } else { free( p_sys->stream.p_buffer ); } while( p_sys->i_list > 0 ) free( p_sys->list[--(p_sys->i_list)] ); free( p_sys->list ); free( psz_list ); free( s->p_sys ); vlc_object_detach( s ); vlc_object_release( s ); return NULL;}/**************************************************************************** * AStreamDestroy: ****************************************************************************/static void AStreamDestroy( stream_t *s ){ stream_sys_t *p_sys = s->p_sys; vlc_object_detach( s ); if( p_sys->method == Block ) block_ChainRelease( p_sys->block.p_first ); else if ( p_sys->method == Immediate ) free( p_sys->immediate.p_buffer ); else free( p_sys->stream.p_buffer ); free( p_sys->p_peek ); if( p_sys->p_list_access && p_sys->p_list_access != p_sys->p_access ) access_Delete( p_sys->p_list_access ); while( p_sys->i_list-- ) { free( p_sys->list[p_sys->i_list]->psz_path ); free( p_sys->list[p_sys->i_list] ); } free( p_sys->list ); free( p_sys ); vlc_object_release( s );}static void UStreamDestroy( stream_t *s ){ access_t *p_access = (access_t *)s->p_parent; AStreamDestroy( s ); access_Delete( p_access );}/**************************************************************************** * stream_AccessReset: ****************************************************************************/void stream_AccessReset( stream_t *s ){ stream_sys_t *p_sys = s->p_sys; p_sys->i_pos = p_sys->p_access->info.i_pos; if( p_sys->method == Block ) { block_ChainRelease( p_sys->block.p_first ); /* Init all fields of p_sys->block */ p_sys->block.i_start = p_sys->i_pos; p_sys->block.i_offset = 0; p_sys->block.p_current = NULL; p_sys->block.i_size = 0; p_sys->block.p_first = NULL; p_sys->block.pp_last = &p_sys->block.p_first; /* Do the prebuffering */ AStreamPrebufferBlock( s ); } else if( p_sys->method == Immediate ) { stream_buffer_empty( s, stream_buffered_size( s ) ); } else /* ( p_sys->method == Stream ) */ { int i; /* Setup our tracks */ p_sys->stream.i_offset = 0; p_sys->stream.i_tk = 0; p_sys->stream.i_used = 0; for( i = 0; i < STREAM_CACHE_TRACK; i++ ) { p_sys->stream.tk[i].i_date = 0; p_sys->stream.tk[i].i_start = p_sys->i_pos; p_sys->stream.tk[i].i_end = p_sys->i_pos; } /* Do the prebuffering */ AStreamPrebufferStream( s ); }}/**************************************************************************** * stream_AccessUpdate: ****************************************************************************/void stream_AccessUpdate( stream_t *s ){ stream_sys_t *p_sys = s->p_sys; p_sys->i_pos = p_sys->p_access->info.i_pos; if( p_sys->i_list ) { int i; for( i = 0; i < p_sys->i_list_index; i++ ) { p_sys->i_pos += p_sys->list[i]->i_size; } }}/**************************************************************************** * AStreamControl: ****************************************************************************/static int AStreamControl( stream_t *s, int i_query, va_list args ){ stream_sys_t *p_sys = s->p_sys; access_t *p_access = p_sys->p_access; bool *p_bool; int64_t *pi_64, i_64; int i_int; switch( i_query ) { case STREAM_GET_SIZE: pi_64 = (int64_t*)va_arg( args, int64_t * ); if( s->p_sys->i_list ) { int i; *pi_64 = 0; for( i = 0; i < s->p_sys->i_list; i++ ) *pi_64 += s->p_sys->list[i]->i_size; break; } *pi_64 = p_access->info.i_size; break; case STREAM_CAN_SEEK: p_bool = (bool*)va_arg( args, bool * ); access_Control( p_access, ACCESS_CAN_SEEK, p_bool ); break; case STREAM_CAN_FASTSEEK: p_bool = (bool*)va_arg( args, bool * ); access_Control( p_access, ACCESS_CAN_FASTSEEK, p_bool ); break; case STREAM_GET_POSITION: pi_64 = (int64_t*)va_arg( args, int64_t * ); *pi_64 = p_sys->i_pos; break; case STREAM_SET_POSITION: i_64 = (int64_t)va_arg( args, int64_t ); if( p_sys->method == Block ) return AStreamSeekBlock( s, i_64 ); else if( p_sys->method == Immediate ) return AStreamSeekImmediate( s, i_64 ); else /* ( p_sys->method == Stream ) */ return AStreamSeekStream( s, i_64 ); case STREAM_GET_MTU: return VLC_EGENERIC; case STREAM_CONTROL_ACCESS: i_int = (int) va_arg( args, int ); if( i_int != ACCESS_SET_PRIVATE_ID_STATE && i_int != ACCESS_SET_PRIVATE_ID_CA && i_int != ACCESS_GET_PRIVATE_ID_STATE ) { msg_Err( s, "Hey, what are you thinking ?" "DON'T USE STREAM_CONTROL_ACCESS !!!" ); return VLC_EGENERIC; } return access_vaControl( p_access, i_int, args ); case STREAM_GET_CONTENT_TYPE: return access_Control( p_access, ACCESS_GET_CONTENT_TYPE, va_arg( args, char ** ) ); default: msg_Err( s, "invalid stream_vaControl query=0x%x", i_query ); return VLC_EGENERIC; } return VLC_SUCCESS;}/**************************************************************************** * Method 1: ****************************************************************************/static void AStreamPrebufferBlock( stream_t *s ){ stream_sys_t *p_sys = s->p_sys; access_t *p_access = p_sys->p_access; int64_t i_first = 0; int64_t i_start; msg_Dbg( s, "pre buffering" ); i_start = mdate(); for( ;; ) { int64_t i_date = mdate(); bool b_eof; block_t *b; if( s->b_die || p_sys->block.i_size > STREAM_CACHE_PREBUFFER_SIZE || ( i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date ) ) { int64_t i_byterate; /* Update stat */ p_sys->stat.i_bytes = p_sys->block.i_size; p_sys->stat.i_read_time = i_date - i_start; i_byterate = ( INT64_C(1000000) * p_sys->stat.i_bytes ) / (p_sys->stat.i_read_time + 1); msg_Dbg( s, "prebuffering done %"PRId64" bytes in %"PRId64"s - " "%"PRId64" kbytes/s", p_sys->stat.i_bytes, p_sys->stat.i_read_time / INT64_C(1000000), i_byterate / 1024 ); break; } /* Fetch a block */ if( ( b = AReadBlock( s, &b_eof ) ) == NULL ) { if( b_eof ) break; msleep( STREAM_DATA_WAIT ); continue; } while( b ) { /* Append the block */ p_sys->block.i_size += b->i_buffer; *p_sys->block.pp_last = b; p_sys->block.pp_last = &b->p_next; p_sys->stat.i_read_count++; b = b->p_next; } if( p_access->info.b_prebuffered ) { /* Access has already prebufferred - update stats and exit */ p_sys->stat.i_bytes = p_sys->block.i_size; p_sys->stat.i_read_time = mdate() - i_start; break; } if( i_first == 0 ) { i_first = mdate(); msg_Dbg( s, "received first data for our buffer"); } } p_sys->block.p_current = p_sys->block.p_first;}static int AStreamRefillBlock( stream_t *s );static int AStreamReadBlock( stream_t *s, void *p_read, unsigned int i_read ){ stream_sys_t *p_sys = s->p_sys; uint8_t *p_data= (uint8_t*)p_read; unsigned int i_data = 0; /* It means EOF */ if( p_sys->block.p_current == NULL ) return 0; if( p_read == NULL ) { /* seek within this stream if possible, else use plain old read and discard */ stream_sys_t *p_sys = s->p_sys; access_t *p_access = p_sys->p_access; bool b_aseek; access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek ); if( b_aseek ) return AStreamSeekBlock( s, p_sys->i_pos + i_read ) ? 0 : i_read; } while( i_data < i_read ) { int i_current = p_sys->block.p_current->i_buffer - p_sys->block.i_offset; unsigned int i_copy = __MIN( (unsigned int)__MAX(i_current,0), i_read - i_data); /* Copy data */ if( p_data ) { memcpy( p_data, &p_sys->block.p_current->p_buffer[p_sys->block.i_offset], i_copy ); p_data += i_copy; } i_data += i_copy; p_sys->block.i_offset += i_copy; if( p_sys->block.i_offset >= p_sys->block.p_current->i_buffer ) { /* Current block is now empty, switch to next */ if( p_sys->block.p_current ) { p_sys->block.i_offset = 0; p_sys->block.p_current = p_sys->block.p_current->p_next; } /*Get a new block if needed */ if( !p_sys->block.p_current && AStreamRefillBlock( s ) ) { break; } } } p_sys->i_pos += i_data; return i_data;}static int AStreamPeekBlock( stream_t *s, const uint8_t **pp_peek, unsigned int i_read ){ stream_sys_t *p_sys = s->p_sys; uint8_t *p_data; unsigned int i_data = 0; block_t *b; unsigned int i_offset; if( p_sys->block.p_current == NULL ) return 0; /* EOF */ /* We can directly give a pointer over our buffer */ if( i_read <= p_sys->block.p_current->i_buffer - p_sys->block.i_offset ) { *pp_peek = &p_sys->block.p_current->p_buffer[p_sys->block.i_offset]; return i_read; } /* We need to create a local copy */ if( p_sys->i_peek < i_read ) { p_sys->p_peek = realloc( p_sys->p_peek, i_read ); if( !p_sys->p_peek ) { p_sys->i_peek = 0; return 0; } p_sys->i_peek = i_read; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -