/***************************************************************************** * 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; }
//--------------------------------------------------------------------------- // DemuxControl //--------------------------------------------------------------------------- static int DemuxControl( demux_t *p_demux, int i_query, va_list args ) { return demux_vaControlHelper( p_demux->s, 0, 0, 0, 1, i_query, args ); }
/***************************************************************************** * 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; vlc_tick_t i64; vlc_tick_t *pi64; switch( i_query ) { case DEMUX_CAN_SEEK: *va_arg( args, bool * ) = true; return VLC_SUCCESS; case DEMUX_GET_POSITION: pf = va_arg( args, double* ); if( p_sys->i_length > 0 ) { double current = date_Get( &p_sys->pts ) - VLC_TICK_0; double length = p_sys->i_length; *pf = current / length; return VLC_SUCCESS; } return VLC_EGENERIC; case DEMUX_SET_POSITION: f = va_arg( args, double ); i64 = f * p_sys->i_length; if( i64 >= 0 && i64 <= p_sys->i_length ) { ModPlug_Seek( p_sys->f, MS_FROM_VLC_TICK(i64) ); date_Set( &p_sys->pts, VLC_TICK_0 + i64 ); return VLC_SUCCESS; } return VLC_EGENERIC; case DEMUX_GET_TIME: *va_arg( args, vlc_tick_t * ) = date_Get( &p_sys->pts ); return VLC_SUCCESS; case DEMUX_GET_LENGTH: pi64 = va_arg( args, vlc_tick_t * ); *pi64 = p_sys->i_length; return VLC_SUCCESS; case DEMUX_SET_TIME: i64 = va_arg( args, vlc_tick_t ); if( likely(i64 >= 0) && i64 <= p_sys->i_length ) { ModPlug_Seek( p_sys->f, MS_FROM_VLC_TICK( i64 ) ); date_Set( &p_sys->pts, VLC_TICK_0 + i64 ); return VLC_SUCCESS; } return VLC_EGENERIC; case DEMUX_HAS_UNSUPPORTED_META: { bool *pb_bool = va_arg( args, bool* ); *pb_bool = false; /* FIXME I am not sure of this one */ return VLC_SUCCESS; } case DEMUX_GET_META: { vlc_meta_t *p_meta = va_arg( args, vlc_meta_t * ); unsigned i_num_samples = ModPlug_NumSamples( p_sys->f ), i_num_instruments = ModPlug_NumInstruments( p_sys->f ); unsigned i_num_patterns = ModPlug_NumPatterns( p_sys->f ), i_num_channels = ModPlug_NumChannels( p_sys->f ); // unsigned modType = ModPlug_GetModuleType( p_sys->f ); char psz_temp[2048]; /* 32 * 240 max, but only need start */ char *psz_module_info, *psz_instrument_info; unsigned i_temp_index = 0; const char *psz_name = ModPlug_GetName( p_sys->f ); if( psz_name && *psz_name && IsUTF8( psz_name ) ) vlc_meta_SetTitle( p_meta, psz_name ); /* Comment field from artist - not in every type of MOD */ psz_name = ModPlug_GetMessage( p_sys->f ); if( psz_name && *psz_name && IsUTF8( psz_name ) ) vlc_meta_SetDescription( p_meta, psz_name ); /* Instruments only in newer MODs - so don't show if 0 */ if( asprintf( &psz_instrument_info, ", %i Instruments", i_num_instruments ) >= 0 ) { if( asprintf( &psz_module_info, "%i Channels, %i Patterns\n" "%i Samples%s\n", i_num_channels, i_num_patterns, i_num_samples, ( i_num_instruments ? psz_instrument_info : "" ) ) >= 0 ) { vlc_meta_AddExtra( p_meta, "Module Information", psz_module_info ); free( psz_module_info ); } free( psz_instrument_info ); } /* Make list of instruments (XM, IT, etc) */ if( i_num_instruments ) { i_temp_index = 0; for( unsigned i = 0; i < i_num_instruments && i_temp_index < sizeof(psz_temp); i++ ) { char lBuffer[33]; ModPlug_InstrumentName( p_sys->f, i, lBuffer ); if ( !lBuffer[0] || !IsUTF8( lBuffer ) ) continue; i_temp_index += snprintf( &psz_temp[i_temp_index], sizeof(psz_temp) - i_temp_index, "%s\n", lBuffer ); } vlc_meta_AddExtra( p_meta, "Instruments", psz_temp ); } /* Make list of samples */ for( unsigned int i = 0; i < i_num_samples && i_temp_index < sizeof(psz_temp); i++ ) { char psz_buffer[33]; ModPlug_SampleName( p_sys->f, i, psz_buffer ); if ( !psz_buffer[0] || !IsUTF8( psz_buffer ) ) continue; i_temp_index += snprintf( &psz_temp[i_temp_index], sizeof(psz_temp) - i_temp_index, "%s\n", psz_buffer ); } vlc_meta_AddExtra( p_meta, "Samples", psz_temp ); return VLC_SUCCESS; } case DEMUX_GET_FPS: /* meaningless */ return VLC_EGENERIC; case DEMUX_CAN_PAUSE: case DEMUX_CAN_CONTROL_PACE: case DEMUX_GET_PTS_DELAY: case DEMUX_SET_PAUSE_STATE: 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; 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; } }
static int Control( demux_t* p_demux, int i_query, va_list args ) { demux_sys_t *p_sys = p_demux->p_sys; vlc_tick_t i64; double *pf, f; bool b; switch( i_query ) { case DEMUX_CAN_SEEK: *va_arg( args, bool * ) = true; return VLC_SUCCESS; case DEMUX_GET_TIME: *va_arg( args, vlc_tick_t * ) = p_sys->i_next_demux_time; return VLC_SUCCESS; case DEMUX_SET_TIME: if( p_sys->times.i_count ) { tt_time_t t = tt_time_Create( va_arg( args, vlc_tick_t ) - VLC_TICK_0 ); size_t i_index = tt_timings_FindLowerIndex( p_sys->times.p_array, p_sys->times.i_count, t, &b ); p_sys->times.i_current = i_index; p_sys->b_first_time = true; return VLC_SUCCESS; } break; case DEMUX_SET_NEXT_DEMUX_TIME: p_sys->i_next_demux_time = va_arg( args, vlc_tick_t ); p_sys->b_slave = true; return VLC_SUCCESS; case DEMUX_GET_LENGTH: if( p_sys->times.i_count ) { tt_time_t t = tt_time_Sub( p_sys->times.p_array[p_sys->times.i_count - 1], p_sys->temporal_extent.begin ); *va_arg( args, vlc_tick_t * ) = tt_time_Convert( &t ); return VLC_SUCCESS; } break; case DEMUX_GET_POSITION: pf = va_arg( args, double * ); if( p_sys->times.i_current >= p_sys->times.i_count ) { *pf = 1.0; } else if( p_sys->times.i_count > 0 ) { i64 = tt_time_Convert( &p_sys->times.p_array[p_sys->times.i_count - 1] ); *pf = (double) p_sys->i_next_demux_time / (i64 + VLC_TICK_FROM_MS(500)); } else { *pf = 0.0; } return VLC_SUCCESS; case DEMUX_SET_POSITION: f = va_arg( args, double ); if( p_sys->times.i_count ) { i64 = f * tt_time_Convert( &p_sys->times.p_array[p_sys->times.i_count - 1] ); tt_time_t t = tt_time_Create( i64 ); size_t i_index = tt_timings_FindLowerIndex( p_sys->times.p_array, p_sys->times.i_count, t, &b ); p_sys->times.i_current = i_index; p_sys->b_first_time = true; return VLC_SUCCESS; } break; case DEMUX_CAN_PAUSE: case DEMUX_SET_PAUSE_STATE: case DEMUX_CAN_CONTROL_PACE: return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args ); case DEMUX_GET_PTS_DELAY: case DEMUX_GET_FPS: case DEMUX_GET_META: case DEMUX_GET_ATTACHMENTS: case DEMUX_GET_TITLE_INFO: case DEMUX_HAS_UNSUPPORTED_META: case DEMUX_CAN_RECORD: default: break; } return VLC_EGENERIC; }