📄 stream.c
字号:
return VLC_EGENERIC; } /* Date the current track */ p_sys->stream.tk[p_sys->stream.i_tk].i_date = mdate(); /* Try to reuse already read data */ for( i = 0; i < STREAM_CACHE_TRACK; i++ ) { stream_track_t *tk = &p_sys->stream.tk[i]; if( i_pos >= tk->i_start && i_pos <= tk->i_end ) {#ifdef STREAM_DEBUG msg_Dbg( s, "AStreamSeekStream: reusing %d start=%"PRId64 " end=%"PRId64, i, tk->i_start, tk->i_end );#endif /* Seek at the end of the buffer */ if( ASeek( s, tk->i_end ) ) return VLC_EGENERIC; /* That's it */ p_sys->i_pos = i_pos; p_sys->stream.i_tk = i; p_sys->stream.i_offset = i_pos - tk->i_start; if( p_sys->stream.i_used < 1024 ) p_sys->stream.i_used = 1024; if( AStreamRefillStream( s ) && i_pos == tk->i_end ) return VLC_EGENERIC; return VLC_SUCCESS; } } access_Control( p_access, ACCESS_CAN_SEEK, &b_afastseek ); /* FIXME compute seek cost (instead of static 'stupid' value) */ i_maxth = __MIN( p_sys->stream.i_read_size, STREAM_READ_ATONCE / 2 ); if( !b_afastseek ) i_maxth *= 3; /* FIXME TODO */#if 0 /* Search closest segment TODO */ for( i = 0; i < STREAM_CACHE_TRACK; i++ ) { stream_track_t *tk = &p_sys->stream.tk[i]; if( i_pos + i_maxth >= tk->i_start ) { msg_Dbg( s, "good segment before current pos, TODO" ); } if( i_pos - i_maxth <= tk->i_end ) { msg_Dbg( s, "good segment after current pos, TODO" ); } }#endif /* Nothing good, seek and choose oldest segment */ if( ASeek( s, i_pos ) ) return VLC_EGENERIC; p_sys->i_pos = i_pos; i_new = 0; for( i = 1; i < STREAM_CACHE_TRACK; i++ ) { if( p_sys->stream.tk[i].i_date < p_sys->stream.tk[i_new].i_date ) i_new = i; } /* Reset the segment */ p_sys->stream.i_tk = i_new; p_sys->stream.i_offset = 0; p_sys->stream.tk[i_new].i_start = i_pos; p_sys->stream.tk[i_new].i_end = i_pos; /* Read data */ if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 ) p_sys->stream.i_used = STREAM_READ_ATONCE / 2; if( AStreamRefillStream( s ) ) return VLC_EGENERIC; return VLC_SUCCESS;}static int AStreamRefillStream( stream_t *s ){ stream_sys_t *p_sys = s->p_sys; stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk]; /* We read but won't increase i_start after initial start + offset */ int i_toread = __MIN( p_sys->stream.i_used, STREAM_CACHE_TRACK_SIZE - (tk->i_end - tk->i_start - p_sys->stream.i_offset) ); bool b_read = false; int64_t i_start, i_stop; if( i_toread <= 0 ) return VLC_EGENERIC; /* EOF */#ifdef STREAM_DEBUG msg_Dbg( s, "AStreamRefillStream: used=%d toread=%d", p_sys->stream.i_used, i_toread );#endif i_start = mdate(); while( i_toread > 0 ) { int i_off = tk->i_end % STREAM_CACHE_TRACK_SIZE; int i_read; if( s->b_die ) return VLC_EGENERIC; i_read = __MIN( i_toread, STREAM_CACHE_TRACK_SIZE - i_off ); i_read = AReadStream( s, &tk->p_buffer[i_off], i_read ); /* msg_Dbg( s, "AStreamRefillStream: read=%d", i_read ); */ if( i_read < 0 ) { msleep( STREAM_DATA_WAIT ); continue; } else if( i_read == 0 ) { if( !b_read ) return VLC_EGENERIC; return VLC_SUCCESS; } b_read = true; /* Update end */ tk->i_end += i_read; /* Windows of STREAM_CACHE_TRACK_SIZE */ if( tk->i_end - tk->i_start > STREAM_CACHE_TRACK_SIZE ) { int i_invalid = tk->i_end - tk->i_start - STREAM_CACHE_TRACK_SIZE; tk->i_start += i_invalid; p_sys->stream.i_offset -= i_invalid; } i_toread -= i_read; p_sys->stream.i_used -= i_read; p_sys->stat.i_bytes += i_read; p_sys->stat.i_read_count++; } i_stop = mdate(); p_sys->stat.i_read_time += i_stop - i_start; return VLC_SUCCESS;}static void AStreamPrebufferStream( 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; int64_t i_prebuffer = p_sys->b_quick ? STREAM_CACHE_TRACK_SIZE /100 : ( (p_access->info.i_title > 1 || p_access->info.i_seekpoint > 1) ? STREAM_CACHE_PREBUFFER_SIZE : STREAM_CACHE_TRACK_SIZE / 3 ); msg_Dbg( s, "pre-buffering..." ); i_start = mdate(); for( ;; ) { stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk]; int64_t i_date = mdate(); int i_read; if( s->b_die || tk->i_end >= i_prebuffer || (i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date) ) { int64_t i_byterate; /* Update stat */ p_sys->stat.i_bytes = tk->i_end - tk->i_start; 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, "pre-buffering 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; } /* */ i_read = STREAM_CACHE_TRACK_SIZE - tk->i_end; i_read = __MIN( p_sys->stream.i_read_size, i_read ); i_read = AReadStream( s, &tk->p_buffer[tk->i_end], i_read ); if( i_read < 0 ) { msleep( STREAM_DATA_WAIT ); continue; } else if( i_read == 0 ) { /* EOF */ break; } if( i_first == 0 ) { i_first = mdate(); msg_Dbg( s, "received first data for our buffer"); } tk->i_end += i_read; p_sys->stat.i_read_count++; }}/**************************************************************************** * Method 3: ****************************************************************************/static int AStreamReadImmediate( stream_t *s, void *p_read, unsigned int i_read ){ stream_sys_t *p_sys = s->p_sys;#ifdef STREAM_DEBUG msg_Dbg( s, "AStreamReadImmediate p_read=%p i_read=%d", p_read, i_read );#endif /* First, check if we already have some data in the buffer, * that we could copy directly */ int i_copy = __MIN( stream_buffered_size( s ), i_read ); if( i_copy ) {#ifdef STREAM_DEBUG msg_Dbg( s, "AStreamReadImmediate: copy %d from %p", i_copy, stream_buffer( s ) );#endif assert( i_copy <= STREAM_CACHE_SIZE ); if( p_read ) { memcpy( p_read, stream_buffer( s ), i_copy ); p_read = (uint8_t *)p_read + i_copy; } } /* Now that we've read our buffer we don't need its i_copy bytes */ stream_buffer_empty( s, i_copy ); /* Now check if we have still to really read some data */ int i_to_read = i_read - i_copy; if( i_to_read ) { if( p_read ) i_to_read = AReadStream( s, p_read, i_to_read ); else { void * dummy = malloc(i_to_read); i_to_read = AReadStream( s, dummy, i_to_read ); free(dummy); } } p_sys->i_pos += i_to_read; return i_to_read + i_copy;}static int AStreamPeekImmediate( stream_t *s, const uint8_t **pp_peek, unsigned int i_read ){#ifdef STREAM_DEBUG msg_Dbg( s, "AStreamPeekImmediate: %d size=%"PRId64, i_read, size_buffered_size( s ) );#endif /* Avoid problem, but that shouldn't happen */ if( i_read > STREAM_CACHE_SIZE / 2 ) i_read = STREAM_CACHE_SIZE / 2; int i_to_read = i_read - stream_buffered_size( s ); if( i_to_read > 0 ) {#ifdef STREAM_DEBUG msg_Dbg( s, "AStreamPeekImmediate: Reading %d", i_to_read );#endif i_to_read = AReadStream( s, stream_buffer( s ) + stream_buffered_size( s ), i_to_read ); if( i_to_read > 0 ) stream_buffer_fill( s, i_to_read ); } *pp_peek = stream_buffer( s ); return __MIN(stream_buffered_size( s ), i_read);}static int AStreamSeekImmediate( stream_t *s, int64_t i_pos ){ stream_sys_t *p_sys = s->p_sys; access_t *p_access = p_sys->p_access; bool b_aseek;#ifdef STREAM_DEBUG msg_Dbg( s, "AStreamSeekImmediate to %"PRId64" pos=%"PRId64 i_pos, p_sys->i_pos );#endif access_Control( p_access, ACCESS_CAN_SEEK, &b_aseek ); if( !b_aseek ) { /* We can't do nothing */ msg_Dbg( s, "AStreamSeekImmediate: can't seek" ); return VLC_EGENERIC; } /* Just reset our buffer */ stream_buffer_empty( s, stream_buffered_size( s ) ); if( ASeek( s, i_pos ) ) return VLC_EGENERIC; return VLC_SUCCESS;}/**************************************************************************** * stream_ReadLine: ****************************************************************************//** * Read from the stream untill first newline. * \param s Stream handle to read from * \return A pointer to the allocated output string. You need to free this when you are done. */#define STREAM_PROBE_LINE 2048#define STREAM_LINE_MAX (2048*100)char * stream_ReadLine( stream_t *s ){ char *p_line = NULL; int i_line = 0, i_read = 0; while( i_read < STREAM_LINE_MAX ) { char *psz_eol; const uint8_t *p_data; int i_data; int64_t i_pos; /* Probe new data */ i_data = stream_Peek( s, &p_data, STREAM_PROBE_LINE ); if( i_data <= 0 ) break; /* No more data */ /* BOM detection */ i_pos = stream_Tell( s ); if( i_pos == 0 && i_data > 4 ) { int i_bom_size = 0; char *psz_encoding = NULL; if( p_data[0] == 0xEF && p_data[1] == 0xBB && p_data[2] == 0xBF ) { psz_encoding = strdup( "UTF-8" ); i_bom_size = 3; } else if( p_data[0] == 0x00 && p_data[1] == 0x00 ) { if( p_data[2] == 0xFE && p_data[3] == 0xFF ) { psz_encoding = strdup( "UTF-32BE" ); s->i_char_width = 4; i_bom_size = 4; } } else if( p_data[0] == 0xFF && p_data[1] == 0xFE ) { if( p_data[2] == 0x00 && p_data[3] == 0x00 ) { psz_encoding = strdup( "UTF-32LE" ); s->i_char_width = 4; s->b_little_endian = true; i_bom_size = 4; } else { psz_encoding = strdup( "UTF-16LE" ); s->b_little_endian = true; s->i_char_width = 2; i_bom_size = 2; } } else if( p_data[0] == 0xFE && p_data[1] == 0xFF ) { psz_encoding = strdup( "UTF-16BE" ); s->i_char_width = 2; i_bom_size = 2; } /* Seek past the BOM */ if( i_bom_size ) { stream_Seek( s, i_bom_size ); p_data += i_bom_size; i_data -= i_bom_size; } /* Open the converter if we need it */ if( psz_encoding != NULL ) { input_thread_t *p_input; msg_Dbg( s, "%s BOM detected", psz_encoding ); p_input = (input_thread_t *)vlc_object_find( s, VLC_OBJECT_INPUT, FIND_PARENT ); if( s->i_char_width > 1 ) { s->conv = vlc_iconv_open( "UTF-8", psz_encoding ); if( s->conv == (vlc_iconv_t)-1 ) { msg_Err( s, "iconv_open failed" ); } } if( p_input != NULL) { var_Create( p_input, "subsdec-encoding", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -