static ssize_t SeekCallback(struct archive *p_archive, void *p_object, ssize_t i_offset, int i_whence) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; access_sys_t *p_sys = p_data->p_access->p_sys; ssize_t i_pos; switch(i_whence) { case SEEK_CUR: i_pos = vlc_stream_Tell(p_sys->p_stream); break; case SEEK_SET: i_pos = 0; break; case SEEK_END: i_pos = stream_Size(p_sys->p_stream) - 1; break; default: return -1; } if (i_pos < 0) return -1; vlc_stream_Seek(p_sys->p_stream, i_pos + i_offset); /* We don't care about return val */ return vlc_stream_Tell(p_sys->p_stream); }
static ssize_t SkipCallback(struct archive *p_archive, void *p_object, ssize_t i_request) { VLC_UNUSED(p_archive); callback_data_t *p_data = (callback_data_t *) p_object; access_sys_t *p_sys = p_data->p_access->p_sys; ssize_t i_skipped = 0; /* be smart as small seeks converts to reads */ if (p_sys->b_source_canseek) { int64_t i_pos = vlc_stream_Tell(p_sys->p_stream); if (i_pos >=0) vlc_stream_Seek(p_sys->p_stream, i_pos + i_request); i_skipped = vlc_stream_Tell(p_sys->p_stream) - i_pos; } else while(i_request) { int i_skip = __MIN(INT32_MAX, i_request); int i_read = vlc_stream_Read(p_sys->p_stream, NULL, i_skip); if (i_read > 0) i_skipped += i_read; else break; i_request -= i_read; } return i_skipped; }
static int64_t IOSeek( void *opaque, int64_t offset, int whence ) { demux_t *p_demux = opaque; int64_t i_absolute; int64_t i_size = stream_Size( p_demux->s ); #ifdef AVFORMAT_DEBUG msg_Warn( p_demux, "IOSeek offset: %"PRId64", whence: %i", offset, whence ); #endif switch( whence ) { #ifdef AVSEEK_SIZE case AVSEEK_SIZE: return i_size; #endif case SEEK_SET: i_absolute = (int64_t)offset; break; case SEEK_CUR: i_absolute = vlc_stream_Tell( p_demux->s ) + (int64_t)offset; break; case SEEK_END: i_absolute = i_size + (int64_t)offset; break; default: return -1; } if( i_absolute < 0 ) { msg_Dbg( p_demux, "Trying to seek before the beginning" ); return -1; } if( i_size > 0 && i_absolute >= i_size ) { msg_Dbg( p_demux, "Trying to seek too far : EOF?" ); return -1; } if( vlc_stream_Seek( p_demux->s, i_absolute ) ) { msg_Warn( p_demux, "we were not allowed to seek, or EOF " ); return -1; } return vlc_stream_Tell( p_demux->s ); }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; int64_t i_offset; unsigned i_frames = p_sys->i_block_frames; i_offset = vlc_stream_Tell( p_demux->s ); if( p_sys->i_data_size > 0 && i_offset >= p_sys->i_data_offset + p_sys->i_data_size ) { /* EOF */ return 0; } p_block = vlc_stream_Block( p_demux->s, p_sys->i_frame_size * i_frames ); if( p_block == NULL ) { msg_Warn( p_demux, "cannot read data" ); return 0; } i_frames = p_block->i_buffer / p_sys->i_frame_size; p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts ); es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); date_Increment( &p_sys->pts, i_frames * FRAME_LENGTH ); return 1; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; mtime_t i_date; mtime_t i_delta; i_delta = INT64_C(1000000) / CDG_FRAME_RATE; p_block = vlc_stream_Block( p_demux->s, CDG_FRAME_SIZE ); if( p_block == NULL ) { msg_Dbg( p_demux, "cannot read data, eof" ); return 0; } i_date = vlc_stream_Tell( p_demux->s ) / CDG_FRAME_SIZE * i_delta; if( i_date >= date_Get( &p_sys->pts ) + i_delta ) { p_block->i_dts = p_block->i_pts = i_date; date_Set( &p_sys->pts, i_date ); } else { p_block->i_dts = i_date; p_block->i_pts = date_Get( &p_sys->pts ); } es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); return 1; }
/***************************************************************************** * Demux: read packet and send them to decoders ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, 1 otherwise *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; int64_t i_offset = vlc_stream_Tell( p_demux->s ); unsigned i_frames = p_sys->i_block_frames; if( p_sys->i_data_size > 0 && (i_offset - HEADER_LENGTH) >= p_sys->i_data_size ) { return VLC_DEMUXER_EOF; } p_block = vlc_stream_Block( p_demux->s, p_sys->i_frame_size * i_frames ); if( p_block == NULL ) { msg_Warn( p_demux, "cannot read data" ); return VLC_DEMUXER_EOF; } i_frames = p_block->i_buffer / p_sys->i_frame_size; p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts ); es_out_SetPCR( p_demux->out, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es, p_block ); date_Increment( &p_sys->pts, i_frames * FRAME_LENGTH ); return VLC_DEMUXER_SUCCESS; }
/**************************************************************************** * * Basics functions to manipulates chunks * ****************************************************************************/ static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk ) { const uint8_t *p_peek; memset( p_chk, 0, sizeof( avi_chunk_t ) ); if( vlc_stream_Peek( s, &p_peek, 8 ) < 8 ) return VLC_EGENERIC; p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek ); p_chk->common.i_chunk_size = GetDWLE( p_peek + 4 ); p_chk->common.i_chunk_pos = vlc_stream_Tell( s ); p_chk->common.p_father = NULL; p_chk->common.p_next = NULL; p_chk->common.p_first = NULL; p_chk->common.p_next = NULL; #ifdef AVI_DEBUG msg_Dbg( (vlc_object_t*)s, "found chunk, fourcc: %4.4s size:%"PRId64" pos:%"PRId64, (char*)&p_chk->common.i_chunk_fourcc, p_chk->common.i_chunk_size, p_chk->common.i_chunk_pos ); #endif return VLC_SUCCESS; }
/***************************************************************************** * Control: *****************************************************************************/ static int Control( demux_t *p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; uint64_t i_old_offset = vlc_stream_Tell( p_demux->s ); int i_ret = demux_vaControlHelper( p_demux->s, 0, -1, 8*CDG_FRAME_SIZE*CDG_FRAME_RATE, CDG_FRAME_SIZE, i_query, args ); if( !i_ret && ( i_query == DEMUX_SET_POSITION || i_query == DEMUX_SET_TIME ) ) { date_Set( &p_sys->pts, PosToDate( p_demux ) ); if ( i_old_offset > vlc_stream_Tell( p_demux->s ) ) i_ret = vlc_stream_Seek( p_demux->s, 0 ); else i_ret = vlc_stream_Seek( p_demux->s, i_old_offset ); } return i_ret; }
int AVI_ChunkReadRoot( stream_t *s, avi_chunk_t *p_root ) { avi_chunk_list_t *p_list = (avi_chunk_list_t*)p_root; avi_chunk_t *p_chk; bool b_seekable; vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable ); p_list->i_chunk_pos = 0; p_list->i_chunk_size = stream_Size( s ); p_list->i_chunk_fourcc = AVIFOURCC_LIST; p_list->p_father = NULL; p_list->p_next = NULL; p_list->p_first = NULL; p_list->p_last = NULL; p_list->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' ); for( ; ; ) { p_chk = xmalloc( sizeof( avi_chunk_t ) ); memset( p_chk, 0, sizeof( avi_chunk_t ) ); if( !p_root->common.p_first ) { p_root->common.p_first = p_chk; } else { p_root->common.p_last->common.p_next = p_chk; } p_root->common.p_last = p_chk; if( AVI_ChunkRead( s, p_chk, p_root ) || ( vlc_stream_Tell( s ) >= (off_t)p_chk->common.p_father->common.i_chunk_pos + (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) ) { break; } /* If we can't seek then stop when we 've found first RIFF-AVI */ if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF && p_chk->list.i_type == AVIFOURCC_AVI && !b_seekable ) { break; } } AVI_ChunkDumpDebug_level( (vlc_object_t*)s, p_root, 0 ); return VLC_SUCCESS; }
static la_int64_t libarchive_seek_cb( libarchive_t* p_arc, void* p_obj, la_int64_t offset, int whence ) { VLC_UNUSED( p_arc ); libarchive_callback_t* p_cb = (libarchive_callback_t*)p_obj; stream_t* p_source = p_cb->p_source; ssize_t whence_pos; switch( whence ) { case SEEK_SET: whence_pos = 0; break; case SEEK_CUR: whence_pos = vlc_stream_Tell( p_source ); break; case SEEK_END: whence_pos = stream_Size( p_source ); break; default: vlc_assert_unreachable(); } if( whence_pos < 0 || vlc_stream_Seek( p_source, whence_pos + offset ) ) return ARCHIVE_FATAL; return vlc_stream_Tell( p_source ); }
static bool FindLength( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; int64_t i_current_pos = -1, i_size = 0, i_end = 0; if( !var_CreateGetBool( p_demux, "ps-trust-timestamps" ) ) return true; if( p_sys->i_length == VLC_TICK_INVALID ) /* First time */ { p_sys->i_length = VLC_TICK_0; /* Check beginning */ int i = 0; i_current_pos = vlc_stream_Tell( p_demux->s ); while( i < 40 && Probe( p_demux, false ) > 0 ) i++; /* Check end */ i_size = stream_Size( p_demux->s ); i_end = VLC_CLIP( i_size, 0, 200000 ); if( vlc_stream_Seek( p_demux->s, i_size - i_end ) == VLC_SUCCESS ) { i = 0; while( i < 400 && Probe( p_demux, true ) > 0 ) i++; if( i_current_pos >= 0 && vlc_stream_Seek( p_demux->s, i_current_pos ) != VLC_SUCCESS ) return false; } else return false; } /* Find the longest track */ for( int i = 0; i < PS_TK_COUNT; i++ ) { ps_track_t *tk = &p_sys->tk[i]; if( tk->i_first_pts != VLC_TICK_INVALID && tk->i_last_pts > tk->i_first_pts ) { vlc_tick_t i_length = tk->i_last_pts - tk->i_first_pts; if( i_length > p_sys->i_length ) { p_sys->i_length = i_length; p_sys->i_time_track_index = i; msg_Dbg( p_demux, "we found a length of: %"PRId64 "s", SEC_FROM_VLC_TICK(p_sys->i_length) ); } } } return true; }
/* Allow to append indexes after starting playback */ int AVI_ChunkFetchIndexes( stream_t *s, avi_chunk_t *p_riff ) { avi_chunk_t *p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 ); if ( !p_movi ) return VLC_EGENERIC; avi_chunk_t *p_chk; uint64_t i_indexpos = 8 + p_movi->common.i_chunk_pos + p_movi->common.i_chunk_size; bool b_seekable = false; int i_ret = VLC_SUCCESS; vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable ); if ( !b_seekable || vlc_stream_Seek( s, i_indexpos ) ) return VLC_EGENERIC; for( ; ; ) { p_chk = xmalloc( sizeof( avi_chunk_t ) ); memset( p_chk, 0, sizeof( avi_chunk_t ) ); if (unlikely( !p_riff->common.p_first )) p_riff->common.p_first = p_chk; else p_riff->common.p_last->common.p_next = p_chk; p_riff->common.p_last = p_chk; i_ret = AVI_ChunkRead( s, p_chk, p_riff ); if( i_ret ) break; if( p_chk->common.p_father->common.i_chunk_size > 0 && ( vlc_stream_Tell( s ) > (off_t)p_chk->common.p_father->common.i_chunk_pos + (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) ) { break; } /* If we can't seek then stop when we 've found any index */ if( p_chk->common.i_chunk_fourcc == AVIFOURCC_indx || p_chk->common.i_chunk_fourcc == AVIFOURCC_idx1 ) { break; } } return i_ret; }
static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk ) { avi_chunk_t chk; if( !p_chk ) { if( AVI_ChunkReadCommon( s, &chk ) ) { return VLC_EGENERIC; } p_chk = &chk; } if( p_chk->common.p_father ) { if( p_chk->common.p_father->common.i_chunk_pos + __EVEN( p_chk->common.p_father->common.i_chunk_size ) + 8 < p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8 ) { return VLC_EGENERIC; } } bool b_seekable = false; uint64_t i_offset = p_chk->common.i_chunk_pos + __EVEN( p_chk->common.i_chunk_size ) + 8; if ( !vlc_stream_Control(s, STREAM_CAN_SEEK, &b_seekable) && b_seekable ) { return vlc_stream_Seek( s, i_offset ); } else { ssize_t i_read = i_offset - vlc_stream_Tell( s ); return (i_read >=0 && vlc_stream_Read( s, NULL, i_read ) == i_read) ? VLC_SUCCESS : VLC_EGENERIC; } }
static la_int64_t libarchive_skip_cb( libarchive_t* p_arc, void* p_obj, off_t i_request ) { VLC_UNUSED( p_arc ); libarchive_callback_t* p_cb = (libarchive_callback_t*)p_obj; stream_t* p_source = p_cb->p_source; private_sys_t* p_sys = p_cb->p_sys; /* TODO: fix b_seekable_source on libarchive_callback_t */ if( p_sys->b_seekable_source ) { if( vlc_stream_Seek( p_source, vlc_stream_Tell( p_source ) + i_request ) ) return ARCHIVE_FATAL; return i_request; } ssize_t i_read = vlc_stream_Read( p_source, NULL, i_request ); return i_read >= 0 ? i_read : ARCHIVE_FATAL; }
static vlc_tick_t PosToDate( demux_t *p_demux ) { return vlc_stream_Tell( p_demux->s ) / CDG_FRAME_SIZE * CDG_FRAME_DELTA; }
static int RefineSeek( demux_t *p_demux, mtime_t i_time, double i_bytemicrorate, uint64_t i_lowpos, uint64_t i_highpos ) { demux_sys_t *p_sys = p_demux->p_sys; bool b_found = false; block_t *p_block_out; block_t *p_block_in; unsigned i_frame_size = FLAC_MIN_FRAME_SIZE; bool b_canfastseek = false; (int) vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_canfastseek ); uint64_t i_start_pos = vlc_stream_Tell( p_demux->s ); while( !b_found ) { FlushPacketizer( p_sys->p_packetizer ); p_block_out = NULL; p_block_in = NULL; while( !p_block_out ) { if( !p_block_in ) { if( !(p_block_in = vlc_stream_Block( p_demux->s, i_frame_size )) ) break; } p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in ); } if( !p_block_out ) { if( p_block_in ) block_Release( p_block_in ); break; } if( p_block_out->i_buffer > i_frame_size ) i_frame_size = p_block_out->i_buffer; /* If we are further than wanted block */ if( p_block_out->i_dts >= i_time ) { mtime_t i_diff = p_block_out->i_dts - i_time; /* Not in acceptable approximation range */ if( i_diff > CLOCK_FREQ / 10 && i_diff / i_bytemicrorate > i_frame_size ) { i_highpos = i_start_pos; i_start_pos -= ( i_diff / i_bytemicrorate ); i_start_pos = __MAX(i_start_pos, i_lowpos + i_frame_size); } else b_found = true; } else if( p_block_out->i_dts < i_time ) { mtime_t i_diff = i_time - p_block_out->i_dts; /* Not in acceptable NEXT_TIME demux range */ if( i_diff >= ((b_canfastseek) ? FLAC_MAX_PREROLL : FLAC_MAX_SLOW_PREROLL) && i_diff / i_bytemicrorate > i_frame_size ) { i_lowpos = i_start_pos; i_start_pos += ( i_diff / i_bytemicrorate ); i_start_pos = __MIN(i_start_pos, i_highpos - i_frame_size); } else b_found = true; } if( p_block_out ) block_Release( p_block_out ); if( p_block_in ) block_Release( p_block_in ); if( !b_found ) { if( i_highpos < i_lowpos || i_highpos - i_lowpos < i_frame_size ) break; if( VLC_SUCCESS != vlc_stream_Seek( p_demux->s, i_start_pos ) ) break; } } return b_found ? VLC_SUCCESS : VLC_EGENERIC; }
/***************************************************************************** * Open: check file and initializes structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; xa_header_t p_xa; const uint8_t *p_buf; /* XA file heuristic */ if( vlc_stream_Peek( p_demux->s, &p_buf, sizeof( p_xa ) ) < (signed)sizeof( p_xa ) ) return VLC_EGENERIC; memcpy( &p_xa, p_buf, sizeof( p_xa ) ); if( ( strncmp( p_xa.xa_id, "XAI", 4 ) && strncmp( p_xa.xa_id, "XAJ", 4 ) ) || ( GetWLE( &p_xa.wFormatTag ) != 0x0001) || ( GetWLE( &p_xa.wBitsPerSample ) != 16) ) return VLC_EGENERIC; p_sys = malloc( sizeof( demux_sys_t ) ); if( unlikely( p_sys == NULL ) ) return VLC_ENOMEM; p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys; p_sys->p_es = NULL; /* skip XA header -- cannot fail */ vlc_stream_Read( p_demux->s, NULL, sizeof( p_xa ) ); es_format_t fmt; es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC('X','A','J',0) ); msg_Dbg( p_demux, "assuming EA ADPCM audio codec" ); fmt.audio.i_rate = GetDWLE( &p_xa.nSamplesPerSec ); fmt.audio.i_bytes_per_frame = 15 * GetWLE( &p_xa.nChannels ); fmt.audio.i_frame_length = FRAME_LENGTH; fmt.audio.i_channels = GetWLE ( &p_xa.nChannels ); fmt.audio.i_blockalign = fmt.audio.i_bytes_per_frame; fmt.audio.i_bitspersample = 16; fmt.i_bitrate = (fmt.audio.i_rate * fmt.audio.i_bytes_per_frame * 8) / fmt.audio.i_frame_length; p_sys->i_data_offset = vlc_stream_Tell( p_demux->s ); /* FIXME: better computation */ p_sys->i_data_size = p_xa.iSize * 15 / 56; /* How many frames per block (1:1 is too CPU intensive) */ p_sys->i_block_frames = fmt.audio.i_rate / (FRAME_LENGTH * 20) + 1; p_sys->i_frame_size = fmt.audio.i_bytes_per_frame; p_sys->i_bitrate = fmt.i_bitrate; msg_Dbg( p_demux, "fourcc: %4.4s, channels: %d, " "freq: %d Hz, bitrate: %dKo/s, blockalign: %d", (char *)&fmt.i_codec, fmt.audio.i_channels, fmt.audio.i_rate, fmt.i_bitrate / 8192, fmt.audio.i_blockalign ); if( fmt.audio.i_rate == 0 || fmt.audio.i_channels == 0 ) { free( p_sys ); return VLC_EGENERIC; } p_sys->p_es = es_out_Add( p_demux->out, &fmt ); date_Init( &p_sys->pts, fmt.audio.i_rate, 1 ); date_Set( &p_sys->pts, VLC_TS_0 ); return VLC_SUCCESS; }
char *vlc_stream_ReadLine( stream_t *s ) { stream_priv_t *priv = (stream_priv_t *)s; char *p_line = NULL; int i_line = 0, i_read = 0; /* Let's fail quickly if this is a readdir access */ if( s->pf_read == NULL ) return NULL; for( ;; ) { char *psz_eol; const uint8_t *p_data; int i_data; int64_t i_pos; /* Probe new data */ i_data = vlc_stream_Peek( s, &p_data, STREAM_PROBE_LINE ); if( i_data <= 0 ) break; /* No more data */ /* BOM detection */ i_pos = vlc_stream_Tell( s ); if( i_pos == 0 && i_data >= 2 ) { const char *psz_encoding = NULL; if( !memcmp( p_data, "\xFF\xFE", 2 ) ) { psz_encoding = "UTF-16LE"; priv->text.little_endian = true; } else if( !memcmp( p_data, "\xFE\xFF", 2 ) ) { psz_encoding = "UTF-16BE"; } /* Open the converter if we need it */ if( psz_encoding != NULL ) { msg_Dbg( s, "UTF-16 BOM detected" ); priv->text.char_width = 2; priv->text.conv = vlc_iconv_open( "UTF-8", psz_encoding ); if( priv->text.conv == (vlc_iconv_t)-1 ) msg_Err( s, "iconv_open failed" ); } } if( i_data % priv->text.char_width ) { /* keep i_char_width boundary */ i_data = i_data - ( i_data % priv->text.char_width ); msg_Warn( s, "the read is not i_char_width compatible"); } if( i_data == 0 ) break; /* Check if there is an EOL */ if( priv->text.char_width == 1 ) { /* UTF-8: 0A <LF> */ psz_eol = memchr( p_data, '\n', i_data ); if( psz_eol == NULL ) /* UTF-8: 0D <CR> */ psz_eol = memchr( p_data, '\r', i_data ); } else { const uint8_t *p_last = p_data + i_data - priv->text.char_width; uint16_t eol = priv->text.little_endian ? 0x0A00 : 0x00A0; assert( priv->text.char_width == 2 ); psz_eol = NULL; /* UTF-16: 000A <LF> */ for( const uint8_t *p = p_data; p <= p_last; p += 2 ) { if( U16_AT( p ) == eol ) { psz_eol = (char *)p + 1; break; } } if( psz_eol == NULL ) { /* UTF-16: 000D <CR> */ eol = priv->text.little_endian ? 0x0D00 : 0x00D0; for( const uint8_t *p = p_data; p <= p_last; p += 2 ) { if( U16_AT( p ) == eol ) { psz_eol = (char *)p + 1; break; } } } } if( psz_eol ) { i_data = (psz_eol - (char *)p_data) + 1; p_line = realloc_or_free( p_line, i_line + i_data + priv->text.char_width ); /* add \0 */ if( !p_line ) goto error; i_data = vlc_stream_Read( s, &p_line[i_line], i_data ); if( i_data <= 0 ) break; /* Hmmm */ i_line += i_data - priv->text.char_width; /* skip \n */; i_read += i_data; /* We have our line */ break; } /* Read data (+1 for easy \0 append) */ p_line = realloc_or_free( p_line, i_line + STREAM_PROBE_LINE + priv->text.char_width ); if( !p_line ) goto error; i_data = vlc_stream_Read( s, &p_line[i_line], STREAM_PROBE_LINE ); if( i_data <= 0 ) break; /* Hmmm */ i_line += i_data; i_read += i_data; if( i_read >= STREAM_LINE_MAX ) goto error; /* line too long */ } if( i_read > 0 ) { memset(p_line + i_line, 0, priv->text.char_width); i_line += priv->text.char_width; /* the added \0 */ if( priv->text.char_width > 1 ) { int i_new_line = 0; size_t i_in = 0, i_out = 0; const char * p_in = NULL; char * p_out = NULL; char * psz_new_line = NULL; /* iconv */ /* UTF-8 needs at most 150% of the buffer as many as UTF-16 */ i_new_line = i_line * 3 / 2; psz_new_line = malloc( i_new_line ); if( psz_new_line == NULL ) goto error; i_in = (size_t)i_line; i_out = (size_t)i_new_line; p_in = p_line; p_out = psz_new_line; if( vlc_iconv( priv->text.conv, &p_in, &i_in, &p_out, &i_out ) == (size_t)-1 ) { msg_Err( s, "iconv failed" ); msg_Dbg( s, "original: %d, in %d, out %d", i_line, (int)i_in, (int)i_out ); } free( p_line ); p_line = psz_new_line; i_line = (size_t)i_new_line - i_out; /* does not include \0 */ } /* Remove trailing LF/CR */ while( i_line >= 2 && ( p_line[i_line-2] == '\r' || p_line[i_line-2] == '\n') ) i_line--; /* Make sure the \0 is there */ p_line[i_line-1] = '\0'; return p_line; } error: /* We failed to read any data, probably EOF */ free( p_line ); /* */ if( priv->text.conv != (vlc_iconv_t)(-1) ) { vlc_iconv_close( priv->text.conv ); priv->text.conv = (vlc_iconv_t)(-1); } return NULL; }
/***************************************************************************** * Demux: *****************************************************************************/ static int Demux( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; int i_ret, i_mux_rate; block_t *p_pkt; i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack ); if( i_ret < 0 ) { return VLC_DEMUXER_EOF; } else if( i_ret == 0 ) { if( !p_sys->b_lost_sync ) { msg_Warn( p_demux, "garbage at input from %"PRIu64", trying to resync...", vlc_stream_Tell(p_demux->s) ); NotifyDiscontinuity( p_sys->tk, p_demux->out ); } p_sys->b_lost_sync = true; return VLC_DEMUXER_SUCCESS; } if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" ); p_sys->b_lost_sync = false; if( p_sys->i_length == VLC_TICK_INVALID && p_sys->b_seekable ) { if( !FindLength( p_demux ) ) return VLC_DEMUXER_EGENERIC; } if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL ) { return VLC_DEMUXER_EOF; } if( p_pkt->i_buffer < 4 ) { block_Release( p_pkt ); return VLC_DEMUXER_EGENERIC; } const uint8_t i_stream_id = p_pkt->p_buffer[3]; switch( i_stream_id ) { case PS_STREAM_ID_END_STREAM: block_Release( p_pkt ); break; case PS_STREAM_ID_PACK_HEADER: if( !ps_pkt_parse_pack( p_pkt, &p_sys->i_pack_scr, &i_mux_rate ) ) { if( p_sys->i_first_scr == VLC_TICK_INVALID ) p_sys->i_first_scr = p_sys->i_pack_scr; CheckPCR( p_sys, p_demux->out, p_sys->i_pack_scr ); p_sys->i_scr = p_sys->i_pack_scr; p_sys->i_lastpack_byte = vlc_stream_Tell( p_demux->s ); if( !p_sys->b_have_pack ) p_sys->b_have_pack = true; /* done later on to work around bad vcd/svcd streams */ /* es_out_SetPCR( p_demux->out, p_sys->i_scr ); */ if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate; } block_Release( p_pkt ); break; case PS_STREAM_ID_SYSTEM_HEADER: if( !ps_pkt_parse_system( p_pkt, &p_sys->psm, p_sys->tk ) ) { int i; for( i = 0; i < PS_TK_COUNT; i++ ) { ps_track_t *tk = &p_sys->tk[i]; if( !tk->b_configured && tk->fmt.i_cat != UNKNOWN_ES ) { if( tk->b_seen ) tk->es = es_out_Add( p_demux->out, &tk->fmt ); /* else create when seeing packet */ tk->b_configured = true; } } } block_Release( p_pkt ); break; case PS_STREAM_ID_MAP: if( p_sys->psm.i_version == 0xFFFF ) msg_Dbg( p_demux, "contains a PSM"); ps_psm_fill( &p_sys->psm, p_pkt, p_sys->tk, p_demux->out ); block_Release( p_pkt ); break; default: /* Reject non video/audio nor PES */ if( i_stream_id < 0xC0 || i_stream_id > 0xEF ) { block_Release( p_pkt ); break; } /* fallthrough */ case PS_STREAM_ID_PRIVATE_STREAM1: case PS_STREAM_ID_EXTENDED: { int i_id = ps_pkt_id( p_pkt ); /* Small heuristic to improve MLP detection from AOB */ if( i_id == 0xa001 && p_sys->i_aob_mlp_count < 500 ) { p_sys->i_aob_mlp_count++; } else if( i_id == 0xbda1 && p_sys->i_aob_mlp_count > 0 ) { p_sys->i_aob_mlp_count--; i_id = 0xa001; } bool b_new = false; ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)]; if( !tk->b_configured ) { if( !ps_track_fill( tk, &p_sys->psm, i_id, p_pkt, false ) ) { /* No PSM and no probing yet */ if( p_sys->format == PSMF_PS ) { if( tk->fmt.i_cat == VIDEO_ES ) tk->fmt.i_codec = VLC_CODEC_H264; #if 0 if( i_stream_id == PS_STREAM_ID_PRIVATE_STREAM1 ) { es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_ATRAC3P ); tk->fmt.audio.i_blockalign = 376; tk->fmt.audio.i_channels = 2; tk->fmt.audio.i_rate = 44100; } #endif } tk->es = es_out_Add( p_demux->out, &tk->fmt ); b_new = true; tk->b_configured = true; } else { msg_Dbg( p_demux, "es id=0x%x format unknown", i_id ); } } /* Late creation from system header */ if( !tk->b_seen && tk->b_configured && !tk->es && tk->fmt.i_cat != UNKNOWN_ES ) tk->es = es_out_Add( p_demux->out, &tk->fmt ); tk->b_seen = true; /* The popular VCD/SVCD subtitling WinSubMux does not * renumber the SCRs when merging subtitles into the PES */ if( tk->b_seen && !p_sys->b_bad_scr && ( tk->fmt.i_codec == VLC_CODEC_OGT || tk->fmt.i_codec == VLC_CODEC_CVD ) ) { p_sys->b_bad_scr = true; p_sys->i_first_scr = VLC_TICK_INVALID; } if( p_sys->i_pack_scr != VLC_TICK_INVALID && !p_sys->b_bad_scr ) { if( (tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES) && tk->i_first_pts != VLC_TICK_INVALID && tk->i_first_pts - p_sys->i_pack_scr > VLC_TICK_FROM_SEC(2)) { msg_Warn( p_demux, "Incorrect SCR timing offset by of %"PRId64 "ms, disabling", MS_FROM_VLC_TICK(tk->i_first_pts - p_sys->i_pack_scr) ); p_sys->b_bad_scr = true; /* Disable Offset SCR */ p_sys->i_first_scr = VLC_TICK_INVALID; } else es_out_SetPCR( p_demux->out, p_sys->i_pack_scr ); } if( tk->b_configured && tk->es && !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) ) { if( tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES ) { if( !p_sys->b_bad_scr && p_sys->i_pack_scr != VLC_TICK_INVALID && p_pkt->i_pts != VLC_TICK_INVALID && p_sys->i_pack_scr > p_pkt->i_pts + VLC_TICK_FROM_MS(250) ) { msg_Warn( p_demux, "Incorrect SCR timing in advance of %" PRId64 "ms, disabling", MS_FROM_VLC_TICK(p_sys->i_pack_scr - p_pkt->i_pts) ); p_sys->b_bad_scr = true; p_sys->i_first_scr = VLC_TICK_INVALID; } if( (p_sys->b_bad_scr || !p_sys->b_have_pack) && !p_sys->i_scr_track_id ) { p_sys->i_scr_track_id = tk->i_id; } } if( ((!b_new && !p_sys->b_have_pack) || p_sys->b_bad_scr) && p_sys->i_scr_track_id == tk->i_id && p_pkt->i_pts != VLC_TICK_INVALID ) { /* A hack to sync the A/V on PES files. */ msg_Dbg( p_demux, "force SCR: %"PRId64, p_pkt->i_pts ); CheckPCR( p_sys, p_demux->out, p_pkt->i_pts ); p_sys->i_scr = p_pkt->i_pts; if( p_sys->i_first_scr == VLC_TICK_INVALID ) p_sys->i_first_scr = p_sys->i_scr; es_out_SetPCR( p_demux->out, p_pkt->i_pts ); } if( tk->fmt.i_codec == VLC_CODEC_TELETEXT && p_pkt->i_pts == VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID ) { /* Teletext may have missing PTS (ETSI EN 300 472 Annexe A) * In this case use the last SCR + 40ms */ p_pkt->i_pts = p_sys->i_scr + VLC_TICK_FROM_MS(40); } if( p_pkt->i_pts > p_sys->i_current_pts ) { p_sys->i_current_pts = p_pkt->i_pts; } if( tk->i_next_block_flags ) { p_pkt->i_flags = tk->i_next_block_flags; tk->i_next_block_flags = 0; } #if 0 if( tk->fmt.i_codec == VLC_CODEC_ATRAC3P ) { p_pkt->p_buffer += 14; p_pkt->i_buffer -= 14; } #endif es_out_Send( p_demux->out, tk->es, p_pkt ); } else { block_Release( p_pkt ); } p_sys->i_pack_scr = VLC_TICK_INVALID; } break; } demux_UpdateTitleFromStream( p_demux ); return VLC_DEMUXER_SUCCESS; }
/***************************************************************************** * Control: *****************************************************************************/ static int Control( demux_t *p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; const int64_t i_start_time = p_sys->ic->start_time != AV_NOPTS_VALUE ? p_sys->ic->start_time : 0; double f, *pf; int64_t i64; switch( i_query ) { case DEMUX_CAN_SEEK: *va_arg( args, bool * ) = true; return VLC_SUCCESS; case DEMUX_GET_POSITION: pf = va_arg( args, double * ); *pf = 0.0; i64 = stream_Size( p_demux->s ); if( i64 > 0 ) { double current = vlc_stream_Tell( p_demux->s ); *pf = current / (double)i64; } if( (p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE) && (p_sys->i_pcr > 0) ) { *pf = (double)p_sys->i_pcr / (double)p_sys->ic->duration; } return VLC_SUCCESS; case DEMUX_SET_POSITION: { f = va_arg( args, double ); bool precise = va_arg( args, int ); i64 = p_sys->ic->duration * f + i_start_time; msg_Warn( p_demux, "DEMUX_SET_POSITION: %"PRId64, i64 ); /* If we have a duration, we prefer to seek by time but if we don't, or if the seek fails, try BYTE seeking */ if( p_sys->ic->duration == (int64_t)AV_NOPTS_VALUE || (av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BACKWARD ) < 0) ) { int64_t i_size = stream_Size( p_demux->s ); i64 = (i_size * f); msg_Warn( p_demux, "DEMUX_SET_BYTE_POSITION: %"PRId64, i64 ); if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BYTE ) < 0 ) return VLC_EGENERIC; ResetTime( p_demux, -1 ); } else { if( precise ) ResetTime( p_demux, i64 - i_start_time ); else ResetTime( p_demux, -1 ); } return VLC_SUCCESS; } case DEMUX_GET_LENGTH: if( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) *va_arg( args, vlc_tick_t * ) = FROM_AV_TS(p_sys->ic->duration); else *va_arg( args, vlc_tick_t * ) = 0; return VLC_SUCCESS; case DEMUX_GET_TIME: *va_arg( args, vlc_tick_t * ) = p_sys->i_pcr; return VLC_SUCCESS; case DEMUX_SET_TIME: { i64 = TO_AV_TS(va_arg( args, vlc_tick_t )); bool precise = va_arg( args, int ); msg_Warn( p_demux, "DEMUX_SET_TIME: %"PRId64, i64 ); if( av_seek_frame( p_sys->ic, -1, i64 + i_start_time, AVSEEK_FLAG_BACKWARD ) < 0 ) { return VLC_EGENERIC; } if( precise ) ResetTime( p_demux, i64 - i_start_time ); else ResetTime( p_demux, -1 ); return VLC_SUCCESS; } case DEMUX_HAS_UNSUPPORTED_META: { bool *pb_bool = va_arg( args, bool* ); *pb_bool = true; return VLC_SUCCESS; } case DEMUX_GET_META: { static const char names[][10] = { [vlc_meta_Title] = "title", [vlc_meta_Artist] = "artist", [vlc_meta_Genre] = "genre", [vlc_meta_Copyright] = "copyright", [vlc_meta_Album] = "album", //[vlc_meta_TrackNumber] -- TODO: parse number/total value [vlc_meta_Description] = "comment", //[vlc_meta_Rating] [vlc_meta_Date] = "date", [vlc_meta_Setting] = "encoder", //[vlc_meta_URL] [vlc_meta_Language] = "language", //[vlc_meta_NowPlaying] [vlc_meta_Publisher] = "publisher", [vlc_meta_EncodedBy] = "encoded_by", //[vlc_meta_ArtworkURL] //[vlc_meta_TrackID] //[vlc_meta_TrackTotal] }; vlc_meta_t *p_meta = va_arg( args, vlc_meta_t * ); AVDictionary *dict = p_sys->ic->metadata; for( unsigned i = 0; i < sizeof(names) / sizeof(*names); i++) { if( !names[i][0] ) continue; AVDictionaryEntry *e = av_dict_get( dict, names[i], NULL, 0 ); if( e != NULL && e->value != NULL && IsUTF8(e->value) ) vlc_meta_Set( p_meta, i, e->value ); } return VLC_SUCCESS; } case DEMUX_GET_ATTACHMENTS: { input_attachment_t ***ppp_attach = va_arg( args, input_attachment_t*** ); int *pi_int = va_arg( args, int * ); int i; if( p_sys->i_attachments <= 0 ) return VLC_EGENERIC; *ppp_attach = vlc_alloc( p_sys->i_attachments, sizeof(input_attachment_t*) ); if( *ppp_attach == NULL ) return VLC_EGENERIC; for( i = 0; i < p_sys->i_attachments; i++ ) { (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] ); if((*ppp_attach)[i] == NULL) break; } *pi_int = i; return VLC_SUCCESS; } case DEMUX_GET_TITLE_INFO: { input_title_t ***ppp_title = va_arg( args, input_title_t *** ); int *pi_int = va_arg( args, int * ); int *pi_title_offset = va_arg( args, int * ); int *pi_seekpoint_offset = va_arg( args, int * ); if( !p_sys->p_title ) return VLC_EGENERIC; *ppp_title = malloc( sizeof( input_title_t*) ); if( *ppp_title == NULL ) return VLC_EGENERIC; (*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->p_title ); *pi_int = (*ppp_title)[0] ? 1 : 0; *pi_title_offset = 0; *pi_seekpoint_offset = 0; return VLC_SUCCESS; } case DEMUX_SET_TITLE: { const int i_title = va_arg( args, int ); if( !p_sys->p_title || i_title != 0 ) return VLC_EGENERIC; return VLC_SUCCESS; } case DEMUX_SET_SEEKPOINT: { const int i_seekpoint = va_arg( args, int ); if( !p_sys->p_title ) return VLC_EGENERIC; i64 = TO_AV_TS(p_sys->p_title->seekpoint[i_seekpoint]->i_time_offset) + i_start_time; msg_Warn( p_demux, "DEMUX_SET_SEEKPOINT: %"PRId64, i64 ); if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BACKWARD ) < 0 ) { return VLC_EGENERIC; } ResetTime( p_demux, i64 - i_start_time ); return VLC_SUCCESS; } case DEMUX_TEST_AND_CLEAR_FLAGS: { unsigned *restrict flags = va_arg(args, unsigned *); *flags &= p_sys->i_update; p_sys->i_update &= ~*flags; return VLC_SUCCESS; } case DEMUX_GET_TITLE: if( p_sys->p_title == NULL ) return VLC_EGENERIC; *va_arg( args, int * ) = 0; return VLC_SUCCESS; case DEMUX_GET_SEEKPOINT: if( p_sys->p_title == NULL ) return VLC_EGENERIC; *va_arg( args, int * ) = p_sys->i_seekpoint; return VLC_SUCCESS; case DEMUX_CAN_PAUSE: case DEMUX_SET_PAUSE_STATE: case DEMUX_CAN_CONTROL_PACE: case DEMUX_GET_PTS_DELAY: return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args ); default: return VLC_EGENERIC; } }
/***************************************************************************** * Control: *****************************************************************************/ static int Control( demux_t *p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; double f, *pf; int64_t i64; int i_ret; switch( i_query ) { case DEMUX_CAN_SEEK: *va_arg( args, bool * ) = p_sys->b_seekable; return VLC_SUCCESS; case DEMUX_GET_TITLE: *va_arg( args, int * ) = p_sys->current_title; return VLC_SUCCESS; case DEMUX_GET_SEEKPOINT: *va_arg( args, int * ) = p_sys->current_seekpoint; return VLC_SUCCESS; case DEMUX_GET_POSITION: pf = va_arg( args, double * ); i64 = stream_Size( p_demux->s ) - p_sys->i_start_byte; if( i64 > 0 ) { double current = vlc_stream_Tell( p_demux->s ) - p_sys->i_start_byte; *pf = current / (double)i64; } else { *pf = 0.0; } return VLC_SUCCESS; case DEMUX_SET_POSITION: f = va_arg( args, double ); i64 = stream_Size( p_demux->s ) - p_sys->i_start_byte; p_sys->i_current_pts = VLC_TICK_INVALID; p_sys->i_scr = VLC_TICK_INVALID; if( p_sys->format == CDXA_PS ) { i64 = (int64_t)(i64 * f); /* Align to sector payload */ i64 = p_sys->i_start_byte + i64 - (i64 % CDXA_SECTOR_SIZE) + CDXA_SECTOR_HEADER_SIZE; } else { i64 = p_sys->i_start_byte + (int64_t)(i64 * f); } i_ret = vlc_stream_Seek( p_demux->s, i64 ); if( i_ret == VLC_SUCCESS ) { NotifyDiscontinuity( p_sys->tk, p_demux->out ); return i_ret; } break; case DEMUX_GET_TIME: if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID ) { *va_arg( args, vlc_tick_t * ) = p_sys->i_current_pts - p_sys->tk[p_sys->i_time_track_index].i_first_pts; return VLC_SUCCESS; } if( p_sys->i_first_scr != VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID ) { vlc_tick_t i_time = p_sys->i_scr - p_sys->i_first_scr; /* H.222 2.5.2.2 */ if( p_sys->i_mux_rate > 0 && p_sys->b_have_pack ) { uint64_t i_offset = vlc_stream_Tell( p_demux->s ) - p_sys->i_lastpack_byte; i_time += vlc_tick_from_samples(i_offset, p_sys->i_mux_rate * 50); } *va_arg( args, vlc_tick_t * ) = i_time; return VLC_SUCCESS; } *va_arg( args, vlc_tick_t * ) = 0; break; case DEMUX_GET_LENGTH: if( p_sys->i_length > VLC_TICK_0 ) { *va_arg( args, vlc_tick_t * ) = p_sys->i_length; return VLC_SUCCESS; } else if( p_sys->i_mux_rate > 0 ) { *va_arg( args, vlc_tick_t * ) = vlc_tick_from_samples( stream_Size( p_demux->s ) - p_sys->i_start_byte / 50, p_sys->i_mux_rate ); return VLC_SUCCESS; } *va_arg( args, vlc_tick_t * ) = 0; break; case DEMUX_SET_TIME: { if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID && p_sys->i_length > VLC_TICK_0) { vlc_tick_t i_time = va_arg( args, vlc_tick_t ); i_time -= p_sys->tk[p_sys->i_time_track_index].i_first_pts; return demux_Control( p_demux, DEMUX_SET_POSITION, (double) i_time / p_sys->i_length ); } break; } case DEMUX_GET_TITLE_INFO: { struct input_title_t ***v = va_arg( args, struct input_title_t*** ); int *c = va_arg( args, int * ); *va_arg( args, int* ) = 0; /* Title offset */ *va_arg( args, int* ) = 0; /* Chapter offset */ return vlc_stream_Control( p_demux->s, STREAM_GET_TITLE_INFO, v, c ); } case DEMUX_SET_TITLE: return vlc_stream_vaControl( p_demux->s, STREAM_SET_TITLE, args ); case DEMUX_SET_SEEKPOINT: return vlc_stream_vaControl( p_demux->s, STREAM_SET_SEEKPOINT, args ); case DEMUX_TEST_AND_CLEAR_FLAGS: { unsigned *restrict flags = va_arg(args, unsigned *); *flags &= p_sys->updates; p_sys->updates &= ~*flags; return VLC_SUCCESS; } case DEMUX_GET_META: return vlc_stream_vaControl( p_demux->s, STREAM_GET_META, args ); case DEMUX_GET_FPS: break; case DEMUX_CAN_PAUSE: case DEMUX_SET_PAUSE_STATE: case DEMUX_CAN_CONTROL_PACE: case DEMUX_GET_PTS_DELAY: return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args ); default: break; } return VLC_EGENERIC; }
/**************************************************************************** * * Functions to read chunks * ****************************************************************************/ static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container ) { avi_chunk_t *p_chk; const uint8_t *p_peek; bool b_seekable; int i_ret = VLC_SUCCESS; if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 4 ) { /* empty box */ msg_Warn( (vlc_object_t*)s, "empty list chunk" ); return VLC_EGENERIC; } if( vlc_stream_Peek( s, &p_peek, 12 ) < 12 ) { msg_Warn( (vlc_object_t*)s, "cannot peek while reading list chunk" ); return VLC_EGENERIC; } vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable ); p_container->list.i_type = GetFOURCC( p_peek + 8 ); /* XXX fixed for on2 hack */ if( p_container->common.i_chunk_fourcc == AVIFOURCC_ON2 && p_container->list.i_type == AVIFOURCC_ON2f ) { p_container->common.i_chunk_fourcc = AVIFOURCC_RIFF; p_container->list.i_type = AVIFOURCC_AVI; } if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST && p_container->list.i_type == AVIFOURCC_movi ) { if( !b_seekable ) return VLC_SUCCESS; msg_Dbg( (vlc_object_t*)s, "skipping movi chunk" ); return AVI_NextChunk( s, p_container ); /* points at begining of LIST-movi if not seekable */ } if( vlc_stream_Read( s, NULL, 12 ) != 12 ) { msg_Warn( (vlc_object_t*)s, "cannot enter chunk" ); return VLC_EGENERIC; } #ifdef AVI_DEBUG msg_Dbg( (vlc_object_t*)s, "found LIST chunk: \'%4.4s\'", (char*)&p_container->list.i_type ); #endif msg_Dbg( (vlc_object_t*)s, "<list \'%4.4s\'>", (char*)&p_container->list.i_type ); for( ; ; ) { p_chk = xmalloc( sizeof( avi_chunk_t ) ); memset( p_chk, 0, sizeof( avi_chunk_t ) ); if( !p_container->common.p_first ) { p_container->common.p_first = p_chk; } else { p_container->common.p_last->common.p_next = p_chk; } p_container->common.p_last = p_chk; i_ret = AVI_ChunkRead( s, p_chk, p_container ); if( i_ret ) { break; } if( p_chk->common.p_father->common.i_chunk_size > 0 && ( vlc_stream_Tell( s ) > (off_t)p_chk->common.p_father->common.i_chunk_pos + (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) ) { break; } /* If we can't seek then stop when we 've found LIST-movi */ if( p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST && p_chk->list.i_type == AVIFOURCC_movi && ( !b_seekable || p_chk->common.i_chunk_size == 0 ) ) { break; } } msg_Dbg( (vlc_object_t*)s, "</list \'%4.4s\'>", (char*)&p_container->list.i_type ); if ( i_ret == AVI_ZERO_FOURCC ) return i_ret; return VLC_SUCCESS; }