+ if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos ) )
+ return VLC_EGENERIC;
+ p_sys->i_time_offset = p_sys->seekpoint[i]->i_time_offset - p_sys->i_pts;
+ p_sys->i_pts_start = p_sys->i_pts+i_delta_time;
+ es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, p_sys->p_es, p_sys->i_pts_start );
+ }
+ else
+ {
+ if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos + i_delta_offset ) )
+ return VLC_EGENERIC;
+ p_sys->i_pts_start = p_sys->i_pts;
+ p_sys->i_time_offset = (p_sys->seekpoint[i]->i_time_offset+i_delta_time) - p_sys->i_pts;
+ }
+ return VLC_SUCCESS;
+}
+
+static int Control( demux_t *p_demux, int i_query, va_list args )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ if( i_query == DEMUX_GET_META )
+ {
+ vlc_meta_t *p_meta = (vlc_meta_t *)va_arg( args, vlc_meta_t* );
+ if( p_demux->p_sys->p_meta )
+ vlc_meta_Merge( p_meta, p_demux->p_sys->p_meta );
+ return VLC_SUCCESS;
+ }
+ else if( i_query == DEMUX_HAS_UNSUPPORTED_META )
+ {
+ bool *pb_bool = (bool*)va_arg( args, bool* );
+ *pb_bool = true;
+ return VLC_SUCCESS;
+ }
+ else if( i_query == DEMUX_GET_LENGTH )
+ {
+ int64_t *pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = ControlGetLength( p_demux );
+ return VLC_SUCCESS;
+ }
+ else if( i_query == DEMUX_SET_TIME )
+ {
+ int64_t i_time = (int64_t)va_arg( args, int64_t );
+ return ControlSetTime( p_demux, i_time );
+ }
+ else if( i_query == DEMUX_SET_POSITION )
+ {
+ const double f = (double)va_arg( args, double );
+ int64_t i_time = f * ControlGetLength( p_demux );
+ return ControlSetTime( p_demux, i_time );
+ }
+ else if( i_query == DEMUX_GET_TIME )
+ {
+ int64_t *pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = ControlGetTime( p_demux );
+ return VLC_SUCCESS;
+ }
+ else if( i_query == DEMUX_GET_POSITION )
+ {
+ double *pf = (double*)va_arg( args, double * );
+ const int64_t i_length = ControlGetLength(p_demux);
+ if( i_length > 0 )
+ *pf = (double)ControlGetTime(p_demux) / (double)i_length;
+ else
+ *pf= 0.0;
+ return VLC_SUCCESS;
+ }
+ else if( i_query == DEMUX_GET_ATTACHMENTS )
+ {
+ input_attachment_t ***ppp_attach =
+ (input_attachment_t***)va_arg( args, input_attachment_t*** );
+ int *pi_int = (int*)va_arg( args, int * );
+ int i;
+
+ if( p_sys->i_attachments <= 0 )
+ return VLC_EGENERIC;
+
+ *pi_int = p_sys->i_attachments;;
+ *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachments );
+ for( i = 0; i < p_sys->i_attachments; i++ )
+ (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] );
+ return VLC_SUCCESS;
+ }
+
+ return demux_vaControlHelper( p_demux->s, p_sys->i_data_pos, -1,
+ 8*0, 1, i_query, args );
+}
+
+enum
+{
+ META_STREAMINFO = 0,
+ META_SEEKTABLE = 3,
+ META_COMMENT = 4,
+ META_PICTURE = 6,
+};
+
+static inline int Get24bBE( const uint8_t *p )
+{
+ return (p[0] << 16)|(p[1] << 8)|(p[2]);
+}
+
+static void ParseStreamInfo( demux_t *p_demux, int *pi_rate, int64_t *pi_count, uint8_t *p_data, int i_data );
+static void ParseSeekTable( demux_t *p_demux, const uint8_t *p_data, int i_data,
+ int i_sample_rate );
+static void ParseComment( demux_t *, const uint8_t *p_data, int i_data );
+static void ParsePicture( demux_t *, const uint8_t *p_data, int i_data );
+
+static int ReadMeta( demux_t *p_demux, uint8_t **pp_streaminfo, int *pi_streaminfo )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ int i_peek;
+ const uint8_t *p_peek;
+ bool b_last;
+ int i_sample_rate;
+ int64_t i_sample_count;
+ seekpoint_t *s;
+
+ /* Read STREAMINFO */
+ i_peek = stream_Peek( p_demux->s, &p_peek, 8 );
+ if( (p_peek[4] & 0x7F) != META_STREAMINFO )
+ {
+ msg_Err( p_demux, "this isn't a STREAMINFO metadata block" );
+ return VLC_EGENERIC;
+ }
+ if( Get24bBE(&p_peek[5]) != (STREAMINFO_SIZE - 4) )
+ {
+ msg_Err( p_demux, "invalid size for a STREAMINFO metadata block" );
+ return VLC_EGENERIC;
+ }
+
+ *pi_streaminfo = 4 + STREAMINFO_SIZE;
+ *pp_streaminfo = malloc( 4 + STREAMINFO_SIZE );
+ if( *pp_streaminfo == NULL )
+ return VLC_EGENERIC;
+
+ if( stream_Read( p_demux->s, *pp_streaminfo, 4+STREAMINFO_SIZE ) != 4+STREAMINFO_SIZE )
+ {
+ msg_Err( p_demux, "failed to read STREAMINFO metadata block" );
+ free( *pp_streaminfo );
+ return VLC_EGENERIC;
+ }
+
+ /* */
+ ParseStreamInfo( p_demux, &i_sample_rate, &i_sample_count, *pp_streaminfo, *pi_streaminfo );
+ if( i_sample_rate > 0 )
+ p_sys->i_length = i_sample_count * INT64_C(1000000)/i_sample_rate;
+
+ /* Be sure we have seekpoint 0 */
+ s = vlc_seekpoint_New();
+ s->i_time_offset = 0;
+ s->i_byte_offset = 0;
+ TAB_APPEND( p_sys->i_seekpoint, p_sys->seekpoint, s );
+
+ b_last = (*pp_streaminfo)[4]&0x80;
+ while( !b_last )
+ {
+ int i_len;
+ int i_type;
+
+ i_peek = stream_Peek( p_demux->s, &p_peek, 4 );
+ if( i_peek < 4 )
+ break;
+ b_last = p_peek[0]&0x80;
+ i_type = p_peek[0]&0x7f;
+ i_len = Get24bBE( &p_peek[1] );
+
+ if( i_type == META_SEEKTABLE )